tracking-lib-ott 1.0.1 → 1.0.3

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/dist/index.cjs CHANGED
@@ -20,15 +20,27 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ cleanupSessionTracking: () => cleanupSessionTracking,
23
24
  default: () => index_default,
25
+ defaultConfig: () => defaultConfig,
26
+ defaultPageMap: () => defaultPageMap,
24
27
  getPageInfo: () => getPageInfo,
28
+ getSessionDuration: () => getSessionDuration,
29
+ initSessionTracking: () => initSessionTracking,
25
30
  initTracking: () => initTracking,
31
+ isSessionStarted: () => isSessionStarted,
26
32
  sendEvent: () => sendEvent,
33
+ sendSessionEnd: () => sendSessionEnd,
34
+ sendSessionProgress: () => sendSessionProgress,
35
+ sendSessionStart: () => sendSessionStart,
27
36
  trackEvent: () => trackEvent,
28
37
  trackPageView: () => trackPageView,
38
+ updateSessionConfig: () => updateSessionConfig,
29
39
  usePageViewTracking: () => usePageViewTracking
30
40
  });
31
41
  module.exports = __toCommonJS(index_exports);
42
+
43
+ // src/constants.ts
32
44
  var defaultConfig = {
33
45
  baseURL: "",
34
46
  appName: "on_plus",
@@ -37,28 +49,26 @@ var defaultConfig = {
37
49
  platform: "Web",
38
50
  debug: false,
39
51
  // Required properties
40
- session_id: "",
41
- session_sign: "",
42
- user_id: -1,
52
+ sessionId: "",
53
+ sessionSign: "",
54
+ userId: -1,
43
55
  deviceId: "",
44
56
  deviceModel: "",
45
57
  deviceBrand: "",
46
- ip_address: "",
58
+ ipAddress: "",
47
59
  // Optional properties
48
- ad_id: "",
49
- os_version: "",
50
- net_type: "",
51
- carrier_net: "",
52
- sdk_version: "",
53
- app_version: "",
54
- build_number: "",
60
+ adId: "",
61
+ osVersion: "",
62
+ netType: "",
63
+ carrierNet: "",
64
+ sdkVersion: "",
65
+ appVersion: "",
66
+ buildNumber: "",
55
67
  language: "",
56
68
  country: "",
57
69
  events: []
58
70
  };
59
- var config = { ...defaultConfig };
60
- var previousPageId = null;
61
- var pageMap = {
71
+ var defaultPageMap = {
62
72
  "": { name: "Home", id: "home" },
63
73
  home: { name: "Home", id: "home" },
64
74
  search: { name: "Search", id: "search" },
@@ -70,6 +80,11 @@ var pageMap = {
70
80
  profile: { name: "Profile", id: "profile" },
71
81
  login: { name: "Login", id: "login" }
72
82
  };
83
+
84
+ // src/tracking.ts
85
+ var config = { ...defaultConfig };
86
+ var previousPageId = null;
87
+ var pageMap = { ...defaultPageMap };
73
88
  var initTracking = (options = {}) => {
74
89
  config = { ...config, ...options };
75
90
  if (options.pageMap) {
@@ -102,21 +117,21 @@ var sendEvent = async (eventData) => {
102
117
  app_id: config.appId,
103
118
  package_id: config.packageId,
104
119
  platform: config.platform,
105
- session_id: config.session_id,
106
- session_sign: config.session_sign,
107
- user_id: config.user_id,
120
+ session_id: config.sessionId,
121
+ session_sign: config.sessionSign,
122
+ user_id: config.userId,
108
123
  device_id: config.deviceId,
109
124
  device_model: config.deviceModel,
110
125
  device_brand: config.deviceBrand,
111
- ip_address: config.ip_address,
126
+ ip_address: config.ipAddress,
112
127
  // Optional properties
113
- ad_id: config.ad_id,
114
- os_version: config.os_version,
115
- net_type: config.net_type,
116
- carrier_net: config.carrier_net,
117
- sdk_version: config.sdk_version,
118
- app_version: config.app_version,
119
- build_number: config.build_number,
128
+ ad_id: config.adId,
129
+ os_version: config.osVersion,
130
+ net_type: config.netType,
131
+ carrier_net: config.carrierNet,
132
+ sdk_version: config.sdkVersion,
133
+ app_version: config.appVersion,
134
+ build_number: config.buildNumber,
120
135
  language: config.language,
121
136
  country: config.country,
122
137
  // Events batch (tuỳ backend)
@@ -172,22 +187,185 @@ var usePageViewTracking = (router) => {
172
187
  router.events.off("routeChangeComplete", handleRouteChange);
173
188
  };
174
189
  };
190
+
191
+ // src/session.ts
192
+ var defaultSessionConfig = {
193
+ progressInterval: 5 * 60 * 1e3,
194
+ // 5 phút
195
+ autoStart: true,
196
+ debug: false
197
+ };
198
+ var sessionConfig = { ...defaultSessionConfig };
199
+ var progressTimer = null;
200
+ var isSessionActive = false;
201
+ var sessionStartTime = 0;
202
+ var log = (...args) => {
203
+ if (sessionConfig.debug) {
204
+ console.log("[Session]", ...args);
205
+ }
206
+ };
207
+ var sendSessionStart = () => {
208
+ if (isSessionActive) {
209
+ log("Session already started, skipping...");
210
+ return;
211
+ }
212
+ sessionStartTime = Date.now();
213
+ isSessionActive = true;
214
+ sendEvent({
215
+ events: [
216
+ {
217
+ event_name: "session_start",
218
+ event_time: sessionStartTime
219
+ }
220
+ ]
221
+ });
222
+ log("Session started at:", new Date(sessionStartTime).toISOString());
223
+ startProgressTimer();
224
+ };
225
+ var sendSessionProgress = () => {
226
+ if (!isSessionActive) return;
227
+ const now = Math.floor(Date.now() / 1e3);
228
+ const duration = now - sessionStartTime;
229
+ sendEvent({
230
+ events: [
231
+ {
232
+ event_name: "session_progress",
233
+ event_time: now,
234
+ session_duration: duration
235
+ }
236
+ ]
237
+ });
238
+ log("Session progress - Duration:", Math.round(duration / 1e3), "seconds");
239
+ };
240
+ var sendSessionEnd = () => {
241
+ if (!isSessionActive) return;
242
+ const now = Math.floor(Date.now() / 1e3);
243
+ const duration = now - sessionStartTime;
244
+ sendEvent({
245
+ events: [
246
+ {
247
+ event_name: "session_end",
248
+ event_time: now,
249
+ session_duration: duration
250
+ }
251
+ ]
252
+ });
253
+ log(
254
+ "Session ended - Total duration:",
255
+ Math.round(duration / 1e3),
256
+ "seconds"
257
+ );
258
+ stopProgressTimer();
259
+ isSessionActive = false;
260
+ };
261
+ var startProgressTimer = () => {
262
+ stopProgressTimer();
263
+ if (sessionConfig.progressInterval && sessionConfig.progressInterval > 0) {
264
+ progressTimer = setInterval(() => {
265
+ if (document.visibilityState === "visible") {
266
+ sendSessionProgress();
267
+ }
268
+ }, sessionConfig.progressInterval);
269
+ log(
270
+ "Progress timer started, interval:",
271
+ sessionConfig.progressInterval,
272
+ "ms"
273
+ );
274
+ }
275
+ };
276
+ var stopProgressTimer = () => {
277
+ if (progressTimer) {
278
+ clearInterval(progressTimer);
279
+ progressTimer = null;
280
+ log("Progress timer stopped");
281
+ }
282
+ };
283
+ var handleVisibilityChange = () => {
284
+ if (document.visibilityState === "hidden") {
285
+ log("Tab hidden - pausing progress");
286
+ stopProgressTimer();
287
+ } else if (document.visibilityState === "visible") {
288
+ log("Tab visible - resuming progress");
289
+ if (isSessionActive) {
290
+ startProgressTimer();
291
+ }
292
+ }
293
+ };
294
+ var handleBeforeUnload = () => {
295
+ sendSessionEnd();
296
+ };
297
+ var handlePageHide = (event) => {
298
+ if (event.persisted) {
299
+ return;
300
+ }
301
+ sendSessionEnd();
302
+ };
303
+ var initSessionTracking = (options = {}) => {
304
+ if (typeof window === "undefined") return;
305
+ sessionConfig = { ...defaultSessionConfig, ...options };
306
+ log("Initializing with config:", sessionConfig);
307
+ document.addEventListener("visibilitychange", handleVisibilityChange);
308
+ window.addEventListener("beforeunload", handleBeforeUnload);
309
+ window.addEventListener("pagehide", handlePageHide);
310
+ if (sessionConfig.autoStart) {
311
+ sendSessionStart();
312
+ }
313
+ };
314
+ var cleanupSessionTracking = () => {
315
+ if (typeof window === "undefined") return;
316
+ log("Cleaning up...");
317
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
318
+ window.removeEventListener("beforeunload", handleBeforeUnload);
319
+ window.removeEventListener("pagehide", handlePageHide);
320
+ stopProgressTimer();
321
+ isSessionActive = false;
322
+ };
323
+ var updateSessionConfig = (options) => {
324
+ sessionConfig = { ...sessionConfig, ...options };
325
+ if (options.progressInterval !== void 0 && isSessionActive) {
326
+ startProgressTimer();
327
+ }
328
+ log("Config updated:", sessionConfig);
329
+ };
330
+ var isSessionStarted = () => isSessionActive;
331
+ var getSessionDuration = () => {
332
+ if (!isSessionActive) return 0;
333
+ return Date.now() - sessionStartTime;
334
+ };
335
+
336
+ // src/index.ts
175
337
  var tracking = {
176
338
  init: initTracking,
177
339
  trackPageView,
178
340
  trackEvent,
179
341
  sendEvent,
180
342
  getPageInfo,
181
- usePageViewTracking
343
+ usePageViewTracking,
344
+ // Session lifecycle
345
+ initSession: initSessionTracking,
346
+ cleanupSession: cleanupSessionTracking,
347
+ sessionStart: sendSessionStart,
348
+ sessionProgress: sendSessionProgress,
349
+ sessionEnd: sendSessionEnd
182
350
  };
183
351
  var index_default = tracking;
184
352
  // Annotate the CommonJS export names for ESM import in node:
185
353
  0 && (module.exports = {
354
+ cleanupSessionTracking,
355
+ defaultConfig,
356
+ defaultPageMap,
186
357
  getPageInfo,
358
+ getSessionDuration,
359
+ initSessionTracking,
187
360
  initTracking,
361
+ isSessionStarted,
188
362
  sendEvent,
363
+ sendSessionEnd,
364
+ sendSessionProgress,
365
+ sendSessionStart,
189
366
  trackEvent,
190
367
  trackPageView,
368
+ updateSessionConfig,
191
369
  usePageViewTracking
192
370
  });
193
371
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.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\nexport type TrackingConfig = {\r\n baseURL: string;\r\n appName?: string;\r\n appId?: string;\r\n packageId?: string;\r\n platform?: \"Web\" | \"Ios\" | \"Android\" | string;\r\n debug?: boolean;\r\n\r\n // Required properties\r\n session_id: string;\r\n session_sign: string;\r\n user_id: number;\r\n deviceId: string;\r\n deviceModel: string;\r\n deviceBrand: string;\r\n ip_address: string;\r\n\r\n // Optional properties\r\n ad_id?: string;\r\n os_version?: string;\r\n net_type?: string;\r\n carrier_net?: string;\r\n sdk_version?: string;\r\n app_version?: string;\r\n build_number?: string;\r\n language?: string;\r\n country?: string;\r\n\r\n // Optional: events (nếu backend cần batch)\r\n events?: any[];\r\n};\r\n\r\nexport type PageInfo = {\r\n name: string;\r\n id: string;\r\n};\r\n\r\nexport type PageMap = Record<string, PageInfo>;\r\n\r\nexport type EventData = Record<string, any>;\r\n\r\nconst 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 session_id: \"\",\r\n session_sign: \"\",\r\n user_id: -1,\r\n deviceId: \"\",\r\n deviceModel: \"\",\r\n deviceBrand: \"\",\r\n ip_address: \"\",\r\n\r\n // Optional properties\r\n ad_id: \"\",\r\n os_version: \"\",\r\n net_type: \"\",\r\n carrier_net: \"\",\r\n sdk_version: \"\",\r\n app_version: \"\",\r\n build_number: \"\",\r\n language: \"\",\r\n country: \"\",\r\n\r\n events: [],\r\n};\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 = {\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/**\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 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.session_id,\r\n session_sign: config.session_sign,\r\n user_id: config.user_id,\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.ip_address,\r\n\r\n // Optional properties\r\n ad_id: config.ad_id,\r\n os_version: config.os_version,\r\n net_type: config.net_type,\r\n carrier_net: config.carrier_net,\r\n sdk_version: config.sdk_version,\r\n app_version: config.app_version,\r\n build_number: config.build_number,\r\n language: config.language,\r\n country: config.country,\r\n\r\n // Events batch (tuỳ backend)\r\n events: config.events ?? [],\r\n\r\n // Data riêng cho event\r\n ...eventData,\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 type NextRouterLike = {\r\n asPath: string;\r\n events: {\r\n on: (event: \"routeChangeComplete\", cb: (url: string) => void) => void;\r\n off: (event: \"routeChangeComplete\", cb: (url: string) => void) => void;\r\n };\r\n};\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// 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};\r\n\r\nexport default tracking;\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 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 (tuỳ backend)\r\n events: config.events ?? [],\r\n\r\n // Data riêng cho event\r\n ...eventData,\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};\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 },\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 },\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 },\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":[]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,52 @@
1
1
  /**
2
- * Tracking Library v2 (Fetch + TypeScript)
3
- * Thư viện tracking events thể dùng cho nhiều project
2
+ * Session Lifecycle Tracking
3
+ * - session_start: Khi user mở app
4
+ * - session_progress: Định kỳ khi user đang active (foreground)
5
+ * - session_end: Khi user thoát app
6
+ */
7
+ type SessionConfig = {
8
+ /** Khoảng thời gian gửi session_progress (ms). Default: 5 phút */
9
+ progressInterval?: number;
10
+ /** Có tự động start session khi init không. Default: true */
11
+ autoStart?: boolean;
12
+ /** Debug mode */
13
+ debug?: boolean;
14
+ };
15
+ /**
16
+ * Gửi event session_start
17
+ */
18
+ declare const sendSessionStart: () => void;
19
+ /**
20
+ * Gửi event session_progress
21
+ */
22
+ declare const sendSessionProgress: () => void;
23
+ /**
24
+ * Gửi event session_end
25
+ */
26
+ declare const sendSessionEnd: () => void;
27
+ /**
28
+ * Khởi tạo session tracking
29
+ */
30
+ declare const initSessionTracking: (options?: SessionConfig) => void;
31
+ /**
32
+ * Cleanup - gọi khi unmount component
33
+ */
34
+ declare const cleanupSessionTracking: () => void;
35
+ /**
36
+ * Cập nhật config (ví dụ: thay đổi interval)
37
+ */
38
+ declare const updateSessionConfig: (options: Partial<SessionConfig>) => void;
39
+ /**
40
+ * Kiểm tra session đang active không
41
+ */
42
+ declare const isSessionStarted: () => boolean;
43
+ /**
44
+ * Lấy thời gian session hiện tại (ms)
45
+ */
46
+ declare const getSessionDuration: () => number;
47
+
48
+ /**
49
+ * Type definitions for Tracking Library
4
50
  */
5
51
  type TrackingConfig = {
6
52
  baseURL: string;
@@ -9,20 +55,20 @@ type TrackingConfig = {
9
55
  packageId?: string;
10
56
  platform?: "Web" | "Ios" | "Android" | string;
11
57
  debug?: boolean;
12
- session_id: string;
13
- session_sign: string;
14
- user_id: number;
58
+ sessionId: string;
59
+ sessionSign: string;
60
+ userId: number;
15
61
  deviceId: string;
16
62
  deviceModel: string;
17
63
  deviceBrand: string;
18
- ip_address: string;
19
- ad_id?: string;
20
- os_version?: string;
21
- net_type?: string;
22
- carrier_net?: string;
23
- sdk_version?: string;
24
- app_version?: string;
25
- build_number?: string;
64
+ ipAddress: string;
65
+ adId?: string;
66
+ osVersion?: string;
67
+ netType?: string;
68
+ carrierNet?: string;
69
+ sdkVersion?: string;
70
+ appVersion?: string;
71
+ buildNumber?: string;
26
72
  language?: string;
27
73
  country?: string;
28
74
  events?: any[];
@@ -33,6 +79,25 @@ type PageInfo = {
33
79
  };
34
80
  type PageMap = Record<string, PageInfo>;
35
81
  type EventData = Record<string, any>;
82
+ type NextRouterLike = {
83
+ asPath: string;
84
+ events: {
85
+ on: (event: "routeChangeComplete", cb: (url: string) => void) => void;
86
+ off: (event: "routeChangeComplete", cb: (url: string) => void) => void;
87
+ };
88
+ };
89
+
90
+ /**
91
+ * Constants for Tracking Library
92
+ */
93
+
94
+ declare const defaultConfig: TrackingConfig;
95
+ declare const defaultPageMap: PageMap;
96
+
97
+ /**
98
+ * Core Tracking Functions
99
+ */
100
+
36
101
  /**
37
102
  * Khởi tạo tracking với config
38
103
  */
@@ -59,14 +124,8 @@ declare const trackEvent: (eventName: string, params?: EventData) => void;
59
124
  * Hook cho Next.js - auto track page views
60
125
  * Dùng cho Next.js Pages Router (next/router)
61
126
  */
62
- type NextRouterLike = {
63
- asPath: string;
64
- events: {
65
- on: (event: "routeChangeComplete", cb: (url: string) => void) => void;
66
- off: (event: "routeChangeComplete", cb: (url: string) => void) => void;
67
- };
68
- };
69
127
  declare const usePageViewTracking: (router: NextRouterLike) => (() => void) | undefined;
128
+
70
129
  declare const tracking: {
71
130
  init: (options?: Partial<TrackingConfig> & {
72
131
  pageMap?: Partial<PageMap>;
@@ -76,6 +135,11 @@ declare const tracking: {
76
135
  sendEvent: (eventData: EventData) => Promise<Response | void>;
77
136
  getPageInfo: (url: string) => PageInfo;
78
137
  usePageViewTracking: (router: NextRouterLike) => (() => void) | undefined;
138
+ initSession: (options?: SessionConfig) => void;
139
+ cleanupSession: () => void;
140
+ sessionStart: () => void;
141
+ sessionProgress: () => void;
142
+ sessionEnd: () => void;
79
143
  };
80
144
 
81
- export { type EventData, type NextRouterLike, type PageInfo, type PageMap, type TrackingConfig, tracking as default, getPageInfo, initTracking, sendEvent, trackEvent, trackPageView, usePageViewTracking };
145
+ export { type EventData, type NextRouterLike, type PageInfo, type PageMap, type SessionConfig, type TrackingConfig, cleanupSessionTracking, tracking as default, defaultConfig, defaultPageMap, getPageInfo, getSessionDuration, initSessionTracking, initTracking, isSessionStarted, sendEvent, sendSessionEnd, sendSessionProgress, sendSessionStart, trackEvent, trackPageView, updateSessionConfig, usePageViewTracking };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,52 @@
1
1
  /**
2
- * Tracking Library v2 (Fetch + TypeScript)
3
- * Thư viện tracking events thể dùng cho nhiều project
2
+ * Session Lifecycle Tracking
3
+ * - session_start: Khi user mở app
4
+ * - session_progress: Định kỳ khi user đang active (foreground)
5
+ * - session_end: Khi user thoát app
6
+ */
7
+ type SessionConfig = {
8
+ /** Khoảng thời gian gửi session_progress (ms). Default: 5 phút */
9
+ progressInterval?: number;
10
+ /** Có tự động start session khi init không. Default: true */
11
+ autoStart?: boolean;
12
+ /** Debug mode */
13
+ debug?: boolean;
14
+ };
15
+ /**
16
+ * Gửi event session_start
17
+ */
18
+ declare const sendSessionStart: () => void;
19
+ /**
20
+ * Gửi event session_progress
21
+ */
22
+ declare const sendSessionProgress: () => void;
23
+ /**
24
+ * Gửi event session_end
25
+ */
26
+ declare const sendSessionEnd: () => void;
27
+ /**
28
+ * Khởi tạo session tracking
29
+ */
30
+ declare const initSessionTracking: (options?: SessionConfig) => void;
31
+ /**
32
+ * Cleanup - gọi khi unmount component
33
+ */
34
+ declare const cleanupSessionTracking: () => void;
35
+ /**
36
+ * Cập nhật config (ví dụ: thay đổi interval)
37
+ */
38
+ declare const updateSessionConfig: (options: Partial<SessionConfig>) => void;
39
+ /**
40
+ * Kiểm tra session đang active không
41
+ */
42
+ declare const isSessionStarted: () => boolean;
43
+ /**
44
+ * Lấy thời gian session hiện tại (ms)
45
+ */
46
+ declare const getSessionDuration: () => number;
47
+
48
+ /**
49
+ * Type definitions for Tracking Library
4
50
  */
5
51
  type TrackingConfig = {
6
52
  baseURL: string;
@@ -9,20 +55,20 @@ type TrackingConfig = {
9
55
  packageId?: string;
10
56
  platform?: "Web" | "Ios" | "Android" | string;
11
57
  debug?: boolean;
12
- session_id: string;
13
- session_sign: string;
14
- user_id: number;
58
+ sessionId: string;
59
+ sessionSign: string;
60
+ userId: number;
15
61
  deviceId: string;
16
62
  deviceModel: string;
17
63
  deviceBrand: string;
18
- ip_address: string;
19
- ad_id?: string;
20
- os_version?: string;
21
- net_type?: string;
22
- carrier_net?: string;
23
- sdk_version?: string;
24
- app_version?: string;
25
- build_number?: string;
64
+ ipAddress: string;
65
+ adId?: string;
66
+ osVersion?: string;
67
+ netType?: string;
68
+ carrierNet?: string;
69
+ sdkVersion?: string;
70
+ appVersion?: string;
71
+ buildNumber?: string;
26
72
  language?: string;
27
73
  country?: string;
28
74
  events?: any[];
@@ -33,6 +79,25 @@ type PageInfo = {
33
79
  };
34
80
  type PageMap = Record<string, PageInfo>;
35
81
  type EventData = Record<string, any>;
82
+ type NextRouterLike = {
83
+ asPath: string;
84
+ events: {
85
+ on: (event: "routeChangeComplete", cb: (url: string) => void) => void;
86
+ off: (event: "routeChangeComplete", cb: (url: string) => void) => void;
87
+ };
88
+ };
89
+
90
+ /**
91
+ * Constants for Tracking Library
92
+ */
93
+
94
+ declare const defaultConfig: TrackingConfig;
95
+ declare const defaultPageMap: PageMap;
96
+
97
+ /**
98
+ * Core Tracking Functions
99
+ */
100
+
36
101
  /**
37
102
  * Khởi tạo tracking với config
38
103
  */
@@ -59,14 +124,8 @@ declare const trackEvent: (eventName: string, params?: EventData) => void;
59
124
  * Hook cho Next.js - auto track page views
60
125
  * Dùng cho Next.js Pages Router (next/router)
61
126
  */
62
- type NextRouterLike = {
63
- asPath: string;
64
- events: {
65
- on: (event: "routeChangeComplete", cb: (url: string) => void) => void;
66
- off: (event: "routeChangeComplete", cb: (url: string) => void) => void;
67
- };
68
- };
69
127
  declare const usePageViewTracking: (router: NextRouterLike) => (() => void) | undefined;
128
+
70
129
  declare const tracking: {
71
130
  init: (options?: Partial<TrackingConfig> & {
72
131
  pageMap?: Partial<PageMap>;
@@ -76,6 +135,11 @@ declare const tracking: {
76
135
  sendEvent: (eventData: EventData) => Promise<Response | void>;
77
136
  getPageInfo: (url: string) => PageInfo;
78
137
  usePageViewTracking: (router: NextRouterLike) => (() => void) | undefined;
138
+ initSession: (options?: SessionConfig) => void;
139
+ cleanupSession: () => void;
140
+ sessionStart: () => void;
141
+ sessionProgress: () => void;
142
+ sessionEnd: () => void;
79
143
  };
80
144
 
81
- export { type EventData, type NextRouterLike, type PageInfo, type PageMap, type TrackingConfig, tracking as default, getPageInfo, initTracking, sendEvent, trackEvent, trackPageView, usePageViewTracking };
145
+ export { type EventData, type NextRouterLike, type PageInfo, type PageMap, type SessionConfig, type TrackingConfig, cleanupSessionTracking, tracking as default, defaultConfig, defaultPageMap, getPageInfo, getSessionDuration, initSessionTracking, initTracking, isSessionStarted, sendEvent, sendSessionEnd, sendSessionProgress, sendSessionStart, trackEvent, trackPageView, updateSessionConfig, usePageViewTracking };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // src/index.ts
1
+ // src/constants.ts
2
2
  var defaultConfig = {
3
3
  baseURL: "",
4
4
  appName: "on_plus",
@@ -7,28 +7,26 @@ var defaultConfig = {
7
7
  platform: "Web",
8
8
  debug: false,
9
9
  // Required properties
10
- session_id: "",
11
- session_sign: "",
12
- user_id: -1,
10
+ sessionId: "",
11
+ sessionSign: "",
12
+ userId: -1,
13
13
  deviceId: "",
14
14
  deviceModel: "",
15
15
  deviceBrand: "",
16
- ip_address: "",
16
+ ipAddress: "",
17
17
  // Optional properties
18
- ad_id: "",
19
- os_version: "",
20
- net_type: "",
21
- carrier_net: "",
22
- sdk_version: "",
23
- app_version: "",
24
- build_number: "",
18
+ adId: "",
19
+ osVersion: "",
20
+ netType: "",
21
+ carrierNet: "",
22
+ sdkVersion: "",
23
+ appVersion: "",
24
+ buildNumber: "",
25
25
  language: "",
26
26
  country: "",
27
27
  events: []
28
28
  };
29
- var config = { ...defaultConfig };
30
- var previousPageId = null;
31
- var pageMap = {
29
+ var defaultPageMap = {
32
30
  "": { name: "Home", id: "home" },
33
31
  home: { name: "Home", id: "home" },
34
32
  search: { name: "Search", id: "search" },
@@ -40,6 +38,11 @@ var pageMap = {
40
38
  profile: { name: "Profile", id: "profile" },
41
39
  login: { name: "Login", id: "login" }
42
40
  };
41
+
42
+ // src/tracking.ts
43
+ var config = { ...defaultConfig };
44
+ var previousPageId = null;
45
+ var pageMap = { ...defaultPageMap };
43
46
  var initTracking = (options = {}) => {
44
47
  config = { ...config, ...options };
45
48
  if (options.pageMap) {
@@ -72,21 +75,21 @@ var sendEvent = async (eventData) => {
72
75
  app_id: config.appId,
73
76
  package_id: config.packageId,
74
77
  platform: config.platform,
75
- session_id: config.session_id,
76
- session_sign: config.session_sign,
77
- user_id: config.user_id,
78
+ session_id: config.sessionId,
79
+ session_sign: config.sessionSign,
80
+ user_id: config.userId,
78
81
  device_id: config.deviceId,
79
82
  device_model: config.deviceModel,
80
83
  device_brand: config.deviceBrand,
81
- ip_address: config.ip_address,
84
+ ip_address: config.ipAddress,
82
85
  // Optional properties
83
- ad_id: config.ad_id,
84
- os_version: config.os_version,
85
- net_type: config.net_type,
86
- carrier_net: config.carrier_net,
87
- sdk_version: config.sdk_version,
88
- app_version: config.app_version,
89
- build_number: config.build_number,
86
+ ad_id: config.adId,
87
+ os_version: config.osVersion,
88
+ net_type: config.netType,
89
+ carrier_net: config.carrierNet,
90
+ sdk_version: config.sdkVersion,
91
+ app_version: config.appVersion,
92
+ build_number: config.buildNumber,
90
93
  language: config.language,
91
94
  country: config.country,
92
95
  // Events batch (tuỳ backend)
@@ -142,22 +145,185 @@ var usePageViewTracking = (router) => {
142
145
  router.events.off("routeChangeComplete", handleRouteChange);
143
146
  };
144
147
  };
148
+
149
+ // src/session.ts
150
+ var defaultSessionConfig = {
151
+ progressInterval: 5 * 60 * 1e3,
152
+ // 5 phút
153
+ autoStart: true,
154
+ debug: false
155
+ };
156
+ var sessionConfig = { ...defaultSessionConfig };
157
+ var progressTimer = null;
158
+ var isSessionActive = false;
159
+ var sessionStartTime = 0;
160
+ var log = (...args) => {
161
+ if (sessionConfig.debug) {
162
+ console.log("[Session]", ...args);
163
+ }
164
+ };
165
+ var sendSessionStart = () => {
166
+ if (isSessionActive) {
167
+ log("Session already started, skipping...");
168
+ return;
169
+ }
170
+ sessionStartTime = Date.now();
171
+ isSessionActive = true;
172
+ sendEvent({
173
+ events: [
174
+ {
175
+ event_name: "session_start",
176
+ event_time: sessionStartTime
177
+ }
178
+ ]
179
+ });
180
+ log("Session started at:", new Date(sessionStartTime).toISOString());
181
+ startProgressTimer();
182
+ };
183
+ var sendSessionProgress = () => {
184
+ if (!isSessionActive) return;
185
+ const now = Math.floor(Date.now() / 1e3);
186
+ const duration = now - sessionStartTime;
187
+ sendEvent({
188
+ events: [
189
+ {
190
+ event_name: "session_progress",
191
+ event_time: now,
192
+ session_duration: duration
193
+ }
194
+ ]
195
+ });
196
+ log("Session progress - Duration:", Math.round(duration / 1e3), "seconds");
197
+ };
198
+ var sendSessionEnd = () => {
199
+ if (!isSessionActive) return;
200
+ const now = Math.floor(Date.now() / 1e3);
201
+ const duration = now - sessionStartTime;
202
+ sendEvent({
203
+ events: [
204
+ {
205
+ event_name: "session_end",
206
+ event_time: now,
207
+ session_duration: duration
208
+ }
209
+ ]
210
+ });
211
+ log(
212
+ "Session ended - Total duration:",
213
+ Math.round(duration / 1e3),
214
+ "seconds"
215
+ );
216
+ stopProgressTimer();
217
+ isSessionActive = false;
218
+ };
219
+ var startProgressTimer = () => {
220
+ stopProgressTimer();
221
+ if (sessionConfig.progressInterval && sessionConfig.progressInterval > 0) {
222
+ progressTimer = setInterval(() => {
223
+ if (document.visibilityState === "visible") {
224
+ sendSessionProgress();
225
+ }
226
+ }, sessionConfig.progressInterval);
227
+ log(
228
+ "Progress timer started, interval:",
229
+ sessionConfig.progressInterval,
230
+ "ms"
231
+ );
232
+ }
233
+ };
234
+ var stopProgressTimer = () => {
235
+ if (progressTimer) {
236
+ clearInterval(progressTimer);
237
+ progressTimer = null;
238
+ log("Progress timer stopped");
239
+ }
240
+ };
241
+ var handleVisibilityChange = () => {
242
+ if (document.visibilityState === "hidden") {
243
+ log("Tab hidden - pausing progress");
244
+ stopProgressTimer();
245
+ } else if (document.visibilityState === "visible") {
246
+ log("Tab visible - resuming progress");
247
+ if (isSessionActive) {
248
+ startProgressTimer();
249
+ }
250
+ }
251
+ };
252
+ var handleBeforeUnload = () => {
253
+ sendSessionEnd();
254
+ };
255
+ var handlePageHide = (event) => {
256
+ if (event.persisted) {
257
+ return;
258
+ }
259
+ sendSessionEnd();
260
+ };
261
+ var initSessionTracking = (options = {}) => {
262
+ if (typeof window === "undefined") return;
263
+ sessionConfig = { ...defaultSessionConfig, ...options };
264
+ log("Initializing with config:", sessionConfig);
265
+ document.addEventListener("visibilitychange", handleVisibilityChange);
266
+ window.addEventListener("beforeunload", handleBeforeUnload);
267
+ window.addEventListener("pagehide", handlePageHide);
268
+ if (sessionConfig.autoStart) {
269
+ sendSessionStart();
270
+ }
271
+ };
272
+ var cleanupSessionTracking = () => {
273
+ if (typeof window === "undefined") return;
274
+ log("Cleaning up...");
275
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
276
+ window.removeEventListener("beforeunload", handleBeforeUnload);
277
+ window.removeEventListener("pagehide", handlePageHide);
278
+ stopProgressTimer();
279
+ isSessionActive = false;
280
+ };
281
+ var updateSessionConfig = (options) => {
282
+ sessionConfig = { ...sessionConfig, ...options };
283
+ if (options.progressInterval !== void 0 && isSessionActive) {
284
+ startProgressTimer();
285
+ }
286
+ log("Config updated:", sessionConfig);
287
+ };
288
+ var isSessionStarted = () => isSessionActive;
289
+ var getSessionDuration = () => {
290
+ if (!isSessionActive) return 0;
291
+ return Date.now() - sessionStartTime;
292
+ };
293
+
294
+ // src/index.ts
145
295
  var tracking = {
146
296
  init: initTracking,
147
297
  trackPageView,
148
298
  trackEvent,
149
299
  sendEvent,
150
300
  getPageInfo,
151
- usePageViewTracking
301
+ usePageViewTracking,
302
+ // Session lifecycle
303
+ initSession: initSessionTracking,
304
+ cleanupSession: cleanupSessionTracking,
305
+ sessionStart: sendSessionStart,
306
+ sessionProgress: sendSessionProgress,
307
+ sessionEnd: sendSessionEnd
152
308
  };
153
309
  var index_default = tracking;
154
310
  export {
311
+ cleanupSessionTracking,
155
312
  index_default as default,
313
+ defaultConfig,
314
+ defaultPageMap,
156
315
  getPageInfo,
316
+ getSessionDuration,
317
+ initSessionTracking,
157
318
  initTracking,
319
+ isSessionStarted,
158
320
  sendEvent,
321
+ sendSessionEnd,
322
+ sendSessionProgress,
323
+ sendSessionStart,
159
324
  trackEvent,
160
325
  trackPageView,
326
+ updateSessionConfig,
161
327
  usePageViewTracking
162
328
  };
163
329
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.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\nexport type TrackingConfig = {\r\n baseURL: string;\r\n appName?: string;\r\n appId?: string;\r\n packageId?: string;\r\n platform?: \"Web\" | \"Ios\" | \"Android\" | string;\r\n debug?: boolean;\r\n\r\n // Required properties\r\n session_id: string;\r\n session_sign: string;\r\n user_id: number;\r\n deviceId: string;\r\n deviceModel: string;\r\n deviceBrand: string;\r\n ip_address: string;\r\n\r\n // Optional properties\r\n ad_id?: string;\r\n os_version?: string;\r\n net_type?: string;\r\n carrier_net?: string;\r\n sdk_version?: string;\r\n app_version?: string;\r\n build_number?: string;\r\n language?: string;\r\n country?: string;\r\n\r\n // Optional: events (nếu backend cần batch)\r\n events?: any[];\r\n};\r\n\r\nexport type PageInfo = {\r\n name: string;\r\n id: string;\r\n};\r\n\r\nexport type PageMap = Record<string, PageInfo>;\r\n\r\nexport type EventData = Record<string, any>;\r\n\r\nconst 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 session_id: \"\",\r\n session_sign: \"\",\r\n user_id: -1,\r\n deviceId: \"\",\r\n deviceModel: \"\",\r\n deviceBrand: \"\",\r\n ip_address: \"\",\r\n\r\n // Optional properties\r\n ad_id: \"\",\r\n os_version: \"\",\r\n net_type: \"\",\r\n carrier_net: \"\",\r\n sdk_version: \"\",\r\n app_version: \"\",\r\n build_number: \"\",\r\n language: \"\",\r\n country: \"\",\r\n\r\n events: [],\r\n};\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 = {\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/**\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 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.session_id,\r\n session_sign: config.session_sign,\r\n user_id: config.user_id,\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.ip_address,\r\n\r\n // Optional properties\r\n ad_id: config.ad_id,\r\n os_version: config.os_version,\r\n net_type: config.net_type,\r\n carrier_net: config.carrier_net,\r\n sdk_version: config.sdk_version,\r\n app_version: config.app_version,\r\n build_number: config.build_number,\r\n language: config.language,\r\n country: config.country,\r\n\r\n // Events batch (tuỳ backend)\r\n events: config.events ?? [],\r\n\r\n // Data riêng cho event\r\n ...eventData,\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 type NextRouterLike = {\r\n asPath: string;\r\n events: {\r\n on: (event: \"routeChangeComplete\", cb: (url: string) => void) => void;\r\n off: (event: \"routeChangeComplete\", cb: (url: string) => void) => void;\r\n };\r\n};\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// 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};\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 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 (tuỳ backend)\r\n events: config.events ?? [],\r\n\r\n // Data riêng cho event\r\n ...eventData,\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};\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 },\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 },\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 },\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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tracking-lib-ott",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",