@kontextso/sdk-react-native 4.0.0-rc.3 → 4.0.0-rc.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.mjs CHANGED
@@ -151,373 +151,20 @@ var InlineAd = ({ messageId, session, onDebugEvent }) => {
151
151
  );
152
152
  };
153
153
 
154
- // src/Configuration.ts
155
- var DEFAULT_AD_SERVER_URL = "https://server.megabrain.co";
156
- var DEFAULT_PLACEMENT_CODE = "inlineAd";
157
- var DEFAULT_LOG_LEVEL = "info";
158
- var Configuration = class {
159
- config;
160
- constructor(config) {
161
- this.config = config;
162
- }
163
- get publisherToken() {
164
- return this.config.publisherToken;
165
- }
166
- get userId() {
167
- return this.config.userId;
168
- }
169
- get conversationId() {
170
- return this.config.conversationId;
171
- }
172
- get character() {
173
- return this.config.character;
174
- }
175
- get placementCode() {
176
- return this.config.placementCode ?? DEFAULT_PLACEMENT_CODE;
177
- }
178
- get variantId() {
179
- return this.config.variantId;
180
- }
181
- get regulatory() {
182
- return this.config.regulatory;
183
- }
184
- get logLevel() {
185
- return this.config.logLevel ?? DEFAULT_LOG_LEVEL;
186
- }
187
- get userEmail() {
188
- return this.config.userEmail;
189
- }
190
- get adServerUrl() {
191
- return this.config.adServerUrl ?? DEFAULT_AD_SERVER_URL;
192
- }
193
- };
194
-
195
- // src/Logger.ts
196
- var Logger = class {
197
- localLevel = "log";
198
- remoteLevel = "error";
199
- remoteConfig = null;
200
- levels = {
201
- debug: 0,
202
- info: 1,
203
- log: 2,
204
- warn: 3,
205
- error: 4,
206
- silent: 5
207
- };
208
- getLocalLevel() {
209
- return this.localLevel;
210
- }
211
- setLocalLevel(level) {
212
- this.localLevel = level;
213
- }
214
- getRemoteLevel() {
215
- return this.remoteLevel;
216
- }
217
- setRemoteLevel(level) {
218
- this.remoteLevel = level;
219
- }
220
- configureRemote(url, params) {
221
- this.remoteConfig = { url, params };
222
- }
223
- shouldLog(level, targetLevel) {
224
- if (targetLevel === "silent") {
225
- return false;
226
- }
227
- return this.levels[level] >= this.levels[targetLevel];
228
- }
229
- logToConsole(level, ...args) {
230
- if (this.shouldLog(level, this.localLevel)) {
231
- if (level === "silent") {
232
- return;
233
- }
234
- console[level](...args);
235
- }
236
- }
237
- logToRemote(level, ...args) {
238
- if (this.remoteConfig && this.shouldLog(level, this.remoteLevel)) {
239
- fetch(`${this.remoteConfig.url}/log`, {
240
- method: "POST",
241
- body: JSON.stringify({
242
- ...this.remoteConfig.params,
243
- level,
244
- message: args,
245
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
246
- })
247
- }).catch((e) => {
248
- });
249
- }
250
- }
251
- debug(...args) {
252
- this.logToConsole("debug", ...args);
253
- this.logToRemote("debug", ...args);
254
- }
255
- info(...args) {
256
- this.logToConsole("info", ...args);
257
- this.logToRemote("info", ...args);
258
- }
259
- log(...args) {
260
- this.logToConsole("log", ...args);
261
- this.logToRemote("log", ...args);
262
- }
263
- warn(...args) {
264
- this.logToConsole("warn", ...args);
265
- this.logToRemote("warn", ...args);
266
- }
267
- error(...args) {
268
- this.logToConsole("error", ...args);
269
- this.logToRemote("error", ...args);
270
- }
271
- };
272
-
273
- // src/utils/request.ts
274
- async function fetchWithRetry(url, options = {}) {
275
- const { retry = {}, timeout, abortController: abortControllerOption, ...fetchOptions } = options;
276
- const maxRetries = retry.maxRetries ?? 3;
277
- const baseDelay = retry.baseDelay ?? 1e3;
278
- const backoffFactor = retry.backoffFactor ?? 2;
279
- const abortController = abortControllerOption || new AbortController();
280
- fetchOptions.signal = abortController.signal;
281
- let timeoutId = null;
282
- if (timeout) {
283
- timeoutId = setTimeout(() => abortController.abort("timeout"), timeout);
284
- }
285
- let lastError = null;
286
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
287
- try {
288
- const response = await fetch(url, fetchOptions);
289
- if (response.status >= 500 || response.status === 429) {
290
- const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
291
- error.status = response.status;
292
- throw error;
293
- }
294
- return response;
295
- } catch (error) {
296
- if (abortController.signal.aborted) {
297
- throw new Error(`Fetch aborted: ${abortController.signal.reason}`);
298
- }
299
- lastError = error instanceof Error ? error : new Error("Unknown error");
300
- const shouldRetry = error instanceof TypeError || // Network error
301
- error.status >= 500 || // Server error
302
- error.status === 429;
303
- if (attempt === maxRetries || !shouldRetry) {
304
- break;
305
- }
306
- const delay = baseDelay * backoffFactor ** attempt;
307
- await new Promise((resolve) => setTimeout(resolve, delay));
308
- } finally {
309
- if (timeoutId) {
310
- clearTimeout(timeoutId);
311
- }
312
- }
313
- }
314
- throw lastError;
315
- }
316
-
317
- // src/Preload.ts
318
- var Preload = class {
319
- session;
320
- messages = [];
321
- abortController;
322
- running = false;
323
- bid = null;
324
- constructor(session, messages) {
325
- this.session = session;
326
- this.abortController = new AbortController();
327
- this.setMessages(messages);
328
- }
329
- setMessages(messages) {
330
- this.messages = messages;
331
- }
332
- hasBid() {
333
- return this.bid !== null;
334
- }
335
- getBid() {
336
- return this.bid;
337
- }
338
- setBid(bid) {
339
- this.bid = bid;
340
- }
341
- cancel() {
342
- this.abortController.abort();
343
- this.running = false;
344
- }
345
- isRunning() {
346
- return this.running;
347
- }
348
- /*
349
- private async getDevice () {
350
- try {
351
- return await getDevice()
352
- } catch (error) {
353
- this.session.logger.error('Error getting device:', error)
354
- return {} as DeviceConfig
355
- }
356
- }
357
- */
358
- async getPreloadBody() {
359
- const config = this.session.config;
360
- const preloadBody = {
361
- messages: this.messages,
362
- sessionId: this.session.getSessionId(),
363
- publisherToken: config.publisherToken,
364
- userId: config.userId,
365
- userEmail: config.userEmail,
366
- conversationId: config.conversationId,
367
- character: config.character,
368
- enabledPlacementCodes: [config.placementCode],
369
- variantId: config.variantId,
370
- regulatory: config.regulatory,
371
- sdk: this.session.sdk
372
- };
373
- return preloadBody;
374
- }
375
- canRequestAd() {
376
- if (this.session.isSessionDisabled()) {
377
- return {
378
- status: "error",
379
- message: "Session is disabled"
380
- };
381
- }
382
- if (!this.messages.length) {
383
- return {
384
- status: "error",
385
- message: "No messages"
386
- };
387
- }
388
- return null;
389
- }
390
- async requestAd() {
391
- this.running = true;
392
- const cannotRequestAdReason = this.canRequestAd();
393
- if (cannotRequestAdReason) {
394
- return cannotRequestAdReason;
395
- }
396
- const config = this.session.config;
397
- const preloadBody = await this.getPreloadBody();
398
- try {
399
- const response = await fetchWithRetry(`${config.adServerUrl}/preload`, {
400
- method: "POST",
401
- body: JSON.stringify(preloadBody),
402
- headers: {
403
- "Kontextso-Is-Disabled": "0",
404
- "Kontextso-Publisher-Token": config.publisherToken
405
- },
406
- timeout: 16e3,
407
- abortController: this.abortController
408
- });
409
- const jsonResponse = await response.json();
410
- const bid = jsonResponse.bids?.[0] ?? null;
411
- if (jsonResponse.sessionId) {
412
- this.session.setSessionId(jsonResponse.sessionId);
413
- }
414
- if (bid) {
415
- this.setBid(bid);
416
- }
417
- this.session.updateBids();
418
- return {
419
- status: "success"
420
- };
421
- } catch (error) {
422
- this.session.logger.error("Error requesting ad:", error);
423
- return {
424
- status: "error"
425
- };
426
- } finally {
427
- this.running = false;
428
- }
429
- }
430
- };
431
-
432
- // src/Session.ts
433
- var Session = class {
434
- config;
435
- logger;
436
- sdk;
437
- sessionId = null;
438
- sessionDisabled = false;
439
- messages = [];
440
- bids = [];
441
- onUpdateBidsCallback = null;
442
- // only one preload instance is allowed at a time
443
- preloadInstance = null;
444
- constructor(config, { sdk }) {
445
- this.config = config;
446
- this.logger = new Logger();
447
- this.sdk = sdk;
448
- }
449
- setOnUpdateBids(callback) {
450
- this.onUpdateBidsCallback = callback;
451
- }
452
- isSessionDisabled() {
453
- return this.sessionDisabled;
454
- }
455
- setSessionDisabled(disabled) {
456
- this.sessionDisabled = disabled;
457
- }
458
- getSessionId() {
459
- return this.sessionId;
460
- }
461
- setSessionId(sessionId) {
462
- this.logger.info("Session ID set:", sessionId);
463
- this.sessionId = sessionId;
464
- }
465
- addMessage(message) {
466
- this.messages.push(message);
467
- this.updateBids();
468
- }
469
- getMessages() {
470
- return this.messages;
471
- }
472
- updateBids() {
473
- if (!this.preloadInstance?.hasBid()) {
474
- return;
475
- }
476
- const bid = this.preloadInstance.getBid();
477
- if (!bid) {
478
- return;
479
- }
480
- const lastMessage = this.messages[this.messages.length - 1];
481
- if (!lastMessage || lastMessage.role !== "assistant") {
482
- return;
483
- }
484
- const assignedBid = this.bids.find((b) => {
485
- if (b.bidId === bid?.bidId) {
486
- return true;
487
- }
488
- if (b.messageId === lastMessage.id) {
489
- return true;
490
- }
491
- return false;
492
- });
493
- if (assignedBid) {
494
- return;
495
- }
496
- this.bids.push({
497
- bidId: bid.bidId,
498
- messageId: lastMessage.id
499
- });
500
- this.onUpdateBidsCallback?.();
501
- }
502
- preload() {
503
- if (this.preloadInstance?.isRunning()) {
504
- this.preloadInstance.cancel();
505
- }
506
- this.preloadInstance = new Preload(this, [...this.messages]);
507
- return this.preloadInstance;
508
- }
509
- getLastBid() {
510
- return this.bids[this.bids.length - 1];
511
- }
512
- };
513
-
514
154
  // src/KontextAds.ts
155
+ import { Session } from "@kontextso/sdk-js/src/Session";
156
+ import { Configuration } from "@kontextso/sdk-js/src/Configuration";
515
157
  import { Platform } from "react-native";
516
158
 
517
159
  // package.json
518
- var version = "4.0.0-rc.2";
160
+ var version = "4.0.0-rc.4";
519
161
 
520
162
  // src/KontextAds.ts
163
+ var getSdkConfig = () => ({
164
+ name: "sdk-react-native",
165
+ platform: Platform.OS === "ios" ? "ios" : "android",
166
+ version
167
+ });
521
168
  var KontextAds = (config) => {
522
169
  return {
523
170
  createSession: (sessionConfig) => createSession({
@@ -527,11 +174,7 @@ var KontextAds = (config) => {
527
174
  };
528
175
  };
529
176
  var createSession = (options) => {
530
- const sdk = {
531
- name: "sdk-react-native",
532
- platform: Platform.OS === "ios" ? "ios" : "android",
533
- version
534
- };
177
+ const sdk = getSdkConfig();
535
178
  const instance = new Session(new Configuration(options), { sdk });
536
179
  return {
537
180
  addMessage: (message) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextso/sdk-react-native",
3
- "version": "4.0.0-rc.3",
3
+ "version": "4.0.0-rc.4",
4
4
  "description": "Kontext SDK for React Native",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -51,7 +51,9 @@
51
51
  "react-native-device-info": ">=10.0.0 <15.0.0",
52
52
  "react-native-webview": "^13.10.0"
53
53
  },
54
- "dependencies": {},
54
+ "dependencies": {
55
+ "@kontextso/sdk-js": "^2.0.0-rc.1"
56
+ },
55
57
  "files": [
56
58
  "dist/*",
57
59
  "src",
package/src/InlineAd.tsx CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  import {
2
3
  handleIframeMessage,
3
4
  type IframeMessage,
@@ -5,7 +6,8 @@ import {
5
6
  type IframeMessageType,
6
7
  makeIframeMessage,
7
8
  } from '@kontextso/sdk-common'
8
- import { Session } from './Session'
9
+
10
+ import type { Session } from '@kontextso/sdk-js/src/Session'
9
11
  import { useRef, useEffect, useState, useCallback } from 'react'
10
12
  import { WebView, type WebViewMessageEvent } from 'react-native-webview'
11
13
 
package/src/KontextAds.ts CHANGED
@@ -1,12 +1,15 @@
1
- import { type ConfigOptions, Configuration } from './Configuration'
2
- import type { Message } from '@kontextso/sdk-common'
3
- import { Session } from './Session'
1
+ import type { ConfigOptions, Message, SDKConfig, GlobalConfig, SessionConfig } from '@kontextso/sdk-js/src/Interface'
2
+ import { Session } from '@kontextso/sdk-js/src/Session'
3
+ import { Configuration } from '@kontextso/sdk-js/src/Configuration'
4
4
  import { Platform } from 'react-native'
5
5
  import * as packageJson from '../package.json'
6
6
 
7
- type GlobalConfig = Pick<ConfigOptions, 'publisherToken' | 'userId' | 'userEmail' | 'adServerUrl' | 'logLevel' | 'placementCode'>
7
+ const getSdkConfig = (): SDKConfig => ({
8
+ name: 'sdk-react-native',
9
+ platform: Platform.OS === 'ios' ? 'ios' : 'android',
10
+ version: packageJson.version,
11
+ })
8
12
 
9
- type SessionConfig = Pick<ConfigOptions, 'conversationId' | 'character' | 'variantId' | 'regulatory'>
10
13
 
11
14
  const KontextAds = (config: GlobalConfig) => {
12
15
  return {
@@ -18,11 +21,7 @@ const KontextAds = (config: GlobalConfig) => {
18
21
  }
19
22
 
20
23
  const createSession = (options: ConfigOptions) => {
21
- const sdk = {
22
- name: 'sdk-react-native',
23
- platform: Platform.OS === 'ios' ? 'ios' : 'android',
24
- version: packageJson.version,
25
- } as any
24
+ const sdk = getSdkConfig()
26
25
  const instance = new Session(new Configuration(options), { sdk })
27
26
  return {
28
27
  addMessage: (message: Message) => {
@@ -1,141 +0,0 @@
1
- import { handleIframeMessage, type IframeMessage, makeIframeMessage } from '@kontextso/sdk-common'
2
- import type { Session } from './Session'
3
-
4
- export abstract class AbstractStream {
5
- protected session: Session
6
- protected element: HTMLIFrameElement | null = null
7
-
8
- constructor(session: Session) {
9
- this.session = session
10
- }
11
-
12
- public getIframeUrl() {
13
- const bid = this.session.getLastBid()
14
- if (!bid) {
15
- return null
16
- }
17
- const messageId = bid.messageId
18
- const bidId = bid.bidId
19
-
20
- const params = new URLSearchParams({
21
- code: 'inlineAd',
22
- messageId,
23
- sdk: 'sdk-js',
24
- })
25
- const adServerUrl = this.session.config.adServerUrl
26
- return `${adServerUrl}/api/frame/${bidId}?${params}`
27
- }
28
-
29
- protected updateHeight(height: number) {
30
- if (this.element) {
31
- this.element.style.height = `${height}px`
32
- }
33
- }
34
-
35
- protected updateDisplay(display: string) {
36
- if (this.element) {
37
- this.element.style.display = display
38
- }
39
- }
40
-
41
- protected sendUpdateMessage() {
42
- const bid = this.session.getLastBid()
43
- if (!bid) {
44
- return
45
- }
46
- this.element?.contentWindow?.postMessage(
47
- makeIframeMessage('update-iframe', {
48
- code: 'inlineAd',
49
- data: {
50
- messages: this.session.getMessages(),
51
- sdk: 'sdk-js',
52
- messageId: bid.messageId,
53
- otherParams: {},
54
- },
55
- }),
56
- '*'
57
- )
58
- }
59
-
60
- protected processInitIframeMessage() {
61
- this.updateDisplay('block')
62
- this.sendUpdateMessage()
63
- }
64
-
65
- protected processErrorIframeMessage(message: IframeMessage<'error-iframe'>) {
66
- console.log('error-iframe', message.data)
67
- }
68
-
69
- protected processResizeIframeMessage(message: IframeMessage<'resize-iframe'>) {
70
- this.updateHeight(message.data.height)
71
- }
72
-
73
- protected processEventIframeMessage(message: IframeMessage<'event-iframe'>) {
74
- console.log('event-iframe', message.data)
75
- }
76
-
77
- protected processShowIframeMessage() {
78
- this.updateDisplay('block')
79
- }
80
-
81
- protected processHideIframeMessage() {
82
- this.updateDisplay('none')
83
- }
84
-
85
- protected setupMessageListener() {
86
- const { adServerUrl, placementCode } = this.session.config
87
- const messageHandler = handleIframeMessage(
88
- (message) => {
89
- switch (message.type) {
90
- case 'init-iframe':
91
- this.processInitIframeMessage()
92
- break
93
-
94
- case 'error-iframe':
95
- this.processErrorIframeMessage(message)
96
- break
97
-
98
- case 'resize-iframe':
99
- this.processResizeIframeMessage(message)
100
- break
101
-
102
- case 'event-iframe':
103
- this.processEventIframeMessage(message)
104
- break
105
-
106
- case 'show-iframe':
107
- this.processShowIframeMessage()
108
- break
109
-
110
- case 'hide-iframe':
111
- this.processHideIframeMessage()
112
- break
113
- }
114
- },
115
- {
116
- origin: adServerUrl,
117
- code: placementCode,
118
- }
119
- )
120
- // TODO: remove listener on unmount
121
- window.addEventListener('message', messageHandler)
122
- }
123
-
124
- protected createIframe() {
125
- const iframeUrl = this.getIframeUrl()
126
- if (!iframeUrl) {
127
- return
128
- }
129
- const iframe = document.createElement('iframe')
130
- iframe.src = iframeUrl
131
- iframe.title = 'ad-iframe'
132
- iframe.dataset.testid = 'ad-iframe'
133
- iframe.style.display = 'none'
134
- iframe.style.height = '100%'
135
- iframe.style.width = '100%'
136
- iframe.style.background = 'transparent'
137
- iframe.style.border = '0'
138
- iframe.style.colorScheme = 'auto'
139
- this.element = iframe
140
- }
141
- }