react-native-test-adx 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,11 +36,7 @@ import { AdaxonProvider, useAdaxon } from 'react-native-test-adx';
36
36
 
37
37
  Both packages expose the same API. Only the npm name differs.
38
38
 
39
- Recommended storage helper:
40
-
41
- ```sh
42
- npx expo install expo-secure-store
43
- ```
39
+ `expo-secure-store` is **not** required. The SDK does not depend on it.
44
40
 
45
41
  ## Quick start (React Native)
46
42
 
@@ -61,7 +57,7 @@ The SDK owns the tracker host and API paths (`/event/tracking`, `/api/mts/recomm
61
57
  | `testMode` | No | `false` (`sdk_version` gets a `-test` suffix when true) |
62
58
  | `externalUserId` | No | Unset |
63
59
 
64
- Pass `storage` in production so the anonymous id and queued events survive restart. The SDK detects the device platform and collects device/app fields automatically. Do **not** pass a tracker URL — requests go to the SDK `BASE_URL`.
60
+ The SDK detects the device platform and collects device/app fields automatically. Do **not** pass a tracker URL — requests go to the SDK `BASE_URL`.
65
61
 
66
62
  ```tsx
67
63
  import {
@@ -70,7 +66,6 @@ import {
70
66
  useAdaxon,
71
67
  type RecommendationOffer,
72
68
  } from 'react-native-adaxon';
73
- import * as SecureStore from 'expo-secure-store';
74
69
  import { Button, Text, View } from 'react-native';
75
70
 
76
71
  function App() {
@@ -80,11 +75,6 @@ function App() {
80
75
  appId: 'adx_your_app_id',
81
76
  sdkKey: 'your_sdk_key',
82
77
  testMode: __DEV__,
83
- storage: {
84
- getItem: (key) => SecureStore.getItemAsync(key),
85
- setItem: (key, value) => SecureStore.setItemAsync(key, value),
86
- removeItem: (key) => SecureStore.deleteItemAsync(key),
87
- },
88
78
  }}
89
79
  >
90
80
  <HomeScreen />
@@ -156,6 +146,41 @@ function HomeScreen() {
156
146
 
157
147
  Do **not** pass device or app fields. The SDK attaches `device` and `app` automatically on every event.
158
148
 
149
+ ### Storage
150
+
151
+ `storage` is optional. You do not have to install `expo-secure-store` (or any other store) for the SDK to run. Only `appId` and `sdkKey` are required.
152
+
153
+ | What you pass | What happens |
154
+ |---|---|
155
+ | No `storage` | SDK uses built-in in-memory storage. Tracking works. Anonymous id and queued events are lost when the app closes. |
156
+ | A storage adapter | Anonymous id and queued events survive restart. |
157
+
158
+ The adapter is only `getItem` / `setItem` / `removeItem`. You do not implement the queue. Any store works: Expo SecureStore, AsyncStorage, MMKV, or your own.
159
+
160
+ Optional SecureStore helper (not required):
161
+
162
+ ```sh
163
+ npx expo install expo-secure-store
164
+ ```
165
+
166
+ ```tsx
167
+ import * as SecureStore from 'expo-secure-store';
168
+
169
+ <AdaxonProvider
170
+ configuration={{
171
+ appId: 'adx_your_app_id',
172
+ sdkKey: 'your_sdk_key',
173
+ storage: {
174
+ getItem: (key) => SecureStore.getItemAsync(key),
175
+ setItem: (key, value) => SecureStore.setItemAsync(key, value),
176
+ removeItem: (key) => SecureStore.deleteItemAsync(key),
177
+ },
178
+ }}
179
+ >
180
+ ```
181
+
182
+ SecureStore has a small per-key size limit. For a large event queue, prefer AsyncStorage (or similar) and keep SecureStore for the anonymous id if you want.
183
+
159
184
  ### Non-component boot
160
185
 
161
186
  `Adaxon.initialize()` is still available if you are not inside a React tree. Prefer the provider in React Native apps.
@@ -218,16 +243,27 @@ POST /event/tracking
218
243
 
219
244
  Rules:
220
245
 
221
- - Pending events are stored through the `storage` adapter, so they survive app restart.
246
+ - Pending events are stored through the `storage` adapter when you pass one, so they survive app restart. If you omit `storage`, they stay in memory only.
222
247
  - Events are processed in creation order (FIFO).
223
248
  - Each request contains at most **100** events. A queue of 250 is sent as 100 + 100 + 50.
224
249
  - Events are removed only after the API confirms success (`success: true`). On network, HTTP, or unknown errors they stay in the queue.
225
250
  - Only one processor runs at a time for the same app. A second `processPendingEvents()` call returns `already_processing`.
226
251
  - Large queues are read 100 events at a time. The SDK does not load the whole queue into memory.
227
- - On `Adaxon.initialize()` / `AdaxonProvider` mount, pending events start flushing in the background without blocking startup.
252
+ - On `Adaxon.initialize()` / `AdaxonProvider` mount, pending events start flushing in the background without blocking startup when the network is available.
228
253
  - Pass `removeItem` on the storage adapter so successful events can be deleted. If it is omitted, the SDK writes an empty value instead.
229
254
 
230
- Expo SecureStore has a small per-key size limit. For a large event queue, use a storage backend that can hold JSON payloads (for example AsyncStorage) and keep SecureStore for the anonymous id if you want.
255
+ ## Network loss
256
+
257
+ The SDK watches connectivity through the host app's NetInfo / Expo Network listener. It does **not** poll.
258
+
259
+ - Online: `track` / `trackBatch` send immediately, same as before.
260
+ - Offline: events are stored in the event queue and no API request is made.
261
+ - Offline → online: the batch processor is notified once and pending events are flushed. Duplicate `ONLINE` events do not start extra processors.
262
+ - `isNetworkAvailable()` reports the current state. `destroy()` (and Provider unmount) removes the network listener.
263
+
264
+ A missing or failing network module does not crash the app. Tracking continues as online until the device is known to be offline.
265
+
266
+ Offline events use the same `storage` adapter as above. Without it, they are held in memory and are lost if the app is closed before the network returns.
231
267
 
232
268
  ## Automatic device information
233
269
 
@@ -253,7 +289,7 @@ Values come from React Native `Platform` (`src/platform/reactNative.ts`). They a
253
289
  "app": {
254
290
  "package_name": "com.example.app",
255
291
  "app_version": "2.4.1",
256
- "sdk_version": "0.1.1"
292
+ "sdk_version": "0.1.2"
257
293
  }
258
294
  }
259
295
  ```
@@ -3,7 +3,7 @@
3
3
  import { AdaxonClient } from "./core/AdaxonClient.js";
4
4
  import { MEDIATION_PROVIDER, OFFER_OPENED_EVENT } from "./config/ApiConstants.js";
5
5
  import { AdaxonSdkError } from "./errors/AdaxonSdkError.js";
6
- import { detectReactNativePlatform, reactNativeAppInfoReader, reactNativeDeviceReader, reactNativeNetworkInfoReader, reactNativeUrlOpener } from "./platform/reactNative.js";
6
+ import { detectReactNativePlatform, reactNativeAppInfoReader, reactNativeDeviceReader, reactNativeNetworkInfoReader, reactNativeNetworkStatusReader, reactNativeUrlOpener } from "./platform/reactNative.js";
7
7
  import { buildAddToCartProperties, buildPurchaseProperties, normalizeEventValues } from "./services/event/normalizeProperties.js";
8
8
  import { AdxEvent } from "./services/event/predefined.js";
9
9
  export class AdaxonSdk {
@@ -18,18 +18,25 @@ export class AdaxonSdk {
18
18
  }
19
19
  async initialize(configuration, listener) {
20
20
  try {
21
- this.client = new AdaxonClient({
21
+ const previous = this.client;
22
+ const client = new AdaxonClient({
22
23
  ...configuration,
23
24
  platform: detectReactNativePlatform(),
24
25
  deviceInfoReader: reactNativeDeviceReader,
25
26
  appInfoReader: reactNativeAppInfoReader,
26
- networkInfoReader: reactNativeNetworkInfoReader
27
+ networkInfoReader: reactNativeNetworkInfoReader,
28
+ networkStatusReader: reactNativeNetworkStatusReader
27
29
  });
30
+ await client.start();
31
+ previous?.destroy();
32
+ this.client = client;
28
33
  this.testMode = Boolean(configuration.testMode);
29
34
  listener?.onInitializationComplete();
30
- this.client.processPendingEvents().catch(() => undefined);
35
+ if (client.isNetworkAvailable()) {
36
+ client.processPendingEvents().catch(() => undefined);
37
+ }
31
38
  } catch (error) {
32
- this.reset();
39
+ this.destroy();
33
40
  const message = AdaxonSdkError.messageOf(error, 'Initialization failed.');
34
41
  const code = error instanceof AdaxonSdkError && error.code === 'INVALID_CONFIG' ? 'INVALID_CONFIG' : 'UNKNOWN';
35
42
  listener?.onInitializationFailed(code, message);
@@ -107,14 +114,18 @@ export class AdaxonSdk {
107
114
  setExternalUserId(externalUserId) {
108
115
  this.requireClient().setExternalUserId(externalUserId);
109
116
  }
117
+ isNetworkAvailable() {
118
+ return this.client?.isNetworkAvailable() ?? false;
119
+ }
120
+ destroy() {
121
+ this.client?.destroy();
122
+ this.client = null;
123
+ this.testMode = false;
124
+ }
110
125
  requireClient() {
111
126
  if (!this.client) {
112
127
  throw new AdaxonSdkError('INVALID_CONFIG', 'Adaxon SDK is not initialized. Call Adaxon.initialize(...) first.');
113
128
  }
114
129
  return this.client;
115
130
  }
116
- reset() {
117
- this.client = null;
118
- this.testMode = false;
119
- }
120
131
  }
@@ -20,10 +20,12 @@ export function AdaxonProvider({
20
20
  useEffect(() => {
21
21
  let cancelled = false;
22
22
  sdk.initialize(configurationRef.current, listenerRef.current).then(() => {
23
- if (!cancelled) {
24
- setIsInitialized(true);
25
- setInitializationError(null);
23
+ if (cancelled) {
24
+ sdk.destroy();
25
+ return;
26
26
  }
27
+ setIsInitialized(true);
28
+ setInitializationError(null);
27
29
  }).catch(error => {
28
30
  if (!cancelled) {
29
31
  setIsInitialized(false);
@@ -32,6 +34,7 @@ export function AdaxonProvider({
32
34
  });
33
35
  return () => {
34
36
  cancelled = true;
37
+ sdk.destroy();
35
38
  };
36
39
  }, [sdk]);
37
40
  const value = useMemo(() => ({
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- export const SDK_VERSION = '0.1.1';
3
+ export const SDK_VERSION = '0.1.2';
4
4
  export const MEDIATION_PROVIDER = 'mts';
5
5
  export const BASE_URL = 'http://localhost:3002';
6
6
  export const EVENT_TRACKING_PATH = '/event/tracking';
@@ -10,10 +10,12 @@ import { EventQueueService } from "../services/event/EventQueueService.js";
10
10
  import { EventService } from "../services/event/EventService.js";
11
11
  import { ApiClient } from "../services/network/ApiClient.js";
12
12
  import { NetworkInfoService } from "../services/network/NetworkInfoService.js";
13
+ import { NetworkService } from "../services/network/NetworkService.js";
13
14
  import { AnonymousIdService } from "../storage/AnonymousIdService.js";
14
15
  import { EventQueueStorage } from "../storage/EventQueueStorage.js";
15
16
  import { EventValidator } from "../validation/EventValidator.js";
16
17
  export class AdaxonClient {
18
+ started = false;
17
19
  constructor(config) {
18
20
  const auth = new AuthenticationService(config);
19
21
  this.validator = new EventValidator();
@@ -42,12 +44,48 @@ export class AdaxonClient {
42
44
  queue: this.eventQueue,
43
45
  sendBatch: payloads => this.events.sendPayloads(payloads)
44
46
  });
47
+ this.network = new NetworkService(config.networkStatusReader);
48
+ }
49
+ async start() {
50
+ if (this.started) {
51
+ return;
52
+ }
53
+ this.started = true;
54
+ await this.network.initialize();
55
+ this.network.subscribe(() => {
56
+ this.batchProcessor.process().catch(() => undefined);
57
+ });
58
+ }
59
+ destroy() {
60
+ this.network.destroy();
61
+ this.started = false;
62
+ }
63
+ isNetworkAvailable() {
64
+ return this.network.isAvailable();
45
65
  }
46
66
  track(eventName, properties = {}, options = {}) {
47
- return this.events.track(eventName, properties, options);
67
+ return this.trackBatch([{
68
+ eventName,
69
+ properties,
70
+ ...options
71
+ }]);
48
72
  }
49
- trackBatch(events) {
50
- return this.events.trackBatch(events);
73
+ async trackBatch(events) {
74
+ if (this.network.isAvailable()) {
75
+ return this.events.trackBatch(events);
76
+ }
77
+ this.validator.validateBatch(events);
78
+ const payloads = await Promise.all(events.map(event => this.builder.build(event)));
79
+ for (const payload of payloads) {
80
+ await this.eventQueue.add(payload);
81
+ }
82
+ return {
83
+ success: true,
84
+ message: 'queued',
85
+ accepted: payloads.length,
86
+ received: payloads.length,
87
+ rejected: 0
88
+ };
51
89
  }
52
90
  async enqueueEvent(eventName, properties = {}, options = {}) {
53
91
  const payload = await this.builder.build({
@@ -13,6 +13,26 @@ function publicIpAddress(value) {
13
13
  const ip = usableIpAddress(value);
14
14
  return ip && !isPrivateIpAddress(ip) ? ip : undefined;
15
15
  }
16
+ export function isOnlineFromNativeState(state) {
17
+ const value = asNativeNetworkState(state);
18
+ if (!value) {
19
+ return null;
20
+ }
21
+ if (value.isConnected === false || value.isInternetReachable === false) {
22
+ return false;
23
+ }
24
+ const type = nonEmptyString(value.type)?.toLowerCase();
25
+ if (type === 'none') {
26
+ return false;
27
+ }
28
+ if (value.isConnected === true) {
29
+ return true;
30
+ }
31
+ if (type && type !== 'unknown') {
32
+ return true;
33
+ }
34
+ return null;
35
+ }
16
36
  export function connectionTypeFromNativeState(state) {
17
37
  const type = nonEmptyString(asNativeNetworkState(state)?.type)?.toLowerCase();
18
38
  return type && CONNECTION_TYPES.has(type) ? type : undefined;
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
 
3
- import { Linking, NativeModules, Platform } from 'react-native';
3
+ import { Linking, NativeEventEmitter, NativeModules, Platform } from 'react-native';
4
4
  import { nonEmptyString, setIfPresent } from "../utils/strings.js";
5
5
  import { readLocaleFields } from "../utils/locale.js";
6
6
  import { appFieldsFromNative } from "./app.js";
7
7
  import { deviceFieldsFromAndroid } from "./android.js";
8
8
  import { deviceFieldsFromIos } from "./ios.js";
9
- import { connectionTypeFromNativeState, ipAddressFromNativeState, usableIpAddress } from "./network.js";
9
+ import { connectionTypeFromNativeState, ipAddressFromNativeState, isOnlineFromNativeState, usableIpAddress } from "./network.js";
10
10
  export function detectReactNativePlatform() {
11
11
  return Platform.OS === 'ios' || Platform.OS === 'android' ? Platform.OS : 'web';
12
12
  }
@@ -36,6 +36,10 @@ export const reactNativeAppInfoReader = {
36
36
  export const reactNativeNetworkInfoReader = {
37
37
  readNetworkInfo: collectFromNativeNetwork
38
38
  };
39
+ export const reactNativeNetworkStatusReader = {
40
+ getIsOnline: readIsOnlineFromNative,
41
+ subscribe: subscribeNativeNetworkStatus
42
+ };
39
43
  export const reactNativeUrlOpener = Linking;
40
44
  function readNativeAppConstants() {
41
45
  const modules = NativeModules ?? {};
@@ -48,6 +52,63 @@ function readNativeAppConstants() {
48
52
  ...expoApp
49
53
  };
50
54
  }
55
+ function nativeNetworkModules() {
56
+ const modules = NativeModules ?? {};
57
+ return {
58
+ netInfo: modules.RNCNetInfo,
59
+ expoNetwork: modules.ExpoNetwork
60
+ };
61
+ }
62
+ function safeUnsubscribe(remove) {
63
+ return () => {
64
+ try {
65
+ remove?.();
66
+ } catch {
67
+ // Native unsubscribe can throw after the module is torn down.
68
+ }
69
+ };
70
+ }
71
+ async function readIsOnlineFromNative() {
72
+ const {
73
+ netInfo,
74
+ expoNetwork
75
+ } = nativeNetworkModules();
76
+ const getCurrentState = netInfo?.getCurrentState;
77
+ if (typeof getCurrentState === 'function') {
78
+ const online = isOnlineFromNativeState(await readOptionalNative(() => getCurrentState(null)));
79
+ if (online !== null) {
80
+ return online;
81
+ }
82
+ }
83
+ const getNetworkState = expoNetwork?.getNetworkStateAsync;
84
+ if (typeof getNetworkState === 'function') {
85
+ return isOnlineFromNativeState(await readOptionalNative(getNetworkState));
86
+ }
87
+ return null;
88
+ }
89
+ function subscribeNativeNetworkStatus(listener) {
90
+ const {
91
+ netInfo,
92
+ expoNetwork
93
+ } = nativeNetworkModules();
94
+ const onState = state => {
95
+ listener(isOnlineFromNativeState(state));
96
+ };
97
+ try {
98
+ if (netInfo) {
99
+ const subscription = new NativeEventEmitter(NativeModules.RNCNetInfo).addListener('netInfo.networkStatusDidChange', onState);
100
+ return safeUnsubscribe(() => subscription.remove());
101
+ }
102
+ const addListener = expoNetwork?.addListener;
103
+ if (typeof addListener === 'function') {
104
+ const subscription = addListener.call(expoNetwork, 'onNetworkStateChanged', onState);
105
+ return safeUnsubscribe(() => subscription?.remove?.());
106
+ }
107
+ } catch (error) {
108
+ console.error('[Adaxon] Failed to register the network listener', error);
109
+ }
110
+ return () => undefined;
111
+ }
51
112
  async function readOptionalNative(read) {
52
113
  try {
53
114
  return await read();
@@ -57,9 +118,10 @@ async function readOptionalNative(read) {
57
118
  }
58
119
  async function collectFromNativeNetwork() {
59
120
  const network = {};
60
- const modules = NativeModules ?? {};
61
- const netInfo = modules.RNCNetInfo;
62
- const expoNetwork = modules.ExpoNetwork;
121
+ const {
122
+ netInfo,
123
+ expoNetwork
124
+ } = nativeNetworkModules();
63
125
  const getCurrentState = netInfo?.getCurrentState;
64
126
  if (typeof getCurrentState === 'function') {
65
127
  const state = await readOptionalNative(() => getCurrentState(null));
@@ -8,13 +8,6 @@ export class EventService {
8
8
  this.builder = config.builder;
9
9
  this.validator = config.validator;
10
10
  }
11
- track(eventName, properties = {}, options = {}) {
12
- return this.trackBatch([{
13
- eventName,
14
- properties,
15
- ...options
16
- }]);
17
- }
18
11
  async trackBatch(events) {
19
12
  this.validator.validateBatch(events);
20
13
  const payloads = await Promise.all(events.map(event => this.builder.build(event)));
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ function toState(isOnline) {
4
+ if (isOnline === true) {
5
+ return 'ONLINE';
6
+ }
7
+ if (isOnline === false) {
8
+ return 'OFFLINE';
9
+ }
10
+ return 'UNKNOWN';
11
+ }
12
+ export class NetworkService {
13
+ state = 'UNKNOWN';
14
+ started = false;
15
+ listeners = new Set();
16
+ constructor(reader) {
17
+ this.reader = reader;
18
+ }
19
+ getState() {
20
+ return this.state;
21
+ }
22
+ isAvailable() {
23
+ return this.state !== 'OFFLINE';
24
+ }
25
+ async initialize() {
26
+ if (this.started) {
27
+ return;
28
+ }
29
+ this.started = true;
30
+ if (!this.reader) {
31
+ this.applyState('ONLINE');
32
+ return;
33
+ }
34
+ try {
35
+ this.applyState(toState(await this.reader.getIsOnline()));
36
+ } catch (error) {
37
+ console.error('[Adaxon] Network monitoring failed', error);
38
+ this.applyState('UNKNOWN');
39
+ }
40
+ try {
41
+ this.unsubscribeReader = this.reader.subscribe(isOnline => {
42
+ this.applyState(toState(isOnline));
43
+ });
44
+ } catch (error) {
45
+ console.error('[Adaxon] Network monitoring failed', error);
46
+ this.applyState('UNKNOWN');
47
+ }
48
+ }
49
+ subscribe(listener) {
50
+ this.listeners.add(listener);
51
+ return () => {
52
+ this.listeners.delete(listener);
53
+ };
54
+ }
55
+ destroy() {
56
+ try {
57
+ this.unsubscribeReader?.();
58
+ } catch (error) {
59
+ console.error('[Adaxon] Failed to remove the network listener', error);
60
+ }
61
+ this.unsubscribeReader = undefined;
62
+ this.started = false;
63
+ this.listeners.clear();
64
+ }
65
+ applyState(next) {
66
+ const previous = this.state;
67
+ if (previous === next) {
68
+ return;
69
+ }
70
+ this.state = next;
71
+ if (previous !== 'OFFLINE' || next !== 'ONLINE') {
72
+ return;
73
+ }
74
+ for (const listener of [...this.listeners]) {
75
+ try {
76
+ listener();
77
+ } catch (error) {
78
+ console.error('[Adaxon] Network listener failed', error);
79
+ }
80
+ }
81
+ }
82
+ }
@@ -22,7 +22,8 @@ export declare class AdaxonSdk {
22
22
  loadRecommendations(eventName: string, properties?: EventProperties, listener?: AdaxonRecommendationLoadListener): Promise<RecommendationOffer[]>;
23
23
  showOffer(offer: RecommendationOffer, listener?: AdaxonOfferShowListener): Promise<void>;
24
24
  setExternalUserId(externalUserId?: string): void;
25
+ isNetworkAvailable(): boolean;
26
+ destroy(): void;
25
27
  private requireClient;
26
- private reset;
27
28
  }
28
29
  //# sourceMappingURL=AdaxonSdk.d.ts.map
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "0.1.1";
1
+ export declare const SDK_VERSION = "0.1.2";
2
2
  export declare const MEDIATION_PROVIDER = "mts";
3
3
  export declare const BASE_URL = "http://localhost:3002";
4
4
  export declare const EVENT_TRACKING_PATH = "/event/tracking";
@@ -1,4 +1,4 @@
1
- import type { AppInfoReader, DeviceInfoReader, NetworkInfoReader } from '../platform/types.js';
1
+ import type { AppInfoReader, DeviceInfoReader, NetworkInfoReader, NetworkStatusReader } from '../platform/types.js';
2
2
  import type { AdaxonSdkConfig } from '../types/AdaxonConfig.js';
3
3
  import type { EventIngestionResponse, RecommendationResponse } from '../types/ApiTypes.js';
4
4
  import type { AdaxonPlatform, ClickAttribution, EventProperties, TrackEventInput, TrackEventOptions } from '../types/EventTypes.js';
@@ -8,6 +8,7 @@ interface AdaxonClientConfig extends AdaxonSdkConfig {
8
8
  deviceInfoReader?: DeviceInfoReader;
9
9
  appInfoReader?: AppInfoReader;
10
10
  networkInfoReader?: NetworkInfoReader;
11
+ networkStatusReader?: NetworkStatusReader;
11
12
  }
12
13
  export declare class AdaxonClient {
13
14
  private readonly events;
@@ -15,7 +16,12 @@ export declare class AdaxonClient {
15
16
  private readonly validator;
16
17
  private readonly eventQueue;
17
18
  private readonly batchProcessor;
19
+ private readonly network;
20
+ private started;
18
21
  constructor(config: AdaxonClientConfig);
22
+ start(): Promise<void>;
23
+ destroy(): void;
24
+ isNetworkAvailable(): boolean;
19
25
  track(eventName: string, properties?: EventProperties, options?: TrackEventOptions): Promise<EventIngestionResponse>;
20
26
  trackBatch(events: readonly TrackEventInput[]): Promise<EventIngestionResponse>;
21
27
  enqueueEvent(eventName: string, properties?: EventProperties, options?: TrackEventOptions): Promise<void>;
@@ -1,3 +1,4 @@
1
+ export declare function isOnlineFromNativeState(state: unknown): boolean | null;
1
2
  export declare function connectionTypeFromNativeState(state: unknown): string | undefined;
2
3
  export declare function ipAddressFromNativeState(state: unknown): string | undefined;
3
4
  export declare function usableIpAddress(value: string | undefined): string | undefined;
@@ -1,8 +1,9 @@
1
1
  import type { AdaxonPlatform } from '../types/EventTypes.js';
2
- import type { AppInfoReader, DeviceInfoReader, NetworkInfoReader, UrlOpener } from './types.js';
2
+ import type { AppInfoReader, DeviceInfoReader, NetworkInfoReader, NetworkStatusReader, UrlOpener } from './types.js';
3
3
  export declare function detectReactNativePlatform(): AdaxonPlatform;
4
4
  export declare const reactNativeDeviceReader: DeviceInfoReader;
5
5
  export declare const reactNativeAppInfoReader: AppInfoReader;
6
6
  export declare const reactNativeNetworkInfoReader: NetworkInfoReader;
7
+ export declare const reactNativeNetworkStatusReader: NetworkStatusReader;
7
8
  export declare const reactNativeUrlOpener: UrlOpener;
8
9
  //# sourceMappingURL=reactNative.d.ts.map
@@ -12,4 +12,8 @@ export interface UrlOpener {
12
12
  canOpenURL(url: string): Promise<boolean>;
13
13
  openURL(url: string): Promise<void>;
14
14
  }
15
+ export interface NetworkStatusReader {
16
+ getIsOnline(): Promise<boolean | null>;
17
+ subscribe(listener: (isOnline: boolean | null) => void): () => void;
18
+ }
15
19
  //# sourceMappingURL=types.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import type { ApiClient } from '../network/ApiClient.js';
2
2
  import type { EventIngestionResponse, RecommendationResponse } from '../../types/ApiTypes.js';
3
- import type { EventPayload, EventProperties, TrackEventInput, TrackEventOptions } from '../../types/EventTypes.js';
3
+ import type { EventPayload, TrackEventInput } from '../../types/EventTypes.js';
4
4
  import type { EventBuilder } from './EventBuilder.js';
5
5
  import type { EventValidator } from '../../validation/EventValidator.js';
6
6
  interface EventServiceConfig {
@@ -13,7 +13,6 @@ export declare class EventService {
13
13
  private readonly builder;
14
14
  private readonly validator;
15
15
  constructor(config: EventServiceConfig);
16
- track(eventName: string, properties?: EventProperties, options?: TrackEventOptions): Promise<EventIngestionResponse>;
17
16
  trackBatch(events: readonly TrackEventInput[]): Promise<EventIngestionResponse>;
18
17
  sendPayloads(payloads: readonly EventPayload[]): Promise<EventIngestionResponse>;
19
18
  getRecommendations(input: TrackEventInput): Promise<RecommendationResponse>;
@@ -0,0 +1,17 @@
1
+ import type { NetworkStatusReader } from '../../platform/types.js';
2
+ export type NetworkState = 'ONLINE' | 'OFFLINE' | 'UNKNOWN';
3
+ export declare class NetworkService {
4
+ private readonly reader?;
5
+ private state;
6
+ private started;
7
+ private unsubscribeReader?;
8
+ private readonly listeners;
9
+ constructor(reader?: NetworkStatusReader | undefined);
10
+ getState(): NetworkState;
11
+ isAvailable(): boolean;
12
+ initialize(): Promise<void>;
13
+ subscribe(listener: () => void): () => void;
14
+ destroy(): void;
15
+ private applyState;
16
+ }
17
+ //# sourceMappingURL=NetworkService.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-test-adx",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Adaxon React Native / Expo SDK for event tracking and offer recommendations.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",