@kontextso/sdk-react-native 0.0.4

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 ADDED
@@ -0,0 +1,1229 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ AdsContext: () => AdsContext,
34
+ AdsProvider: () => AdsProvider,
35
+ InlineAd: () => InlineAd_default,
36
+ VISITOR_ID_KEY: () => VISITOR_ID_KEY,
37
+ useAd: () => useAd
38
+ });
39
+ module.exports = __toCommonJS(src_exports);
40
+
41
+ // src/formats/InlineAd.tsx
42
+ var import_react11 = require("react");
43
+ var import_react_native5 = require("react-native");
44
+
45
+ // src/hooks/useAdViewed.tsx
46
+ var import_react5 = require("react");
47
+
48
+ // src/context/AdsProvider.tsx
49
+ var import_react4 = __toESM(require("react"));
50
+
51
+ // src/hooks/useInitializeAds.tsx
52
+ var import_react = require("react");
53
+
54
+ // src/utils.ts
55
+ var UNRETRIABLE_ERRORS = [403, 429];
56
+ var fetchWithTimeout = async (input, init) => {
57
+ const { timeout = 16e3 } = init || {};
58
+ const controller = new AbortController();
59
+ const id = setTimeout(() => controller.abort(), timeout);
60
+ try {
61
+ const response = await fetch(input, {
62
+ ...init,
63
+ signal: controller.signal
64
+ });
65
+ clearTimeout(id);
66
+ return response;
67
+ } catch (e) {
68
+ clearTimeout(id);
69
+ throw e;
70
+ }
71
+ };
72
+ var fetchRetry = async (input, init, maxRetries = 3, retryPeriod = 500) => {
73
+ let retries = 0;
74
+ let response;
75
+ let unretriableError;
76
+ while (retries < maxRetries) {
77
+ try {
78
+ response = await fetchWithTimeout(input, init);
79
+ if (UNRETRIABLE_ERRORS.includes(response.status)) {
80
+ unretriableError = new Error(response.statusText);
81
+ break;
82
+ }
83
+ if (response.ok) {
84
+ return response;
85
+ } else {
86
+ throw new Error(`Failed with status ${response.status}`);
87
+ }
88
+ } catch (error) {
89
+ retries++;
90
+ await new Promise((resolve) => setTimeout(resolve, retryPeriod));
91
+ }
92
+ }
93
+ if (unretriableError) {
94
+ throw unretriableError;
95
+ }
96
+ throw new Error("Failed to fetch after multiple retries");
97
+ };
98
+ var fixUrl = (adserverUrl, ad) => {
99
+ if (ad.content) {
100
+ ad.content = ad.content.replace("/ad/", `${adserverUrl}/ad/`);
101
+ }
102
+ return { ...ad, url: `${adserverUrl}${ad.url}` };
103
+ };
104
+ var mergeAds = ({
105
+ initAds,
106
+ preloadAds,
107
+ streamAds,
108
+ viewedAds
109
+ }) => {
110
+ const ads = [...initAds];
111
+ if (Array.isArray(preloadAds)) {
112
+ for (const ad of preloadAds) {
113
+ const index = ads.findIndex((a) => a.code === ad.code);
114
+ if (index !== -1) {
115
+ ads[index] = ad;
116
+ } else {
117
+ ads.push(ad);
118
+ }
119
+ }
120
+ }
121
+ if (Array.isArray(streamAds)) {
122
+ for (const ad of streamAds) {
123
+ const index = ads.findIndex(
124
+ (a) => a.code === ad.code && a.messageId === ad.messageId
125
+ );
126
+ if (index !== -1) {
127
+ ads[index] = ad;
128
+ } else {
129
+ ads.push(ad);
130
+ }
131
+ }
132
+ }
133
+ for (const ad of ads) {
134
+ ad.viewed = viewedAds.includes(ad?.id || "placeholder");
135
+ }
136
+ return ads;
137
+ };
138
+ function mergeStyles(propStyles, defaultStyles, overridingStyles) {
139
+ function deepMerge(target, source) {
140
+ if (typeof target !== "object" || typeof source !== "object") {
141
+ return source;
142
+ }
143
+ const result = { ...target };
144
+ for (const key in source) {
145
+ if (source.hasOwnProperty(key)) {
146
+ if (typeof source[key] === "object" && !Array.isArray(source[key])) {
147
+ result[key] = deepMerge(target[key], source[key]);
148
+ } else {
149
+ result[key] = source[key];
150
+ }
151
+ }
152
+ }
153
+ return result;
154
+ }
155
+ let mergedStyles = deepMerge({ ...defaultStyles }, propStyles || {});
156
+ mergedStyles = deepMerge(mergedStyles, overridingStyles || {});
157
+ return mergedStyles;
158
+ }
159
+ var parseMessageText = (text) => {
160
+ const parts = [];
161
+ let start = 0;
162
+ const regex = /(\*(.*?)\*)|\[([^\]]+)\]\(([^)]+)\)/g;
163
+ let match;
164
+ while ((match = regex.exec(text)) !== null) {
165
+ if (match.index > start) {
166
+ parts.push({ text: text.substring(start, match.index), textType: "normal" });
167
+ }
168
+ if (match[1]) {
169
+ const themedText = match[2];
170
+ const innerMatches = themedText.match(/\[([^\]]+)\]\(([^)]+)\)/g);
171
+ if (innerMatches) {
172
+ let innerStart = 0;
173
+ innerMatches.forEach((linkMatch) => {
174
+ const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/;
175
+ const innerLink = linkMatch.match(linkRegex);
176
+ const linkIndex = themedText.indexOf(linkMatch, innerStart);
177
+ if (linkIndex > innerStart) {
178
+ parts.push({ text: themedText.substring(innerStart, linkIndex), textType: "themed" });
179
+ }
180
+ parts.push({ text: innerLink[1], textType: "link", url: innerLink[2] });
181
+ innerStart = linkIndex + linkMatch.length;
182
+ });
183
+ if (innerStart < themedText.length) {
184
+ parts.push({ text: themedText.substring(innerStart), textType: "themed" });
185
+ }
186
+ } else {
187
+ parts.push({ text: themedText, textType: "themed" });
188
+ }
189
+ } else if (match[3] && match[4]) {
190
+ parts.push({ text: match[3], textType: "link", url: match[4] });
191
+ }
192
+ start = match.index + match[0].length;
193
+ }
194
+ if (start < text.length) {
195
+ parts.push({ text: text.substring(start), textType: "normal" });
196
+ }
197
+ return parts;
198
+ };
199
+
200
+ // src/hooks/useInitializeAds.tsx
201
+ var import_loglevel = __toESM(require("loglevel"));
202
+
203
+ // package.json
204
+ var version = "0.0.4";
205
+
206
+ // src/hooks/useInitializeAds.tsx
207
+ async function initialize(adServerUrl, publisherToken, userId, conversationId, legacyVisitorId, character) {
208
+ import_loglevel.default.log("[BRAIN] init ads started");
209
+ const response = await fetchRetry(
210
+ `${adServerUrl}/init`,
211
+ {
212
+ timeout: 1e4,
213
+ method: "POST",
214
+ body: JSON.stringify({
215
+ publisherToken,
216
+ userId,
217
+ visitorId: userId,
218
+ conversationId,
219
+ sdkVersion: `native-${version}`,
220
+ legacyVisitorId,
221
+ character
222
+ })
223
+ },
224
+ 3,
225
+ 1e3
226
+ );
227
+ const {
228
+ sessionId,
229
+ enabledPlacements,
230
+ ads,
231
+ sessionDisabled,
232
+ streamAdServer,
233
+ onlyStream,
234
+ defaultReactNativeStyles,
235
+ overridingReactNativeStyles
236
+ } = await response.json();
237
+ const fixedAds = ads.map((ad) => {
238
+ return fixUrl(adServerUrl, ad);
239
+ });
240
+ import_loglevel.default.log("[BRAIN] init ads done");
241
+ return {
242
+ sessionDisabled,
243
+ sessionId,
244
+ enabledPlacements,
245
+ ads: fixedAds,
246
+ streamAdServer,
247
+ onlyStream,
248
+ defaultReactNativeStylesResponse: defaultReactNativeStyles,
249
+ overridingReactNativeStylesResponse: overridingReactNativeStyles
250
+ };
251
+ }
252
+ function useInitializeAds({
253
+ adServerUrl,
254
+ publisherToken,
255
+ userId,
256
+ conversationId,
257
+ isDisabled,
258
+ character,
259
+ legacyVisitorId
260
+ }) {
261
+ const [enabledPlacements, setEnabledPlacements] = (0, import_react.useState)([]);
262
+ const [ads, setAds] = (0, import_react.useState)([]);
263
+ const [error, setError] = (0, import_react.useState)();
264
+ const [streamAdServerUrl, setStreamAdServerUrl] = (0, import_react.useState)();
265
+ const [onlyStream, setOnlyStream] = (0, import_react.useState)(false);
266
+ const [sessionId, setSessionId] = (0, import_react.useState)();
267
+ const [defaultReactNativeStyles, setDefaultReactNativeStyles] = (0, import_react.useState)();
268
+ const [overridingReactNativeStyles, setOverridingReactNativeStyles] = (0, import_react.useState)();
269
+ (0, import_react.useEffect)(() => {
270
+ setSessionId(void 0);
271
+ if (!isDisabled && userId) {
272
+ import_loglevel.default.debug("[BRAIN] Initializing ads.");
273
+ initialize(
274
+ adServerUrl,
275
+ publisherToken,
276
+ userId,
277
+ conversationId,
278
+ legacyVisitorId,
279
+ character
280
+ ).then(
281
+ ({
282
+ sessionId: sessionId2,
283
+ enabledPlacements: enabledPlacements2,
284
+ ads: ads2,
285
+ sessionDisabled,
286
+ streamAdServer,
287
+ onlyStream: onlyStream2,
288
+ defaultReactNativeStylesResponse,
289
+ overridingReactNativeStylesResponse
290
+ }) => {
291
+ if (!sessionDisabled) {
292
+ setSessionId(sessionId2);
293
+ setEnabledPlacements(enabledPlacements2);
294
+ setAds(ads2);
295
+ setStreamAdServerUrl(streamAdServer);
296
+ setOnlyStream(onlyStream2);
297
+ setDefaultReactNativeStyles(defaultReactNativeStylesResponse);
298
+ setOverridingReactNativeStyles(overridingReactNativeStylesResponse);
299
+ } else {
300
+ import_loglevel.default.debug("[BRAIN] Session is disabled by server.");
301
+ }
302
+ }
303
+ ).catch((e) => {
304
+ import_loglevel.default.error("[BRAIN] Error initializing ads", e);
305
+ setError(e.message);
306
+ });
307
+ } else {
308
+ import_loglevel.default.debug("[BRAIN] Ads are disabled.");
309
+ }
310
+ }, [
311
+ adServerUrl,
312
+ publisherToken,
313
+ userId,
314
+ conversationId,
315
+ isDisabled
316
+ ]);
317
+ return {
318
+ ads,
319
+ sessionId,
320
+ enabledPlacements,
321
+ error,
322
+ streamAdServerUrl,
323
+ onlyStream,
324
+ defaultReactNativeStyles,
325
+ overridingReactNativeStyles
326
+ };
327
+ }
328
+
329
+ // src/hooks/usePreloadAds.tsx
330
+ var import_react2 = require("react");
331
+ var import_loglevel2 = __toESM(require("loglevel"));
332
+ function usePreloadAds({
333
+ userId,
334
+ sessionId,
335
+ conversationId,
336
+ adserverUrl,
337
+ messages,
338
+ publisherToken,
339
+ character,
340
+ onlyStream
341
+ }) {
342
+ const [preloadDone, setPreloadDone] = (0, import_react2.useState)(false);
343
+ const [ads, setAds] = (0, import_react2.useState)([]);
344
+ const userMessagesContent = messages.filter((m) => m.role === "user").map((m) => m.content).join(" ");
345
+ (0, import_react2.useEffect)(() => {
346
+ if (onlyStream) {
347
+ setPreloadDone(true);
348
+ import_loglevel2.default.log("[BRAIN] skipping preload ads");
349
+ return;
350
+ }
351
+ async function preload() {
352
+ setPreloadDone(false);
353
+ if (!sessionId) {
354
+ return;
355
+ }
356
+ import_loglevel2.default.log("[BRAIN] preload ads started");
357
+ try {
358
+ const response = await fetchRetry(
359
+ `${adserverUrl}/preload`,
360
+ {
361
+ timeout: 1e4,
362
+ method: "POST",
363
+ body: JSON.stringify({
364
+ messages,
365
+ sessionId,
366
+ userId,
367
+ visitorId: userId,
368
+ publisherToken,
369
+ conversationId,
370
+ character,
371
+ sdkVersion: "native"
372
+ })
373
+ },
374
+ 3,
375
+ 1e3
376
+ );
377
+ const { ads: ads2 } = await response.json();
378
+ setAds((oldAds) => {
379
+ const newAds = ads2.map((ad) => fixUrl(adserverUrl, ad));
380
+ return [...oldAds, ...newAds];
381
+ });
382
+ setPreloadDone(true);
383
+ import_loglevel2.default.log("[BRAIN] preload ads finished");
384
+ } catch (e) {
385
+ import_loglevel2.default.error("[BRAIN] Error preloading ads", e);
386
+ setPreloadDone(true);
387
+ }
388
+ }
389
+ preload();
390
+ }, [sessionId, userMessagesContent, conversationId]);
391
+ return { preloadDone, ads };
392
+ }
393
+
394
+ // src/hooks/useStreamAds.tsx
395
+ var import_react3 = require("react");
396
+
397
+ // src/hooks/data-stream.ts
398
+ var textStreamPart = {
399
+ code: "0",
400
+ name: "text",
401
+ parse: (value) => {
402
+ if (typeof value !== "string") {
403
+ throw new Error('"text" parts expect a string value.');
404
+ }
405
+ return { type: "text", value };
406
+ }
407
+ };
408
+ var functionCallStreamPart = {
409
+ code: "1",
410
+ name: "function_call",
411
+ parse: (value) => {
412
+ if (value == null || typeof value !== "object" || !("function_call" in value) || typeof value.function_call !== "object" || value.function_call == null || !("name" in value.function_call) || !("arguments" in value.function_call) || typeof value.function_call.name !== "string" || typeof value.function_call.arguments !== "string") {
413
+ throw new Error(
414
+ '"function_call" parts expect an object with a "function_call" property.'
415
+ );
416
+ }
417
+ return {
418
+ type: "function_call",
419
+ value
420
+ };
421
+ }
422
+ };
423
+ var dataStreamPart = {
424
+ code: "2",
425
+ name: "data",
426
+ parse: (value) => {
427
+ if (!Array.isArray(value)) {
428
+ throw new Error('"data" parts expect an array value.');
429
+ }
430
+ return { type: "data", value };
431
+ }
432
+ };
433
+ var errorStreamPart = {
434
+ code: "3",
435
+ name: "error",
436
+ parse: (value) => {
437
+ if (typeof value !== "string") {
438
+ throw new Error('"error" parts expect a string value.');
439
+ }
440
+ return { type: "error", value };
441
+ }
442
+ };
443
+ var assistantMessageStreamPart = {
444
+ code: "4",
445
+ name: "assistant_message",
446
+ parse: (value) => {
447
+ if (value == null || typeof value !== "object" || !("id" in value) || !("role" in value) || !("content" in value) || typeof value.id !== "string" || typeof value.role !== "string" || value.role !== "assistant" || !Array.isArray(value.content) || !value.content.every(
448
+ (item) => item != null && typeof item === "object" && "type" in item && item.type === "text" && "text" in item && item.text != null && typeof item.text === "object" && "value" in item.text && typeof item.text.value === "string"
449
+ )) {
450
+ throw new Error(
451
+ '"assistant_message" parts expect an object with an "id", "role", and "content" property.'
452
+ );
453
+ }
454
+ return {
455
+ type: "assistant_message",
456
+ value
457
+ };
458
+ }
459
+ };
460
+ var assistantControlDataStreamPart = {
461
+ code: "5",
462
+ name: "assistant_control_data",
463
+ parse: (value) => {
464
+ if (value == null || typeof value !== "object" || !("threadId" in value) || !("messageId" in value) || typeof value.threadId !== "string" || typeof value.messageId !== "string") {
465
+ throw new Error(
466
+ '"assistant_control_data" parts expect an object with a "threadId" and "messageId" property.'
467
+ );
468
+ }
469
+ return {
470
+ type: "assistant_control_data",
471
+ value: {
472
+ threadId: value.threadId,
473
+ messageId: value.messageId
474
+ }
475
+ };
476
+ }
477
+ };
478
+ var dataMessageStreamPart = {
479
+ code: "6",
480
+ name: "data_message",
481
+ parse: (value) => {
482
+ if (value == null || typeof value !== "object" || !("role" in value) || !("data" in value) || typeof value.role !== "string" || value.role !== "data") {
483
+ throw new Error(
484
+ '"data_message" parts expect an object with a "role" and "data" property.'
485
+ );
486
+ }
487
+ return {
488
+ type: "data_message",
489
+ value
490
+ };
491
+ }
492
+ };
493
+ var toolCallStreamPart = {
494
+ code: "7",
495
+ name: "tool_calls",
496
+ parse: (value) => {
497
+ if (value == null || typeof value !== "object" || !("tool_calls" in value) || typeof value.tool_calls !== "object" || value.tool_calls == null || !Array.isArray(value.tool_calls) || value.tool_calls.some((tc) => {
498
+ tc == null || typeof tc !== "object" || !("id" in tc) || typeof tc.id !== "string" || !("type" in tc) || typeof tc.type !== "string" || !("function" in tc) || tc.function == null || typeof tc.function !== "object" || !("arguments" in tc.function) || typeof tc.function.name !== "string" || typeof tc.function.arguments !== "string";
499
+ })) {
500
+ throw new Error(
501
+ '"tool_calls" parts expect an object with a ToolCallPayload.'
502
+ );
503
+ }
504
+ return {
505
+ type: "tool_calls",
506
+ value
507
+ };
508
+ }
509
+ };
510
+ var messageAnnotationsStreamPart = {
511
+ code: "8",
512
+ name: "message_annotations",
513
+ parse: (value) => {
514
+ if (!Array.isArray(value)) {
515
+ throw new Error('"message_annotations" parts expect an array value.');
516
+ }
517
+ return { type: "message_annotations", value };
518
+ }
519
+ };
520
+ var streamParts = [
521
+ textStreamPart,
522
+ functionCallStreamPart,
523
+ dataStreamPart,
524
+ errorStreamPart,
525
+ assistantMessageStreamPart,
526
+ assistantControlDataStreamPart,
527
+ dataMessageStreamPart,
528
+ toolCallStreamPart,
529
+ messageAnnotationsStreamPart
530
+ ];
531
+ var streamPartsByCode = {
532
+ [textStreamPart.code]: textStreamPart,
533
+ [functionCallStreamPart.code]: functionCallStreamPart,
534
+ [dataStreamPart.code]: dataStreamPart,
535
+ [errorStreamPart.code]: errorStreamPart,
536
+ [assistantMessageStreamPart.code]: assistantMessageStreamPart,
537
+ [assistantControlDataStreamPart.code]: assistantControlDataStreamPart,
538
+ [dataMessageStreamPart.code]: dataMessageStreamPart,
539
+ [toolCallStreamPart.code]: toolCallStreamPart,
540
+ [messageAnnotationsStreamPart.code]: messageAnnotationsStreamPart
541
+ };
542
+ var StreamStringPrefixes = {
543
+ [textStreamPart.name]: textStreamPart.code,
544
+ [functionCallStreamPart.name]: functionCallStreamPart.code,
545
+ [dataStreamPart.name]: dataStreamPart.code,
546
+ [errorStreamPart.name]: errorStreamPart.code,
547
+ [assistantMessageStreamPart.name]: assistantMessageStreamPart.code,
548
+ [assistantControlDataStreamPart.name]: assistantControlDataStreamPart.code,
549
+ [dataMessageStreamPart.name]: dataMessageStreamPart.code,
550
+ [toolCallStreamPart.name]: toolCallStreamPart.code,
551
+ [messageAnnotationsStreamPart.name]: messageAnnotationsStreamPart.code
552
+ };
553
+ var validCodes = streamParts.map((part) => part.code);
554
+ var parseStreamPart = (line) => {
555
+ const firstSeparatorIndex = line.indexOf(":");
556
+ if (firstSeparatorIndex === -1) {
557
+ throw new Error("Failed to parse stream string. No separator found.");
558
+ }
559
+ const prefix = line.slice(0, firstSeparatorIndex);
560
+ if (!validCodes.includes(prefix)) {
561
+ throw new Error(`Failed to parse stream string. Invalid code ${prefix}.`);
562
+ }
563
+ const code = prefix;
564
+ const textValue = line.slice(firstSeparatorIndex + 1);
565
+ const any = JSON.parse(textValue);
566
+ return streamPartsByCode[code].parse(any);
567
+ };
568
+ var NEWLINE = "\n".charCodeAt(0);
569
+ function concatChunks(chunks, totalLength) {
570
+ const concatenatedChunks = new Uint8Array(totalLength);
571
+ let offset = 0;
572
+ for (const chunk of chunks) {
573
+ concatenatedChunks.set(chunk, offset);
574
+ offset += chunk.length;
575
+ }
576
+ chunks.length = 0;
577
+ return concatenatedChunks;
578
+ }
579
+ async function* readDataStream(reader, {
580
+ isAborted
581
+ } = {}) {
582
+ const decoder = new TextDecoder();
583
+ const chunks = [];
584
+ let totalLength = 0;
585
+ while (true) {
586
+ const { value } = await reader.read();
587
+ if (value) {
588
+ chunks.push(value);
589
+ totalLength += value.length;
590
+ if (value[value.length - 1] !== NEWLINE) {
591
+ continue;
592
+ }
593
+ }
594
+ if (chunks.length === 0) {
595
+ break;
596
+ }
597
+ const concatenatedChunks = concatChunks(chunks, totalLength);
598
+ totalLength = 0;
599
+ const streamParts2 = decoder.decode(concatenatedChunks, { stream: true }).split("\n").filter((line) => line !== "").map(parseStreamPart);
600
+ let i = 0;
601
+ for (const streamPart of streamParts2) {
602
+ if (!(i % 5)) {
603
+ await new Promise((resolve) => setTimeout(resolve));
604
+ }
605
+ i++;
606
+ yield streamPart;
607
+ }
608
+ if (isAborted?.()) {
609
+ reader.cancel();
610
+ break;
611
+ }
612
+ }
613
+ }
614
+
615
+ // src/hooks/useStreamAds.tsx
616
+ var import_encoding = require("react-native-polyfill-globals/src/encoding");
617
+ var import_readable_stream = require("react-native-polyfill-globals/src/readable-stream");
618
+ var import_react_native = require("react-native");
619
+ var import_loglevel3 = __toESM(require("loglevel"));
620
+ var patchFetch = fetch;
621
+ if (import_react_native.Platform.OS !== "web") {
622
+ (0, import_encoding.polyfill)();
623
+ (0, import_readable_stream.polyfill)();
624
+ patchFetch = require("react-native-fetch-api").fetch;
625
+ }
626
+ ErrorUtils.setGlobalHandler((error, isFatal) => {
627
+ import_loglevel3.default.error(error);
628
+ });
629
+ function useStreamAds({
630
+ userId,
631
+ sessionId,
632
+ conversationId,
633
+ adserverUrl,
634
+ messages,
635
+ isLoading,
636
+ preloadDone,
637
+ enabledPlacements,
638
+ character,
639
+ publisherToken
640
+ }) {
641
+ const [ads, setAds] = (0, import_react3.useState)([]);
642
+ const fetchStream = async (messages2, code) => {
643
+ const lastAssistantMessage = [...messages2].reverse().find((m) => m.role === "assistant");
644
+ if (!lastAssistantMessage) {
645
+ return;
646
+ }
647
+ setAds((oldAds) => {
648
+ const newAds = [...oldAds];
649
+ newAds.push({
650
+ isLoading: true,
651
+ code,
652
+ messageId: lastAssistantMessage.id
653
+ });
654
+ return newAds;
655
+ });
656
+ const body = JSON.stringify({
657
+ userId,
658
+ visitorId: userId,
659
+ sessionId,
660
+ code,
661
+ messages: messages2,
662
+ publisherToken,
663
+ character,
664
+ conversationId,
665
+ sdkVersion: "native"
666
+ });
667
+ try {
668
+ const response = await patchFetch(`${adserverUrl}/stream`, {
669
+ method: "POST",
670
+ body,
671
+ headers: {
672
+ "Content-Type": "application/json"
673
+ },
674
+ reactNative: { textStreaming: true }
675
+ });
676
+ if (!response.ok) {
677
+ throw new Error("Error streaming ad");
678
+ }
679
+ if (!response.body) {
680
+ throw new Error("Response body is not a readable stream");
681
+ }
682
+ setAds(
683
+ (oldAds) => oldAds.map((ad) => ad.messageId === lastAssistantMessage.id && ad.code === code ? { ...ad, isLoading: false, isStreaming: true } : ad)
684
+ );
685
+ let data = "";
686
+ let adData = {};
687
+ import_loglevel3.default.log(`[BRAIN] streaming ${code} ad started`);
688
+ const reader = response.body.getReader();
689
+ for await (const { type, value } of readDataStream(reader)) {
690
+ switch (type) {
691
+ case "text":
692
+ data += value;
693
+ break;
694
+ case "data": {
695
+ let val = value;
696
+ if (Array.isArray(val)) {
697
+ val = val[0];
698
+ }
699
+ adData = { ...adData, ...val };
700
+ break;
701
+ }
702
+ case "error":
703
+ throw new Error(`Error streaming ad ${value}`);
704
+ }
705
+ setAds(
706
+ (oldAds) => oldAds.map((ad) => {
707
+ if (ad.messageId === lastAssistantMessage.id && ad.code === code) {
708
+ const content = adData.content ?? data;
709
+ const newAd = fixUrl(adserverUrl, {
710
+ ...ad,
711
+ ...adData,
712
+ isLoading: false,
713
+ isStreaming: true,
714
+ content: content.replace(
715
+ new RegExp(`/ad/${adData.product.id}/redirect`, "g"),
716
+ `/ad/${adData.id}/redirect`
717
+ )
718
+ });
719
+ return newAd;
720
+ }
721
+ return ad;
722
+ })
723
+ );
724
+ }
725
+ setAds(
726
+ (oldAds) => oldAds.map(
727
+ (ad) => ad.messageId === lastAssistantMessage.id && ad.code === code ? { ...ad, isStreaming: false } : ad
728
+ )
729
+ );
730
+ import_loglevel3.default.log(`[BRAIN] streaming ${code} ad done`);
731
+ } catch (e) {
732
+ import_loglevel3.default.error("[BRAIN] Error streaming ad", e);
733
+ setAds((oldAds) => [...oldAds, { isError: true, code }]);
734
+ }
735
+ };
736
+ (0, import_react3.useEffect)(() => {
737
+ if (!isLoading && sessionId && messages.length > 2 && messages[messages.length - 1]?.role === "assistant" && preloadDone) {
738
+ enabledPlacements.forEach((placement) => {
739
+ if (["QUERY_STREAM", "INLINE_AD", "BOX_AD"].includes(placement.format)) {
740
+ fetchStream(messages, String(placement.code));
741
+ }
742
+ });
743
+ }
744
+ }, [isLoading, preloadDone, sessionId, messages[messages.length - 1]?.role]);
745
+ return { ads };
746
+ }
747
+
748
+ // src/context/AdsProvider.tsx
749
+ var import_loglevel4 = __toESM(require("loglevel"));
750
+ var import_jsx_runtime = require("react/jsx-runtime");
751
+ var AdsContext = import_react4.default.createContext(null);
752
+ AdsContext.displayName = "AdsContext";
753
+ var VISITOR_ID_KEY = "brain-visitor-id";
754
+ var AdsProvider = ({
755
+ children,
756
+ messages,
757
+ publisherToken,
758
+ isLoading,
759
+ adserverUrl,
760
+ isDisabled,
761
+ character,
762
+ conversationId,
763
+ userId,
764
+ logLevel,
765
+ onAdView,
766
+ onAdClick,
767
+ ...props
768
+ }) => {
769
+ const [viewedAds, setViewedAds] = (0, import_react4.useState)([]);
770
+ const adServerUrlOrDefault = adserverUrl || "https://server.megabrain.co";
771
+ import_loglevel4.default.setLevel(logLevel || "ERROR");
772
+ const {
773
+ ads: initAds,
774
+ sessionId,
775
+ enabledPlacements,
776
+ error,
777
+ streamAdServerUrl,
778
+ onlyStream,
779
+ defaultReactNativeStyles,
780
+ overridingReactNativeStyles
781
+ } = useInitializeAds({
782
+ adServerUrl: adServerUrlOrDefault,
783
+ publisherToken,
784
+ userId,
785
+ legacyVisitorId: void 0,
786
+ conversationId,
787
+ character,
788
+ isDisabled: !!isDisabled
789
+ });
790
+ const styles = mergeStyles(props.styles, defaultReactNativeStyles, overridingReactNativeStyles);
791
+ const isInitialised = !!isDisabled || !!error || !!sessionId;
792
+ const { preloadDone, ads: preloadAds } = usePreloadAds({
793
+ sessionId,
794
+ adserverUrl: adServerUrlOrDefault,
795
+ messages,
796
+ publisherToken,
797
+ conversationId,
798
+ userId,
799
+ character,
800
+ onlyStream
801
+ });
802
+ const { ads: streamAds } = useStreamAds({
803
+ userId,
804
+ sessionId,
805
+ adserverUrl: onlyStream && streamAdServerUrl ? streamAdServerUrl : adServerUrlOrDefault,
806
+ conversationId,
807
+ messages,
808
+ isLoading,
809
+ character,
810
+ preloadDone,
811
+ enabledPlacements,
812
+ publisherToken
813
+ });
814
+ const ads = mergeAds({ initAds, preloadAds, streamAds, viewedAds });
815
+ const markAdAsViewed = (ad) => {
816
+ import_loglevel4.default.debug("[Brain] Calling onAdView");
817
+ onAdView && onAdView({
818
+ id: ad.id,
819
+ code: ad.code,
820
+ messageId: ad.messageId,
821
+ content: ad.content
822
+ });
823
+ if (!ad.id) return;
824
+ if (viewedAds.includes(ad.id)) return;
825
+ setViewedAds((old) => [...old, ad.id]);
826
+ };
827
+ const onAdClickInternal = (ad) => {
828
+ import_loglevel4.default.debug("[Brain] Calling onAdClick");
829
+ onAdClick && onAdClick({
830
+ id: ad.id,
831
+ code: ad.code,
832
+ messageId: ad.messageId,
833
+ content: ad.content
834
+ });
835
+ };
836
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
837
+ AdsContext.Provider,
838
+ {
839
+ value: {
840
+ adserverUrl: adServerUrlOrDefault,
841
+ streamAdServerUrl,
842
+ children,
843
+ messages,
844
+ publisherToken,
845
+ isLoading,
846
+ ads,
847
+ sessionId,
848
+ isInitialised,
849
+ isDisabled,
850
+ onAdClickInternal,
851
+ enabledPlacements,
852
+ userId,
853
+ markAdAsViewed,
854
+ onlyStream,
855
+ styles
856
+ },
857
+ children
858
+ }
859
+ );
860
+ };
861
+
862
+ // src/hooks/useAdViewed.tsx
863
+ var import_react6 = require("react");
864
+ var import_loglevel5 = __toESM(require("loglevel"));
865
+ function useAdViewed(ad) {
866
+ const context = (0, import_react6.useContext)(AdsContext);
867
+ const [stillMounted, setStillMounted] = (0, import_react5.useState)(false);
868
+ const sendRequest = async () => {
869
+ if (!context?.adserverUrl || !ad?.id) {
870
+ return;
871
+ }
872
+ context.markAdAsViewed(ad);
873
+ let serverUrl = context.adserverUrl;
874
+ if (context.onlyStream && context.streamAdServerUrl) {
875
+ serverUrl = context.streamAdServerUrl;
876
+ }
877
+ try {
878
+ const response = await fetch(`${serverUrl}/ad/${ad.id}/view`, {
879
+ method: "POST"
880
+ });
881
+ if (!response.ok) {
882
+ throw new Error("Error sending view request");
883
+ }
884
+ import_loglevel5.default.log("[BRAIN] ad marked as viewed", ad.id, ad.code);
885
+ } catch (e) {
886
+ import_loglevel5.default.error("[BRAIN] Error sending view request", e);
887
+ }
888
+ };
889
+ (0, import_react5.useEffect)(() => {
890
+ if (!ad || ad.isError || ad.isLoading || ad.isStreaming || ad.viewed || stillMounted) {
891
+ return;
892
+ }
893
+ import_loglevel5.default.log("[BRAIN] setting timeout", ad.id, ad.code);
894
+ setTimeout(() => {
895
+ import_loglevel5.default.log("[BRAIN] setting setStillMounted", ad.id, ad.code);
896
+ setStillMounted(true);
897
+ }, 1e3);
898
+ }, [ad]);
899
+ (0, import_react5.useEffect)(() => {
900
+ if (stillMounted) {
901
+ import_loglevel5.default.log("[BRAIN] sending request");
902
+ sendRequest();
903
+ }
904
+ }, [stillMounted]);
905
+ }
906
+
907
+ // src/formats/InlineAd.tsx
908
+ var import_loglevel8 = __toESM(require("loglevel"));
909
+
910
+ // src/components/MarkdownText.tsx
911
+ var import_loglevel6 = __toESM(require("loglevel"));
912
+ var import_react7 = require("react");
913
+ var import_react_native2 = require("react-native");
914
+ var import_jsx_runtime2 = require("react/jsx-runtime");
915
+ function MarkdownText({
916
+ content,
917
+ onLinkClick
918
+ }) {
919
+ const context = (0, import_react7.useContext)(AdsContext);
920
+ const textParts = parseMessageText(content);
921
+ const styles = context?.styles?.markdownText;
922
+ const linkClickHandler = (href) => {
923
+ onLinkClick();
924
+ import_react_native2.Linking.openURL(href).catch(
925
+ (err) => import_loglevel6.default.error("Failed to open URL:", err)
926
+ );
927
+ return false;
928
+ };
929
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: textParts.map((t, i) => {
930
+ if (t.textType === "link") {
931
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
932
+ import_react_native2.Text,
933
+ {
934
+ style: styles?.link,
935
+ onPress: () => {
936
+ linkClickHandler(t.url);
937
+ },
938
+ children: t.text
939
+ },
940
+ i + "link"
941
+ );
942
+ } else if (t.textType === "themed") {
943
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles?.em, children: t.text }, i + "em");
944
+ } else {
945
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles?.normal, children: t.text }, i + "normal");
946
+ }
947
+ }) });
948
+ }
949
+
950
+ // src/components/VideoPlayer.tsx
951
+ var import_expo_av = require("expo-av");
952
+ var import_loglevel7 = __toESM(require("loglevel"));
953
+ var import_react9 = require("react");
954
+ var import_react_native4 = require("react-native");
955
+
956
+ // src/components/VideoProgressBar.tsx
957
+ var import_react8 = require("react");
958
+ var import_react_native3 = require("react-native");
959
+ var import_jsx_runtime3 = require("react/jsx-runtime");
960
+ function VideoProgressBar({ videoRef }) {
961
+ const [progress, setProgress] = (0, import_react8.useState)(0);
962
+ const styles = (0, import_react8.useContext)(AdsContext)?.styles?.videoPlayer?.videoProgress;
963
+ (0, import_react8.useEffect)(() => {
964
+ const interval = setInterval(() => {
965
+ if (!videoRef.current) {
966
+ return;
967
+ }
968
+ videoRef.current.getStatusAsync().then((status) => {
969
+ if (status.isLoaded) {
970
+ const currentTime = status.positionMillis;
971
+ const duration = status.durationMillis;
972
+ const percentage = currentTime / duration * 100;
973
+ setProgress(percentage);
974
+ }
975
+ });
976
+ }, 1e3);
977
+ return () => clearInterval(interval);
978
+ }, [videoRef.current]);
979
+ 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}%` }] }) });
980
+ }
981
+
982
+ // src/components/VideoPlayer.tsx
983
+ var import_jsx_runtime4 = require("react/jsx-runtime");
984
+ var VideoPlayer = ({
985
+ src,
986
+ onProgress,
987
+ endText,
988
+ badgeText,
989
+ videoPosterUrl,
990
+ videoOrientation,
991
+ ctaText,
992
+ clickUrl,
993
+ mediaPlacement,
994
+ onLinkClick
995
+ }) => {
996
+ const videoRef = (0, import_react9.useRef)(null);
997
+ const [isPlaying, setIsPlaying] = (0, import_react9.useState)(false);
998
+ const [isPaused, setIsPaused] = (0, import_react9.useState)(true);
999
+ const [isEnded, setIsEnded] = (0, import_react9.useState)(false);
1000
+ const [showDownloadBadge, setShowDownloadBadge] = (0, import_react9.useState)(false);
1001
+ const lastCallbackTimeRef = (0, import_react9.useRef)(0);
1002
+ const styles = (0, import_react9.useContext)(AdsContext)?.styles?.videoPlayer;
1003
+ (0, import_react9.useEffect)(() => {
1004
+ const interval = setInterval(() => {
1005
+ if (videoRef.current) {
1006
+ videoRef.current.getStatusAsync().then((status) => {
1007
+ if (status.isLoaded) {
1008
+ const progress = status.positionMillis / status.durationMillis * 100;
1009
+ const now = Date.now();
1010
+ if (now - lastCallbackTimeRef.current >= 3e3) {
1011
+ lastCallbackTimeRef.current = now;
1012
+ onProgress(progress);
1013
+ }
1014
+ if (status.positionMillis >= 5e3 && !showDownloadBadge) {
1015
+ setShowDownloadBadge(true);
1016
+ }
1017
+ }
1018
+ });
1019
+ }
1020
+ }, 1e3);
1021
+ return () => clearInterval(interval);
1022
+ }, [showDownloadBadge]);
1023
+ const handlePlayPause = () => {
1024
+ if (videoRef.current) {
1025
+ if (isPlaying) {
1026
+ videoRef.current.pauseAsync();
1027
+ setIsPaused(true);
1028
+ handleLinkClick(clickUrl);
1029
+ } else {
1030
+ videoRef.current.playAsync();
1031
+ setIsPaused(false);
1032
+ setIsEnded(false);
1033
+ }
1034
+ setIsPlaying(!isPlaying);
1035
+ }
1036
+ };
1037
+ const handleBadgeClick = () => {
1038
+ if (isPlaying) {
1039
+ videoRef.current?.pauseAsync();
1040
+ setIsPaused(true);
1041
+ setIsPlaying(false);
1042
+ }
1043
+ handleLinkClick(clickUrl);
1044
+ };
1045
+ const handleLinkClick = (url) => {
1046
+ if (url) {
1047
+ import_react_native4.Linking.openURL(url).catch((err) => import_loglevel7.default.error("Failed to open URL:", err));
1048
+ onLinkClick();
1049
+ }
1050
+ };
1051
+ const handleEnded = () => {
1052
+ setIsPlaying(false);
1053
+ setIsEnded(true);
1054
+ setIsPaused(false);
1055
+ onProgress(100);
1056
+ };
1057
+ 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: [
1058
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1059
+ import_expo_av.Video,
1060
+ {
1061
+ ref: videoRef,
1062
+ source: { uri: src },
1063
+ resizeMode: import_expo_av.ResizeMode.CONTAIN,
1064
+ shouldPlay: false,
1065
+ onTouchStart: handlePlayPause,
1066
+ style: videoOrientation === "horizontal" ? styles?.videoInnerContainerHorizontal : styles?.videoInnerContainerVertical,
1067
+ videoStyle: videoOrientation === "horizontal" ? styles?.videoElementHorizontal : styles?.videoElementVertical,
1068
+ onPlaybackStatusUpdate: (status) => {
1069
+ if (status.isLoaded && status.didJustFinish && !status.isLooping) {
1070
+ handleEnded();
1071
+ }
1072
+ }
1073
+ }
1074
+ ),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VideoProgressBar, { videoRef }),
1076
+ !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" }) }),
1077
+ (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 }) }),
1078
+ isEnded && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: styles?.endOverlay, children: [
1079
+ /* @__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 }) }),
1080
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: styles?.endText, children: endText })
1081
+ ] })
1082
+ ] });
1083
+ };
1084
+
1085
+ // src/hooks/useAd.tsx
1086
+ var import_react10 = require("react");
1087
+ function useAd({ code, messageId }) {
1088
+ const context = (0, import_react10.useContext)(AdsContext);
1089
+ if (!context) {
1090
+ return null;
1091
+ }
1092
+ const ad = context.ads.find((ad2) => {
1093
+ if (messageId) {
1094
+ return ad2.code === code && ad2.messageId === messageId;
1095
+ }
1096
+ return ad2.code === code;
1097
+ });
1098
+ if (!ad) {
1099
+ return null;
1100
+ }
1101
+ const placement = context.enabledPlacements.find((p) => p.code === code);
1102
+ if (!placement) {
1103
+ return null;
1104
+ }
1105
+ const dependencies = placement.config.dependencies?.split(",").map((d) => d.trim()).filter((d) => d);
1106
+ if (!dependencies || dependencies.length === 0) {
1107
+ return ad;
1108
+ }
1109
+ const dependencyAds = context.enabledPlacements.filter(
1110
+ (p) => dependencies.includes(p.code)
1111
+ );
1112
+ if (!dependencyAds.length) {
1113
+ return ad;
1114
+ }
1115
+ const allAdsLoadedAndNotStreaming = dependencyAds.every((p) => {
1116
+ let a;
1117
+ if (messageId) {
1118
+ a = context.ads.find(
1119
+ (ad2) => ad2.code === p.code && ad2.messageId === messageId
1120
+ );
1121
+ } else {
1122
+ a = context.ads.find((ad2) => ad2.code === p.code);
1123
+ }
1124
+ return a && !a.isLoading && !a.isStreaming || a && a.isError;
1125
+ });
1126
+ if (!allAdsLoadedAndNotStreaming) {
1127
+ return null;
1128
+ }
1129
+ return ad;
1130
+ }
1131
+
1132
+ // src/formats/InlineAd.tsx
1133
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1134
+ var InlineAd = ({ code, messageId, wrapper }) => {
1135
+ const ad = useAd({ code, messageId });
1136
+ const [linkIncluded, setLinkIncluded] = (0, import_react11.useState)(false);
1137
+ const context = (0, import_react11.useContext)(AdsContext);
1138
+ const styles = context?.styles?.inlineAd;
1139
+ useAdViewed(ad);
1140
+ (0, import_react11.useEffect)(() => {
1141
+ if (ad?.content && !ad.isStreaming && !ad.content.match(/\[.*?\]\(.*?\)/) && !linkIncluded) {
1142
+ setLinkIncluded(true);
1143
+ }
1144
+ }, [ad]);
1145
+ if (!ad || !ad.content || context?.isDisabled) return null;
1146
+ if (ad.isLoading || ad.content?.trim().toLowerCase().includes("none"))
1147
+ return null;
1148
+ const onProgress = (progress) => {
1149
+ import_loglevel8.default.log(`Progress: ${progress}`);
1150
+ };
1151
+ const handleImageClick = (url) => {
1152
+ if (url) {
1153
+ context?.onAdClickInternal(ad);
1154
+ if (import_react_native5.Platform.OS === "web") {
1155
+ window.open(url, "_blank");
1156
+ } else {
1157
+ import_react_native5.Linking.openURL(url).catch(
1158
+ (err) => import_loglevel8.default.error("Failed to open URL:", err)
1159
+ );
1160
+ }
1161
+ }
1162
+ };
1163
+ const content = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles?.container, children: [
1164
+ /* @__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" }) }),
1165
+ ad.imageUrl && ad.mediaPlacement === "top" && !ad.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1166
+ import_react_native5.TouchableOpacity,
1167
+ {
1168
+ style: styles?.imageContainer,
1169
+ onPress: () => handleImageClick(ad.url),
1170
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Image, { source: { uri: ad.imageUrl }, style: styles?.image })
1171
+ }
1172
+ ),
1173
+ ad.videoUrl && ad.mediaPlacement === "top" && !ad.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1174
+ VideoPlayer,
1175
+ {
1176
+ src: ad.videoUrl,
1177
+ onProgress,
1178
+ endText: ad.videoEndText,
1179
+ badgeText: ad.videoBadgeText,
1180
+ videoPosterUrl: ad.videoPosterUrl,
1181
+ videoOrientation: ad.videoOrientation,
1182
+ mediaPlacement: ad.mediaPlacement,
1183
+ ctaText: ad.videoCtaText,
1184
+ onLinkClick: () => context?.onAdClickInternal(ad),
1185
+ clickUrl: ad.url
1186
+ }
1187
+ ),
1188
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: styles?.contentContainer, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1189
+ MarkdownText,
1190
+ {
1191
+ onLinkClick: () => context?.onAdClickInternal(ad),
1192
+ content: ad.content
1193
+ }
1194
+ ) }),
1195
+ ad.imageUrl && ad.mediaPlacement === "bottom" && !ad.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1196
+ import_react_native5.TouchableOpacity,
1197
+ {
1198
+ style: styles?.imageContainer,
1199
+ onPress: () => handleImageClick(ad.url),
1200
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Image, { source: { uri: ad.imageUrl }, style: styles?.image })
1201
+ }
1202
+ ),
1203
+ ad.videoUrl && ad.mediaPlacement === "bottom" && !ad.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1204
+ VideoPlayer,
1205
+ {
1206
+ src: ad.videoUrl,
1207
+ onProgress,
1208
+ endText: ad.videoEndText,
1209
+ badgeText: ad.videoBadgeText,
1210
+ videoPosterUrl: ad.videoPosterUrl,
1211
+ videoOrientation: ad.videoOrientation,
1212
+ mediaPlacement: ad.mediaPlacement,
1213
+ ctaText: ad.videoCtaText,
1214
+ onLinkClick: () => context?.onAdClickInternal(ad),
1215
+ clickUrl: ad.url
1216
+ }
1217
+ )
1218
+ ] });
1219
+ return wrapper ? wrapper(content) : content;
1220
+ };
1221
+ var InlineAd_default = InlineAd;
1222
+ // Annotate the CommonJS export names for ESM import in node:
1223
+ 0 && (module.exports = {
1224
+ AdsContext,
1225
+ AdsProvider,
1226
+ InlineAd,
1227
+ VISITOR_ID_KEY,
1228
+ useAd
1229
+ });