@adopture/next
Version:
Next.js SDK for Adopture feature adoption tracking with SSR support
1 lines • 13.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/shared/utils.ts"],"names":["now","delay","ms","resolve","retryWithBackoff","fn","maxAttempts","baseDelay","lastError","attempt","error","delayMs","timeout","promise","_","reject","sanitizeMetadata","metadata","sensitiveKeys","result","key","value","lowerKey","sensitiveKey","extractRoute","pathname","shouldExcludeRoute","excludeRoutes","includeRoutes","route","pattern","matchRoute","regexPattern","extractUserId","headers","cookies","customExtractor","customId","authHeader","match","userIdCookie","TTLCache","defaultTTL","ttl","expiry","entry","currentTime","callback"],"mappings":"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","file":"chunk-XGA5AKPV.mjs","sourcesContent":["/**\n * Shared utilities for Next.js SDK\n */\n\n/**\n * Generate a unique ID for tracking\n */\nexport function generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n}\n\n/**\n * Safely parse JSON with fallback\n */\nexport function safeJsonParse<T>(json: string, fallback: T): T {\n try {\n return JSON.parse(json);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely stringify JSON with fallback\n */\nexport function safeJsonStringify(obj: any, fallback: string = '{}'): string {\n try {\n return JSON.stringify(obj);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Deep merge two objects\n */\nexport function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n if (source.hasOwnProperty(key)) {\n const value = source[key];\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n result[key] = deepMerge(result[key] || {} as any, value);\n } else if (value !== undefined) {\n result[key] = value as any;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Debounce function calls\n */\nexport function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: NodeJS.Timeout | null = null;\n \n return (...args: Parameters<T>) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n \n timeout = setTimeout(() => {\n func(...args);\n }, wait);\n };\n}\n\n/**\n * Throttle function calls\n */\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n limit: number\n): (...args: Parameters<T>) => void {\n let inThrottle = false;\n \n return (...args: Parameters<T>) => {\n if (!inThrottle) {\n func(...args);\n inThrottle = true;\n setTimeout(() => {\n inThrottle = false;\n }, limit);\n }\n };\n}\n\n/**\n * Get current timestamp in milliseconds\n */\nexport function now(): number {\n return Date.now();\n}\n\n/**\n * Format timestamp to ISO string\n */\nexport function formatTimestamp(timestamp?: number): string {\n return new Date(timestamp || now()).toISOString();\n}\n\n/**\n * Check if a value is a promise\n */\nexport function isPromise<T = any>(value: any): value is Promise<T> {\n return value != null && typeof value.then === 'function';\n}\n\n/**\n * Create a promise that resolves after a delay\n */\nexport function delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Retry a function with exponential backoff\n */\nexport async function retryWithBackoff<T>(\n fn: () => Promise<T>,\n maxAttempts: number = 3,\n baseDelay: number = 1000\n): Promise<T> {\n let lastError: Error;\n \n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error as Error;\n \n if (attempt === maxAttempts) {\n throw lastError;\n }\n \n const delayMs = baseDelay * Math.pow(2, attempt - 1);\n await delay(delayMs);\n }\n }\n \n throw lastError!;\n}\n\n/**\n * Create a timeout promise that rejects after a delay\n */\nexport function timeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Operation timed out after ${ms}ms`));\n }, ms);\n }),\n ]);\n}\n\n/**\n * Sanitize metadata to remove sensitive information\n */\nexport function sanitizeMetadata(metadata: Record<string, any>): Record<string, any> {\n const sensitiveKeys = ['password', 'token', 'secret', 'key', 'auth', 'credential'];\n const result: Record<string, any> = {};\n \n for (const [key, value] of Object.entries(metadata)) {\n const lowerKey = key.toLowerCase();\n const isSensitive = sensitiveKeys.some(sensitiveKey => lowerKey.includes(sensitiveKey));\n \n if (isSensitive) {\n result[key] = '[REDACTED]';\n } else if (typeof value === 'object' && value !== null) {\n result[key] = sanitizeMetadata(value);\n } else {\n result[key] = value;\n }\n }\n \n return result;\n}\n\n/**\n * Extract route from Next.js pathname\n */\nexport function extractRoute(pathname: string): string {\n // Remove query parameters and hash\n const cleanPath = pathname.split('?')[0].split('#')[0];\n \n // Remove dynamic segments (e.g., /users/[id] becomes /users/*)\n return cleanPath.replace(/\\/\\[[^\\]]+\\]/g, '/*');\n}\n\n/**\n * Check if route should be excluded from tracking\n */\nexport function shouldExcludeRoute(\n pathname: string,\n excludeRoutes?: string[],\n includeRoutes?: string[]\n): boolean {\n if (!excludeRoutes && !includeRoutes) {\n return false;\n }\n \n const route = extractRoute(pathname);\n \n // If includeRoutes is specified, only include those routes\n if (includeRoutes && includeRoutes.length > 0) {\n return !includeRoutes.some(pattern => matchRoute(route, pattern));\n }\n \n // Otherwise, exclude routes in excludeRoutes\n if (excludeRoutes && excludeRoutes.length > 0) {\n return excludeRoutes.some(pattern => matchRoute(route, pattern));\n }\n \n return false;\n}\n\n/**\n * Match route against pattern (supports wildcards)\n */\nexport function matchRoute(route: string, pattern: string): boolean {\n // Convert pattern to regex (replace * with .*)\n const regexPattern = pattern.replace(/\\*/g, '.*').replace(/\\//g, '\\\\/');\n const regex = new RegExp(`^${regexPattern}$`);\n \n return regex.test(route);\n}\n\n/**\n * Extract user ID from various sources\n */\nexport function extractUserId(\n headers: Headers,\n cookies?: { [key: string]: string },\n customExtractor?: (headers: Headers) => string | null\n): string | null {\n // Try custom extractor first\n if (customExtractor) {\n const customId = customExtractor(headers);\n if (customId) {\n return customId;\n }\n }\n \n // Try common header patterns\n const authHeader = headers.get('authorization');\n if (authHeader) {\n // Extract from Bearer token or similar\n const match = authHeader.match(/user[_-]?id[=:]([a-zA-Z0-9-_]+)/i);\n if (match) {\n return match[1];\n }\n }\n \n // Try cookies\n if (cookies) {\n const userIdCookie = cookies.userId || cookies.user_id || cookies['user-id'];\n if (userIdCookie) {\n return userIdCookie;\n }\n }\n \n return null;\n}\n\n/**\n * Calculate size of an object in bytes (approximate)\n */\nexport function calculateObjectSize(obj: any): number {\n const jsonString = safeJsonStringify(obj);\n return new Blob([jsonString]).size;\n}\n\n/**\n * Create a cache with TTL\n */\nexport class TTLCache<K, V> {\n private cache = new Map<K, { value: V; expiry: number }>();\n private defaultTTL: number;\n\n constructor(defaultTTL: number = 300000) { // 5 minutes default\n this.defaultTTL = defaultTTL;\n }\n\n set(key: K, value: V, ttl?: number): void {\n const expiry = now() + (ttl ?? this.defaultTTL);\n this.cache.set(key, { value, expiry });\n }\n\n get(key: K): V | undefined {\n const entry = this.cache.get(key);\n if (!entry) {\n return undefined;\n }\n\n if (now() > entry.expiry) {\n this.cache.delete(key);\n return undefined;\n }\n\n return entry.value;\n }\n\n has(key: K): boolean {\n return this.get(key) !== undefined;\n }\n\n delete(key: K): boolean {\n return this.cache.delete(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n cleanup(): void {\n const currentTime = now();\n for (const [key, entry] of this.cache.entries()) {\n if (currentTime > entry.expiry) {\n this.cache.delete(key);\n }\n }\n }\n\n size(): number {\n this.cleanup();\n return this.cache.size;\n }\n\n forEach(callback: (value: V, key: K) => void): void {\n const currentTime = now();\n for (const [key, entry] of this.cache.entries()) {\n if (currentTime <= entry.expiry) {\n callback(entry.value, key);\n } else {\n // Clean up expired entries during iteration\n this.cache.delete(key);\n }\n }\n }\n}"]}