@product-intelligence-hub/sdk-react-native 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +198 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +155 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle.d.ts +42 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +91 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/screen-tracker.d.ts +59 -0
- package/dist/screen-tracker.d.ts.map +1 -0
- package/dist/screen-tracker.js +122 -0
- package/dist/screen-tracker.js.map +1 -0
- package/dist/storage.d.ts +16 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +76 -0
- package/dist/storage.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Product Intelligence Hub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# @product-intelligence-hub/sdk-react-native
|
|
2
|
+
|
|
3
|
+
React Native SDK for Product Intelligence Hub.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @product-intelligence-hub/sdk-react-native
|
|
9
|
+
# or
|
|
10
|
+
yarn add @product-intelligence-hub/sdk-react-native
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @product-intelligence-hub/sdk-react-native
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Peer Dependencies
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @react-native-async-storage/async-storage
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Optional for screen tracking:
|
|
22
|
+
```bash
|
|
23
|
+
npm install @react-navigation/native
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import PIH from "@product-intelligence-hub/sdk-react-native";
|
|
30
|
+
|
|
31
|
+
// Initialize the SDK
|
|
32
|
+
const pih = PIH.init({
|
|
33
|
+
apiUrl: "https://your-ingest-api.com",
|
|
34
|
+
apiKey: "your-api-key",
|
|
35
|
+
projectId: "proj_xxx",
|
|
36
|
+
environment: "production",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Track an event
|
|
40
|
+
pih.track("button_pressed", {
|
|
41
|
+
button_id: "checkout",
|
|
42
|
+
screen: "Cart",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Identify a user
|
|
46
|
+
pih.identify("user_123", {
|
|
47
|
+
email: "user@example.com",
|
|
48
|
+
subscription: "premium",
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Configuration Options
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
PIH.init({
|
|
56
|
+
// Required
|
|
57
|
+
apiUrl: string; // Ingestion API URL
|
|
58
|
+
apiKey: string; // Environment API key
|
|
59
|
+
projectId: string; // Project ID (proj_xxx)
|
|
60
|
+
environment: string; // Environment name
|
|
61
|
+
|
|
62
|
+
// Optional
|
|
63
|
+
tenantId?: string; // Tenant ID for multi-tenant apps
|
|
64
|
+
debug?: boolean; // Enable debug logging (default: false)
|
|
65
|
+
flushInterval?: number; // Batch flush interval in ms (default: 10000)
|
|
66
|
+
flushAt?: number; // Flush when queue reaches this size (default: 20)
|
|
67
|
+
maxQueueSize?: number; // Max events to queue (default: 1000)
|
|
68
|
+
sessionTimeout?: number; // Session timeout in ms (default: 1800000)
|
|
69
|
+
trackLifecycle?: boolean; // Track app lifecycle events (default: true)
|
|
70
|
+
|
|
71
|
+
// Callbacks
|
|
72
|
+
onError?: (error: PIHError) => void;
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## API
|
|
77
|
+
|
|
78
|
+
### `PIH.init(config)`
|
|
79
|
+
|
|
80
|
+
Initialize the SDK. Returns the client instance.
|
|
81
|
+
|
|
82
|
+
### `pih.track(eventName, properties?, options?)`
|
|
83
|
+
|
|
84
|
+
Track an event.
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
pih.track("item_added_to_cart", {
|
|
88
|
+
product_id: "prod_123",
|
|
89
|
+
quantity: 2,
|
|
90
|
+
price: 29.99,
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `pih.identify(userId, traits?)`
|
|
95
|
+
|
|
96
|
+
Identify the current user.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
pih.identify("user_123", {
|
|
100
|
+
email: "user@example.com",
|
|
101
|
+
name: "Jane Doe",
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `pih.trackScreen(screenName, params?)`
|
|
106
|
+
|
|
107
|
+
Manually track a screen view.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
pih.trackScreen("ProductDetail", { product_id: "prod_123" });
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### `pih.flush()`
|
|
114
|
+
|
|
115
|
+
Force flush the event queue.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
await pih.flush();
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `pih.reset()`
|
|
122
|
+
|
|
123
|
+
Reset identity (for logout).
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
await pih.reset();
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Screen Tracking with React Navigation
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { NavigationContainer } from "@react-navigation/native";
|
|
133
|
+
import PIH from "@product-intelligence-hub/sdk-react-native";
|
|
134
|
+
|
|
135
|
+
function App() {
|
|
136
|
+
const navigationRef = useNavigationContainerRef();
|
|
137
|
+
const pih = PIH.getInstance();
|
|
138
|
+
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (pih) {
|
|
141
|
+
const cleanup = pih.setupScreenTracking(navigationRef, {
|
|
142
|
+
// Optional: transform screen names
|
|
143
|
+
getScreenName: (route) => route.name,
|
|
144
|
+
// Optional: include route params
|
|
145
|
+
includeParams: true,
|
|
146
|
+
});
|
|
147
|
+
return cleanup;
|
|
148
|
+
}
|
|
149
|
+
}, []);
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<NavigationContainer ref={navigationRef}>
|
|
153
|
+
{/* ... */}
|
|
154
|
+
</NavigationContainer>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Lifecycle Tracking
|
|
160
|
+
|
|
161
|
+
By default, the SDK tracks app lifecycle events:
|
|
162
|
+
|
|
163
|
+
- `app_opened` - App comes to foreground
|
|
164
|
+
- `app_backgrounded` - App goes to background
|
|
165
|
+
|
|
166
|
+
Disable with:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
PIH.init({
|
|
170
|
+
// ...
|
|
171
|
+
trackLifecycle: false,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Or at runtime
|
|
175
|
+
pih.disableLifecycleTracking();
|
|
176
|
+
pih.enableLifecycleTracking();
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Platform Detection
|
|
180
|
+
|
|
181
|
+
The SDK automatically detects the platform (`ios` or `android`) from React Native.
|
|
182
|
+
|
|
183
|
+
## TypeScript Support
|
|
184
|
+
|
|
185
|
+
Full TypeScript support included:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import type {
|
|
189
|
+
RNPIHConfig,
|
|
190
|
+
TrackEvent,
|
|
191
|
+
ScreenTrackerOptions,
|
|
192
|
+
} from "@product-intelligence-hub/sdk-react-native";
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Related
|
|
196
|
+
|
|
197
|
+
- [SDK Core](../sdk-core/README.md) - Core SDK internals
|
|
198
|
+
- [SDK Spec](/docs/06_SDK_SPEC.md) - Full SDK specification
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { NavigationContainerRef, ParamListBase } from "@react-navigation/native";
|
|
2
|
+
import { PIHClient, type PIHConfig, type StorageAdapter } from "@product-intelligence-hub/sdk-core";
|
|
3
|
+
import { createScreenTracker, type ScreenTrackerOptions, type ScreenTracker } from "./screen-tracker.js";
|
|
4
|
+
/**
|
|
5
|
+
* React Native specific PIH configuration
|
|
6
|
+
*/
|
|
7
|
+
export interface RNPIHConfig extends Omit<PIHConfig, "platform"> {
|
|
8
|
+
/** Platform will be auto-detected from React Native */
|
|
9
|
+
platform?: "ios" | "android" | "react-native";
|
|
10
|
+
/** Enable lifecycle tracking (default: true) */
|
|
11
|
+
trackLifecycle?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* React Native PIH Client
|
|
15
|
+
* Extends the base client with React Native-specific features
|
|
16
|
+
*/
|
|
17
|
+
export declare class RNPIHClient extends PIHClient {
|
|
18
|
+
private lifecycle;
|
|
19
|
+
private screenTracker;
|
|
20
|
+
private trackLifecycle;
|
|
21
|
+
constructor(config: RNPIHConfig, storage?: StorageAdapter);
|
|
22
|
+
/**
|
|
23
|
+
* Initialize the React Native client
|
|
24
|
+
*/
|
|
25
|
+
initialize(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Setup screen tracking with React Navigation
|
|
28
|
+
*/
|
|
29
|
+
setupScreenTracking(navigationRef: NavigationContainerRef<ParamListBase>, options?: ScreenTrackerOptions): () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Get the screen tracker instance
|
|
32
|
+
*/
|
|
33
|
+
getScreenTracker(): ScreenTracker | null;
|
|
34
|
+
/**
|
|
35
|
+
* Manually track a screen view
|
|
36
|
+
*/
|
|
37
|
+
trackScreen(screenName: string, params?: Record<string, unknown>): void;
|
|
38
|
+
/**
|
|
39
|
+
* Handle app state change
|
|
40
|
+
* Can be called manually if automatic lifecycle tracking is disabled
|
|
41
|
+
*/
|
|
42
|
+
onAppStateChange(state: "active" | "background" | "inactive"): void;
|
|
43
|
+
/**
|
|
44
|
+
* Enable lifecycle tracking
|
|
45
|
+
*/
|
|
46
|
+
enableLifecycleTracking(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Disable lifecycle tracking
|
|
49
|
+
*/
|
|
50
|
+
disableLifecycleTracking(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Destroy the client
|
|
53
|
+
*/
|
|
54
|
+
destroy(): void;
|
|
55
|
+
protected log(...args: unknown[]): void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Initialize the PIH React Native SDK
|
|
59
|
+
*/
|
|
60
|
+
declare function init(config: RNPIHConfig): RNPIHClient;
|
|
61
|
+
/**
|
|
62
|
+
* Get the current instance
|
|
63
|
+
*/
|
|
64
|
+
declare function getInstance(): RNPIHClient | null;
|
|
65
|
+
/**
|
|
66
|
+
* Reset the singleton (for testing)
|
|
67
|
+
*/
|
|
68
|
+
declare function resetInstance(): void;
|
|
69
|
+
declare const PIH: {
|
|
70
|
+
init: typeof init;
|
|
71
|
+
getInstance: typeof getInstance;
|
|
72
|
+
resetInstance: typeof resetInstance;
|
|
73
|
+
RNPIHClient: typeof RNPIHClient;
|
|
74
|
+
createScreenTracker: typeof createScreenTracker;
|
|
75
|
+
};
|
|
76
|
+
export default PIH;
|
|
77
|
+
export { init, getInstance, resetInstance, createScreenTracker };
|
|
78
|
+
export type { ScreenTrackerOptions, ScreenTracker };
|
|
79
|
+
export type { PIHConfig, TrackEvent, TrackOptions, TransportOptions, PIHError, PIHErrorCode, } from "@product-intelligence-hub/sdk-core";
|
|
80
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACtF,OAAO,EACL,SAAS,EACT,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EACL,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC9D,uDAAuD;IACvD,QAAQ,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,cAAc,CAAC;IAC9C,gDAAgD;IAChD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,qBAAa,WAAY,SAAQ,SAAS;IACxC,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,cAAc,CAAU;gBAEpB,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,cAAc;IAgBzD;;OAEG;IACY,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY1C;;OAEG;IACH,mBAAmB,CACjB,aAAa,EAAE,sBAAsB,CAAC,aAAa,CAAC,EACpD,OAAO,CAAC,EAAE,oBAAoB,GAC7B,MAAM,IAAI;IAKb;;OAEG;IACH,gBAAgB,IAAI,aAAa,GAAG,IAAI;IAIxC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAYvE;;;OAGG;IACH,gBAAgB,CAAC,KAAK,EAAE,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,IAAI;IAWnE;;OAEG;IACH,uBAAuB,IAAI,IAAI;IAO/B;;OAEG;IACH,wBAAwB,IAAI,IAAI;IAOhC;;OAEG;IACM,OAAO,IAAI,IAAI;cAOL,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;CAKjD;AAOD;;GAEG;AACH,iBAAS,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAc9C;AAED;;GAEG;AACH,iBAAS,WAAW,IAAI,WAAW,GAAG,IAAI,CAEzC;AAED;;GAEG;AACH,iBAAS,aAAa,IAAI,IAAI,CAK7B;AAGD,QAAA,MAAM,GAAG;;;;;;CAMR,CAAC;AAEF,eAAe,GAAG,CAAC;AACnB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,mBAAmB,EAAE,CAAC;AACjE,YAAY,EAAE,oBAAoB,EAAE,aAAa,EAAE,CAAC;AAGpD,YAAY,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,QAAQ,EACR,YAAY,GACb,MAAM,oCAAoC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
|
+
import { PIHClient, } from "@product-intelligence-hub/sdk-core";
|
|
3
|
+
import { createRNStorage } from "./storage.js";
|
|
4
|
+
import { LifecycleManager } from "./lifecycle.js";
|
|
5
|
+
import { createScreenTracker, } from "./screen-tracker.js";
|
|
6
|
+
/**
|
|
7
|
+
* React Native PIH Client
|
|
8
|
+
* Extends the base client with React Native-specific features
|
|
9
|
+
*/
|
|
10
|
+
export class RNPIHClient extends PIHClient {
|
|
11
|
+
lifecycle = null;
|
|
12
|
+
screenTracker = null;
|
|
13
|
+
trackLifecycle;
|
|
14
|
+
constructor(config, storage) {
|
|
15
|
+
// Auto-detect platform from React Native
|
|
16
|
+
const platform = config.platform ?? (Platform.OS === "ios" ? "ios" : "android");
|
|
17
|
+
const rnConfig = {
|
|
18
|
+
...config,
|
|
19
|
+
platform,
|
|
20
|
+
};
|
|
21
|
+
// Use provided storage or create RN storage
|
|
22
|
+
super(rnConfig, storage ?? createRNStorage());
|
|
23
|
+
this.trackLifecycle = config.trackLifecycle !== false;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the React Native client
|
|
27
|
+
*/
|
|
28
|
+
async initialize() {
|
|
29
|
+
await super.initialize();
|
|
30
|
+
// Start lifecycle manager
|
|
31
|
+
if (this.trackLifecycle) {
|
|
32
|
+
this.lifecycle = new LifecycleManager(this, this.config.debug);
|
|
33
|
+
this.lifecycle.start();
|
|
34
|
+
}
|
|
35
|
+
this.log("React Native client initialized");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Setup screen tracking with React Navigation
|
|
39
|
+
*/
|
|
40
|
+
setupScreenTracking(navigationRef, options) {
|
|
41
|
+
this.screenTracker = createScreenTracker(this, options);
|
|
42
|
+
return this.screenTracker.setup(navigationRef);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get the screen tracker instance
|
|
46
|
+
*/
|
|
47
|
+
getScreenTracker() {
|
|
48
|
+
return this.screenTracker;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Manually track a screen view
|
|
52
|
+
*/
|
|
53
|
+
trackScreen(screenName, params) {
|
|
54
|
+
if (this.screenTracker) {
|
|
55
|
+
this.screenTracker.trackScreen(screenName, params);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Track without screen tracker
|
|
59
|
+
this.track("screen_viewed", {
|
|
60
|
+
screen_name: screenName,
|
|
61
|
+
params,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Handle app state change
|
|
67
|
+
* Can be called manually if automatic lifecycle tracking is disabled
|
|
68
|
+
*/
|
|
69
|
+
onAppStateChange(state) {
|
|
70
|
+
this.log("App state change:", state);
|
|
71
|
+
if (state === "background" || state === "inactive") {
|
|
72
|
+
// Flush events when app goes to background
|
|
73
|
+
this.flush().catch((error) => {
|
|
74
|
+
this.log("Flush error on app state change:", error);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Enable lifecycle tracking
|
|
80
|
+
*/
|
|
81
|
+
enableLifecycleTracking() {
|
|
82
|
+
if (!this.lifecycle) {
|
|
83
|
+
this.lifecycle = new LifecycleManager(this, this.config.debug);
|
|
84
|
+
this.lifecycle.start();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Disable lifecycle tracking
|
|
89
|
+
*/
|
|
90
|
+
disableLifecycleTracking() {
|
|
91
|
+
if (this.lifecycle) {
|
|
92
|
+
this.lifecycle.stop();
|
|
93
|
+
this.lifecycle = null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Destroy the client
|
|
98
|
+
*/
|
|
99
|
+
destroy() {
|
|
100
|
+
if (this.lifecycle) {
|
|
101
|
+
this.lifecycle.stop();
|
|
102
|
+
}
|
|
103
|
+
super.destroy();
|
|
104
|
+
}
|
|
105
|
+
log(...args) {
|
|
106
|
+
if (this.config.debug) {
|
|
107
|
+
console.log("[PIH RN]", ...args);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Singleton instance
|
|
113
|
+
*/
|
|
114
|
+
let instance = null;
|
|
115
|
+
/**
|
|
116
|
+
* Initialize the PIH React Native SDK
|
|
117
|
+
*/
|
|
118
|
+
function init(config) {
|
|
119
|
+
if (instance) {
|
|
120
|
+
console.warn("[PIH] SDK already initialized. Returning existing instance.");
|
|
121
|
+
return instance;
|
|
122
|
+
}
|
|
123
|
+
instance = new RNPIHClient(config);
|
|
124
|
+
// Auto-initialize
|
|
125
|
+
instance.initialize().catch((error) => {
|
|
126
|
+
console.error("[PIH] Failed to initialize:", error);
|
|
127
|
+
});
|
|
128
|
+
return instance;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get the current instance
|
|
132
|
+
*/
|
|
133
|
+
function getInstance() {
|
|
134
|
+
return instance;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Reset the singleton (for testing)
|
|
138
|
+
*/
|
|
139
|
+
function resetInstance() {
|
|
140
|
+
if (instance) {
|
|
141
|
+
instance.destroy();
|
|
142
|
+
instance = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Default export
|
|
146
|
+
const PIH = {
|
|
147
|
+
init,
|
|
148
|
+
getInstance,
|
|
149
|
+
resetInstance,
|
|
150
|
+
RNPIHClient,
|
|
151
|
+
createScreenTracker,
|
|
152
|
+
};
|
|
153
|
+
export default PIH;
|
|
154
|
+
export { init, getInstance, resetInstance, createScreenTracker };
|
|
155
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type AppStateStatus } from "react-native";
|
|
2
|
+
import type { PIHClient } from "@product-intelligence-hub/sdk-core";
|
|
3
|
+
/**
|
|
4
|
+
* Lifecycle manager for React Native app state changes
|
|
5
|
+
*/
|
|
6
|
+
export declare class LifecycleManager {
|
|
7
|
+
private client;
|
|
8
|
+
private appState;
|
|
9
|
+
private subscription;
|
|
10
|
+
private debug;
|
|
11
|
+
constructor(client: PIHClient, debug?: boolean);
|
|
12
|
+
/**
|
|
13
|
+
* Start listening to app state changes
|
|
14
|
+
*/
|
|
15
|
+
start(): void;
|
|
16
|
+
/**
|
|
17
|
+
* Stop listening to app state changes
|
|
18
|
+
*/
|
|
19
|
+
stop(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Handle app state change
|
|
22
|
+
*/
|
|
23
|
+
private handleAppStateChange;
|
|
24
|
+
/**
|
|
25
|
+
* Handle app going to background
|
|
26
|
+
*/
|
|
27
|
+
private handleAppBackground;
|
|
28
|
+
/**
|
|
29
|
+
* Handle app coming to foreground
|
|
30
|
+
*/
|
|
31
|
+
private handleAppForeground;
|
|
32
|
+
/**
|
|
33
|
+
* Get current app state
|
|
34
|
+
*/
|
|
35
|
+
getCurrentState(): AppStateStatus;
|
|
36
|
+
/**
|
|
37
|
+
* Set debug mode
|
|
38
|
+
*/
|
|
39
|
+
setDebug(enabled: boolean): void;
|
|
40
|
+
private log;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEpE;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,KAAK,CAAU;gBAEX,MAAM,EAAE,SAAS,EAAE,KAAK,UAAQ;IAM5C;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;OAEG;IACH,IAAI,IAAI,IAAI;IAQZ;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAe1B;IAEF;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAc3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;OAEG;IACH,eAAe,IAAI,cAAc;IAIjC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIhC,OAAO,CAAC,GAAG;CAKZ"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { AppState } from "react-native";
|
|
2
|
+
/**
|
|
3
|
+
* Lifecycle manager for React Native app state changes
|
|
4
|
+
*/
|
|
5
|
+
export class LifecycleManager {
|
|
6
|
+
client;
|
|
7
|
+
appState;
|
|
8
|
+
subscription = null;
|
|
9
|
+
debug;
|
|
10
|
+
constructor(client, debug = false) {
|
|
11
|
+
this.client = client;
|
|
12
|
+
this.appState = AppState.currentState;
|
|
13
|
+
this.debug = debug;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Start listening to app state changes
|
|
17
|
+
*/
|
|
18
|
+
start() {
|
|
19
|
+
// AppState.addEventListener returns a subscription in React Native 0.65+
|
|
20
|
+
this.subscription = AppState.addEventListener("change", this.handleAppStateChange);
|
|
21
|
+
this.log("Lifecycle manager started, initial state:", this.appState);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Stop listening to app state changes
|
|
25
|
+
*/
|
|
26
|
+
stop() {
|
|
27
|
+
if (this.subscription) {
|
|
28
|
+
this.subscription.remove();
|
|
29
|
+
this.subscription = null;
|
|
30
|
+
}
|
|
31
|
+
this.log("Lifecycle manager stopped");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Handle app state change
|
|
35
|
+
*/
|
|
36
|
+
handleAppStateChange = (nextState) => {
|
|
37
|
+
const previousState = this.appState;
|
|
38
|
+
this.log("App state change:", previousState, "->", nextState);
|
|
39
|
+
// App going to background
|
|
40
|
+
if (previousState === "active" && nextState.match(/inactive|background/)) {
|
|
41
|
+
this.handleAppBackground();
|
|
42
|
+
}
|
|
43
|
+
// App coming to foreground
|
|
44
|
+
if (previousState.match(/inactive|background/) && nextState === "active") {
|
|
45
|
+
this.handleAppForeground();
|
|
46
|
+
}
|
|
47
|
+
this.appState = nextState;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Handle app going to background
|
|
51
|
+
*/
|
|
52
|
+
handleAppBackground() {
|
|
53
|
+
this.log("App going to background, flushing events");
|
|
54
|
+
// Flush any pending events
|
|
55
|
+
this.client.flush().catch((error) => {
|
|
56
|
+
this.log("Flush error on background:", error);
|
|
57
|
+
});
|
|
58
|
+
// Track app backgrounded event
|
|
59
|
+
this.client.track("app_backgrounded", {
|
|
60
|
+
timestamp: new Date().toISOString(),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Handle app coming to foreground
|
|
65
|
+
*/
|
|
66
|
+
handleAppForeground() {
|
|
67
|
+
this.log("App coming to foreground");
|
|
68
|
+
// Track app foregrounded event
|
|
69
|
+
this.client.track("app_foregrounded", {
|
|
70
|
+
timestamp: new Date().toISOString(),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get current app state
|
|
75
|
+
*/
|
|
76
|
+
getCurrentState() {
|
|
77
|
+
return this.appState;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Set debug mode
|
|
81
|
+
*/
|
|
82
|
+
setDebug(enabled) {
|
|
83
|
+
this.debug = enabled;
|
|
84
|
+
}
|
|
85
|
+
log(...args) {
|
|
86
|
+
if (this.debug) {
|
|
87
|
+
console.log("[PIH Lifecycle]", ...args);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { NavigationContainerRef, ParamListBase } from "@react-navigation/native";
|
|
2
|
+
import type { PIHClient } from "@product-intelligence-hub/sdk-core";
|
|
3
|
+
/**
|
|
4
|
+
* Screen tracking options
|
|
5
|
+
*/
|
|
6
|
+
export interface ScreenTrackerOptions {
|
|
7
|
+
/** Whether to track screen params (default: false for privacy) */
|
|
8
|
+
trackParams?: boolean;
|
|
9
|
+
/** Custom event name (default: "screen_viewed") */
|
|
10
|
+
eventName?: string;
|
|
11
|
+
/** Screens to ignore */
|
|
12
|
+
ignoreScreens?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create a screen tracker for React Navigation
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { NavigationContainer } from '@react-navigation/native';
|
|
20
|
+
* import { useRef } from 'react';
|
|
21
|
+
* import { analytics, createScreenTracker } from '@product-intelligence-hub/sdk-react-native';
|
|
22
|
+
*
|
|
23
|
+
* function App() {
|
|
24
|
+
* const navigationRef = useRef(null);
|
|
25
|
+
* const routeNameRef = useRef<string>();
|
|
26
|
+
*
|
|
27
|
+
* return (
|
|
28
|
+
* <NavigationContainer
|
|
29
|
+
* ref={navigationRef}
|
|
30
|
+
* onReady={() => {
|
|
31
|
+
* routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name;
|
|
32
|
+
* }}
|
|
33
|
+
* onStateChange={async () => {
|
|
34
|
+
* const previousRouteName = routeNameRef.current;
|
|
35
|
+
* const currentRouteName = navigationRef.current?.getCurrentRoute()?.name;
|
|
36
|
+
*
|
|
37
|
+
* if (currentRouteName && previousRouteName !== currentRouteName) {
|
|
38
|
+
* analytics.track('screen_viewed', { screen_name: currentRouteName });
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* routeNameRef.current = currentRouteName;
|
|
42
|
+
* }}
|
|
43
|
+
* >
|
|
44
|
+
* {children}
|
|
45
|
+
* </NavigationContainer>
|
|
46
|
+
* );
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function createScreenTracker(client: PIHClient, options?: ScreenTrackerOptions): {
|
|
51
|
+
setup: (navigationRef: NavigationContainerRef<ParamListBase>) => () => void;
|
|
52
|
+
getCurrentRouteName: () => string | undefined;
|
|
53
|
+
trackScreen: (screenName: string, params?: Record<string, unknown>) => void;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Type for the screen tracker
|
|
57
|
+
*/
|
|
58
|
+
export type ScreenTracker = ReturnType<typeof createScreenTracker>;
|
|
59
|
+
//# sourceMappingURL=screen-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-tracker.d.ts","sourceRoot":"","sources":["../src/screen-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE,oBAAyB;2BAcjB,sBAAsB,CAAC,aAAa,CAAC,KACnD,MAAM,IAAI;+BAsCmB,MAAM,GAAG,SAAS;8BAQpC,MAAM,WACT,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC/B,IAAI;EAuBR;AAoCD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a screen tracker for React Navigation
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* import { NavigationContainer } from '@react-navigation/native';
|
|
7
|
+
* import { useRef } from 'react';
|
|
8
|
+
* import { analytics, createScreenTracker } from '@product-intelligence-hub/sdk-react-native';
|
|
9
|
+
*
|
|
10
|
+
* function App() {
|
|
11
|
+
* const navigationRef = useRef(null);
|
|
12
|
+
* const routeNameRef = useRef<string>();
|
|
13
|
+
*
|
|
14
|
+
* return (
|
|
15
|
+
* <NavigationContainer
|
|
16
|
+
* ref={navigationRef}
|
|
17
|
+
* onReady={() => {
|
|
18
|
+
* routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name;
|
|
19
|
+
* }}
|
|
20
|
+
* onStateChange={async () => {
|
|
21
|
+
* const previousRouteName = routeNameRef.current;
|
|
22
|
+
* const currentRouteName = navigationRef.current?.getCurrentRoute()?.name;
|
|
23
|
+
*
|
|
24
|
+
* if (currentRouteName && previousRouteName !== currentRouteName) {
|
|
25
|
+
* analytics.track('screen_viewed', { screen_name: currentRouteName });
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* routeNameRef.current = currentRouteName;
|
|
29
|
+
* }}
|
|
30
|
+
* >
|
|
31
|
+
* {children}
|
|
32
|
+
* </NavigationContainer>
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function createScreenTracker(client, options = {}) {
|
|
38
|
+
const { trackParams = false, eventName = "screen_viewed", ignoreScreens = [], } = options;
|
|
39
|
+
let currentRouteName;
|
|
40
|
+
/**
|
|
41
|
+
* Setup screen tracking on a navigation container
|
|
42
|
+
*/
|
|
43
|
+
function setup(navigationRef) {
|
|
44
|
+
const unsubscribe = navigationRef.addListener("state", () => {
|
|
45
|
+
const previousRouteName = currentRouteName;
|
|
46
|
+
const currentRoute = navigationRef.getCurrentRoute();
|
|
47
|
+
currentRouteName = currentRoute?.name;
|
|
48
|
+
// Skip if no route name or same as previous
|
|
49
|
+
if (!currentRouteName || currentRouteName === previousRouteName) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Skip ignored screens
|
|
53
|
+
if (ignoreScreens.includes(currentRouteName)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Track screen view
|
|
57
|
+
const properties = {
|
|
58
|
+
screen_name: currentRouteName,
|
|
59
|
+
previous_screen: previousRouteName ?? null,
|
|
60
|
+
};
|
|
61
|
+
// Optionally include params
|
|
62
|
+
if (trackParams && currentRoute?.params) {
|
|
63
|
+
properties["params"] = sanitizeParams(currentRoute.params);
|
|
64
|
+
}
|
|
65
|
+
client.track(eventName, properties);
|
|
66
|
+
});
|
|
67
|
+
return unsubscribe;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the current route name
|
|
71
|
+
*/
|
|
72
|
+
function getCurrentRouteName() {
|
|
73
|
+
return currentRouteName;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Manually track a screen view
|
|
77
|
+
*/
|
|
78
|
+
function trackScreen(screenName, params) {
|
|
79
|
+
if (ignoreScreens.includes(screenName)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const properties = {
|
|
83
|
+
screen_name: screenName,
|
|
84
|
+
previous_screen: currentRouteName ?? null,
|
|
85
|
+
};
|
|
86
|
+
if (trackParams && params) {
|
|
87
|
+
properties["params"] = sanitizeParams(params);
|
|
88
|
+
}
|
|
89
|
+
currentRouteName = screenName;
|
|
90
|
+
client.track(eventName, properties);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
setup,
|
|
94
|
+
getCurrentRouteName,
|
|
95
|
+
trackScreen,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Sanitize params to remove potentially sensitive data
|
|
100
|
+
*/
|
|
101
|
+
function sanitizeParams(params) {
|
|
102
|
+
const sanitized = {};
|
|
103
|
+
for (const [key, value] of Object.entries(params)) {
|
|
104
|
+
// Skip potentially sensitive keys
|
|
105
|
+
const lowerKey = key.toLowerCase();
|
|
106
|
+
if (lowerKey.includes("password") ||
|
|
107
|
+
lowerKey.includes("token") ||
|
|
108
|
+
lowerKey.includes("secret") ||
|
|
109
|
+
lowerKey.includes("key") ||
|
|
110
|
+
lowerKey.includes("auth")) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
// Only include primitive values
|
|
114
|
+
if (typeof value === "string" ||
|
|
115
|
+
typeof value === "number" ||
|
|
116
|
+
typeof value === "boolean") {
|
|
117
|
+
sanitized[key] = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return sanitized;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=screen-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-tracker.js","sourceRoot":"","sources":["../src/screen-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { StorageAdapter } from "@product-intelligence-hub/sdk-core";
|
|
2
|
+
/** Shape of an AsyncStorage-compatible module */
|
|
3
|
+
export type AsyncStorageCompat = {
|
|
4
|
+
getItem: (key: string) => Promise<string | null>;
|
|
5
|
+
setItem: (key: string, value: string) => Promise<void>;
|
|
6
|
+
removeItem: (key: string) => Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Create the React Native storage adapter
|
|
10
|
+
*/
|
|
11
|
+
export declare function createRNStorage(asyncStorage?: AsyncStorageCompat): StorageAdapter;
|
|
12
|
+
/**
|
|
13
|
+
* Export the storage adapter singleton
|
|
14
|
+
*/
|
|
15
|
+
export declare const rnStorage: StorageAdapter;
|
|
16
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,iDAAiD;AACjD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C,CAAC;AAmEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,CAAC,EAAE,kBAAkB,GAAG,cAAc,CAYjF;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,gBAAoB,CAAC"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// AsyncStorage is imported dynamically to handle cases where it's not installed
|
|
2
|
+
let AsyncStorageModule = null;
|
|
3
|
+
try {
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
5
|
+
AsyncStorageModule = require("@react-native-async-storage/async-storage").default;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
// AsyncStorage not available
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* AsyncStorage adapter for React Native
|
|
12
|
+
*/
|
|
13
|
+
class AsyncStorageAdapter {
|
|
14
|
+
asyncStorage;
|
|
15
|
+
constructor(asyncStorage) {
|
|
16
|
+
this.asyncStorage = asyncStorage;
|
|
17
|
+
}
|
|
18
|
+
async get(key) {
|
|
19
|
+
try {
|
|
20
|
+
return await this.asyncStorage.getItem(key);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.warn("[PIH] AsyncStorage.getItem error:", error);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async set(key, value) {
|
|
28
|
+
try {
|
|
29
|
+
await this.asyncStorage.setItem(key, value);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.warn("[PIH] AsyncStorage.setItem error:", error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async remove(key) {
|
|
36
|
+
try {
|
|
37
|
+
await this.asyncStorage.removeItem(key);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.warn("[PIH] AsyncStorage.removeItem error:", error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* In-memory storage fallback
|
|
46
|
+
*/
|
|
47
|
+
class MemoryStorage {
|
|
48
|
+
data = new Map();
|
|
49
|
+
async get(key) {
|
|
50
|
+
return this.data.get(key) ?? null;
|
|
51
|
+
}
|
|
52
|
+
async set(key, value) {
|
|
53
|
+
this.data.set(key, value);
|
|
54
|
+
}
|
|
55
|
+
async remove(key) {
|
|
56
|
+
this.data.delete(key);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Create the React Native storage adapter
|
|
61
|
+
*/
|
|
62
|
+
export function createRNStorage(asyncStorage) {
|
|
63
|
+
// Use provided storage or the auto-detected module
|
|
64
|
+
const storageModule = asyncStorage ?? AsyncStorageModule;
|
|
65
|
+
if (storageModule) {
|
|
66
|
+
return new AsyncStorageAdapter(storageModule);
|
|
67
|
+
}
|
|
68
|
+
console.warn("[PIH] AsyncStorage not available, using in-memory storage. " +
|
|
69
|
+
"Make sure @react-native-async-storage/async-storage is installed.");
|
|
70
|
+
return new MemoryStorage();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Export the storage adapter singleton
|
|
74
|
+
*/
|
|
75
|
+
export const rnStorage = createRNStorage();
|
|
76
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AASA,gFAAgF;AAChF,IAAI,kBAAkB,GAA8B,IAAI,CAAC;AAEzD,IAAI,CAAC;IACH,8DAA8D;IAC9D,kBAAkB,GAAG,OAAO,CAAC,2CAA2C,CAAC,CAAC,OAAO,CAAC;AACpF,CAAC;AAAC,MAAM,CAAC;IACP,6BAA6B;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,mBAAmB;IACf,YAAY,CAAqB;IAEzC,YAAY,YAAgC;QAC1C,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;CACF;AAED;;GAEG;AACH,MAAM,aAAa;IACT,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa;QAClC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,YAAiC;IAC/D,mDAAmD;IACnD,MAAM,aAAa,GAAG,YAAY,IAAI,kBAAkB,CAAC;IACzD,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,IAAI,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,CAAC,IAAI,CACV,6DAA6D;QAC3D,mEAAmE,CACtE,CAAC;IACF,OAAO,IAAI,aAAa,EAAE,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@product-intelligence-hub/sdk-react-native",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React Native SDK for Product Intelligence Hub",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/product-intelligence-hub/product-intelligence-hub",
|
|
25
|
+
"directory": "packages/sdk-react-native"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"analytics",
|
|
29
|
+
"product-intelligence",
|
|
30
|
+
"sdk",
|
|
31
|
+
"tracking",
|
|
32
|
+
"events",
|
|
33
|
+
"react-native",
|
|
34
|
+
"mobile"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@product-intelligence-hub/sdk-core": "0.1.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@react-native-async-storage/async-storage": ">=1.0.0",
|
|
41
|
+
"@react-navigation/native": ">=6.0.0",
|
|
42
|
+
"react-native": ">=0.60.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependenciesMeta": {
|
|
45
|
+
"@react-navigation/native": {
|
|
46
|
+
"optional": true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@react-native-async-storage/async-storage": "^1.23.0",
|
|
51
|
+
"@react-navigation/native": "^6.1.0",
|
|
52
|
+
"@types/node": "^20.12.0",
|
|
53
|
+
"@types/react-native": "^0.73.0",
|
|
54
|
+
"typescript": "^5.4.0",
|
|
55
|
+
"vitest": "^1.6.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsc",
|
|
59
|
+
"dev": "tsc --watch",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"lint": "eslint src --ext .ts",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"test:watch": "vitest"
|
|
64
|
+
}
|
|
65
|
+
}
|