tracking-lib-ott 1.0.6 → 1.0.8

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/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Tracking Library OTT
2
2
 
3
3
  Thư viện tracking events dành cho các dự án OTT (Web, iOS, Android).
4
+ npm version patch
5
+ npm publish
4
6
 
5
7
  ## Cài đặt
6
8
 
package/dist/index.cjs CHANGED
@@ -114,7 +114,7 @@ var sendEvent = async (eventData) => {
114
114
  const { event_name, ...eventParams } = eventData;
115
115
  const eventObject = {
116
116
  event_name: event_name || "unknown",
117
- event_params: eventParams,
117
+ event_params: JSON.stringify(eventParams),
118
118
  event_time: Math.floor(Date.now() / 1e3),
119
119
  user_id: config.userId
120
120
  };
@@ -217,13 +217,8 @@ var sendSessionStart = () => {
217
217
  sessionStartTime = Date.now();
218
218
  isSessionActive = true;
219
219
  sendEvent({
220
- events: [
221
- {
222
- event_name: "session_start",
223
- event_time: sessionStartTime,
224
- user_id: sessionConfig.userId
225
- }
226
- ]
220
+ event_name: "session_start",
221
+ event_time: sessionStartTime
227
222
  });
228
223
  log("Session started at:", new Date(sessionStartTime).toISOString());
229
224
  startProgressTimer();
@@ -233,14 +228,8 @@ var sendSessionProgress = () => {
233
228
  const now = Math.floor(Date.now() / 1e3);
234
229
  const duration = now - sessionStartTime;
235
230
  sendEvent({
236
- events: [
237
- {
238
- event_name: "session_progress",
239
- event_time: now,
240
- session_duration: duration,
241
- user_id: sessionConfig.userId
242
- }
243
- ]
231
+ event_name: "session_progress",
232
+ session_duration: duration
244
233
  });
245
234
  log("Session progress - Duration:", Math.round(duration / 1e3), "seconds");
246
235
  };
@@ -249,14 +238,8 @@ var sendSessionEnd = () => {
249
238
  const now = Math.floor(Date.now() / 1e3);
250
239
  const duration = now - sessionStartTime;
251
240
  sendEvent({
252
- events: [
253
- {
254
- event_name: "session_end",
255
- event_time: now,
256
- session_duration: duration,
257
- user_id: sessionConfig.userId
258
- }
259
- ]
241
+ event_name: "session_end",
242
+ session_duration: duration
260
243
  });
261
244
  log(
262
245
  "Session ended - Total duration:",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/tracking.ts","../src/session.ts"],"sourcesContent":["/**\r\n * Tracking Library v2 (Fetch + TypeScript)\r\n * Thư viện tracking events có thể dùng cho nhiều project\r\n */\r\n\r\n// Re-export types\r\nexport type {\r\n TrackingConfig,\r\n PageInfo,\r\n PageMap,\r\n EventData,\r\n NextRouterLike,\r\n} from \"./types\";\r\n\r\nexport type { SessionConfig } from \"./session\";\r\n\r\n// Re-export constants\r\nexport { defaultConfig, defaultPageMap } from \"./constants\";\r\n\r\n// Re-export functions\r\nexport {\r\n initTracking,\r\n getPageInfo,\r\n sendEvent,\r\n trackPageView,\r\n trackEvent,\r\n usePageViewTracking,\r\n} from \"./tracking\";\r\n\r\n// Re-export session functions\r\nexport {\r\n initSessionTracking,\r\n cleanupSessionTracking,\r\n sendSessionStart,\r\n sendSessionProgress,\r\n sendSessionEnd,\r\n updateSessionConfig,\r\n isSessionStarted,\r\n getSessionDuration,\r\n} from \"./session\";\r\n\r\n// Import for default export\r\nimport {\r\n initTracking,\r\n getPageInfo,\r\n sendEvent,\r\n trackPageView,\r\n trackEvent,\r\n usePageViewTracking,\r\n} from \"./tracking\";\r\n\r\nimport {\r\n initSessionTracking,\r\n cleanupSessionTracking,\r\n sendSessionStart,\r\n sendSessionProgress,\r\n sendSessionEnd,\r\n} from \"./session\";\r\n\r\n// Export default object\r\nconst tracking = {\r\n init: initTracking,\r\n trackPageView,\r\n trackEvent,\r\n sendEvent,\r\n getPageInfo,\r\n usePageViewTracking,\r\n // Session lifecycle\r\n initSession: initSessionTracking,\r\n cleanupSession: cleanupSessionTracking,\r\n sessionStart: sendSessionStart,\r\n sessionProgress: sendSessionProgress,\r\n sessionEnd: sendSessionEnd,\r\n};\r\n\r\nexport default tracking;\r\n","/**\r\n * Constants for Tracking Library\r\n */\r\n\r\nimport type { TrackingConfig, PageMap } from \"./types\";\r\n\r\nexport const defaultConfig: TrackingConfig = {\r\n baseURL: \"\",\r\n appName: \"on_plus\",\r\n appId: \"\",\r\n packageId: \"com.vtvcab.onsportstv\",\r\n platform: \"Web\",\r\n debug: false,\r\n\r\n // Required properties\r\n sessionId: \"\",\r\n sessionSign: \"\",\r\n userId: -1,\r\n deviceId: \"\",\r\n deviceModel: \"\",\r\n deviceBrand: \"\",\r\n ipAddress: \"\",\r\n\r\n // Optional properties\r\n adId: \"\",\r\n osVersion: \"\",\r\n netType: \"\",\r\n carrierNet: \"\",\r\n sdkVersion: \"\",\r\n appVersion: \"\",\r\n buildNumber: \"\",\r\n language: \"\",\r\n country: \"\",\r\n\r\n events: [],\r\n};\r\n\r\nexport const defaultPageMap: PageMap = {\r\n \"\": { name: \"Home\", id: \"home\" },\r\n home: { name: \"Home\", id: \"home\" },\r\n search: { name: \"Search\", id: \"search\" },\r\n detail: { name: \"Detail\", id: \"detail\" },\r\n player: { name: \"Player\", id: \"player\" },\r\n video: { name: \"Video\", id: \"video\" },\r\n live: { name: \"Live\", id: \"live\" },\r\n category: { name: \"Category\", id: \"category\" },\r\n profile: { name: \"Profile\", id: \"profile\" },\r\n login: { name: \"Login\", id: \"login\" },\r\n};\r\n","/**\r\n * Core Tracking Functions\r\n */\r\n\r\nimport type {\r\n TrackingConfig,\r\n PageMap,\r\n PageInfo,\r\n EventData,\r\n NextRouterLike,\r\n} from \"./types\";\r\nimport { defaultConfig, defaultPageMap } from \"./constants\";\r\n\r\n// Config runtime\r\nlet config: TrackingConfig = { ...defaultConfig };\r\n\r\n// State\r\nlet previousPageId: string | null = null;\r\n\r\n// Page mapping\r\nlet pageMap: any = { ...defaultPageMap };\r\n\r\n/**\r\n * Khởi tạo tracking với config\r\n */\r\nexport const initTracking = (\r\n options: Partial<TrackingConfig> & { pageMap?: Partial<PageMap> } = {},\r\n) => {\r\n config = { ...config, ...options };\r\n\r\n if (options.pageMap) {\r\n pageMap = { ...pageMap, ...options.pageMap };\r\n }\r\n\r\n if (!config.baseURL) {\r\n console.warn(\"[Tracking] baseURL is required.\");\r\n }\r\n\r\n if (config.debug) {\r\n console.log(\"[Tracking] Initialized with config:\", config);\r\n }\r\n};\r\n\r\n/**\r\n * Lấy thông tin page từ URL\r\n */\r\nexport const getPageInfo = (url: string): PageInfo => {\r\n const path = (url || \"\").split(\"?\")[0];\r\n const pathSegment = path.split(\"/\").filter(Boolean)[0] || \"home\";\r\n\r\n return (\r\n pageMap[pathSegment] || {\r\n name: pathSegment.charAt(0).toUpperCase() + pathSegment.slice(1),\r\n id: pathSegment,\r\n }\r\n );\r\n};\r\n\r\n/**\r\n * Send Event -> POST JSON\r\n */\r\nexport const sendEvent = async (\r\n eventData: EventData,\r\n): Promise<Response | void> => {\r\n if (!config.baseURL) {\r\n console.warn(\"[Tracking] Not initialized. Call initTracking() first.\");\r\n return;\r\n }\r\n\r\n try {\r\n // Tách event_name ra khỏi eventData để tạo event object\r\n const { event_name, ...eventParams } = eventData;\r\n\r\n // Tạo event object với format chuẩn\r\n const eventObject = {\r\n event_name: event_name || \"unknown\",\r\n event_params: eventParams,\r\n event_time: Math.floor(Date.now() / 1000),\r\n user_id: config.userId,\r\n };\r\n\r\n const payload = {\r\n // Required properties\r\n app_name: config.appName,\r\n app_id: config.appId,\r\n package_id: config.packageId,\r\n platform: config.platform,\r\n\r\n session_id: config.sessionId,\r\n session_sign: config.sessionSign,\r\n user_id: config.userId,\r\n\r\n device_id: config.deviceId,\r\n device_model: config.deviceModel,\r\n device_brand: config.deviceBrand,\r\n ip_address: config.ipAddress,\r\n\r\n // Optional properties\r\n ad_id: config.adId,\r\n os_version: config.osVersion,\r\n net_type: config.netType,\r\n carrier_net: config.carrierNet,\r\n sdk_version: config.sdkVersion,\r\n app_version: config.appVersion,\r\n build_number: config.buildNumber,\r\n language: config.language,\r\n country: config.country,\r\n\r\n // Events batch - tự động thêm event vào mảng\r\n events: [...(config.events ?? []), eventObject],\r\n };\r\n\r\n if (config.debug) {\r\n console.log(\"[Tracking] Sending event:\", payload);\r\n }\r\n\r\n const res = await fetch(config.baseURL, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(payload),\r\n });\r\n\r\n if (!res.ok && config.debug) {\r\n const text = await res.text().catch(() => \"\");\r\n console.error(\"[Tracking] HTTP Error:\", res.status, text);\r\n }\r\n\r\n return res;\r\n } catch (error) {\r\n if (config.debug) {\r\n console.error(\"[Tracking] Error:\", error);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Track page view event\r\n */\r\nexport const trackPageView = (url: string) => {\r\n const pageInfo = getPageInfo(url);\r\n\r\n sendEvent({\r\n event_name: \"page_view\",\r\n page_name: pageInfo.name,\r\n page_id: pageInfo.id,\r\n page_path: url,\r\n referrer_page_id: previousPageId || \"\",\r\n });\r\n\r\n previousPageId = pageInfo.id;\r\n};\r\n\r\n/**\r\n * Track custom event\r\n */\r\nexport const trackEvent = (eventName: string, params: EventData = {}) => {\r\n sendEvent({\r\n event_name: eventName,\r\n ...params,\r\n });\r\n};\r\n\r\n/**\r\n * Hook cho Next.js - auto track page views\r\n * Dùng cho Next.js Pages Router (next/router)\r\n */\r\nexport const usePageViewTracking = (router: NextRouterLike) => {\r\n if (typeof window === \"undefined\") return;\r\n if (!router) return;\r\n\r\n // Track initial page\r\n trackPageView(router.asPath);\r\n\r\n const handleRouteChange = (url: string) => {\r\n trackPageView(url);\r\n };\r\n\r\n router.events.on(\"routeChangeComplete\", handleRouteChange);\r\n\r\n return () => {\r\n router.events.off(\"routeChangeComplete\", handleRouteChange);\r\n };\r\n};\r\n","/**\r\n * Session Lifecycle Tracking\r\n * - session_start: Khi user mở app\r\n * - session_progress: Định kỳ khi user đang active (foreground)\r\n * - session_end: Khi user thoát app\r\n */\r\n\r\nimport { sendEvent } from \"./tracking\";\r\n\r\nexport type SessionConfig = {\r\n /** Khoảng thời gian gửi session_progress (ms). Default: 5 phút */\r\n progressInterval?: number;\r\n /** Có tự động start session khi init không. Default: true */\r\n autoStart?: boolean;\r\n /** Debug mode */\r\n debug?: boolean;\r\n /** User ID */\r\n userId?: string;\r\n};\r\n\r\nconst defaultSessionConfig: SessionConfig = {\r\n progressInterval: 5 * 60 * 1000, // 5 phút\r\n autoStart: true,\r\n debug: false,\r\n};\r\n\r\n// State\r\nlet sessionConfig: SessionConfig = { ...defaultSessionConfig };\r\nlet progressTimer: ReturnType<typeof setInterval> | null = null;\r\nlet isSessionActive = false;\r\nlet sessionStartTime: number = 0;\r\n\r\n/**\r\n * Log helper\r\n */\r\nconst log = (...args: any[]) => {\r\n if (sessionConfig.debug) {\r\n console.log(\"[Session]\", ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Gửi event session_start\r\n */\r\nexport const sendSessionStart = () => {\r\n if (isSessionActive) {\r\n log(\"Session already started, skipping...\");\r\n return;\r\n }\r\n\r\n sessionStartTime = Date.now();\r\n isSessionActive = true;\r\n\r\n sendEvent({\r\n events: [\r\n {\r\n event_name: \"session_start\",\r\n event_time: sessionStartTime,\r\n user_id: sessionConfig.userId,\r\n },\r\n ],\r\n });\r\n\r\n log(\"Session started at:\", new Date(sessionStartTime).toISOString());\r\n\r\n // Bắt đầu timer cho session_progress\r\n startProgressTimer();\r\n};\r\n\r\n/**\r\n * Gửi event session_progress\r\n */\r\nexport const sendSessionProgress = () => {\r\n if (!isSessionActive) return;\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const duration = now - sessionStartTime;\r\n\r\n sendEvent({\r\n events: [\r\n {\r\n event_name: \"session_progress\",\r\n event_time: now,\r\n session_duration: duration,\r\n user_id: sessionConfig.userId,\r\n },\r\n ],\r\n });\r\n\r\n log(\"Session progress - Duration:\", Math.round(duration / 1000), \"seconds\");\r\n};\r\n\r\n/**\r\n * Gửi event session_end\r\n */\r\nexport const sendSessionEnd = () => {\r\n if (!isSessionActive) return;\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const duration = now - sessionStartTime;\r\n\r\n // Dùng sendBeacon để đảm bảo gửi được khi page unload\r\n // Fallback về sendEvent nếu không support\r\n sendEvent({\r\n events: [\r\n {\r\n event_name: \"session_end\",\r\n event_time: now,\r\n session_duration: duration,\r\n user_id: sessionConfig.userId,\r\n },\r\n ],\r\n });\r\n\r\n log(\r\n \"Session ended - Total duration:\",\r\n Math.round(duration / 1000),\r\n \"seconds\",\r\n );\r\n\r\n stopProgressTimer();\r\n isSessionActive = false;\r\n};\r\n\r\n/**\r\n * Start progress timer\r\n */\r\nconst startProgressTimer = () => {\r\n stopProgressTimer(); // Clear existing timer\r\n\r\n if (sessionConfig.progressInterval && sessionConfig.progressInterval > 0) {\r\n progressTimer = setInterval(() => {\r\n if (document.visibilityState === \"visible\") {\r\n sendSessionProgress();\r\n }\r\n }, sessionConfig.progressInterval);\r\n\r\n log(\r\n \"Progress timer started, interval:\",\r\n sessionConfig.progressInterval,\r\n \"ms\",\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Stop progress timer\r\n */\r\nconst stopProgressTimer = () => {\r\n if (progressTimer) {\r\n clearInterval(progressTimer);\r\n progressTimer = null;\r\n log(\"Progress timer stopped\");\r\n }\r\n};\r\n\r\n/**\r\n * Handle visibility change\r\n * Pause/resume tracking khi user switch tab hoặc minimize\r\n */\r\nconst handleVisibilityChange = () => {\r\n if (document.visibilityState === \"hidden\") {\r\n // User rời khỏi tab - có thể gửi session_progress cuối\r\n log(\"Tab hidden - pausing progress\");\r\n stopProgressTimer();\r\n } else if (document.visibilityState === \"visible\") {\r\n // User quay lại tab - resume timer\r\n log(\"Tab visible - resuming progress\");\r\n if (isSessionActive) {\r\n startProgressTimer();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Handle page unload (user đóng tab/browser)\r\n */\r\nconst handleBeforeUnload = () => {\r\n sendSessionEnd();\r\n};\r\n\r\n/**\r\n * Handle page hide (mobile: switch app, close tab)\r\n * Dùng pagehide thay vì beforeunload cho mobile\r\n */\r\nconst handlePageHide = (event: PageTransitionEvent) => {\r\n if (event.persisted) {\r\n // Page được cache (bfcache) - không phải thực sự đóng\r\n return;\r\n }\r\n sendSessionEnd();\r\n};\r\n\r\n/**\r\n * Khởi tạo session tracking\r\n */\r\nexport const initSessionTracking = (options: SessionConfig = {}) => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n sessionConfig = { ...defaultSessionConfig, ...options };\r\n\r\n log(\"Initializing with config:\", sessionConfig);\r\n\r\n // Đăng ký event listeners\r\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\r\n window.addEventListener(\"beforeunload\", handleBeforeUnload);\r\n window.addEventListener(\"pagehide\", handlePageHide);\r\n\r\n // Auto start session\r\n if (sessionConfig.autoStart) {\r\n sendSessionStart();\r\n }\r\n};\r\n\r\n/**\r\n * Cleanup - gọi khi unmount component\r\n */\r\nexport const cleanupSessionTracking = () => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n log(\"Cleaning up...\");\r\n\r\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\r\n window.removeEventListener(\"beforeunload\", handleBeforeUnload);\r\n window.removeEventListener(\"pagehide\", handlePageHide);\r\n\r\n stopProgressTimer();\r\n isSessionActive = false;\r\n};\r\n\r\n/**\r\n * Cập nhật config (ví dụ: thay đổi interval)\r\n */\r\nexport const updateSessionConfig = (options: Partial<SessionConfig>) => {\r\n sessionConfig = { ...sessionConfig, ...options };\r\n\r\n // Restart timer nếu interval thay đổi\r\n if (options.progressInterval !== undefined && isSessionActive) {\r\n startProgressTimer();\r\n }\r\n\r\n log(\"Config updated:\", sessionConfig);\r\n};\r\n\r\n/**\r\n * Kiểm tra session đang active không\r\n */\r\nexport const isSessionStarted = () => isSessionActive;\r\n\r\n/**\r\n * Lấy thời gian session hiện tại (ms)\r\n */\r\nexport const getSessionDuration = () => {\r\n if (!isSessionActive) return 0;\r\n return Date.now() - sessionStartTime;\r\n};\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/tracking.ts","../src/session.ts"],"sourcesContent":["/**\r\n * Tracking Library v2 (Fetch + TypeScript)\r\n * Thư viện tracking events có thể dùng cho nhiều project\r\n */\r\n\r\n// Re-export types\r\nexport type {\r\n TrackingConfig,\r\n PageInfo,\r\n PageMap,\r\n EventData,\r\n NextRouterLike,\r\n} from \"./types\";\r\n\r\nexport type { SessionConfig } from \"./session\";\r\n\r\n// Re-export constants\r\nexport { defaultConfig, defaultPageMap } from \"./constants\";\r\n\r\n// Re-export functions\r\nexport {\r\n initTracking,\r\n getPageInfo,\r\n sendEvent,\r\n trackPageView,\r\n trackEvent,\r\n usePageViewTracking,\r\n} from \"./tracking\";\r\n\r\n// Re-export session functions\r\nexport {\r\n initSessionTracking,\r\n cleanupSessionTracking,\r\n sendSessionStart,\r\n sendSessionProgress,\r\n sendSessionEnd,\r\n updateSessionConfig,\r\n isSessionStarted,\r\n getSessionDuration,\r\n} from \"./session\";\r\n\r\n// Import for default export\r\nimport {\r\n initTracking,\r\n getPageInfo,\r\n sendEvent,\r\n trackPageView,\r\n trackEvent,\r\n usePageViewTracking,\r\n} from \"./tracking\";\r\n\r\nimport {\r\n initSessionTracking,\r\n cleanupSessionTracking,\r\n sendSessionStart,\r\n sendSessionProgress,\r\n sendSessionEnd,\r\n} from \"./session\";\r\n\r\n// Export default object\r\nconst tracking = {\r\n init: initTracking,\r\n trackPageView,\r\n trackEvent,\r\n sendEvent,\r\n getPageInfo,\r\n usePageViewTracking,\r\n // Session lifecycle\r\n initSession: initSessionTracking,\r\n cleanupSession: cleanupSessionTracking,\r\n sessionStart: sendSessionStart,\r\n sessionProgress: sendSessionProgress,\r\n sessionEnd: sendSessionEnd,\r\n};\r\n\r\nexport default tracking;\r\n","/**\r\n * Constants for Tracking Library\r\n */\r\n\r\nimport type { TrackingConfig, PageMap } from \"./types\";\r\n\r\nexport const defaultConfig: TrackingConfig = {\r\n baseURL: \"\",\r\n appName: \"on_plus\",\r\n appId: \"\",\r\n packageId: \"com.vtvcab.onsportstv\",\r\n platform: \"Web\",\r\n debug: false,\r\n\r\n // Required properties\r\n sessionId: \"\",\r\n sessionSign: \"\",\r\n userId: -1,\r\n deviceId: \"\",\r\n deviceModel: \"\",\r\n deviceBrand: \"\",\r\n ipAddress: \"\",\r\n\r\n // Optional properties\r\n adId: \"\",\r\n osVersion: \"\",\r\n netType: \"\",\r\n carrierNet: \"\",\r\n sdkVersion: \"\",\r\n appVersion: \"\",\r\n buildNumber: \"\",\r\n language: \"\",\r\n country: \"\",\r\n\r\n events: [],\r\n};\r\n\r\nexport const defaultPageMap: PageMap = {\r\n \"\": { name: \"Home\", id: \"home\" },\r\n home: { name: \"Home\", id: \"home\" },\r\n search: { name: \"Search\", id: \"search\" },\r\n detail: { name: \"Detail\", id: \"detail\" },\r\n player: { name: \"Player\", id: \"player\" },\r\n video: { name: \"Video\", id: \"video\" },\r\n live: { name: \"Live\", id: \"live\" },\r\n category: { name: \"Category\", id: \"category\" },\r\n profile: { name: \"Profile\", id: \"profile\" },\r\n login: { name: \"Login\", id: \"login\" },\r\n};\r\n","/**\r\n * Core Tracking Functions\r\n */\r\n\r\nimport type {\r\n TrackingConfig,\r\n PageMap,\r\n PageInfo,\r\n EventData,\r\n NextRouterLike,\r\n} from \"./types\";\r\nimport { defaultConfig, defaultPageMap } from \"./constants\";\r\n\r\n// Config runtime\r\nlet config: TrackingConfig = { ...defaultConfig };\r\n\r\n// State\r\nlet previousPageId: string | null = null;\r\n\r\n// Page mapping\r\nlet pageMap: any = { ...defaultPageMap };\r\n\r\n/**\r\n * Khởi tạo tracking với config\r\n */\r\nexport const initTracking = (\r\n options: Partial<TrackingConfig> & { pageMap?: Partial<PageMap> } = {},\r\n) => {\r\n config = { ...config, ...options };\r\n\r\n if (options.pageMap) {\r\n pageMap = { ...pageMap, ...options.pageMap };\r\n }\r\n\r\n if (!config.baseURL) {\r\n console.warn(\"[Tracking] baseURL is required.\");\r\n }\r\n\r\n if (config.debug) {\r\n console.log(\"[Tracking] Initialized with config:\", config);\r\n }\r\n};\r\n\r\n/**\r\n * Lấy thông tin page từ URL\r\n */\r\nexport const getPageInfo = (url: string): PageInfo => {\r\n const path = (url || \"\").split(\"?\")[0];\r\n const pathSegment = path.split(\"/\").filter(Boolean)[0] || \"home\";\r\n\r\n return (\r\n pageMap[pathSegment] || {\r\n name: pathSegment.charAt(0).toUpperCase() + pathSegment.slice(1),\r\n id: pathSegment,\r\n }\r\n );\r\n};\r\n\r\n/**\r\n * Send Event -> POST JSON\r\n */\r\nexport const sendEvent = async (\r\n eventData: EventData,\r\n): Promise<Response | void> => {\r\n if (!config.baseURL) {\r\n console.warn(\"[Tracking] Not initialized. Call initTracking() first.\");\r\n return;\r\n }\r\n\r\n try {\r\n // Tách event_name ra khỏi eventData để tạo event object\r\n const { event_name, ...eventParams } = eventData;\r\n\r\n // Tạo event object với format chuẩn\r\n const eventObject = {\r\n event_name: event_name || \"unknown\",\r\n event_params: JSON.stringify(eventParams),\r\n event_time: Math.floor(Date.now() / 1000),\r\n user_id: config.userId,\r\n };\r\n\r\n const payload = {\r\n // Required properties\r\n app_name: config.appName,\r\n app_id: config.appId,\r\n package_id: config.packageId,\r\n platform: config.platform,\r\n\r\n session_id: config.sessionId,\r\n session_sign: config.sessionSign,\r\n user_id: config.userId,\r\n\r\n device_id: config.deviceId,\r\n device_model: config.deviceModel,\r\n device_brand: config.deviceBrand,\r\n ip_address: config.ipAddress,\r\n\r\n // Optional properties\r\n ad_id: config.adId,\r\n os_version: config.osVersion,\r\n net_type: config.netType,\r\n carrier_net: config.carrierNet,\r\n sdk_version: config.sdkVersion,\r\n app_version: config.appVersion,\r\n build_number: config.buildNumber,\r\n language: config.language,\r\n country: config.country,\r\n\r\n // Events batch - tự động thêm event vào mảng\r\n events: [...(config.events ?? []), eventObject],\r\n };\r\n\r\n if (config.debug) {\r\n console.log(\"[Tracking] Sending event:\", payload);\r\n }\r\n\r\n const res = await fetch(config.baseURL, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(payload),\r\n });\r\n\r\n if (!res.ok && config.debug) {\r\n const text = await res.text().catch(() => \"\");\r\n console.error(\"[Tracking] HTTP Error:\", res.status, text);\r\n }\r\n\r\n return res;\r\n } catch (error) {\r\n if (config.debug) {\r\n console.error(\"[Tracking] Error:\", error);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Track page view event\r\n */\r\nexport const trackPageView = (url: string) => {\r\n const pageInfo = getPageInfo(url);\r\n\r\n sendEvent({\r\n event_name: \"page_view\",\r\n page_name: pageInfo.name,\r\n page_id: pageInfo.id,\r\n page_path: url,\r\n referrer_page_id: previousPageId || \"\",\r\n });\r\n\r\n previousPageId = pageInfo.id;\r\n};\r\n\r\n/**\r\n * Track custom event\r\n */\r\nexport const trackEvent = (eventName: string, params: EventData = {}) => {\r\n sendEvent({\r\n event_name: eventName,\r\n ...params,\r\n });\r\n};\r\n\r\n/**\r\n * Hook cho Next.js - auto track page views\r\n * Dùng cho Next.js Pages Router (next/router)\r\n */\r\nexport const usePageViewTracking = (router: NextRouterLike) => {\r\n if (typeof window === \"undefined\") return;\r\n if (!router) return;\r\n\r\n // Track initial page\r\n trackPageView(router.asPath);\r\n\r\n const handleRouteChange = (url: string) => {\r\n trackPageView(url);\r\n };\r\n\r\n router.events.on(\"routeChangeComplete\", handleRouteChange);\r\n\r\n return () => {\r\n router.events.off(\"routeChangeComplete\", handleRouteChange);\r\n };\r\n};\r\n","/**\r\n * Session Lifecycle Tracking\r\n * - session_start: Khi user mở app\r\n * - session_progress: Định kỳ khi user đang active (foreground)\r\n * - session_end: Khi user thoát app\r\n */\r\n\r\nimport { sendEvent } from \"./tracking\";\r\n\r\nexport type SessionConfig = {\r\n /** Khoảng thời gian gửi session_progress (ms). Default: 5 phút */\r\n progressInterval?: number;\r\n /** Có tự động start session khi init không. Default: true */\r\n autoStart?: boolean;\r\n /** Debug mode */\r\n debug?: boolean;\r\n /** User ID */\r\n userId?: string;\r\n};\r\n\r\nconst defaultSessionConfig: SessionConfig = {\r\n progressInterval: 5 * 60 * 1000, // 5 phút\r\n autoStart: true,\r\n debug: false,\r\n};\r\n\r\n// State\r\nlet sessionConfig: SessionConfig = { ...defaultSessionConfig };\r\nlet progressTimer: ReturnType<typeof setInterval> | null = null;\r\nlet isSessionActive = false;\r\nlet sessionStartTime: number = 0;\r\n\r\n/**\r\n * Log helper\r\n */\r\nconst log = (...args: any[]) => {\r\n if (sessionConfig.debug) {\r\n console.log(\"[Session]\", ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Gửi event session_start\r\n */\r\nexport const sendSessionStart = () => {\r\n if (isSessionActive) {\r\n log(\"Session already started, skipping...\");\r\n return;\r\n }\r\n\r\n sessionStartTime = Date.now();\r\n isSessionActive = true;\r\n\r\n sendEvent({\r\n event_name: \"session_start\",\r\n event_time: sessionStartTime,\r\n });\r\n\r\n log(\"Session started at:\", new Date(sessionStartTime).toISOString());\r\n\r\n // Bắt đầu timer cho session_progress\r\n startProgressTimer();\r\n};\r\n\r\n/**\r\n * Gửi event session_progress\r\n */\r\nexport const sendSessionProgress = () => {\r\n if (!isSessionActive) return;\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const duration = now - sessionStartTime;\r\n\r\n sendEvent({\r\n event_name: \"session_progress\",\r\n session_duration: duration,\r\n });\r\n\r\n log(\"Session progress - Duration:\", Math.round(duration / 1000), \"seconds\");\r\n};\r\n\r\n/**\r\n * Gửi event session_end\r\n */\r\nexport const sendSessionEnd = () => {\r\n if (!isSessionActive) return;\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const duration = now - sessionStartTime;\r\n\r\n // Dùng sendBeacon để đảm bảo gửi được khi page unload\r\n // Fallback về sendEvent nếu không support\r\n sendEvent({\r\n event_name: \"session_end\",\r\n session_duration: duration,\r\n });\r\n\r\n log(\r\n \"Session ended - Total duration:\",\r\n Math.round(duration / 1000),\r\n \"seconds\",\r\n );\r\n\r\n stopProgressTimer();\r\n isSessionActive = false;\r\n};\r\n\r\n/**\r\n * Start progress timer\r\n */\r\nconst startProgressTimer = () => {\r\n stopProgressTimer(); // Clear existing timer\r\n\r\n if (sessionConfig.progressInterval && sessionConfig.progressInterval > 0) {\r\n progressTimer = setInterval(() => {\r\n if (document.visibilityState === \"visible\") {\r\n sendSessionProgress();\r\n }\r\n }, sessionConfig.progressInterval);\r\n\r\n log(\r\n \"Progress timer started, interval:\",\r\n sessionConfig.progressInterval,\r\n \"ms\",\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Stop progress timer\r\n */\r\nconst stopProgressTimer = () => {\r\n if (progressTimer) {\r\n clearInterval(progressTimer);\r\n progressTimer = null;\r\n log(\"Progress timer stopped\");\r\n }\r\n};\r\n\r\n/**\r\n * Handle visibility change\r\n * Pause/resume tracking khi user switch tab hoặc minimize\r\n */\r\nconst handleVisibilityChange = () => {\r\n if (document.visibilityState === \"hidden\") {\r\n // User rời khỏi tab - có thể gửi session_progress cuối\r\n log(\"Tab hidden - pausing progress\");\r\n stopProgressTimer();\r\n } else if (document.visibilityState === \"visible\") {\r\n // User quay lại tab - resume timer\r\n log(\"Tab visible - resuming progress\");\r\n if (isSessionActive) {\r\n startProgressTimer();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Handle page unload (user đóng tab/browser)\r\n */\r\nconst handleBeforeUnload = () => {\r\n sendSessionEnd();\r\n};\r\n\r\n/**\r\n * Handle page hide (mobile: switch app, close tab)\r\n * Dùng pagehide thay vì beforeunload cho mobile\r\n */\r\nconst handlePageHide = (event: PageTransitionEvent) => {\r\n if (event.persisted) {\r\n // Page được cache (bfcache) - không phải thực sự đóng\r\n return;\r\n }\r\n sendSessionEnd();\r\n};\r\n\r\n/**\r\n * Khởi tạo session tracking\r\n */\r\nexport const initSessionTracking = (options: SessionConfig = {}) => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n sessionConfig = { ...defaultSessionConfig, ...options };\r\n\r\n log(\"Initializing with config:\", sessionConfig);\r\n\r\n // Đăng ký event listeners\r\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\r\n window.addEventListener(\"beforeunload\", handleBeforeUnload);\r\n window.addEventListener(\"pagehide\", handlePageHide);\r\n\r\n // Auto start session\r\n if (sessionConfig.autoStart) {\r\n sendSessionStart();\r\n }\r\n};\r\n\r\n/**\r\n * Cleanup - gọi khi unmount component\r\n */\r\nexport const cleanupSessionTracking = () => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n log(\"Cleaning up...\");\r\n\r\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\r\n window.removeEventListener(\"beforeunload\", handleBeforeUnload);\r\n window.removeEventListener(\"pagehide\", handlePageHide);\r\n\r\n stopProgressTimer();\r\n isSessionActive = false;\r\n};\r\n\r\n/**\r\n * Cập nhật config (ví dụ: thay đổi interval)\r\n */\r\nexport const updateSessionConfig = (options: Partial<SessionConfig>) => {\r\n sessionConfig = { ...sessionConfig, ...options };\r\n\r\n // Restart timer nếu interval thay đổi\r\n if (options.progressInterval !== undefined && isSessionActive) {\r\n startProgressTimer();\r\n }\r\n\r\n log(\"Config updated:\", sessionConfig);\r\n};\r\n\r\n/**\r\n * Kiểm tra session đang active không\r\n */\r\nexport const isSessionStarted = () => isSessionActive;\r\n\r\n/**\r\n * Lấy thời gian session hiện tại (ms)\r\n */\r\nexport const getSessionDuration = () => {\r\n if (!isSessionActive) return 0;\r\n return Date.now() - sessionStartTime;\r\n};\r\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -72,7 +72,7 @@ var sendEvent = async (eventData) => {
72
72
  const { event_name, ...eventParams } = eventData;
73
73
  const eventObject = {
74
74
  event_name: event_name || "unknown",
75
- event_params: eventParams,
75
+ event_params: JSON.stringify(eventParams),
76
76
  event_time: Math.floor(Date.now() / 1e3),
77
77
  user_id: config.userId
78
78
  };
@@ -175,13 +175,8 @@ var sendSessionStart = () => {
175
175
  sessionStartTime = Date.now();
176
176
  isSessionActive = true;
177
177
  sendEvent({
178
- events: [
179
- {
180
- event_name: "session_start",
181
- event_time: sessionStartTime,
182
- user_id: sessionConfig.userId
183
- }
184
- ]
178
+ event_name: "session_start",
179
+ event_time: sessionStartTime
185
180
  });
186
181
  log("Session started at:", new Date(sessionStartTime).toISOString());
187
182
  startProgressTimer();
@@ -191,14 +186,8 @@ var sendSessionProgress = () => {
191
186
  const now = Math.floor(Date.now() / 1e3);
192
187
  const duration = now - sessionStartTime;
193
188
  sendEvent({
194
- events: [
195
- {
196
- event_name: "session_progress",
197
- event_time: now,
198
- session_duration: duration,
199
- user_id: sessionConfig.userId
200
- }
201
- ]
189
+ event_name: "session_progress",
190
+ session_duration: duration
202
191
  });
203
192
  log("Session progress - Duration:", Math.round(duration / 1e3), "seconds");
204
193
  };
@@ -207,14 +196,8 @@ var sendSessionEnd = () => {
207
196
  const now = Math.floor(Date.now() / 1e3);
208
197
  const duration = now - sessionStartTime;
209
198
  sendEvent({
210
- events: [
211
- {
212
- event_name: "session_end",
213
- event_time: now,
214
- session_duration: duration,
215
- user_id: sessionConfig.userId
216
- }
217
- ]
199
+ event_name: "session_end",
200
+ session_duration: duration
218
201
  });
219
202
  log(
220
203
  "Session ended - Total duration:",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/tracking.ts","../src/session.ts","../src/index.ts"],"sourcesContent":["/**\r\n * Constants for Tracking Library\r\n */\r\n\r\nimport type { TrackingConfig, PageMap } from \"./types\";\r\n\r\nexport const defaultConfig: TrackingConfig = {\r\n baseURL: \"\",\r\n appName: \"on_plus\",\r\n appId: \"\",\r\n packageId: \"com.vtvcab.onsportstv\",\r\n platform: \"Web\",\r\n debug: false,\r\n\r\n // Required properties\r\n sessionId: \"\",\r\n sessionSign: \"\",\r\n userId: -1,\r\n deviceId: \"\",\r\n deviceModel: \"\",\r\n deviceBrand: \"\",\r\n ipAddress: \"\",\r\n\r\n // Optional properties\r\n adId: \"\",\r\n osVersion: \"\",\r\n netType: \"\",\r\n carrierNet: \"\",\r\n sdkVersion: \"\",\r\n appVersion: \"\",\r\n buildNumber: \"\",\r\n language: \"\",\r\n country: \"\",\r\n\r\n events: [],\r\n};\r\n\r\nexport const defaultPageMap: PageMap = {\r\n \"\": { name: \"Home\", id: \"home\" },\r\n home: { name: \"Home\", id: \"home\" },\r\n search: { name: \"Search\", id: \"search\" },\r\n detail: { name: \"Detail\", id: \"detail\" },\r\n player: { name: \"Player\", id: \"player\" },\r\n video: { name: \"Video\", id: \"video\" },\r\n live: { name: \"Live\", id: \"live\" },\r\n category: { name: \"Category\", id: \"category\" },\r\n profile: { name: \"Profile\", id: \"profile\" },\r\n login: { name: \"Login\", id: \"login\" },\r\n};\r\n","/**\r\n * Core Tracking Functions\r\n */\r\n\r\nimport type {\r\n TrackingConfig,\r\n PageMap,\r\n PageInfo,\r\n EventData,\r\n NextRouterLike,\r\n} from \"./types\";\r\nimport { defaultConfig, defaultPageMap } from \"./constants\";\r\n\r\n// Config runtime\r\nlet config: TrackingConfig = { ...defaultConfig };\r\n\r\n// State\r\nlet previousPageId: string | null = null;\r\n\r\n// Page mapping\r\nlet pageMap: any = { ...defaultPageMap };\r\n\r\n/**\r\n * Khởi tạo tracking với config\r\n */\r\nexport const initTracking = (\r\n options: Partial<TrackingConfig> & { pageMap?: Partial<PageMap> } = {},\r\n) => {\r\n config = { ...config, ...options };\r\n\r\n if (options.pageMap) {\r\n pageMap = { ...pageMap, ...options.pageMap };\r\n }\r\n\r\n if (!config.baseURL) {\r\n console.warn(\"[Tracking] baseURL is required.\");\r\n }\r\n\r\n if (config.debug) {\r\n console.log(\"[Tracking] Initialized with config:\", config);\r\n }\r\n};\r\n\r\n/**\r\n * Lấy thông tin page từ URL\r\n */\r\nexport const getPageInfo = (url: string): PageInfo => {\r\n const path = (url || \"\").split(\"?\")[0];\r\n const pathSegment = path.split(\"/\").filter(Boolean)[0] || \"home\";\r\n\r\n return (\r\n pageMap[pathSegment] || {\r\n name: pathSegment.charAt(0).toUpperCase() + pathSegment.slice(1),\r\n id: pathSegment,\r\n }\r\n );\r\n};\r\n\r\n/**\r\n * Send Event -> POST JSON\r\n */\r\nexport const sendEvent = async (\r\n eventData: EventData,\r\n): Promise<Response | void> => {\r\n if (!config.baseURL) {\r\n console.warn(\"[Tracking] Not initialized. Call initTracking() first.\");\r\n return;\r\n }\r\n\r\n try {\r\n // Tách event_name ra khỏi eventData để tạo event object\r\n const { event_name, ...eventParams } = eventData;\r\n\r\n // Tạo event object với format chuẩn\r\n const eventObject = {\r\n event_name: event_name || \"unknown\",\r\n event_params: eventParams,\r\n event_time: Math.floor(Date.now() / 1000),\r\n user_id: config.userId,\r\n };\r\n\r\n const payload = {\r\n // Required properties\r\n app_name: config.appName,\r\n app_id: config.appId,\r\n package_id: config.packageId,\r\n platform: config.platform,\r\n\r\n session_id: config.sessionId,\r\n session_sign: config.sessionSign,\r\n user_id: config.userId,\r\n\r\n device_id: config.deviceId,\r\n device_model: config.deviceModel,\r\n device_brand: config.deviceBrand,\r\n ip_address: config.ipAddress,\r\n\r\n // Optional properties\r\n ad_id: config.adId,\r\n os_version: config.osVersion,\r\n net_type: config.netType,\r\n carrier_net: config.carrierNet,\r\n sdk_version: config.sdkVersion,\r\n app_version: config.appVersion,\r\n build_number: config.buildNumber,\r\n language: config.language,\r\n country: config.country,\r\n\r\n // Events batch - tự động thêm event vào mảng\r\n events: [...(config.events ?? []), eventObject],\r\n };\r\n\r\n if (config.debug) {\r\n console.log(\"[Tracking] Sending event:\", payload);\r\n }\r\n\r\n const res = await fetch(config.baseURL, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(payload),\r\n });\r\n\r\n if (!res.ok && config.debug) {\r\n const text = await res.text().catch(() => \"\");\r\n console.error(\"[Tracking] HTTP Error:\", res.status, text);\r\n }\r\n\r\n return res;\r\n } catch (error) {\r\n if (config.debug) {\r\n console.error(\"[Tracking] Error:\", error);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Track page view event\r\n */\r\nexport const trackPageView = (url: string) => {\r\n const pageInfo = getPageInfo(url);\r\n\r\n sendEvent({\r\n event_name: \"page_view\",\r\n page_name: pageInfo.name,\r\n page_id: pageInfo.id,\r\n page_path: url,\r\n referrer_page_id: previousPageId || \"\",\r\n });\r\n\r\n previousPageId = pageInfo.id;\r\n};\r\n\r\n/**\r\n * Track custom event\r\n */\r\nexport const trackEvent = (eventName: string, params: EventData = {}) => {\r\n sendEvent({\r\n event_name: eventName,\r\n ...params,\r\n });\r\n};\r\n\r\n/**\r\n * Hook cho Next.js - auto track page views\r\n * Dùng cho Next.js Pages Router (next/router)\r\n */\r\nexport const usePageViewTracking = (router: NextRouterLike) => {\r\n if (typeof window === \"undefined\") return;\r\n if (!router) return;\r\n\r\n // Track initial page\r\n trackPageView(router.asPath);\r\n\r\n const handleRouteChange = (url: string) => {\r\n trackPageView(url);\r\n };\r\n\r\n router.events.on(\"routeChangeComplete\", handleRouteChange);\r\n\r\n return () => {\r\n router.events.off(\"routeChangeComplete\", handleRouteChange);\r\n };\r\n};\r\n","/**\r\n * Session Lifecycle Tracking\r\n * - session_start: Khi user mở app\r\n * - session_progress: Định kỳ khi user đang active (foreground)\r\n * - session_end: Khi user thoát app\r\n */\r\n\r\nimport { sendEvent } from \"./tracking\";\r\n\r\nexport type SessionConfig = {\r\n /** Khoảng thời gian gửi session_progress (ms). Default: 5 phút */\r\n progressInterval?: number;\r\n /** Có tự động start session khi init không. Default: true */\r\n autoStart?: boolean;\r\n /** Debug mode */\r\n debug?: boolean;\r\n /** User ID */\r\n userId?: string;\r\n};\r\n\r\nconst defaultSessionConfig: SessionConfig = {\r\n progressInterval: 5 * 60 * 1000, // 5 phút\r\n autoStart: true,\r\n debug: false,\r\n};\r\n\r\n// State\r\nlet sessionConfig: SessionConfig = { ...defaultSessionConfig };\r\nlet progressTimer: ReturnType<typeof setInterval> | null = null;\r\nlet isSessionActive = false;\r\nlet sessionStartTime: number = 0;\r\n\r\n/**\r\n * Log helper\r\n */\r\nconst log = (...args: any[]) => {\r\n if (sessionConfig.debug) {\r\n console.log(\"[Session]\", ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Gửi event session_start\r\n */\r\nexport const sendSessionStart = () => {\r\n if (isSessionActive) {\r\n log(\"Session already started, skipping...\");\r\n return;\r\n }\r\n\r\n sessionStartTime = Date.now();\r\n isSessionActive = true;\r\n\r\n sendEvent({\r\n events: [\r\n {\r\n event_name: \"session_start\",\r\n event_time: sessionStartTime,\r\n user_id: sessionConfig.userId,\r\n },\r\n ],\r\n });\r\n\r\n log(\"Session started at:\", new Date(sessionStartTime).toISOString());\r\n\r\n // Bắt đầu timer cho session_progress\r\n startProgressTimer();\r\n};\r\n\r\n/**\r\n * Gửi event session_progress\r\n */\r\nexport const sendSessionProgress = () => {\r\n if (!isSessionActive) return;\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const duration = now - sessionStartTime;\r\n\r\n sendEvent({\r\n events: [\r\n {\r\n event_name: \"session_progress\",\r\n event_time: now,\r\n session_duration: duration,\r\n user_id: sessionConfig.userId,\r\n },\r\n ],\r\n });\r\n\r\n log(\"Session progress - Duration:\", Math.round(duration / 1000), \"seconds\");\r\n};\r\n\r\n/**\r\n * Gửi event session_end\r\n */\r\nexport const sendSessionEnd = () => {\r\n if (!isSessionActive) return;\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const duration = now - sessionStartTime;\r\n\r\n // Dùng sendBeacon để đảm bảo gửi được khi page unload\r\n // Fallback về sendEvent nếu không support\r\n sendEvent({\r\n events: [\r\n {\r\n event_name: \"session_end\",\r\n event_time: now,\r\n session_duration: duration,\r\n user_id: sessionConfig.userId,\r\n },\r\n ],\r\n });\r\n\r\n log(\r\n \"Session ended - Total duration:\",\r\n Math.round(duration / 1000),\r\n \"seconds\",\r\n );\r\n\r\n stopProgressTimer();\r\n isSessionActive = false;\r\n};\r\n\r\n/**\r\n * Start progress timer\r\n */\r\nconst startProgressTimer = () => {\r\n stopProgressTimer(); // Clear existing timer\r\n\r\n if (sessionConfig.progressInterval && sessionConfig.progressInterval > 0) {\r\n progressTimer = setInterval(() => {\r\n if (document.visibilityState === \"visible\") {\r\n sendSessionProgress();\r\n }\r\n }, sessionConfig.progressInterval);\r\n\r\n log(\r\n \"Progress timer started, interval:\",\r\n sessionConfig.progressInterval,\r\n \"ms\",\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Stop progress timer\r\n */\r\nconst stopProgressTimer = () => {\r\n if (progressTimer) {\r\n clearInterval(progressTimer);\r\n progressTimer = null;\r\n log(\"Progress timer stopped\");\r\n }\r\n};\r\n\r\n/**\r\n * Handle visibility change\r\n * Pause/resume tracking khi user switch tab hoặc minimize\r\n */\r\nconst handleVisibilityChange = () => {\r\n if (document.visibilityState === \"hidden\") {\r\n // User rời khỏi tab - có thể gửi session_progress cuối\r\n log(\"Tab hidden - pausing progress\");\r\n stopProgressTimer();\r\n } else if (document.visibilityState === \"visible\") {\r\n // User quay lại tab - resume timer\r\n log(\"Tab visible - resuming progress\");\r\n if (isSessionActive) {\r\n startProgressTimer();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Handle page unload (user đóng tab/browser)\r\n */\r\nconst handleBeforeUnload = () => {\r\n sendSessionEnd();\r\n};\r\n\r\n/**\r\n * Handle page hide (mobile: switch app, close tab)\r\n * Dùng pagehide thay vì beforeunload cho mobile\r\n */\r\nconst handlePageHide = (event: PageTransitionEvent) => {\r\n if (event.persisted) {\r\n // Page được cache (bfcache) - không phải thực sự đóng\r\n return;\r\n }\r\n sendSessionEnd();\r\n};\r\n\r\n/**\r\n * Khởi tạo session tracking\r\n */\r\nexport const initSessionTracking = (options: SessionConfig = {}) => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n sessionConfig = { ...defaultSessionConfig, ...options };\r\n\r\n log(\"Initializing with config:\", sessionConfig);\r\n\r\n // Đăng ký event listeners\r\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\r\n window.addEventListener(\"beforeunload\", handleBeforeUnload);\r\n window.addEventListener(\"pagehide\", handlePageHide);\r\n\r\n // Auto start session\r\n if (sessionConfig.autoStart) {\r\n sendSessionStart();\r\n }\r\n};\r\n\r\n/**\r\n * Cleanup - gọi khi unmount component\r\n */\r\nexport const cleanupSessionTracking = () => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n log(\"Cleaning up...\");\r\n\r\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\r\n window.removeEventListener(\"beforeunload\", handleBeforeUnload);\r\n window.removeEventListener(\"pagehide\", handlePageHide);\r\n\r\n stopProgressTimer();\r\n isSessionActive = false;\r\n};\r\n\r\n/**\r\n * Cập nhật config (ví dụ: thay đổi interval)\r\n */\r\nexport const updateSessionConfig = (options: Partial<SessionConfig>) => {\r\n sessionConfig = { ...sessionConfig, ...options };\r\n\r\n // Restart timer nếu interval thay đổi\r\n if (options.progressInterval !== undefined && isSessionActive) {\r\n startProgressTimer();\r\n }\r\n\r\n log(\"Config updated:\", sessionConfig);\r\n};\r\n\r\n/**\r\n * Kiểm tra session đang active không\r\n */\r\nexport const isSessionStarted = () => isSessionActive;\r\n\r\n/**\r\n * Lấy thời gian session hiện tại (ms)\r\n */\r\nexport const getSessionDuration = () => {\r\n if (!isSessionActive) return 0;\r\n return Date.now() - sessionStartTime;\r\n};\r\n","/**\r\n * Tracking Library v2 (Fetch + TypeScript)\r\n * Thư viện tracking events có thể dùng cho nhiều project\r\n */\r\n\r\n// Re-export types\r\nexport type {\r\n TrackingConfig,\r\n PageInfo,\r\n PageMap,\r\n EventData,\r\n NextRouterLike,\r\n} from \"./types\";\r\n\r\nexport type { SessionConfig } from \"./session\";\r\n\r\n// Re-export constants\r\nexport { defaultConfig, defaultPageMap } from \"./constants\";\r\n\r\n// Re-export functions\r\nexport {\r\n initTracking,\r\n getPageInfo,\r\n sendEvent,\r\n trackPageView,\r\n trackEvent,\r\n usePageViewTracking,\r\n} from \"./tracking\";\r\n\r\n// Re-export session functions\r\nexport {\r\n initSessionTracking,\r\n cleanupSessionTracking,\r\n sendSessionStart,\r\n sendSessionProgress,\r\n sendSessionEnd,\r\n updateSessionConfig,\r\n isSessionStarted,\r\n getSessionDuration,\r\n} from \"./session\";\r\n\r\n// Import for default export\r\nimport {\r\n initTracking,\r\n getPageInfo,\r\n sendEvent,\r\n trackPageView,\r\n trackEvent,\r\n usePageViewTracking,\r\n} from \"./tracking\";\r\n\r\nimport {\r\n initSessionTracking,\r\n cleanupSessionTracking,\r\n sendSessionStart,\r\n sendSessionProgress,\r\n sendSessionEnd,\r\n} from \"./session\";\r\n\r\n// Export default object\r\nconst tracking = {\r\n init: initTracking,\r\n trackPageView,\r\n trackEvent,\r\n sendEvent,\r\n getPageInfo,\r\n usePageViewTracking,\r\n // Session lifecycle\r\n initSession: initSessionTracking,\r\n cleanupSession: cleanupSessionTracking,\r\n sessionStart: sendSessionStart,\r\n sessionProgress: sendSessionProgress,\r\n sessionEnd: sendSessionEnd,\r\n};\r\n\r\nexport default tracking;\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/tracking.ts","../src/session.ts","../src/index.ts"],"sourcesContent":["/**\r\n * Constants for Tracking Library\r\n */\r\n\r\nimport type { TrackingConfig, PageMap } from \"./types\";\r\n\r\nexport const defaultConfig: TrackingConfig = {\r\n baseURL: \"\",\r\n appName: \"on_plus\",\r\n appId: \"\",\r\n packageId: \"com.vtvcab.onsportstv\",\r\n platform: \"Web\",\r\n debug: false,\r\n\r\n // Required properties\r\n sessionId: \"\",\r\n sessionSign: \"\",\r\n userId: -1,\r\n deviceId: \"\",\r\n deviceModel: \"\",\r\n deviceBrand: \"\",\r\n ipAddress: \"\",\r\n\r\n // Optional properties\r\n adId: \"\",\r\n osVersion: \"\",\r\n netType: \"\",\r\n carrierNet: \"\",\r\n sdkVersion: \"\",\r\n appVersion: \"\",\r\n buildNumber: \"\",\r\n language: \"\",\r\n country: \"\",\r\n\r\n events: [],\r\n};\r\n\r\nexport const defaultPageMap: PageMap = {\r\n \"\": { name: \"Home\", id: \"home\" },\r\n home: { name: \"Home\", id: \"home\" },\r\n search: { name: \"Search\", id: \"search\" },\r\n detail: { name: \"Detail\", id: \"detail\" },\r\n player: { name: \"Player\", id: \"player\" },\r\n video: { name: \"Video\", id: \"video\" },\r\n live: { name: \"Live\", id: \"live\" },\r\n category: { name: \"Category\", id: \"category\" },\r\n profile: { name: \"Profile\", id: \"profile\" },\r\n login: { name: \"Login\", id: \"login\" },\r\n};\r\n","/**\r\n * Core Tracking Functions\r\n */\r\n\r\nimport type {\r\n TrackingConfig,\r\n PageMap,\r\n PageInfo,\r\n EventData,\r\n NextRouterLike,\r\n} from \"./types\";\r\nimport { defaultConfig, defaultPageMap } from \"./constants\";\r\n\r\n// Config runtime\r\nlet config: TrackingConfig = { ...defaultConfig };\r\n\r\n// State\r\nlet previousPageId: string | null = null;\r\n\r\n// Page mapping\r\nlet pageMap: any = { ...defaultPageMap };\r\n\r\n/**\r\n * Khởi tạo tracking với config\r\n */\r\nexport const initTracking = (\r\n options: Partial<TrackingConfig> & { pageMap?: Partial<PageMap> } = {},\r\n) => {\r\n config = { ...config, ...options };\r\n\r\n if (options.pageMap) {\r\n pageMap = { ...pageMap, ...options.pageMap };\r\n }\r\n\r\n if (!config.baseURL) {\r\n console.warn(\"[Tracking] baseURL is required.\");\r\n }\r\n\r\n if (config.debug) {\r\n console.log(\"[Tracking] Initialized with config:\", config);\r\n }\r\n};\r\n\r\n/**\r\n * Lấy thông tin page từ URL\r\n */\r\nexport const getPageInfo = (url: string): PageInfo => {\r\n const path = (url || \"\").split(\"?\")[0];\r\n const pathSegment = path.split(\"/\").filter(Boolean)[0] || \"home\";\r\n\r\n return (\r\n pageMap[pathSegment] || {\r\n name: pathSegment.charAt(0).toUpperCase() + pathSegment.slice(1),\r\n id: pathSegment,\r\n }\r\n );\r\n};\r\n\r\n/**\r\n * Send Event -> POST JSON\r\n */\r\nexport const sendEvent = async (\r\n eventData: EventData,\r\n): Promise<Response | void> => {\r\n if (!config.baseURL) {\r\n console.warn(\"[Tracking] Not initialized. Call initTracking() first.\");\r\n return;\r\n }\r\n\r\n try {\r\n // Tách event_name ra khỏi eventData để tạo event object\r\n const { event_name, ...eventParams } = eventData;\r\n\r\n // Tạo event object với format chuẩn\r\n const eventObject = {\r\n event_name: event_name || \"unknown\",\r\n event_params: JSON.stringify(eventParams),\r\n event_time: Math.floor(Date.now() / 1000),\r\n user_id: config.userId,\r\n };\r\n\r\n const payload = {\r\n // Required properties\r\n app_name: config.appName,\r\n app_id: config.appId,\r\n package_id: config.packageId,\r\n platform: config.platform,\r\n\r\n session_id: config.sessionId,\r\n session_sign: config.sessionSign,\r\n user_id: config.userId,\r\n\r\n device_id: config.deviceId,\r\n device_model: config.deviceModel,\r\n device_brand: config.deviceBrand,\r\n ip_address: config.ipAddress,\r\n\r\n // Optional properties\r\n ad_id: config.adId,\r\n os_version: config.osVersion,\r\n net_type: config.netType,\r\n carrier_net: config.carrierNet,\r\n sdk_version: config.sdkVersion,\r\n app_version: config.appVersion,\r\n build_number: config.buildNumber,\r\n language: config.language,\r\n country: config.country,\r\n\r\n // Events batch - tự động thêm event vào mảng\r\n events: [...(config.events ?? []), eventObject],\r\n };\r\n\r\n if (config.debug) {\r\n console.log(\"[Tracking] Sending event:\", payload);\r\n }\r\n\r\n const res = await fetch(config.baseURL, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(payload),\r\n });\r\n\r\n if (!res.ok && config.debug) {\r\n const text = await res.text().catch(() => \"\");\r\n console.error(\"[Tracking] HTTP Error:\", res.status, text);\r\n }\r\n\r\n return res;\r\n } catch (error) {\r\n if (config.debug) {\r\n console.error(\"[Tracking] Error:\", error);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Track page view event\r\n */\r\nexport const trackPageView = (url: string) => {\r\n const pageInfo = getPageInfo(url);\r\n\r\n sendEvent({\r\n event_name: \"page_view\",\r\n page_name: pageInfo.name,\r\n page_id: pageInfo.id,\r\n page_path: url,\r\n referrer_page_id: previousPageId || \"\",\r\n });\r\n\r\n previousPageId = pageInfo.id;\r\n};\r\n\r\n/**\r\n * Track custom event\r\n */\r\nexport const trackEvent = (eventName: string, params: EventData = {}) => {\r\n sendEvent({\r\n event_name: eventName,\r\n ...params,\r\n });\r\n};\r\n\r\n/**\r\n * Hook cho Next.js - auto track page views\r\n * Dùng cho Next.js Pages Router (next/router)\r\n */\r\nexport const usePageViewTracking = (router: NextRouterLike) => {\r\n if (typeof window === \"undefined\") return;\r\n if (!router) return;\r\n\r\n // Track initial page\r\n trackPageView(router.asPath);\r\n\r\n const handleRouteChange = (url: string) => {\r\n trackPageView(url);\r\n };\r\n\r\n router.events.on(\"routeChangeComplete\", handleRouteChange);\r\n\r\n return () => {\r\n router.events.off(\"routeChangeComplete\", handleRouteChange);\r\n };\r\n};\r\n","/**\r\n * Session Lifecycle Tracking\r\n * - session_start: Khi user mở app\r\n * - session_progress: Định kỳ khi user đang active (foreground)\r\n * - session_end: Khi user thoát app\r\n */\r\n\r\nimport { sendEvent } from \"./tracking\";\r\n\r\nexport type SessionConfig = {\r\n /** Khoảng thời gian gửi session_progress (ms). Default: 5 phút */\r\n progressInterval?: number;\r\n /** Có tự động start session khi init không. Default: true */\r\n autoStart?: boolean;\r\n /** Debug mode */\r\n debug?: boolean;\r\n /** User ID */\r\n userId?: string;\r\n};\r\n\r\nconst defaultSessionConfig: SessionConfig = {\r\n progressInterval: 5 * 60 * 1000, // 5 phút\r\n autoStart: true,\r\n debug: false,\r\n};\r\n\r\n// State\r\nlet sessionConfig: SessionConfig = { ...defaultSessionConfig };\r\nlet progressTimer: ReturnType<typeof setInterval> | null = null;\r\nlet isSessionActive = false;\r\nlet sessionStartTime: number = 0;\r\n\r\n/**\r\n * Log helper\r\n */\r\nconst log = (...args: any[]) => {\r\n if (sessionConfig.debug) {\r\n console.log(\"[Session]\", ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Gửi event session_start\r\n */\r\nexport const sendSessionStart = () => {\r\n if (isSessionActive) {\r\n log(\"Session already started, skipping...\");\r\n return;\r\n }\r\n\r\n sessionStartTime = Date.now();\r\n isSessionActive = true;\r\n\r\n sendEvent({\r\n event_name: \"session_start\",\r\n event_time: sessionStartTime,\r\n });\r\n\r\n log(\"Session started at:\", new Date(sessionStartTime).toISOString());\r\n\r\n // Bắt đầu timer cho session_progress\r\n startProgressTimer();\r\n};\r\n\r\n/**\r\n * Gửi event session_progress\r\n */\r\nexport const sendSessionProgress = () => {\r\n if (!isSessionActive) return;\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const duration = now - sessionStartTime;\r\n\r\n sendEvent({\r\n event_name: \"session_progress\",\r\n session_duration: duration,\r\n });\r\n\r\n log(\"Session progress - Duration:\", Math.round(duration / 1000), \"seconds\");\r\n};\r\n\r\n/**\r\n * Gửi event session_end\r\n */\r\nexport const sendSessionEnd = () => {\r\n if (!isSessionActive) return;\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n const duration = now - sessionStartTime;\r\n\r\n // Dùng sendBeacon để đảm bảo gửi được khi page unload\r\n // Fallback về sendEvent nếu không support\r\n sendEvent({\r\n event_name: \"session_end\",\r\n session_duration: duration,\r\n });\r\n\r\n log(\r\n \"Session ended - Total duration:\",\r\n Math.round(duration / 1000),\r\n \"seconds\",\r\n );\r\n\r\n stopProgressTimer();\r\n isSessionActive = false;\r\n};\r\n\r\n/**\r\n * Start progress timer\r\n */\r\nconst startProgressTimer = () => {\r\n stopProgressTimer(); // Clear existing timer\r\n\r\n if (sessionConfig.progressInterval && sessionConfig.progressInterval > 0) {\r\n progressTimer = setInterval(() => {\r\n if (document.visibilityState === \"visible\") {\r\n sendSessionProgress();\r\n }\r\n }, sessionConfig.progressInterval);\r\n\r\n log(\r\n \"Progress timer started, interval:\",\r\n sessionConfig.progressInterval,\r\n \"ms\",\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Stop progress timer\r\n */\r\nconst stopProgressTimer = () => {\r\n if (progressTimer) {\r\n clearInterval(progressTimer);\r\n progressTimer = null;\r\n log(\"Progress timer stopped\");\r\n }\r\n};\r\n\r\n/**\r\n * Handle visibility change\r\n * Pause/resume tracking khi user switch tab hoặc minimize\r\n */\r\nconst handleVisibilityChange = () => {\r\n if (document.visibilityState === \"hidden\") {\r\n // User rời khỏi tab - có thể gửi session_progress cuối\r\n log(\"Tab hidden - pausing progress\");\r\n stopProgressTimer();\r\n } else if (document.visibilityState === \"visible\") {\r\n // User quay lại tab - resume timer\r\n log(\"Tab visible - resuming progress\");\r\n if (isSessionActive) {\r\n startProgressTimer();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Handle page unload (user đóng tab/browser)\r\n */\r\nconst handleBeforeUnload = () => {\r\n sendSessionEnd();\r\n};\r\n\r\n/**\r\n * Handle page hide (mobile: switch app, close tab)\r\n * Dùng pagehide thay vì beforeunload cho mobile\r\n */\r\nconst handlePageHide = (event: PageTransitionEvent) => {\r\n if (event.persisted) {\r\n // Page được cache (bfcache) - không phải thực sự đóng\r\n return;\r\n }\r\n sendSessionEnd();\r\n};\r\n\r\n/**\r\n * Khởi tạo session tracking\r\n */\r\nexport const initSessionTracking = (options: SessionConfig = {}) => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n sessionConfig = { ...defaultSessionConfig, ...options };\r\n\r\n log(\"Initializing with config:\", sessionConfig);\r\n\r\n // Đăng ký event listeners\r\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\r\n window.addEventListener(\"beforeunload\", handleBeforeUnload);\r\n window.addEventListener(\"pagehide\", handlePageHide);\r\n\r\n // Auto start session\r\n if (sessionConfig.autoStart) {\r\n sendSessionStart();\r\n }\r\n};\r\n\r\n/**\r\n * Cleanup - gọi khi unmount component\r\n */\r\nexport const cleanupSessionTracking = () => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n log(\"Cleaning up...\");\r\n\r\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\r\n window.removeEventListener(\"beforeunload\", handleBeforeUnload);\r\n window.removeEventListener(\"pagehide\", handlePageHide);\r\n\r\n stopProgressTimer();\r\n isSessionActive = false;\r\n};\r\n\r\n/**\r\n * Cập nhật config (ví dụ: thay đổi interval)\r\n */\r\nexport const updateSessionConfig = (options: Partial<SessionConfig>) => {\r\n sessionConfig = { ...sessionConfig, ...options };\r\n\r\n // Restart timer nếu interval thay đổi\r\n if (options.progressInterval !== undefined && isSessionActive) {\r\n startProgressTimer();\r\n }\r\n\r\n log(\"Config updated:\", sessionConfig);\r\n};\r\n\r\n/**\r\n * Kiểm tra session đang active không\r\n */\r\nexport const isSessionStarted = () => isSessionActive;\r\n\r\n/**\r\n * Lấy thời gian session hiện tại (ms)\r\n */\r\nexport const getSessionDuration = () => {\r\n if (!isSessionActive) return 0;\r\n return Date.now() - sessionStartTime;\r\n};\r\n","/**\r\n * Tracking Library v2 (Fetch + TypeScript)\r\n * Thư viện tracking events có thể dùng cho nhiều project\r\n */\r\n\r\n// Re-export types\r\nexport type {\r\n TrackingConfig,\r\n PageInfo,\r\n PageMap,\r\n EventData,\r\n NextRouterLike,\r\n} from \"./types\";\r\n\r\nexport type { SessionConfig } from \"./session\";\r\n\r\n// Re-export constants\r\nexport { defaultConfig, defaultPageMap } from \"./constants\";\r\n\r\n// Re-export functions\r\nexport {\r\n initTracking,\r\n getPageInfo,\r\n sendEvent,\r\n trackPageView,\r\n trackEvent,\r\n usePageViewTracking,\r\n} from \"./tracking\";\r\n\r\n// Re-export session functions\r\nexport {\r\n initSessionTracking,\r\n cleanupSessionTracking,\r\n sendSessionStart,\r\n sendSessionProgress,\r\n sendSessionEnd,\r\n updateSessionConfig,\r\n isSessionStarted,\r\n getSessionDuration,\r\n} from \"./session\";\r\n\r\n// Import for default export\r\nimport {\r\n initTracking,\r\n getPageInfo,\r\n sendEvent,\r\n trackPageView,\r\n trackEvent,\r\n usePageViewTracking,\r\n} from \"./tracking\";\r\n\r\nimport {\r\n initSessionTracking,\r\n cleanupSessionTracking,\r\n sendSessionStart,\r\n sendSessionProgress,\r\n sendSessionEnd,\r\n} from \"./session\";\r\n\r\n// Export default object\r\nconst tracking = {\r\n init: initTracking,\r\n trackPageView,\r\n trackEvent,\r\n sendEvent,\r\n getPageInfo,\r\n usePageViewTracking,\r\n // Session lifecycle\r\n initSession: initSessionTracking,\r\n cleanupSession: cleanupSessionTracking,\r\n sessionStart: sendSessionStart,\r\n sessionProgress: sendSessionProgress,\r\n sessionEnd: sendSessionEnd,\r\n};\r\n\r\nexport default tracking;\r\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tracking-lib-ott",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",