@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 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
@@ -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"}
@@ -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
+ }