@bananalytics/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 +93 -0
- package/dist/context/app.d.ts +12 -0
- package/dist/context/app.js +34 -0
- package/dist/context/device.d.ts +12 -0
- package/dist/context/device.js +38 -0
- package/dist/context/session.d.ts +49 -0
- package/dist/context/session.js +99 -0
- package/dist/core/client.d.ts +112 -0
- package/dist/core/client.js +283 -0
- package/dist/core/config.d.ts +27 -0
- package/dist/core/config.js +41 -0
- package/dist/core/errors.d.ts +19 -0
- package/dist/core/errors.js +40 -0
- package/dist/hooks/BananalyticsProvider.d.ts +22 -0
- package/dist/hooks/BananalyticsProvider.js +72 -0
- package/dist/hooks/RochadeProvider.d.ts +22 -0
- package/dist/hooks/RochadeProvider.js +72 -0
- package/dist/hooks/useBananalytics.d.ts +16 -0
- package/dist/hooks/useBananalytics.js +26 -0
- package/dist/hooks/useRochade.d.ts +16 -0
- package/dist/hooks/useRochade.js +26 -0
- package/dist/hooks/useTrackScreen.d.ts +14 -0
- package/dist/hooks/useTrackScreen.js +24 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.js +97 -0
- package/dist/privacy/consent.d.ts +39 -0
- package/dist/privacy/consent.js +57 -0
- package/dist/privacy/sanitizer.d.ts +16 -0
- package/dist/privacy/sanitizer.js +40 -0
- package/dist/tracking/event-builder.d.ts +47 -0
- package/dist/tracking/event-builder.js +73 -0
- package/dist/tracking/lifecycle-tracker.d.ts +24 -0
- package/dist/tracking/lifecycle-tracker.js +51 -0
- package/dist/tracking/screen-tracker.d.ts +20 -0
- package/dist/tracking/screen-tracker.js +34 -0
- package/dist/tracking/user-identity.d.ts +40 -0
- package/dist/tracking/user-identity.js +75 -0
- package/dist/transport/batcher.d.ts +44 -0
- package/dist/transport/batcher.js +91 -0
- package/dist/transport/persister.d.ts +49 -0
- package/dist/transport/persister.js +148 -0
- package/dist/transport/queue.d.ts +41 -0
- package/dist/transport/queue.js +67 -0
- package/dist/transport/retry.d.ts +15 -0
- package/dist/transport/retry.js +52 -0
- package/dist/transport/transport.d.ts +23 -0
- package/dist/transport/transport.js +51 -0
- package/dist/types/common.d.ts +6 -0
- package/dist/types/common.js +2 -0
- package/dist/types/config.d.ts +25 -0
- package/dist/types/config.js +2 -0
- package/dist/types/events.d.ts +53 -0
- package/dist/types/events.js +2 -0
- package/dist/utils/id.d.ts +13 -0
- package/dist/utils/id.js +18 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.js +24 -0
- package/dist/utils/network.d.ts +7 -0
- package/dist/utils/network.js +33 -0
- package/dist/utils/time.d.ts +13 -0
- package/dist/utils/time.js +17 -0
- package/dist/utils/validation.d.ts +26 -0
- package/dist/utils/validation.js +60 -0
- package/package.json +64 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useRochade = useRochade;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const RochadeProvider_1 = require("./RochadeProvider");
|
|
6
|
+
/**
|
|
7
|
+
* React hook to access the Rochade client instance.
|
|
8
|
+
*
|
|
9
|
+
* @returns The initialized Rochade client
|
|
10
|
+
* @throws Error if used outside RochadeProvider
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* function MyComponent() {
|
|
15
|
+
* const rochade = useRochade();
|
|
16
|
+
* rochade.track('button_clicked');
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
function useRochade() {
|
|
21
|
+
const client = (0, react_1.useContext)(RochadeProvider_1.RochadeContext);
|
|
22
|
+
if (!client) {
|
|
23
|
+
throw new Error('useRochade must be used within a <RochadeProvider>');
|
|
24
|
+
}
|
|
25
|
+
return client;
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React hook that tracks a screen view when the component mounts.
|
|
3
|
+
*
|
|
4
|
+
* @param screenName - The name of the screen to track
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* function HomeScreen() {
|
|
9
|
+
* useTrackScreen('HomeScreen');
|
|
10
|
+
* return <View>...</View>;
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function useTrackScreen(screenName: string): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useTrackScreen = useTrackScreen;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const useBananalytics_1 = require("./useBananalytics");
|
|
6
|
+
/**
|
|
7
|
+
* React hook that tracks a screen view when the component mounts.
|
|
8
|
+
*
|
|
9
|
+
* @param screenName - The name of the screen to track
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* function HomeScreen() {
|
|
14
|
+
* useTrackScreen('HomeScreen');
|
|
15
|
+
* return <View>...</View>;
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
function useTrackScreen(screenName) {
|
|
20
|
+
const client = (0, useBananalytics_1.useBananalytics)();
|
|
21
|
+
(0, react_1.useEffect)(() => {
|
|
22
|
+
client.screen(screenName);
|
|
23
|
+
}, [client, screenName]);
|
|
24
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export { BananalyticsClient } from './core/client';
|
|
2
|
+
export { BananalyticsProvider } from './hooks/BananalyticsProvider';
|
|
3
|
+
export { useBananalytics } from './hooks/useBananalytics';
|
|
4
|
+
export { useTrackScreen } from './hooks/useTrackScreen';
|
|
5
|
+
export type { BananalyticsConfig } from './types/config';
|
|
6
|
+
export type { EventPayload, EventType, EventContext } from './types/events';
|
|
7
|
+
export type { Properties } from './types/common';
|
|
8
|
+
export { BananalyticsError, NetworkError, ConfigError, ValidationError } from './core/errors';
|
|
9
|
+
import { BananalyticsConfig } from './types/config';
|
|
10
|
+
import { Properties } from './types/common';
|
|
11
|
+
import { AsyncStorageInterface } from './transport/persister';
|
|
12
|
+
/**
|
|
13
|
+
* Static facade for the BananalyticsSDK.
|
|
14
|
+
* Provides a singleton interface for imperative usage outside React components.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Bananalytics} from '@bananalytics/react-native';
|
|
19
|
+
*
|
|
20
|
+
* Bananalytics.init({ apiKey: 'rk_...', endpoint: 'https://...' });
|
|
21
|
+
* Bananalytics.track('button_clicked', { button: 'signup' });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare const Bananalytics: {
|
|
25
|
+
/**
|
|
26
|
+
* Initializes the SDK with the given configuration.
|
|
27
|
+
*
|
|
28
|
+
* @param config - SDK configuration
|
|
29
|
+
* @param asyncStorage - AsyncStorage implementation (optional, auto-detected)
|
|
30
|
+
*/
|
|
31
|
+
init(config: BananalyticsConfig, asyncStorage?: AsyncStorageInterface): void;
|
|
32
|
+
/**
|
|
33
|
+
* Tracks a custom event.
|
|
34
|
+
*
|
|
35
|
+
* @param eventName - The event name
|
|
36
|
+
* @param properties - Optional event properties
|
|
37
|
+
*/
|
|
38
|
+
track(eventName: string, properties?: Properties): void;
|
|
39
|
+
/**
|
|
40
|
+
* Tracks a screen view.
|
|
41
|
+
*
|
|
42
|
+
* @param screenName - The screen name
|
|
43
|
+
* @param properties - Optional screen properties
|
|
44
|
+
*/
|
|
45
|
+
screen(screenName: string, properties?: Properties): void;
|
|
46
|
+
/**
|
|
47
|
+
* Identifies the current user.
|
|
48
|
+
*
|
|
49
|
+
* @param userId - The user identifier
|
|
50
|
+
* @param traits - Optional user traits
|
|
51
|
+
*/
|
|
52
|
+
identify(userId: string, traits?: Properties): void;
|
|
53
|
+
/** Clears user identity and generates a new anonymous ID. */
|
|
54
|
+
reset(): void;
|
|
55
|
+
/** Opts the user into tracking. */
|
|
56
|
+
optIn(): void;
|
|
57
|
+
/** Opts the user out of tracking. */
|
|
58
|
+
optOut(): void;
|
|
59
|
+
/** Manually flushes all queued events. */
|
|
60
|
+
flush(): Promise<void>;
|
|
61
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Bananalytics = exports.ValidationError = exports.ConfigError = exports.NetworkError = exports.BananalyticsError = exports.useTrackScreen = exports.useBananalytics = exports.BananalyticsProvider = exports.BananalyticsClient = void 0;
|
|
4
|
+
// Public API exports
|
|
5
|
+
var client_1 = require("./core/client");
|
|
6
|
+
Object.defineProperty(exports, "BananalyticsClient", { enumerable: true, get: function () { return client_1.BananalyticsClient; } });
|
|
7
|
+
var BananalyticsProvider_1 = require("./hooks/BananalyticsProvider");
|
|
8
|
+
Object.defineProperty(exports, "BananalyticsProvider", { enumerable: true, get: function () { return BananalyticsProvider_1.BananalyticsProvider; } });
|
|
9
|
+
var useBananalytics_1 = require("./hooks/useBananalytics");
|
|
10
|
+
Object.defineProperty(exports, "useBananalytics", { enumerable: true, get: function () { return useBananalytics_1.useBananalytics; } });
|
|
11
|
+
var useTrackScreen_1 = require("./hooks/useTrackScreen");
|
|
12
|
+
Object.defineProperty(exports, "useTrackScreen", { enumerable: true, get: function () { return useTrackScreen_1.useTrackScreen; } });
|
|
13
|
+
// Errors
|
|
14
|
+
var errors_1 = require("./core/errors");
|
|
15
|
+
Object.defineProperty(exports, "BananalyticsError", { enumerable: true, get: function () { return errors_1.BananalyticsError; } });
|
|
16
|
+
Object.defineProperty(exports, "NetworkError", { enumerable: true, get: function () { return errors_1.NetworkError; } });
|
|
17
|
+
Object.defineProperty(exports, "ConfigError", { enumerable: true, get: function () { return errors_1.ConfigError; } });
|
|
18
|
+
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_1.ValidationError; } });
|
|
19
|
+
const client_2 = require("./core/client");
|
|
20
|
+
let instance = null;
|
|
21
|
+
/**
|
|
22
|
+
* Static facade for the BananalyticsSDK.
|
|
23
|
+
* Provides a singleton interface for imperative usage outside React components.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { Bananalytics} from '@bananalytics/react-native';
|
|
28
|
+
*
|
|
29
|
+
* Bananalytics.init({ apiKey: 'rk_...', endpoint: 'https://...' });
|
|
30
|
+
* Bananalytics.track('button_clicked', { button: 'signup' });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
exports.Bananalytics = {
|
|
34
|
+
/**
|
|
35
|
+
* Initializes the SDK with the given configuration.
|
|
36
|
+
*
|
|
37
|
+
* @param config - SDK configuration
|
|
38
|
+
* @param asyncStorage - AsyncStorage implementation (optional, auto-detected)
|
|
39
|
+
*/
|
|
40
|
+
init(config, asyncStorage) {
|
|
41
|
+
try {
|
|
42
|
+
const storage = asyncStorage ??
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- Auto-detect AsyncStorage
|
|
44
|
+
require('@react-native-async-storage/async-storage').default;
|
|
45
|
+
instance = new client_2.BananalyticsClient(config, storage);
|
|
46
|
+
instance.initialize().catch((err) => {
|
|
47
|
+
console.error('[Bananalytics] Initialization failed:', err);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.error('[Bananalytics] Failed to create client:', err);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
/**
|
|
55
|
+
* Tracks a custom event.
|
|
56
|
+
*
|
|
57
|
+
* @param eventName - The event name
|
|
58
|
+
* @param properties - Optional event properties
|
|
59
|
+
*/
|
|
60
|
+
track(eventName, properties) {
|
|
61
|
+
instance?.track(eventName, properties);
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* Tracks a screen view.
|
|
65
|
+
*
|
|
66
|
+
* @param screenName - The screen name
|
|
67
|
+
* @param properties - Optional screen properties
|
|
68
|
+
*/
|
|
69
|
+
screen(screenName, properties) {
|
|
70
|
+
instance?.screen(screenName, properties);
|
|
71
|
+
},
|
|
72
|
+
/**
|
|
73
|
+
* Identifies the current user.
|
|
74
|
+
*
|
|
75
|
+
* @param userId - The user identifier
|
|
76
|
+
* @param traits - Optional user traits
|
|
77
|
+
*/
|
|
78
|
+
identify(userId, traits) {
|
|
79
|
+
instance?.identify(userId, traits);
|
|
80
|
+
},
|
|
81
|
+
/** Clears user identity and generates a new anonymous ID. */
|
|
82
|
+
reset() {
|
|
83
|
+
instance?.reset();
|
|
84
|
+
},
|
|
85
|
+
/** Opts the user into tracking. */
|
|
86
|
+
optIn() {
|
|
87
|
+
instance?.optIn();
|
|
88
|
+
},
|
|
89
|
+
/** Opts the user out of tracking. */
|
|
90
|
+
optOut() {
|
|
91
|
+
instance?.optOut();
|
|
92
|
+
},
|
|
93
|
+
/** Manually flushes all queued events. */
|
|
94
|
+
async flush() {
|
|
95
|
+
await instance?.flush();
|
|
96
|
+
},
|
|
97
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Logger } from '../utils/logger';
|
|
2
|
+
import { Persister } from '../transport/persister';
|
|
3
|
+
/**
|
|
4
|
+
* Manages user consent for analytics tracking.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ConsentManager {
|
|
7
|
+
private optedOut;
|
|
8
|
+
private readonly persister;
|
|
9
|
+
private readonly logger;
|
|
10
|
+
constructor(persister: Persister, logger: Logger);
|
|
11
|
+
/**
|
|
12
|
+
* Initializes consent state from persisted storage.
|
|
13
|
+
*/
|
|
14
|
+
initialize(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Opts the user into tracking.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* consent.optIn();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
optIn(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Opts the user out of tracking. All event tracking stops immediately.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* consent.optOut();
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
optOut(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Returns whether the user has opted out of tracking.
|
|
35
|
+
*
|
|
36
|
+
* @returns true if opted out
|
|
37
|
+
*/
|
|
38
|
+
isOptedOut(): boolean;
|
|
39
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConsentManager = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Manages user consent for analytics tracking.
|
|
6
|
+
*/
|
|
7
|
+
class ConsentManager {
|
|
8
|
+
constructor(persister, logger) {
|
|
9
|
+
this.optedOut = false;
|
|
10
|
+
this.persister = persister;
|
|
11
|
+
this.logger = logger;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Initializes consent state from persisted storage.
|
|
15
|
+
*/
|
|
16
|
+
async initialize() {
|
|
17
|
+
this.optedOut = await this.persister.loadOptOut();
|
|
18
|
+
if (this.optedOut) {
|
|
19
|
+
this.logger.debug('User is opted out of tracking');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Opts the user into tracking.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* consent.optIn();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
async optIn() {
|
|
31
|
+
this.optedOut = false;
|
|
32
|
+
await this.persister.saveOptOut(false);
|
|
33
|
+
this.logger.debug('User opted in to tracking');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Opts the user out of tracking. All event tracking stops immediately.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* consent.optOut();
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
async optOut() {
|
|
44
|
+
this.optedOut = true;
|
|
45
|
+
await this.persister.saveOptOut(true);
|
|
46
|
+
this.logger.debug('User opted out of tracking');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Returns whether the user has opted out of tracking.
|
|
50
|
+
*
|
|
51
|
+
* @returns true if opted out
|
|
52
|
+
*/
|
|
53
|
+
isOptedOut() {
|
|
54
|
+
return this.optedOut;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.ConsentManager = ConsentManager;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Properties } from '../types/common';
|
|
2
|
+
/**
|
|
3
|
+
* Strips properties that look like PII from auto-captured events.
|
|
4
|
+
* Does NOT strip from user-provided properties (only auto-captured).
|
|
5
|
+
*
|
|
6
|
+
* @param properties - The properties to sanitize
|
|
7
|
+
* @param isAutoCaptured - Whether these are auto-captured (vs user-provided)
|
|
8
|
+
* @returns Sanitized properties
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const clean = sanitizeProperties({ email: 'test@example.com' }, true);
|
|
13
|
+
* // {} — stripped because auto-captured
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function sanitizeProperties(properties: Properties, isAutoCaptured: boolean): Properties;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeProperties = sanitizeProperties;
|
|
4
|
+
const PII_PATTERNS = [
|
|
5
|
+
/email/i,
|
|
6
|
+
/password/i,
|
|
7
|
+
/ssn/i,
|
|
8
|
+
/social.?security/i,
|
|
9
|
+
/credit.?card/i,
|
|
10
|
+
/phone.?number/i,
|
|
11
|
+
/passport/i,
|
|
12
|
+
/driver.?licen[sc]e/i,
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Strips properties that look like PII from auto-captured events.
|
|
16
|
+
* Does NOT strip from user-provided properties (only auto-captured).
|
|
17
|
+
*
|
|
18
|
+
* @param properties - The properties to sanitize
|
|
19
|
+
* @param isAutoCaptured - Whether these are auto-captured (vs user-provided)
|
|
20
|
+
* @returns Sanitized properties
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const clean = sanitizeProperties({ email: 'test@example.com' }, true);
|
|
25
|
+
* // {} — stripped because auto-captured
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function sanitizeProperties(properties, isAutoCaptured) {
|
|
29
|
+
if (!isAutoCaptured) {
|
|
30
|
+
return properties;
|
|
31
|
+
}
|
|
32
|
+
const sanitized = {};
|
|
33
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
34
|
+
const isPII = PII_PATTERNS.some((pattern) => pattern.test(key));
|
|
35
|
+
if (!isPII) {
|
|
36
|
+
sanitized[key] = value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return sanitized;
|
|
40
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { EventPayload, EventContext } from '../types/events';
|
|
2
|
+
import { Properties } from '../types/common';
|
|
3
|
+
import { Logger } from '../utils/logger';
|
|
4
|
+
/** Dependencies for building events. */
|
|
5
|
+
export interface EventBuilderDeps {
|
|
6
|
+
getAnonymousId: () => string;
|
|
7
|
+
getUserId: () => string | null;
|
|
8
|
+
getContext: () => EventContext;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Constructs validated event payloads with all required metadata.
|
|
12
|
+
*/
|
|
13
|
+
export declare class EventBuilder {
|
|
14
|
+
private readonly deps;
|
|
15
|
+
private readonly logger;
|
|
16
|
+
constructor(deps: EventBuilderDeps, logger: Logger);
|
|
17
|
+
/**
|
|
18
|
+
* Builds a track event payload.
|
|
19
|
+
*
|
|
20
|
+
* @param eventName - Name of the event
|
|
21
|
+
* @param properties - Optional event properties
|
|
22
|
+
* @returns The event payload, or null if validation fails
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const payload = builder.track('button_clicked', { button: 'signup' });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
track(eventName: string, properties?: Properties): EventPayload | null;
|
|
30
|
+
/**
|
|
31
|
+
* Builds a screen event payload.
|
|
32
|
+
*
|
|
33
|
+
* @param screenName - Name of the screen
|
|
34
|
+
* @param properties - Optional screen properties
|
|
35
|
+
* @returns The event payload, or null if validation fails
|
|
36
|
+
*/
|
|
37
|
+
screen(screenName: string, properties?: Properties): EventPayload | null;
|
|
38
|
+
/**
|
|
39
|
+
* Builds an identify event payload.
|
|
40
|
+
*
|
|
41
|
+
* @param userId - The user identifier
|
|
42
|
+
* @param traits - Optional user traits
|
|
43
|
+
* @returns The event payload, or null if validation fails
|
|
44
|
+
*/
|
|
45
|
+
identify(userId: string, traits?: Properties): EventPayload | null;
|
|
46
|
+
private build;
|
|
47
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventBuilder = void 0;
|
|
4
|
+
const id_1 = require("../utils/id");
|
|
5
|
+
const time_1 = require("../utils/time");
|
|
6
|
+
const validation_1 = require("../utils/validation");
|
|
7
|
+
/**
|
|
8
|
+
* Constructs validated event payloads with all required metadata.
|
|
9
|
+
*/
|
|
10
|
+
class EventBuilder {
|
|
11
|
+
constructor(deps, logger) {
|
|
12
|
+
this.deps = deps;
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Builds a track event payload.
|
|
17
|
+
*
|
|
18
|
+
* @param eventName - Name of the event
|
|
19
|
+
* @param properties - Optional event properties
|
|
20
|
+
* @returns The event payload, or null if validation fails
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const payload = builder.track('button_clicked', { button: 'signup' });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
track(eventName, properties = {}) {
|
|
28
|
+
return this.build(eventName, 'track', properties);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds a screen event payload.
|
|
32
|
+
*
|
|
33
|
+
* @param screenName - Name of the screen
|
|
34
|
+
* @param properties - Optional screen properties
|
|
35
|
+
* @returns The event payload, or null if validation fails
|
|
36
|
+
*/
|
|
37
|
+
screen(screenName, properties = {}) {
|
|
38
|
+
return this.build('$screen', 'screen', { ...properties, name: screenName });
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Builds an identify event payload.
|
|
42
|
+
*
|
|
43
|
+
* @param userId - The user identifier
|
|
44
|
+
* @param traits - Optional user traits
|
|
45
|
+
* @returns The event payload, or null if validation fails
|
|
46
|
+
*/
|
|
47
|
+
identify(userId, traits = {}) {
|
|
48
|
+
return this.build('$identify', 'identify', { ...traits, userId });
|
|
49
|
+
}
|
|
50
|
+
build(eventName, type, properties) {
|
|
51
|
+
const nameError = (0, validation_1.validateEventName)(eventName);
|
|
52
|
+
if (nameError) {
|
|
53
|
+
this.logger.warn(`Invalid event: ${nameError}`);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const propsError = (0, validation_1.validateProperties)(properties);
|
|
57
|
+
if (propsError) {
|
|
58
|
+
this.logger.warn(`Invalid properties for ${eventName}: ${propsError}`);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
event: eventName,
|
|
63
|
+
type,
|
|
64
|
+
properties,
|
|
65
|
+
context: this.deps.getContext(),
|
|
66
|
+
userId: this.deps.getUserId(),
|
|
67
|
+
anonymousId: this.deps.getAnonymousId(),
|
|
68
|
+
timestamp: (0, time_1.now)(),
|
|
69
|
+
messageId: (0, id_1.generateId)(),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.EventBuilder = EventBuilder;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Logger } from '../utils/logger';
|
|
2
|
+
type EventCallback = (eventName: string, properties?: Record<string, unknown>) => void;
|
|
3
|
+
type FlushCallback = () => void;
|
|
4
|
+
type PersistCallback = () => void;
|
|
5
|
+
/**
|
|
6
|
+
* Tracks app lifecycle events (foreground/background).
|
|
7
|
+
* Auto-captures $app_foreground and $app_background events.
|
|
8
|
+
*/
|
|
9
|
+
export declare class LifecycleTracker {
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private subscription;
|
|
12
|
+
constructor(logger: Logger);
|
|
13
|
+
/**
|
|
14
|
+
* Starts listening for app state changes.
|
|
15
|
+
*
|
|
16
|
+
* @param onTrack - Callback to track events
|
|
17
|
+
* @param onFlush - Callback to flush the queue on background
|
|
18
|
+
* @param onPersist - Callback to persist the queue on background
|
|
19
|
+
*/
|
|
20
|
+
start(onTrack: EventCallback, onFlush: FlushCallback, onPersist: PersistCallback): void;
|
|
21
|
+
/** Stops listening for app state changes. */
|
|
22
|
+
stop(): void;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LifecycleTracker = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Tracks app lifecycle events (foreground/background).
|
|
6
|
+
* Auto-captures $app_foreground and $app_background events.
|
|
7
|
+
*/
|
|
8
|
+
class LifecycleTracker {
|
|
9
|
+
constructor(logger) {
|
|
10
|
+
this.subscription = null;
|
|
11
|
+
this.logger = logger;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Starts listening for app state changes.
|
|
15
|
+
*
|
|
16
|
+
* @param onTrack - Callback to track events
|
|
17
|
+
* @param onFlush - Callback to flush the queue on background
|
|
18
|
+
* @param onPersist - Callback to persist the queue on background
|
|
19
|
+
*/
|
|
20
|
+
start(onTrack, onFlush, onPersist) {
|
|
21
|
+
try {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- Runtime require for RN module
|
|
23
|
+
const { AppState } = require('react-native');
|
|
24
|
+
let currentState = AppState.currentState;
|
|
25
|
+
this.subscription = AppState.addEventListener('change', (nextState) => {
|
|
26
|
+
if (currentState === 'background' && nextState === 'active') {
|
|
27
|
+
this.logger.debug('App foregrounded');
|
|
28
|
+
onTrack('$app_foreground');
|
|
29
|
+
}
|
|
30
|
+
else if (currentState === 'active' && nextState === 'background') {
|
|
31
|
+
this.logger.debug('App backgrounded');
|
|
32
|
+
onTrack('$app_background');
|
|
33
|
+
onPersist();
|
|
34
|
+
onFlush();
|
|
35
|
+
}
|
|
36
|
+
currentState = nextState;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
this.logger.warn('Failed to set up lifecycle tracking (AppState not available)');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Stops listening for app state changes. */
|
|
44
|
+
stop() {
|
|
45
|
+
if (this.subscription) {
|
|
46
|
+
this.subscription.remove();
|
|
47
|
+
this.subscription = null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.LifecycleTracker = LifecycleTracker;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Logger } from '../utils/logger';
|
|
2
|
+
type ScreenCallback = (screenName: string, properties?: Record<string, unknown>) => void;
|
|
3
|
+
/**
|
|
4
|
+
* Integrates with React Navigation to auto-track screen views.
|
|
5
|
+
* Requires the user to pass their navigation container ref.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ScreenTracker {
|
|
8
|
+
private readonly logger;
|
|
9
|
+
private currentScreen;
|
|
10
|
+
constructor(logger: Logger);
|
|
11
|
+
/**
|
|
12
|
+
* Called when a navigation state change occurs.
|
|
13
|
+
* Determines the current screen name and fires a screen event if it changed.
|
|
14
|
+
*
|
|
15
|
+
* @param onScreen - Callback to emit screen events
|
|
16
|
+
* @param getCurrentRoute - Function that returns the current route name
|
|
17
|
+
*/
|
|
18
|
+
handleStateChange(onScreen: ScreenCallback, getCurrentRoute: () => string | undefined): void;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScreenTracker = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Integrates with React Navigation to auto-track screen views.
|
|
6
|
+
* Requires the user to pass their navigation container ref.
|
|
7
|
+
*/
|
|
8
|
+
class ScreenTracker {
|
|
9
|
+
constructor(logger) {
|
|
10
|
+
this.currentScreen = null;
|
|
11
|
+
this.logger = logger;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Called when a navigation state change occurs.
|
|
15
|
+
* Determines the current screen name and fires a screen event if it changed.
|
|
16
|
+
*
|
|
17
|
+
* @param onScreen - Callback to emit screen events
|
|
18
|
+
* @param getCurrentRoute - Function that returns the current route name
|
|
19
|
+
*/
|
|
20
|
+
handleStateChange(onScreen, getCurrentRoute) {
|
|
21
|
+
try {
|
|
22
|
+
const routeName = getCurrentRoute();
|
|
23
|
+
if (routeName && routeName !== this.currentScreen) {
|
|
24
|
+
this.currentScreen = routeName;
|
|
25
|
+
this.logger.debug('Screen changed', routeName);
|
|
26
|
+
onScreen(routeName);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
this.logger.error('Screen tracking error', err);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.ScreenTracker = ScreenTracker;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Logger } from '../utils/logger';
|
|
2
|
+
import { Persister } from '../transport/persister';
|
|
3
|
+
/**
|
|
4
|
+
* Manages user identity — anonymous ID, user ID, and identity lifecycle.
|
|
5
|
+
*/
|
|
6
|
+
export declare class UserIdentity {
|
|
7
|
+
private anonymousId;
|
|
8
|
+
private userId;
|
|
9
|
+
private readonly persister;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
constructor(persister: Persister, logger: Logger);
|
|
12
|
+
/**
|
|
13
|
+
* Initializes identity, loading persisted anonymous and user IDs.
|
|
14
|
+
*/
|
|
15
|
+
initialize(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Sets the user ID for all subsequent events.
|
|
18
|
+
*
|
|
19
|
+
* @param userId - The user identifier
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* identity.identify('user-123');
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
identify(userId: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Clears the user ID and generates a new anonymous ID.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* identity.reset();
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
reset(): Promise<void>;
|
|
36
|
+
/** Returns the current anonymous ID. */
|
|
37
|
+
getAnonymousId(): string;
|
|
38
|
+
/** Returns the current user ID, or null if not identified. */
|
|
39
|
+
getUserId(): string | null;
|
|
40
|
+
}
|