@bytem/bytem-tracker-app 0.0.3 → 0.0.6

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.
Files changed (43) hide show
  1. package/README.md +138 -25
  2. package/dist/src/BytemTracker.d.ts +18 -0
  3. package/dist/src/BytemTracker.js +135 -0
  4. package/dist/src/business/index.d.ts +4 -0
  5. package/dist/src/business/index.js +20 -0
  6. package/dist/src/business/trackCheckOutOrder.d.ts +2 -0
  7. package/dist/src/business/trackCheckOutOrder.js +20 -0
  8. package/dist/src/business/trackPayOrder.d.ts +2 -0
  9. package/dist/src/business/trackPayOrder.js +21 -0
  10. package/dist/src/business/trackUser.d.ts +2 -0
  11. package/dist/src/business/trackUser.js +13 -0
  12. package/dist/src/business/trackViewProduct.d.ts +2 -0
  13. package/dist/src/business/trackViewProduct.js +16 -0
  14. package/dist/src/core/base.d.ts +2 -0
  15. package/dist/src/core/base.js +24 -0
  16. package/dist/src/core/device.d.ts +3 -0
  17. package/dist/src/core/device.js +45 -0
  18. package/dist/src/core/request.d.ts +2 -0
  19. package/dist/src/core/request.js +21 -0
  20. package/dist/src/core/session.d.ts +17 -0
  21. package/dist/src/core/session.js +59 -0
  22. package/dist/src/core/storage.d.ts +9 -0
  23. package/dist/src/core/storage.js +41 -0
  24. package/dist/src/index.d.ts +3 -0
  25. package/dist/src/index.js +22 -0
  26. package/dist/src/types.d.ts +56 -0
  27. package/dist/test/BytemTracker.test.d.ts +1 -0
  28. package/dist/test/BytemTracker.test.js +84 -0
  29. package/dist/test/debug.test.d.ts +1 -0
  30. package/dist/test/debug.test.js +58 -0
  31. package/dist/test/setup.d.ts +1 -0
  32. package/dist/test/setup.js +56 -0
  33. package/package.json +30 -11
  34. package/dist/env.d.ts +0 -1
  35. package/dist/env.js +0 -6
  36. package/dist/index.d.ts +0 -4
  37. package/dist/index.js +0 -6
  38. package/dist/tracker.d.ts +0 -26
  39. package/dist/tracker.js +0 -120
  40. package/dist/types.d.ts +0 -24
  41. package/dist/uuid.d.ts +0 -1
  42. package/dist/uuid.js +0 -19
  43. /package/dist/{types.js → src/types.js} +0 -0
package/README.md CHANGED
@@ -1,41 +1,154 @@
1
- # @bytem/bytem-tracker
1
+ # Bytem Tracker SDK (React Native)
2
2
 
3
- ByteM 埋点 SDKReact Native / Expo)
3
+ This is the official Bytem Tracker SDK for React Native applications.
4
4
 
5
- > 本 SDK 为 Flutter `bytem_tracker.dart` 的 **1:1 行为迁移版本**
6
- > 字段、默认值、payload 结构完全一致,后端无需任何改动
5
+ ## Installation
6
+
7
+ Install the package and its peer dependencies using Yarn:
7
8
 
8
- ### 此项目运行起来
9
9
  ```bash
10
- rm -rf dist
11
- yarn install
12
- yarn build
10
+ yarn add @bytem/bytem-tracker-app @react-native-async-storage/async-storage react-native-device-info uuid
13
11
  ```
14
12
 
15
- ---
13
+ ### iOS Setup
14
+ Don't forget to install pods for iOS:
15
+ ```bash
16
+ cd ios && pod install
17
+ ```
16
18
 
17
- ## ✨ 特性
19
+ ## Development
18
20
 
19
- - React Native / Expo 通用
20
- - ✅ 行为 100% 对齐 Flutter SDK
21
- - ✅ 单例模式
22
- - ✅ 自动 deviceId / visitorId 管理
23
- - ✅ TypeScript 支持
24
- - ❌ 不支持 Web(刻意限制,避免误用)
21
+ This project uses **Yarn** for dependency management.
25
22
 
26
- ---
23
+ ### Setup
27
24
 
28
- ## 📦 安装
25
+ ```bash
26
+ yarn install
27
+ ```
29
28
 
30
- ### React Native CLI
29
+ ### Running Tests
31
30
 
32
31
  ```bash
33
- yarn add @bytem/bytem-tracker
34
- yarn add @react-native-async-storage/async-storage
32
+ yarn test
35
33
  ```
36
34
 
37
- ### Expo
35
+ ### Build
36
+
38
37
  ```bash
39
- expo install @react-native-async-storage/async-storage
40
- yarn add @bytem/bytem-tracker
41
- ```
38
+ yarn build
39
+ ```
40
+
41
+ ## Release & Publish
42
+
43
+ Automate version bump and publish via npm scripts:
44
+
45
+ ```bash
46
+ # Patch release (1.0.0 -> 1.0.1)
47
+ npm run release:patch
48
+
49
+ # Minor release (1.0.0 -> 1.1.0)
50
+ npm run release:minor
51
+
52
+ # Major release (1.0.0 -> 2.0.0)
53
+ npm run release:major
54
+
55
+ # Beta prerelease (1.0.0 -> 1.0.1-beta.0)
56
+ npm run release:beta
57
+ ```
58
+
59
+ Notes:
60
+ - These scripts bump package.json version and publish to npm.
61
+ - `prepublishOnly` builds the package before publishing.
62
+ - Configure auth via user-level `~/.npmrc`. Do not commit tokens in the repo.
63
+ ## Usage
64
+
65
+ ### Initialization
66
+ Initialize the tracker in your app entry point (e.g., `App.tsx` or `index.js`). Note that `init` is asynchronous.
67
+
68
+ ```typescript
69
+ import React, { useEffect } from 'react';
70
+ import BytemTracker from '@bytem/bytem-tracker-app';
71
+
72
+ const App = () => {
73
+ useEffect(() => {
74
+ const initTracker = async () => {
75
+ await BytemTracker.init({
76
+ appId: 'your-app-id',
77
+ endpoint: 'https://api.bytem.com/track',
78
+ debug: __DEV__, // Enable debug logs in development
79
+ });
80
+ };
81
+
82
+ initTracker();
83
+ }, []);
84
+
85
+ return <YourApp />;
86
+ };
87
+ ```
88
+
89
+ ### Tracking Events
90
+
91
+ #### Identify User
92
+ Track user identification when a user logs in or updates their profile.
93
+
94
+ ```typescript
95
+ // Signature: trackUser(userId: string, traits?: object)
96
+ BytemTracker.trackUser('user_12345', {
97
+ email: 'user@example.com',
98
+ age: 25,
99
+ membership: 'gold'
100
+ });
101
+ ```
102
+
103
+ #### View Product
104
+ Track when a user views a product details page.
105
+
106
+ ```typescript
107
+ BytemTracker.trackViewProduct({
108
+ productId: 'prod_001',
109
+ name: 'Awesome Gadget',
110
+ price: 99.99,
111
+ currency: 'USD',
112
+ category: 'Electronics'
113
+ });
114
+ ```
115
+
116
+ #### Checkout Order
117
+ Track when a user initiates checkout.
118
+
119
+ ```typescript
120
+ BytemTracker.trackCheckOutOrder({
121
+ orderId: 'order_abc123',
122
+ total: 150.00,
123
+ currency: 'USD',
124
+ products: [
125
+ { productId: 'prod_001', price: 99.99, quantity: 1 },
126
+ { productId: 'prod_002', price: 50.01, quantity: 1 }
127
+ ]
128
+ });
129
+ ```
130
+
131
+ #### Pay Order
132
+ Track when a user completes a payment.
133
+
134
+ ```typescript
135
+ BytemTracker.trackPayOrder({
136
+ orderId: 'order_abc123',
137
+ total: 150.00,
138
+ currency: 'USD',
139
+ products: [
140
+ { productId: 'prod_001', price: 99.99, quantity: 1 },
141
+ { productId: 'prod_002', price: 50.01, quantity: 1 }
142
+ ]
143
+ });
144
+ ```
145
+
146
+ ## Platform Compatibility
147
+
148
+ This SDK is designed for **React Native** and supports:
149
+ - iOS
150
+ - Android
151
+
152
+ It relies on:
153
+ - `@react-native-async-storage/async-storage`: For persisting session and visitor IDs.
154
+ - `react-native-device-info`: For capturing device metrics (model, OS version, etc.).
@@ -0,0 +1,18 @@
1
+ import { TrackerConfig, Product, Order, UserTraits } from './types';
2
+ declare class BytemTracker {
3
+ private static instance;
4
+ private config;
5
+ private isInitialized;
6
+ private visitorId;
7
+ private readonly DEFAULT_ENDPOINT;
8
+ private constructor();
9
+ static getInstance(): BytemTracker;
10
+ init(config: TrackerConfig): Promise<void>;
11
+ private track;
12
+ trackViewProduct(product: Product): void;
13
+ trackCheckOutOrder(order: Order): void;
14
+ trackPayOrder(order: Order): void;
15
+ trackUser(userId: string, traits?: UserTraits): void;
16
+ }
17
+ declare const _default: BytemTracker;
18
+ export default _default;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const base_1 = require("./core/base");
37
+ const request_1 = require("./core/request");
38
+ const Business = __importStar(require("./business"));
39
+ const session_1 = require("./core/session");
40
+ const storage_1 = require("./core/storage");
41
+ const device_1 = require("./core/device");
42
+ class BytemTracker {
43
+ constructor() {
44
+ this.config = null;
45
+ this.isInitialized = false;
46
+ this.visitorId = null;
47
+ this.DEFAULT_ENDPOINT = 'https://tracking.server.bytecon.com/i';
48
+ }
49
+ static getInstance() {
50
+ if (!BytemTracker.instance) {
51
+ BytemTracker.instance = new BytemTracker();
52
+ }
53
+ return BytemTracker.instance;
54
+ }
55
+ async init(config) {
56
+ if (this.isInitialized) {
57
+ console.warn('[BytemTracker] Already initialized');
58
+ return;
59
+ }
60
+ this.config = config;
61
+ this.isInitialized = true;
62
+ // Initialize Visitor ID
63
+ if (config.visitorId) {
64
+ this.visitorId = config.visitorId;
65
+ await (0, storage_1.setItem)(storage_1.StorageKeys.VISITOR_ID, this.visitorId);
66
+ }
67
+ else {
68
+ this.visitorId = await (0, storage_1.getItem)(storage_1.StorageKeys.VISITOR_ID);
69
+ if (!this.visitorId) {
70
+ this.visitorId = (0, device_1.generateUUID)();
71
+ await (0, storage_1.setItem)(storage_1.StorageKeys.VISITOR_ID, this.visitorId);
72
+ }
73
+ }
74
+ // Initialize Session
75
+ await (0, session_1.initSession)();
76
+ if (!this.config.endpoint) {
77
+ this.config.endpoint = this.DEFAULT_ENDPOINT;
78
+ }
79
+ if (config.debug) {
80
+ console.log('[BytemTracker] Initialized with config:', this.config);
81
+ console.log('[BytemTracker] Visitor ID:', this.visitorId);
82
+ }
83
+ }
84
+ async track(payload) {
85
+ if (!this.isInitialized || !this.config || !this.visitorId) {
86
+ console.error('[BytemTracker] Not initialized. Call await init() first.');
87
+ return;
88
+ }
89
+ const baseParams = await (0, base_1.buildBaseRequestParams)(this.config.appId, this.visitorId);
90
+ const finalData = Object.assign(Object.assign({}, baseParams), payload);
91
+ if (this.config.debug) {
92
+ console.log('[BytemTracker] Tracking event:', finalData);
93
+ }
94
+ if (this.config.endpoint) {
95
+ let requestUrl = this.config.endpoint;
96
+ try {
97
+ const urlObj = new URL(this.config.endpoint);
98
+ const hasEndpointPath = urlObj.pathname && urlObj.pathname !== '/';
99
+ const pathToUse = this.config.path;
100
+ if (pathToUse) {
101
+ urlObj.pathname = pathToUse.startsWith('/') ? pathToUse : '/' + pathToUse;
102
+ requestUrl = urlObj.toString();
103
+ }
104
+ else if (!hasEndpointPath) {
105
+ urlObj.pathname = '/i';
106
+ requestUrl = urlObj.toString();
107
+ }
108
+ else {
109
+ requestUrl = this.config.endpoint;
110
+ }
111
+ }
112
+ catch (_a) {
113
+ requestUrl = this.config.endpoint;
114
+ }
115
+ await (0, request_1.sendRequest)(requestUrl, finalData);
116
+ }
117
+ }
118
+ trackViewProduct(product) {
119
+ const payload = Business.trackViewProduct(product);
120
+ this.track(payload);
121
+ }
122
+ trackCheckOutOrder(order) {
123
+ const payload = Business.trackCheckOutOrder(order);
124
+ this.track(payload);
125
+ }
126
+ trackPayOrder(order) {
127
+ const payload = Business.trackPayOrder(order);
128
+ this.track(payload);
129
+ }
130
+ trackUser(userId, traits) {
131
+ const payload = Business.trackUser(userId, traits);
132
+ this.track(payload);
133
+ }
134
+ }
135
+ exports.default = BytemTracker.getInstance();
@@ -0,0 +1,4 @@
1
+ export * from './trackViewProduct';
2
+ export * from './trackCheckOutOrder';
3
+ export * from './trackPayOrder';
4
+ export * from './trackUser';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./trackViewProduct"), exports);
18
+ __exportStar(require("./trackCheckOutOrder"), exports);
19
+ __exportStar(require("./trackPayOrder"), exports);
20
+ __exportStar(require("./trackUser"), exports);
@@ -0,0 +1,2 @@
1
+ import { EventPayload, Order } from '../types';
2
+ export declare const trackCheckOutOrder: (order: Order) => EventPayload;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.trackCheckOutOrder = void 0;
4
+ const trackCheckOutOrder = (order) => {
5
+ return {
6
+ event: 'checkout_order',
7
+ params: {
8
+ order_id: order.orderId,
9
+ total: order.total,
10
+ currency: order.currency,
11
+ products: order.products.map((p) => ({
12
+ product_id: p.productId,
13
+ name: p.name,
14
+ price: p.price,
15
+ quantity: p.quantity,
16
+ })),
17
+ },
18
+ };
19
+ };
20
+ exports.trackCheckOutOrder = trackCheckOutOrder;
@@ -0,0 +1,2 @@
1
+ import { EventPayload, Order } from '../types';
2
+ export declare const trackPayOrder: (order: Order) => EventPayload;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.trackPayOrder = void 0;
4
+ const trackPayOrder = (order) => {
5
+ return {
6
+ event: 'pay_order',
7
+ params: {
8
+ order_id: order.orderId,
9
+ total: order.total,
10
+ currency: order.currency,
11
+ products: order.products.map((p) => ({
12
+ product_id: p.productId,
13
+ name: p.name,
14
+ price: p.price,
15
+ quantity: p.quantity,
16
+ })),
17
+ status: 'success',
18
+ },
19
+ };
20
+ };
21
+ exports.trackPayOrder = trackPayOrder;
@@ -0,0 +1,2 @@
1
+ import { EventPayload, UserTraits } from '../types';
2
+ export declare const trackUser: (userId: string, traits?: UserTraits) => EventPayload;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.trackUser = void 0;
4
+ const trackUser = (userId, traits = {}) => {
5
+ return {
6
+ event: 'identify',
7
+ params: {
8
+ user_id: userId,
9
+ traits: traits,
10
+ },
11
+ };
12
+ };
13
+ exports.trackUser = trackUser;
@@ -0,0 +1,2 @@
1
+ import { EventPayload, Product } from '../types';
2
+ export declare const trackViewProduct: (product: Product) => EventPayload;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.trackViewProduct = void 0;
4
+ const trackViewProduct = (product) => {
5
+ return {
6
+ event: 'view_product',
7
+ params: {
8
+ product_id: product.productId,
9
+ name: product.name,
10
+ price: product.price,
11
+ currency: product.currency,
12
+ category: product.category,
13
+ },
14
+ };
15
+ };
16
+ exports.trackViewProduct = trackViewProduct;
@@ -0,0 +1,2 @@
1
+ import { BaseParams } from '../types';
2
+ export declare const buildBaseRequestParams: (appId: string, visitorId: string) => Promise<BaseParams>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildBaseRequestParams = void 0;
4
+ const device_1 = require("./device");
5
+ const session_1 = require("./session");
6
+ const buildBaseRequestParams = async (appId, visitorId) => {
7
+ const deviceInfo = await (0, device_1.getDeviceInfo)();
8
+ const sessionInfo = (0, session_1.getSessionInfo)();
9
+ return {
10
+ app_id: appId,
11
+ device_id: visitorId,
12
+ session_id: sessionInfo ? sessionInfo.sessionId : '',
13
+ timestamp: Date.now(),
14
+ platform: deviceInfo.platform,
15
+ os: deviceInfo.os,
16
+ os_version: deviceInfo.osVersion,
17
+ model: deviceInfo.model,
18
+ language: deviceInfo.language,
19
+ screen_width: deviceInfo.screenWidth,
20
+ screen_height: deviceInfo.screenHeight,
21
+ user_agent: deviceInfo.userAgent,
22
+ };
23
+ };
24
+ exports.buildBaseRequestParams = buildBaseRequestParams;
@@ -0,0 +1,3 @@
1
+ import { DeviceInfo } from '../types';
2
+ export declare const getDeviceInfo: () => Promise<DeviceInfo>;
3
+ export declare const generateUUID: () => string;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateUUID = exports.getDeviceInfo = void 0;
7
+ const react_native_1 = require("react-native");
8
+ const react_native_device_info_1 = __importDefault(require("react-native-device-info"));
9
+ const getDeviceInfo = async () => {
10
+ var _a, _b, _c;
11
+ const os = react_native_device_info_1.default.getSystemName();
12
+ const osVersion = react_native_device_info_1.default.getSystemVersion();
13
+ const model = react_native_device_info_1.default.getModel();
14
+ const userAgent = await react_native_device_info_1.default.getUserAgent();
15
+ // Try to get language
16
+ let language = 'en';
17
+ if (react_native_1.Platform.OS === 'ios') {
18
+ const settings = (_a = react_native_1.NativeModules.SettingsManager) === null || _a === void 0 ? void 0 : _a.settings;
19
+ language = (settings === null || settings === void 0 ? void 0 : settings.AppleLocale) || ((_b = settings === null || settings === void 0 ? void 0 : settings.AppleLanguages) === null || _b === void 0 ? void 0 : _b[0]) || 'en';
20
+ }
21
+ else if (react_native_1.Platform.OS === 'android') {
22
+ language = ((_c = react_native_1.NativeModules.I18nManager) === null || _c === void 0 ? void 0 : _c.localeIdentifier) || 'en';
23
+ }
24
+ const { width, height } = react_native_1.Dimensions.get('window');
25
+ return {
26
+ platform: react_native_1.Platform.OS,
27
+ os,
28
+ osVersion,
29
+ model,
30
+ screenWidth: width,
31
+ screenHeight: height,
32
+ language,
33
+ userAgent,
34
+ };
35
+ };
36
+ exports.getDeviceInfo = getDeviceInfo;
37
+ const generateUUID = () => {
38
+ // Simple UUID v4 generator that doesn't require crypto polyfills
39
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
40
+ const r = (Math.random() * 16) | 0;
41
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
42
+ return v.toString(16);
43
+ });
44
+ };
45
+ exports.generateUUID = generateUUID;
@@ -0,0 +1,2 @@
1
+ import { EventPayload } from '../types';
2
+ export declare const sendRequest: (endpoint: string, data: EventPayload) => Promise<void>;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendRequest = void 0;
4
+ const sendRequest = async (endpoint, data) => {
5
+ try {
6
+ const response = await fetch(endpoint, {
7
+ method: 'POST',
8
+ headers: {
9
+ 'Content-Type': 'application/json',
10
+ },
11
+ body: JSON.stringify(data),
12
+ });
13
+ if (!response.ok) {
14
+ console.error(`[BytemTracker] Request failed: ${response.statusText}`);
15
+ }
16
+ }
17
+ catch (error) {
18
+ console.error('[BytemTracker] Network error:', error);
19
+ }
20
+ };
21
+ exports.sendRequest = sendRequest;
@@ -0,0 +1,17 @@
1
+ import { SessionInfo } from '../types';
2
+ /**
3
+ * Initialize session. Must be called before tracking events.
4
+ * 1. Checks memory (fastest)
5
+ * 2. Checks storage
6
+ * 3. Creates new if none exists
7
+ */
8
+ export declare const initSession: () => Promise<SessionInfo>;
9
+ /**
10
+ * Force start a new session
11
+ */
12
+ export declare const refreshSession: () => Promise<SessionInfo>;
13
+ /**
14
+ * Get current session info.
15
+ * WARNING: Returns null if initSession() hasn't been called/awaited.
16
+ */
17
+ export declare const getSessionInfo: () => SessionInfo | null;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSessionInfo = exports.refreshSession = exports.initSession = void 0;
4
+ const device_1 = require("./device");
5
+ const storage_1 = require("./storage");
6
+ let currentSession = null;
7
+ /**
8
+ * Initialize session. Must be called before tracking events.
9
+ * 1. Checks memory (fastest)
10
+ * 2. Checks storage
11
+ * 3. Creates new if none exists
12
+ */
13
+ const initSession = async () => {
14
+ if (currentSession) {
15
+ return currentSession;
16
+ }
17
+ try {
18
+ const storedId = await (0, storage_1.getItem)(storage_1.StorageKeys.SESSION_ID);
19
+ const storedStart = await (0, storage_1.getItem)(storage_1.StorageKeys.SESSION_START);
20
+ if (storedId && storedStart) {
21
+ currentSession = {
22
+ sessionId: storedId,
23
+ startTime: parseInt(storedStart, 10),
24
+ };
25
+ }
26
+ else {
27
+ await (0, exports.refreshSession)();
28
+ }
29
+ }
30
+ catch (e) {
31
+ // If error, generate new
32
+ await (0, exports.refreshSession)();
33
+ }
34
+ return currentSession;
35
+ };
36
+ exports.initSession = initSession;
37
+ /**
38
+ * Force start a new session
39
+ */
40
+ const refreshSession = async () => {
41
+ const newId = (0, device_1.generateUUID)();
42
+ const newStart = Date.now();
43
+ currentSession = {
44
+ sessionId: newId,
45
+ startTime: newStart,
46
+ };
47
+ await (0, storage_1.setItem)(storage_1.StorageKeys.SESSION_ID, newId);
48
+ await (0, storage_1.setItem)(storage_1.StorageKeys.SESSION_START, newStart.toString());
49
+ return currentSession;
50
+ };
51
+ exports.refreshSession = refreshSession;
52
+ /**
53
+ * Get current session info.
54
+ * WARNING: Returns null if initSession() hasn't been called/awaited.
55
+ */
56
+ const getSessionInfo = () => {
57
+ return currentSession;
58
+ };
59
+ exports.getSessionInfo = getSessionInfo;
@@ -0,0 +1,9 @@
1
+ export declare const StorageKeys: {
2
+ VISITOR_ID: string;
3
+ DEVICE_ID: string;
4
+ SESSION_ID: string;
5
+ SESSION_START: string;
6
+ };
7
+ export declare const getItem: (key: string) => Promise<string | null>;
8
+ export declare const setItem: (key: string, value: string) => Promise<void>;
9
+ export declare const removeItem: (key: string) => Promise<void>;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.removeItem = exports.setItem = exports.getItem = exports.StorageKeys = void 0;
7
+ const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
8
+ exports.StorageKeys = {
9
+ VISITOR_ID: 'bytem_visitor_id',
10
+ DEVICE_ID: 'bytem_device_id',
11
+ SESSION_ID: 'bytem_session_id',
12
+ SESSION_START: 'bytem_session_start',
13
+ };
14
+ const getItem = async (key) => {
15
+ try {
16
+ return await async_storage_1.default.getItem(key);
17
+ }
18
+ catch (e) {
19
+ console.warn('[BytemTracker] Storage get error:', e);
20
+ return null;
21
+ }
22
+ };
23
+ exports.getItem = getItem;
24
+ const setItem = async (key, value) => {
25
+ try {
26
+ await async_storage_1.default.setItem(key, value);
27
+ }
28
+ catch (e) {
29
+ console.warn('[BytemTracker] Storage set error:', e);
30
+ }
31
+ };
32
+ exports.setItem = setItem;
33
+ const removeItem = async (key) => {
34
+ try {
35
+ await async_storage_1.default.removeItem(key);
36
+ }
37
+ catch (e) {
38
+ console.warn('[BytemTracker] Storage remove error:', e);
39
+ }
40
+ };
41
+ exports.removeItem = removeItem;
@@ -0,0 +1,3 @@
1
+ import BytemTracker from './BytemTracker';
2
+ export * from './types';
3
+ export default BytemTracker;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ const BytemTracker_1 = __importDefault(require("./BytemTracker"));
21
+ __exportStar(require("./types"), exports);
22
+ exports.default = BytemTracker_1.default;
@@ -0,0 +1,56 @@
1
+ export interface TrackerConfig {
2
+ appId: string;
3
+ endpoint?: string;
4
+ path?: string;
5
+ debug?: boolean;
6
+ visitorId?: string;
7
+ }
8
+ export interface DeviceInfo {
9
+ platform: string;
10
+ os: string;
11
+ osVersion: string;
12
+ model: string;
13
+ screenWidth: number;
14
+ screenHeight: number;
15
+ language: string;
16
+ userAgent: string;
17
+ }
18
+ export interface SessionInfo {
19
+ sessionId: string;
20
+ startTime: number;
21
+ }
22
+ export interface BaseParams {
23
+ app_id: string;
24
+ device_id: string;
25
+ session_id: string;
26
+ timestamp: number;
27
+ platform: string;
28
+ os: string;
29
+ os_version: string;
30
+ model: string;
31
+ language: string;
32
+ screen_width: number;
33
+ screen_height: number;
34
+ user_agent: string;
35
+ }
36
+ export interface UserTraits {
37
+ [key: string]: any;
38
+ }
39
+ export interface Product {
40
+ productId: string;
41
+ name?: string;
42
+ price?: number;
43
+ currency?: string;
44
+ category?: string;
45
+ quantity?: number;
46
+ }
47
+ export interface Order {
48
+ orderId: string;
49
+ total: number;
50
+ currency: string;
51
+ products: Product[];
52
+ }
53
+ export interface EventPayload {
54
+ event: string;
55
+ params: Record<string, any>;
56
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const BytemTracker_1 = __importDefault(require("../src/BytemTracker"));
7
+ const storage_1 = require("../src/core/storage");
8
+ const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
9
+ describe('BytemTracker SDK', () => {
10
+ const mockConfig = {
11
+ appId: 'test-app-id',
12
+ endpoint: 'https://api.example.com/track',
13
+ debug: true,
14
+ };
15
+ beforeEach(() => {
16
+ jest.clearAllMocks();
17
+ // Reset singleton instance manually
18
+ // @ts-ignore
19
+ BytemTracker_1.default.instance = undefined;
20
+ // @ts-ignore
21
+ BytemTracker_1.default.isInitialized = false;
22
+ // @ts-ignore
23
+ BytemTracker_1.default.config = null;
24
+ // @ts-ignore
25
+ BytemTracker_1.default.visitorId = null;
26
+ });
27
+ it('should initialize correctly', async () => {
28
+ await BytemTracker_1.default.init(mockConfig);
29
+ // Verify Storage was checked for Visitor ID
30
+ expect(async_storage_1.default.getItem).toHaveBeenCalledWith(storage_1.StorageKeys.VISITOR_ID);
31
+ // Verify Session was initialized (checks storage)
32
+ expect(async_storage_1.default.getItem).toHaveBeenCalledWith(storage_1.StorageKeys.SESSION_ID);
33
+ });
34
+ it('should track an event', async () => {
35
+ // Ensure initialized (singleton persists)
36
+ await BytemTracker_1.default.init(mockConfig);
37
+ const eventName = 'test_event';
38
+ const eventParams = { foo: 'bar' };
39
+ // @ts-ignore - Accessing private method for testing or just use public track methods
40
+ // Since track is private, we'll use a public method like trackUser or just trust the public API
41
+ // Let's use trackUser as a proxy for generic tracking
42
+ BytemTracker_1.default.trackUser('user-123', { age: 25 });
43
+ // Wait for async operations if any (track is async but void return in public API might hide it)
44
+ // In BytemTracker.ts, trackUser calls track, which is async but not awaited by caller.
45
+ // We need to wait for promises to resolve.
46
+ await new Promise(resolve => setTimeout(resolve, 0));
47
+ expect(global.fetch).toHaveBeenCalledTimes(1);
48
+ const fetchCall = global.fetch.mock.calls[0];
49
+ const url = fetchCall[0];
50
+ const options = fetchCall[1];
51
+ expect(url).toBe(mockConfig.endpoint);
52
+ expect(options.method).toBe('POST');
53
+ const body = JSON.parse(options.body);
54
+ expect(body.app_id).toBe(mockConfig.appId);
55
+ // expect(body.event).toBe('identify');
56
+ });
57
+ it('should use default endpoint when not provided', async () => {
58
+ await BytemTracker_1.default.init({
59
+ appId: 'test-app-id',
60
+ // endpoint is omitted
61
+ debug: true,
62
+ });
63
+ BytemTracker_1.default.trackUser('user-123', { age: 25 });
64
+ await new Promise(resolve => setTimeout(resolve, 0));
65
+ expect(global.fetch).toHaveBeenCalledTimes(1);
66
+ const fetchCall = global.fetch.mock.calls[0];
67
+ const url = fetchCall[0];
68
+ expect(url).toBe('https://tracking.server.bytecon.com/i');
69
+ });
70
+ it('should override endpoint path when path is configured', async () => {
71
+ await BytemTracker_1.default.init({
72
+ appId: 'test-app-id-2',
73
+ endpoint: 'https://api.example.com/track',
74
+ path: '/collect',
75
+ debug: true,
76
+ });
77
+ BytemTracker_1.default.trackUser('user-456', { age: 30 });
78
+ await new Promise(resolve => setTimeout(resolve, 0));
79
+ expect(global.fetch).toHaveBeenCalledTimes(1);
80
+ const fetchCall = global.fetch.mock.calls[0];
81
+ const url = fetchCall[0];
82
+ expect(url).toBe('https://api.example.com/collect');
83
+ });
84
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const BytemTracker_1 = __importDefault(require("../src/BytemTracker"));
7
+ const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
8
+ describe('Debug Scenarios', () => {
9
+ const mockConfig = {
10
+ appId: 'debug-app-id',
11
+ endpoint: 'https://debug-api.bytem.com/track',
12
+ debug: true,
13
+ };
14
+ beforeEach(async () => {
15
+ jest.clearAllMocks();
16
+ // Simulate fresh start
17
+ async_storage_1.default.getItem.mockResolvedValue(null);
18
+ await BytemTracker_1.default.init(mockConfig);
19
+ });
20
+ it('Scenario: User Journey - View Product -> Add to Cart -> Checkout', async () => {
21
+ // 1. View Product
22
+ console.log('>>> Step 1: Tracking View Product');
23
+ BytemTracker_1.default.trackViewProduct({
24
+ productId: 'p_1001',
25
+ name: 'Debug Smartphone',
26
+ price: 699.00,
27
+ currency: 'USD',
28
+ category: 'Electronics'
29
+ });
30
+ // Wait for async track
31
+ await new Promise(resolve => setTimeout(resolve, 0));
32
+ // 2. Identify User (Simulate Login)
33
+ console.log('>>> Step 2: User Login');
34
+ BytemTracker_1.default.trackUser('user_debug_001', {
35
+ plan: 'premium',
36
+ login_method: 'email'
37
+ });
38
+ await new Promise(resolve => setTimeout(resolve, 0));
39
+ // 3. Checkout
40
+ console.log('>>> Step 3: Checkout');
41
+ BytemTracker_1.default.trackCheckOutOrder({
42
+ orderId: 'order_999',
43
+ total: 699.00,
44
+ currency: 'USD',
45
+ products: [
46
+ { productId: 'p_1001', price: 699.00, quantity: 1 }
47
+ ]
48
+ });
49
+ await new Promise(resolve => setTimeout(resolve, 0));
50
+ // Assertions to verify flow
51
+ expect(global.fetch).toHaveBeenCalledTimes(3);
52
+ const calls = global.fetch.mock.calls;
53
+ // Check Event Types
54
+ const events = calls.map((call) => JSON.parse(call[1].body).event);
55
+ console.log('>>> Captured Events:', events);
56
+ expect(events).toEqual(['view_product', 'identify', 'checkout_order']);
57
+ });
58
+ });
@@ -0,0 +1 @@
1
+ declare const mockStorage: Record<string, string>;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ // Mock AsyncStorage
3
+ const mockStorage = {};
4
+ jest.mock('@react-native-async-storage/async-storage', () => ({
5
+ setItem: jest.fn((key, value) => {
6
+ mockStorage[key] = value;
7
+ return Promise.resolve(null);
8
+ }),
9
+ getItem: jest.fn((key) => {
10
+ return Promise.resolve(mockStorage[key] || null);
11
+ }),
12
+ removeItem: jest.fn((key) => {
13
+ delete mockStorage[key];
14
+ return Promise.resolve(null);
15
+ }),
16
+ clear: jest.fn(() => {
17
+ for (const key in mockStorage)
18
+ delete mockStorage[key];
19
+ return Promise.resolve(null);
20
+ }),
21
+ }));
22
+ // Mock React Native Device Info
23
+ jest.mock('react-native-device-info', () => ({
24
+ getSystemName: jest.fn(() => 'iOS'),
25
+ getSystemVersion: jest.fn(() => '14.0'),
26
+ getModel: jest.fn(() => 'iPhone 11'),
27
+ getUserAgent: jest.fn(() => Promise.resolve('Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)')),
28
+ }));
29
+ // Mock React Native
30
+ jest.mock('react-native', () => ({
31
+ Platform: {
32
+ OS: 'ios',
33
+ select: jest.fn(),
34
+ },
35
+ Dimensions: {
36
+ get: jest.fn(() => ({ width: 375, height: 812 })),
37
+ },
38
+ NativeModules: {
39
+ SettingsManager: {
40
+ settings: {
41
+ AppleLocale: 'en_US',
42
+ AppleLanguages: ['en-US'],
43
+ },
44
+ },
45
+ I18nManager: {
46
+ localeIdentifier: 'en_US',
47
+ },
48
+ },
49
+ }));
50
+ // Mock global fetch
51
+ global.fetch = jest.fn(() => Promise.resolve({
52
+ ok: true,
53
+ status: 200,
54
+ statusText: 'OK',
55
+ json: () => Promise.resolve({}),
56
+ }));
package/package.json CHANGED
@@ -1,31 +1,50 @@
1
1
  {
2
2
  "name": "@bytem/bytem-tracker-app",
3
- "version": "0.0.3",
3
+ "version": "0.0.6",
4
+ "description": "Bytem Tracker SDK for React Native",
4
5
  "main": "dist/index.js",
5
6
  "types": "dist/index.d.ts",
6
7
  "files": [
7
8
  "dist"
8
9
  ],
9
- "description": "bytem SDK for React Native",
10
- "license": "ISC",
11
- "author": "Barry",
12
10
  "scripts": {
13
11
  "build": "tsc",
14
- "prepublishOnly": "npm run build"
12
+ "test": "jest",
13
+ "prepublishOnly": "npm run build",
14
+ "release:patch": "npm version patch && npm publish",
15
+ "release:minor": "npm version minor && npm publish",
16
+ "release:major": "npm version major && npm publish",
17
+ "release:beta": "npm version prerelease --preid=beta && npm publish --tag beta"
15
18
  },
19
+ "keywords": [
20
+ "tracker",
21
+ "sdk",
22
+ "analytics",
23
+ "react-native"
24
+ ],
25
+ "author": "Barry",
26
+ "license": "ISC",
16
27
  "peerDependencies": {
17
- "react-native": ">=0.60.0"
28
+ "@react-native-async-storage/async-storage": "^1.0.0",
29
+ "react": ">=16.8.0",
30
+ "react-native": ">=0.60.0",
31
+ "react-native-device-info": "^10.0.0"
18
32
  },
19
33
  "dependencies": {
20
- "@react-native-async-storage/async-storage": "^1.21.0",
21
34
  "uuid": "^9.0.0"
22
35
  },
23
36
  "devDependencies": {
24
- "@types/react-native": "^0.73.0",
37
+ "@react-native-async-storage/async-storage": "^1.19.0",
38
+ "@types/jest": "^30.0.0",
39
+ "@types/node": "^20.0.0",
40
+ "@types/react": "^18.0.0",
41
+ "@types/react-native": "^0.72.0",
25
42
  "@types/uuid": "^9.0.0",
26
- "eslint": "^9.39.2",
27
- "eslint-import-resolver-typescript": "^4.4.4",
28
- "eslint-plugin-import": "^2.32.0",
43
+ "jest": "^30.2.0",
44
+ "react": "18.2.0",
45
+ "react-native": "0.72.0",
46
+ "react-native-device-info": "^10.8.0",
47
+ "ts-jest": "^29.4.6",
29
48
  "typescript": "^5.0.0"
30
49
  },
31
50
  "publishConfig": {
package/dist/env.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function isExpoRuntime(): boolean;
package/dist/env.js DELETED
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isExpoRuntime = isExpoRuntime;
4
- function isExpoRuntime() {
5
- return typeof globalThis !== 'undefined' && !!globalThis.__expo;
6
- }
package/dist/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import { BytemTracker } from './tracker';
2
- declare const _default: BytemTracker;
3
- export default _default;
4
- export { BytemTracker };
package/dist/index.js DELETED
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BytemTracker = void 0;
4
- const tracker_1 = require("./tracker");
5
- Object.defineProperty(exports, "BytemTracker", { enumerable: true, get: function () { return tracker_1.BytemTracker; } });
6
- exports.default = tracker_1.BytemTracker.instance;
package/dist/tracker.d.ts DELETED
@@ -1,26 +0,0 @@
1
- export declare class BytemTracker {
2
- private static _instance;
3
- static get instance(): BytemTracker;
4
- private static readonly _sdkName;
5
- private static readonly _sdkVersion;
6
- private static readonly _defaultBaseUrl;
7
- private static readonly _storageDeviceIdKey;
8
- private static readonly _storageVisitorIdKey;
9
- private _appKey;
10
- private _baseUrl;
11
- private _debug;
12
- private _deviceId;
13
- private _visitorId;
14
- private constructor();
15
- init(options: {
16
- appKey: string;
17
- baseUrl?: string;
18
- debug?: boolean;
19
- deviceId?: string;
20
- }): Promise<void>;
21
- track(eventKey: string, params?: Record<string, any>): Promise<void>;
22
- private _loadOrCreateDeviceId;
23
- private _loadOrCreateVisitorId;
24
- private _getScreenInfo;
25
- private _log;
26
- }
package/dist/tracker.js DELETED
@@ -1,120 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.BytemTracker = void 0;
16
- const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
17
- const react_native_1 = require("react-native");
18
- const uuid_1 = require("./uuid");
19
- class BytemTracker {
20
- static get instance() {
21
- if (!this._instance) {
22
- this._instance = new BytemTracker();
23
- }
24
- return this._instance;
25
- }
26
- constructor() {
27
- this._appKey = null;
28
- this._baseUrl = BytemTracker._defaultBaseUrl;
29
- this._debug = false;
30
- this._deviceId = null;
31
- this._visitorId = null;
32
- }
33
- init(options) {
34
- return __awaiter(this, void 0, void 0, function* () {
35
- var _a;
36
- this._appKey = options.appKey;
37
- this._debug = (_a = options.debug) !== null && _a !== void 0 ? _a : false;
38
- if (options.baseUrl) {
39
- this._baseUrl = options.baseUrl;
40
- }
41
- if (options.deviceId) {
42
- this._deviceId = options.deviceId;
43
- yield async_storage_1.default.setItem(BytemTracker._storageDeviceIdKey, this._deviceId);
44
- }
45
- else {
46
- yield this._loadOrCreateDeviceId();
47
- }
48
- yield this._loadOrCreateVisitorId();
49
- this._log('init', {
50
- deviceId: this._deviceId,
51
- visitorId: this._visitorId,
52
- });
53
- });
54
- }
55
- track(eventKey_1) {
56
- return __awaiter(this, arguments, void 0, function* (eventKey, params = {}) {
57
- if (!this._appKey || !this._deviceId || !this._visitorId) {
58
- this._log('track skipped: not initialized');
59
- return;
60
- }
61
- const payload = {
62
- app_key: this._appKey,
63
- device_id: this._deviceId,
64
- visitor_id: this._visitorId,
65
- event_key: eventKey,
66
- params,
67
- sdk: BytemTracker._sdkName,
68
- sdk_version: BytemTracker._sdkVersion,
69
- platform: react_native_1.Platform.OS,
70
- timestamp: Date.now(),
71
- screen: this._getScreenInfo(),
72
- };
73
- this._log('track', payload);
74
- try {
75
- yield fetch(`${this._baseUrl}/track`, {
76
- method: 'POST',
77
- headers: { 'Content-Type': 'application/json' },
78
- body: JSON.stringify(payload),
79
- });
80
- }
81
- catch (e) {
82
- this._log('track error', e);
83
- }
84
- });
85
- }
86
- _loadOrCreateDeviceId() {
87
- return __awaiter(this, void 0, void 0, function* () {
88
- const stored = yield async_storage_1.default.getItem(BytemTracker._storageDeviceIdKey);
89
- this._deviceId = stored !== null && stored !== void 0 ? stored : (0, uuid_1.generateUUID)();
90
- if (!stored && this._deviceId) {
91
- yield async_storage_1.default.setItem(BytemTracker._storageDeviceIdKey, this._deviceId);
92
- }
93
- });
94
- }
95
- _loadOrCreateVisitorId() {
96
- return __awaiter(this, void 0, void 0, function* () {
97
- const stored = yield async_storage_1.default.getItem(BytemTracker._storageVisitorIdKey);
98
- this._visitorId = stored !== null && stored !== void 0 ? stored : (0, uuid_1.generateUUID)();
99
- if (!stored && this._visitorId) {
100
- yield async_storage_1.default.setItem(BytemTracker._storageVisitorIdKey, this._visitorId);
101
- }
102
- });
103
- }
104
- _getScreenInfo() {
105
- const { width, height } = react_native_1.Dimensions.get('window');
106
- return { width, height };
107
- }
108
- _log(...args) {
109
- if (this._debug) {
110
- console.log('[BytemTracker]', ...args);
111
- }
112
- }
113
- }
114
- exports.BytemTracker = BytemTracker;
115
- BytemTracker._instance = null;
116
- BytemTracker._sdkName = 'bytemTrackerReact';
117
- BytemTracker._sdkVersion = '0.0.1';
118
- BytemTracker._defaultBaseUrl = 'https://tracking.server.bytecon.com';
119
- BytemTracker._storageDeviceIdKey = 'bytem_fp';
120
- BytemTracker._storageVisitorIdKey = 'bytem_visitor_id';
package/dist/types.d.ts DELETED
@@ -1,24 +0,0 @@
1
- /** SDK 初始化配置 */
2
- export interface BytemConfig {
3
- appKey: string;
4
- baseUrl?: string;
5
- debug?: boolean;
6
- visitorId?: string;
7
- appScheme?: string;
8
- }
9
- /** 基础事件可选参数 */
10
- export interface BytemEventOptions {
11
- count?: number;
12
- sum?: number;
13
- duration?: number;
14
- }
15
- /** 用户资料参数 */
16
- export interface BytemUserParams {
17
- userId?: string;
18
- name?: string;
19
- email?: string;
20
- phone?: string;
21
- gender?: "M" | "F";
22
- birthYear?: number;
23
- custom?: Record<string, any>;
24
- }
package/dist/uuid.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function generateUUID(): string;
package/dist/uuid.js DELETED
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateUUID = generateUUID;
4
- const uuid_1 = require("uuid");
5
- function jsUUIDv4() {
6
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
7
- const r = (Math.random() * 16) | 0;
8
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
9
- return v.toString(16);
10
- });
11
- }
12
- function generateUUID() {
13
- try {
14
- return (0, uuid_1.v4)();
15
- }
16
- catch (_a) {
17
- return jsUUIDv4();
18
- }
19
- }
File without changes