tracker-api
Version:
A comprehensive JavaScript/TypeScript library for user behavior tracking and analytics
249 lines • 8.81 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TrackingClient = void 0;
// tracking-client.ts - Event tracking API client
const base_client_1 = require("./base-client");
const uuid_1 = require("uuid");
class TrackingClient extends base_client_1.BaseClient {
constructor(options = {}) {
super(options);
this.eventQueue = [];
this.batchTimer = null;
this.visitorId = null;
this.batchSize = options.batchSize || 10;
this.batchTimeout = options.batchTimeout || 2000;
if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
this.visitorId = localStorage.getItem("tracker_api:visitor_id");
if (!this.visitorId) {
this.visitorId = (0, uuid_1.v4)();
localStorage.setItem("tracker_api:visitor_id", this.visitorId);
}
}
else {
// fallback trên server, ví dụ dùng UUID tạm thời hoặc null
console.warn("Running in non-browser environment, using temporary visitor ID");
this.visitorId = (0, uuid_1.v4)(); // hoặc để null
}
// Auto-flush queue when page unloads (browser only)
if (typeof window !== "undefined") {
window.addEventListener("beforeunload", () => {
this.flush();
});
// Periodic flush
setInterval(() => {
if (this.eventQueue.length > 0) {
this.flush();
}
}, 10000);
}
}
/**
* Track a single event
*/
async trackEvent(eventData, immediate = false) {
// Validate required fields
if (!eventData.event_type) {
throw new Error("event_type is required");
}
if (!eventData.event_name) {
throw new Error("event_name is required");
}
if (!eventData.page_url) {
throw new Error("page_url is required");
}
if (!eventData.visitor_id) {
eventData.visitor_id = this.visitorId || (0, uuid_1.v4)();
}
// Set default visitor_id if not provided (for backward compatibility)
if (!eventData.visitor_id && this.visitorId) {
eventData.visitor_id = this.visitorId;
}
// Generate event_id if not provided
if (!eventData.event_id) {
eventData.event_id = (0, uuid_1.v4)();
}
// Set event_date if not provided
if (!eventData.event_date) {
const now = new Date();
eventData.event_date = now.toISOString().split("T")[0]; // YYYY-MM-DD
}
// Set event_time if not provided
if (!eventData.event_time) {
eventData.event_time = new Date().toISOString();
}
const event = {
...eventData,
timestamp: eventData.timestamp || Date.now(), // Keep for backward compatibility
};
if (immediate) {
return this.post("/api/tracking/events", event);
}
this.eventQueue.push(event);
if (this.eventQueue.length >= this.batchSize) {
return this.flush();
}
if (!this.batchTimer) {
this.batchTimer = setTimeout(() => this.flush(), this.batchTimeout);
}
return { success: true, message: "Event queued for batch processing" };
}
/**
* Track multiple events at once
*/
async trackBatch(events) {
// Validate and enhance each event
const processedEvents = events.map((event) => {
// Validate required fields
if (!event.event_type) {
throw new Error("event_type is required for all events");
}
if (!event.event_name) {
throw new Error("event_name is required for all events");
}
if (!event.page_url) {
throw new Error("page_url is required for all events");
}
if (!event.visitor_id) {
throw new Error("visitor_id is required for all events");
}
// Generate event_id if not provided
if (!event.event_id) {
event.event_id = (0, uuid_1.v4)();
}
// Set event_date if not provided
if (!event.event_date) {
const now = new Date();
event.event_date = now.toISOString().split("T")[0]; // YYYY-MM-DD
}
// Set event_time if not provided
if (!event.event_time) {
event.event_time = new Date().toISOString();
}
return {
...event,
timestamp: event.timestamp || Date.now(),
};
});
return this.post("/api/tracking/events/batch", {
events: processedEvents,
});
}
/**
* Flush the event queue
*/
async flush() {
if (this.batchTimer) {
clearTimeout(this.batchTimer);
this.batchTimer = null;
}
if (this.eventQueue.length === 0) {
return { success: true, message: "No events to flush" };
}
const events = [...this.eventQueue];
this.eventQueue = [];
return this.trackBatch(events);
}
/**
* Check tracking health
*/
async healthCheck() {
return this.get("/api/tracking/health");
}
/**
* Get events by date range
*/
async getEvents(token, query) {
const params = new URLSearchParams();
Object.entries(query).forEach(([key, value]) => {
if (value !== undefined) {
params.append(key, String(value));
}
});
return this.get(`/api/tracking/events?${params.toString()}`, token);
}
/**
* Get events by user
*/
async getEventsByUser(token, userId) {
return this.get(`/api/tracking/events/user/${userId}`, token);
}
/**
* Get events by session
*/
async getEventsBySession(token, sessionId) {
return this.get(`/api/tracking/events/session/${sessionId}`, token);
}
/**
* Get daily event statistics
*/
async getDailyStats(token, date, websiteId) {
const params = websiteId ? `?websiteId=${websiteId}` : "";
return this.get(`/api/tracking/stats/daily/${date}${params}`, token);
}
/**
* Get top pages
*/
async getTopPages(token, websiteId, limit = 10) {
const params = new URLSearchParams();
if (websiteId)
params.append("websiteId", websiteId);
if (limit)
params.append("limit", String(limit));
return this.get(`/api/tracking/stats/top-pages?${params.toString()}`, token);
}
// Convenience methods for specific event types
async trackPageView(pageUrl, sessionId, metadata) {
return this.trackEvent({
event_type: "pageview",
event_name: "page_view",
page_url: pageUrl,
visitor_id: this.visitorId || (0, uuid_1.v4)(),
user_id: this.visitorId || (0, uuid_1.v4)(),
session_id: sessionId,
metadata,
});
}
async trackClick(elementType, pageUrl, elementId, sessionId, metadata) {
return this.trackEvent({
event_type: "click",
event_name: `${elementType}_click`,
page_url: pageUrl,
visitor_id: this.visitorId || (0, uuid_1.v4)(),
user_id: this.visitorId || (0, uuid_1.v4)(),
session_id: sessionId,
element_type: elementType,
element_id: elementId,
metadata,
});
}
async trackScroll(pageUrl, scrollPercentage, sessionId, metadata) {
return this.trackEvent({
event_type: "scroll",
event_name: "page_scroll",
page_url: pageUrl,
visitor_id: this.visitorId || (0, uuid_1.v4)(),
user_id: this.visitorId || (0, uuid_1.v4)(),
session_id: sessionId,
properties: {
scroll_percentage: scrollPercentage.toString(),
},
metadata: {
...metadata,
scrollPercentage,
},
});
}
async trackCustomEvent(eventType, pageUrl, sessionId, metadata) {
return this.trackEvent({
event_type: eventType,
event_name: eventType,
page_url: pageUrl,
visitor_id: this.visitorId || (0, uuid_1.v4)(),
user_id: this.visitorId || (0, uuid_1.v4)(),
session_id: sessionId,
metadata,
});
}
}
exports.TrackingClient = TrackingClient;
//# sourceMappingURL=tracking-client.js.map