UNPKG

personalization-middleware

Version:

Next.js middleware for request-based personalization

137 lines (134 loc) 4.18 kB
// src/middleware.ts import { NextResponse } from "next/server"; // src/contextCollector.ts import { UAParser } from "ua-parser-js"; var SESSION_COOKIE_NAME = "personalization_session"; var USER_ID_COOKIE_NAME = "user_id"; function extractDeviceInfo(userAgent) { const parser = new UAParser(userAgent); const browser = parser.getBrowser(); const os = parser.getOS(); const device = parser.getDevice(); return { deviceType: device.type || void 0, browser: browser.name || void 0, os: os.name || void 0 }; } function extractUtmParams(request) { const searchParams = request.nextUrl.searchParams; const utm = {}; for (const [key, value] of searchParams.entries()) { if (key.startsWith("utm_")) { utm[key] = value; } } return utm; } function extractGeolocation(request) { const geoHeader = request.headers.get("x-geo-location"); if (!geoHeader) return void 0; try { return JSON.parse(geoHeader); } catch { return void 0; } } function collectRequestContext(request) { const userAgent = request.headers.get("user-agent") || ""; return { utm: extractUtmParams(request), device: extractDeviceInfo(userAgent), geolocation: extractGeolocation(request), userId: request.cookies.get(USER_ID_COOKIE_NAME)?.value, sessionId: request.cookies.get(SESSION_COOKIE_NAME)?.value, referrer: request.headers.get("referer") || void 0, // Add any custom attributes here if needed customAttributes: {} }; } // src/segmentEvaluator.ts var SegmentEvaluator = class { constructor(config2) { this.config = { timeout: 5e3, maxRetries: 2, ...config2 }; } async evaluateSegments(context) { try { console.log( `[SegmentEvaluator] Fetching segments from ${this.config.apiEndpoint}` ); const response = await fetch(this.config.apiEndpoint, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${this.config.apiKey}` }, body: JSON.stringify({ context }) }); if (!response.ok) { console.error( `[SegmentEvaluator] API request failed with status: ${response.status}` ); const errorBody = await response.text(); console.error(`[SegmentEvaluator] Error body: ${errorBody}`); return { segments: [], context, timestamp: Date.now(), requestId: "" }; } const result = await response.json(); console.log(`[SegmentEvaluator] Successfully received segments.`); return result; } catch (error) { console.error( "[SegmentEvaluator] Critical error during segment evaluation:", error ); return { segments: [], context, timestamp: Date.now(), requestId: "" }; } } }; function createSegmentEvaluator(config2) { return new SegmentEvaluator(config2); } // src/middleware.ts var DEFAULT_CONFIG = { headerName: "x-user-segments" }; function createMiddleware(config2) { const finalConfig = { ...DEFAULT_CONFIG, ...config2 }; const evaluator = createSegmentEvaluator({ apiEndpoint: config2.apiEndpoint, apiKey: config2.apiKey }); return async function middleware(request) { console.log("\u{1F50D} Middleware triggered for:", request.url); try { const context = collectRequestContext(request); const result = await evaluator.evaluateSegments(context); console.log("\u{1F50D} Result:", result); const response = NextResponse.next(); const segments = result.segments?.join(",") || ""; response.headers.set(finalConfig.headerName, segments); return response; } catch (error) { console.error("Personalization middleware error:", error); const response = NextResponse.next(); response.headers.set(finalConfig.headerName, ""); return response; } }; } var createPersonalizationMiddleware = createMiddleware; var config = { matcher: ["/((?!_next/static|_next/image|favicon.ico|public/).*)"] }; export { collectRequestContext, config, createMiddleware, createPersonalizationMiddleware, createSegmentEvaluator }; //# sourceMappingURL=index.mjs.map