tianji-client-sdk
Version:
186 lines (185 loc) • 5.63 kB
JavaScript
;
/**
* Pure Website Tracking SDK for Tianji
* Simple event tracking without DOM manipulation or auto-tracking
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.initWebsiteTracking = initWebsiteTracking;
exports.trackPageView = trackPageView;
exports.reportWebsiteEvent = reportWebsiteEvent;
exports.identifyWebsiteUser = identifyWebsiteUser;
exports.flushBatchQueue = flushBatchQueue;
const batch_manager_1 = require("../utils/batch-manager");
let options;
let batchManager = null;
/**
* Initialize website tracking
*/
function initWebsiteTracking(_options) {
options = _options;
// Initialize batch manager
batchManager = new batch_manager_1.BatchManager({
batchDelay: _options.batchDelay,
disableBatch: _options.disableBatch,
onBatchSend: async (items) => {
await sendBatchRequest(_options.serverUrl, items);
},
onSingleSend: async (item) => {
await sendSingleRequest(_options.serverUrl, item.type, item.payload);
},
});
}
/**
* Get basic browser information if available
*/
function getBrowserInfo() {
if (typeof window === 'undefined') {
return {};
}
const { screen: { width, height }, navigator: { language }, location: { hostname, pathname, search }, document: { title, referrer }, } = window;
return {
hostname,
screen: `${width}x${height}`,
language,
title,
url: `${pathname}${search}`,
referrer: referrer || undefined,
};
}
/**
* Send website page view event to Tianji server
*/
async function trackPageView(url, title) {
if (!options) {
console.warn('Website tracking is not initialized');
return;
}
const browserInfo = getBrowserInfo();
const payload = {
website: options.websiteId,
...browserInfo,
...(url && { url }),
...(title && { title }),
};
sendWebsiteRequest(options.serverUrl, 'event', payload);
}
/**
* Send custom website event to Tianji server
*
* @param eventName - Name of the event
* @param eventData - Event data
*/
async function reportWebsiteEvent(eventName, eventData = {}) {
if (!options) {
console.warn('Website tracking is not initialized');
return;
}
const browserInfo = getBrowserInfo();
const payload = {
website: options.websiteId,
...browserInfo,
name: eventName,
data: eventData,
};
sendWebsiteRequest(options.serverUrl, 'event', payload);
}
/**
* Identify user for website tracking
*
* @param userData - User identification data
*/
async function identifyWebsiteUser(userInfo) {
if (!options) {
console.warn('Website tracking is not initialized');
return;
}
if (!userInfo || Object.keys(userInfo).length === 0) {
console.warn('User data is required for identification');
return;
}
const browserInfo = getBrowserInfo();
const payload = {
website: options.websiteId,
...browserInfo,
data: userInfo,
};
sendWebsiteRequest(options.serverUrl, 'identify', payload);
}
/**
* Send website request with automatic batching
* Events are automatically queued and sent together at fixed intervals (throttling)
* If queue reaches 100 events, it will be sent immediately
*
* @param serverUrl - Tianji server URL
* @param type - Request type ('event' or 'identify')
* @param payload - Request payload
*/
function sendWebsiteRequest(serverUrl, type, payload) {
if (!batchManager) {
console.warn('Website tracking is not initialized');
return;
}
batchManager.add(type, payload);
}
/**
* Send single request to Tianji website API (fallback when batch is disabled)
*
* @param serverUrl - Tianji server URL
* @param type - Request type ('event' or 'identify')
* @param payload - Request payload
*/
async function sendSingleRequest(serverUrl, type, payload) {
try {
const response = await fetch(`${serverUrl}/api/website/send`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
type,
payload,
}),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Failed to send website ${type}: ${errorText}`);
}
}
catch (error) {
console.error(`Error sending website ${type}:`, error);
return; // As event tracking SDK, should not throw error which maybe cause crash
}
}
/**
* Send batch request to Tianji website API
*/
async function sendBatchRequest(serverUrl, items) {
try {
const response = await fetch(`${serverUrl}/api/website/batch`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
events: items,
}),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Failed to send batch request: ${errorText}`);
}
}
catch (error) {
console.error('Error sending batch request:', error);
return; // As event tracking SDK, should not throw error which maybe cause crash
}
}
/**
* Flush batch queue manually (send all pending requests immediately)
* Useful for ensuring events are sent before page unload
*/
async function flushBatchQueue() {
if (batchManager) {
await batchManager.flush();
}
}