@bytem/bytem-tracker-app 0.0.3 → 0.0.7

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 (44) hide show
  1. package/README.md +50 -25
  2. package/dist/src/BytemTracker.d.ts +58 -0
  3. package/dist/src/BytemTracker.js +474 -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 +67 -0
  27. package/dist/src/types.js +12 -0
  28. package/dist/test/BytemTracker.test.d.ts +1 -0
  29. package/dist/test/BytemTracker.test.js +248 -0
  30. package/dist/test/debug.test.d.ts +1 -0
  31. package/dist/test/debug.test.js +90 -0
  32. package/dist/test/setup.d.ts +1 -0
  33. package/dist/test/setup.js +57 -0
  34. package/package.json +30 -11
  35. package/dist/env.d.ts +0 -1
  36. package/dist/env.js +0 -6
  37. package/dist/index.d.ts +0 -4
  38. package/dist/index.js +0 -6
  39. package/dist/tracker.d.ts +0 -26
  40. package/dist/tracker.js +0 -120
  41. package/dist/types.d.ts +0 -24
  42. package/dist/types.js +0 -2
  43. package/dist/uuid.d.ts +0 -1
  44. package/dist/uuid.js +0 -19
@@ -0,0 +1,90 @@
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
+ // Reset singleton instance state manually
17
+ // @ts-ignore
18
+ BytemTracker_1.default.isInitialized = false;
19
+ // @ts-ignore
20
+ BytemTracker_1.default.appKey = null;
21
+ // @ts-ignore
22
+ BytemTracker_1.default.baseUrl = 'https://tracking.server.bytecon.com';
23
+ // @ts-ignore
24
+ BytemTracker_1.default.visitorId = null;
25
+ // @ts-ignore
26
+ BytemTracker_1.default.sessionStarted = false;
27
+ // @ts-ignore
28
+ BytemTracker_1.default.lastBeat = null;
29
+ // Simulate fresh start
30
+ // @ts-ignore
31
+ async_storage_1.default.clear();
32
+ async_storage_1.default.getItem.mockResolvedValue(null);
33
+ await BytemTracker_1.default.init(mockConfig);
34
+ });
35
+ it('Scenario: User Journey - View Product -> Add to Cart -> Checkout', async () => {
36
+ // 1. View Product
37
+ console.log('>>> Step 1: Tracking View Product');
38
+ BytemTracker_1.default.trackViewProduct({
39
+ productId: 'p_1001',
40
+ name: 'Debug Smartphone',
41
+ price: 699.00,
42
+ currency: 'USD',
43
+ category: 'Electronics'
44
+ });
45
+ // Wait for async track
46
+ await new Promise(resolve => setTimeout(resolve, 0));
47
+ // 2. Identify User (Simulate Login)
48
+ console.log('>>> Step 2: User Login');
49
+ BytemTracker_1.default.trackUser('user_debug_001', {
50
+ plan: 'premium',
51
+ login_method: 'email'
52
+ });
53
+ await new Promise(resolve => setTimeout(resolve, 0));
54
+ // 3. Checkout
55
+ console.log('>>> Step 3: Checkout');
56
+ BytemTracker_1.default.trackCheckOutOrder({
57
+ orderId: 'order_999',
58
+ total: 699.00,
59
+ currency: 'USD',
60
+ products: [
61
+ { productId: 'p_1001', price: 699.00, quantity: 1 }
62
+ ]
63
+ });
64
+ await new Promise(resolve => setTimeout(resolve, 0));
65
+ // Assertions to verify flow
66
+ // Expect 4 calls: begin_session, view_product, user_details, check_out_order
67
+ expect(global.fetch).toHaveBeenCalledTimes(4);
68
+ const calls = global.fetch.mock.calls;
69
+ // Check Request Types
70
+ const requestTypes = calls.map((call) => {
71
+ const body = call[1].body;
72
+ if (body.includes('begin_session=1'))
73
+ return 'begin_session';
74
+ if (body.includes('user_details='))
75
+ return 'identify';
76
+ if (body.includes('events=')) {
77
+ // Extract event key
78
+ const match = body.match(/events=(.*?)($|&)/);
79
+ if (match) {
80
+ const eventsJson = decodeURIComponent(match[1]);
81
+ const events = JSON.parse(eventsJson);
82
+ return events[0].key;
83
+ }
84
+ }
85
+ return 'unknown';
86
+ });
87
+ console.log('>>> Captured Requests:', requestTypes);
88
+ expect(requestTypes).toEqual(['begin_session', 'view_product', 'identify', 'check_out_order']);
89
+ });
90
+ });
@@ -0,0 +1 @@
1
+ declare const mockStorage: Record<string, string>;
@@ -0,0 +1,57 @@
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
+ text: () => Promise.resolve('{"status":"success"}'),
57
+ }));
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.7",
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/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
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
- }