UNPKG

@jillen/analytics

Version:

Advanced analytics package for Next.js applications with bot detection and comprehensive tracking

154 lines (147 loc) 5.08 kB
'use strict'; var isbot = require('isbot'); // server/middleware-utils.ts // analytics-constants.ts var ANALYTICS_CONFIG = { SERVER_URL: process.env.NEXT_PUBLIC_ANALYTICS_SERVER_URL || "", SITE_ID: process.env.NEXT_PUBLIC_ANALYTICS_SITE_ID || "" }; function validateAnalyticsConfig() { const { SERVER_URL, SITE_ID } = ANALYTICS_CONFIG; if (!SERVER_URL || !SITE_ID) { console.warn("[Analytics] Missing environment variables:", { SERVER_URL: SERVER_URL ? "\u2713" : "\u2717 NEXT_PUBLIC_ANALYTICS_SERVER_URL", SITE_ID: SITE_ID ? "\u2713" : "\u2717 NEXT_PUBLIC_ANALYTICS_SITE_ID" }); return false; } return true; } // analytics-bot-utils.ts function generateSimpleBotVisitorId(ip, userAgent) { const normalizedUA = userAgent.toLowerCase().replace(/\s+/g, ""); const combined = `bot:${ip}:${normalizedUA}`; return Buffer.from(combined).toString("base64").replace(/[^a-zA-Z0-9]/g, "").substring(0, 16); } function generateSimpleBotSessionId(ip) { const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0]; const combined = `bot-session:${ip}:${today}`; return Buffer.from(combined).toString("base64").replace(/[^a-zA-Z0-9]/g, "").substring(0, 16); } function trackBotVisit(request, pathname) { void (async () => { try { if (!validateAnalyticsConfig()) { return; } const serverUrl = ANALYTICS_CONFIG.SERVER_URL; const siteId = ANALYTICS_CONFIG.SITE_ID; const userAgent = request.headers.get("user-agent") || ""; const ip = request.headers.get("x-forwarded-for")?.split(",")[0] || request.headers.get("x-real-ip") || "unknown"; const visitorId = generateSimpleBotVisitorId(ip, userAgent); const sessionId = generateSimpleBotSessionId(ip); const botPayload = { // Required fields (minimal values) siteId, path: pathname, visitorId, sessionId, eventType: "pageview", // Essential bot data userAgent, ipAddress: ip, // Client-side fields (bots don't have these) isNewVisitor: true, screenResolution: null, viewportSize: null, connectionType: null, clientTimeZone: null, sessionStartTime: (/* @__PURE__ */ new Date()).toISOString(), // Optional server fields (skip expensive lookups) referrer: request.headers.get("referer") || null, country: null, city: null, region: null, continent: null, latitude: null, longitude: null, timezone: null, postalCode: null, host: request.headers.get("host") || null, protocol: request.headers.get("x-forwarded-proto") || null, deploymentUrl: null, edgeRegion: null, language: null, doNotTrack: false, isMobile: /Mobi|Android/i.test(userAgent), cacheStatus: "UNKNOWN" }; const endpoint = `${serverUrl}/api/log/ingest`; await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json" }, mode: "cors", body: JSON.stringify(botPayload) }); } catch { return; } })(); } // server/middleware-utils.ts function setupAnalyticsMiddleware(request) { const pathname = request.nextUrl.pathname; const headers = new Headers(request.headers); headers.set("x-pathname", pathname); const userAgent = request.headers.get("user-agent") || ""; if (isbot.isbot(userAgent)) { trackBotVisit(request, pathname); } return { headers, pathname }; } // server/header-parser.ts function parseAnalyticsHeaders(headers) { const ip = headers.get("x-forwarded-for") || headers.get("x-real-ip") || "unknown"; const country = headers.get("x-vercel-ip-country") || null; const userAgent = headers.get("user-agent") || ""; const city = headers.get("x-vercel-ip-city") || null; const region = headers.get("x-vercel-ip-country-region") || null; const continent = headers.get("x-vercel-ip-continent") || null; const latitude = headers.get("x-vercel-ip-latitude") || null; const longitude = headers.get("x-vercel-ip-longitude") || null; const timezone = headers.get("x-vercel-ip-timezone") || null; const postalCode = headers.get("x-vercel-ip-postal-code") || null; const host = headers.get("host") || null; const protocol = headers.get("x-forwarded-proto"); const deploymentUrl = headers.get("x-vercel-deployment-url") || null; const vercelId = headers.get("x-vercel-id") || null; const edgeRegion = vercelId ? vercelId.split("::")[0] : null; const cacheStatus = null; return { ip, country, city, region, continent, latitude, longitude, timezone, postalCode, host, protocol, deploymentUrl, userAgent, edgeRegion, cacheStatus }; } exports.parseAnalyticsHeaders = parseAnalyticsHeaders; exports.setupAnalyticsMiddleware = setupAnalyticsMiddleware; exports.trackBotVisit = trackBotVisit; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map