@shellapps/experience 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +20 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +20 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -133,21 +133,24 @@ async function drainOfflineQueue(sendFn) {
|
|
|
133
133
|
const db = await openDB();
|
|
134
134
|
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
135
135
|
const store = tx.objectStore(STORE_NAME);
|
|
136
|
-
const
|
|
136
|
+
const cursorReq = store.openCursor();
|
|
137
137
|
await new Promise((resolve, reject) => {
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
138
|
+
cursorReq.onsuccess = async () => {
|
|
139
|
+
const cursor = cursorReq.result;
|
|
140
|
+
if (!cursor) {
|
|
141
|
+
resolve();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const item = cursor.value;
|
|
145
|
+
try {
|
|
146
|
+
await sendFn(item.url, item.body);
|
|
147
|
+
cursor.delete();
|
|
148
|
+
cursor.continue();
|
|
149
|
+
} catch {
|
|
150
|
+
resolve();
|
|
146
151
|
}
|
|
147
|
-
store.clear();
|
|
148
|
-
resolve();
|
|
149
152
|
};
|
|
150
|
-
|
|
153
|
+
cursorReq.onerror = () => reject(cursorReq.error);
|
|
151
154
|
});
|
|
152
155
|
db.close();
|
|
153
156
|
}
|
|
@@ -350,19 +353,16 @@ var Experience = class _Experience {
|
|
|
350
353
|
}
|
|
351
354
|
}
|
|
352
355
|
flushSync() {
|
|
356
|
+
if (typeof navigator.sendBeacon !== "function") return;
|
|
353
357
|
if (this.eventQueue.length > 0) {
|
|
354
358
|
const url = `${this.config.endpoint}/api/v1/ingest/events`;
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
navigator.sendBeacon(url, body);
|
|
358
|
-
}
|
|
359
|
+
const blob = new Blob([JSON.stringify({ events: this.eventQueue.splice(0) })], { type: "application/json" });
|
|
360
|
+
navigator.sendBeacon(url, blob);
|
|
359
361
|
}
|
|
360
362
|
if (this.errorQueue.length > 0) {
|
|
361
363
|
const url = `${this.config.endpoint}/api/v1/ingest/errors`;
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
navigator.sendBeacon(url, body);
|
|
365
|
-
}
|
|
364
|
+
const blob = new Blob([JSON.stringify({ errors: this.errorQueue.splice(0) })], { type: "application/json" });
|
|
365
|
+
navigator.sendBeacon(url, blob);
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
368
|
async sendOrQueue(url, body) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/breadcrumbs.ts","../src/offline.ts","../src/utils.ts","../src/experience.ts"],"sourcesContent":["export { Experience } from './experience';\nexport type {\n ExperienceConfig,\n ExperienceEvent,\n ErrorReport,\n Breadcrumb,\n PageContext,\n ElementContext,\n HeatmapEntry,\n} from './types';\n","import type { Breadcrumb } from './types';\n\nconst MAX_BREADCRUMBS = 50;\n\nexport class BreadcrumbManager {\n private buffer: Breadcrumb[] = [];\n private originalConsole: Pick<Console, 'log' | 'warn' | 'error'>;\n private originalFetch: typeof fetch | null = null;\n private originalXhrOpen: typeof XMLHttpRequest.prototype.open | null = null;\n private clickHandler: ((e: MouseEvent) => void) | null = null;\n\n constructor() {\n this.originalConsole = {\n log: console.log,\n warn: console.warn,\n error: console.error,\n };\n }\n\n add(breadcrumb: Omit<Breadcrumb, 'timestampMs'>): void {\n this.buffer.push({ ...breadcrumb, timestampMs: Date.now() });\n if (this.buffer.length > MAX_BREADCRUMBS) {\n this.buffer.shift();\n }\n }\n\n getAll(): Breadcrumb[] {\n return [...this.buffer];\n }\n\n install(): void {\n (['log', 'warn', 'error'] as const).forEach((level) => {\n const original = this.originalConsole[level];\n console[level] = (...args: unknown[]) => {\n this.add({\n type: 'console',\n category: level,\n message: args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' '),\n });\n original.apply(console, args);\n };\n });\n\n if (typeof fetch !== 'undefined') {\n this.originalFetch = fetch;\n const self = this;\n (window as unknown as Record<string, unknown>).fetch = function (input: RequestInfo | URL, init?: RequestInit) {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;\n const method = init?.method || 'GET';\n self.add({ type: 'http', category: 'fetch', message: `${method} ${url}` });\n return self.originalFetch!.call(window, input, init);\n };\n }\n\n if (typeof XMLHttpRequest !== 'undefined') {\n this.originalXhrOpen = XMLHttpRequest.prototype.open;\n const self = this;\n XMLHttpRequest.prototype.open = function (method: string, url: string | URL) {\n self.add({ type: 'http', category: 'xhr', message: `${method} ${url}` });\n return self.originalXhrOpen!.apply(this, arguments as unknown as Parameters<typeof XMLHttpRequest.prototype.open>);\n };\n }\n\n this.clickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target) return;\n const tag = target.tagName?.toLowerCase() || '';\n const text = (target.textContent || '').slice(0, 100);\n this.add({ type: 'ui', category: 'click', message: `${tag}: ${text}` });\n };\n document.addEventListener('click', this.clickHandler, true);\n }\n\n teardown(): void {\n console.log = this.originalConsole.log;\n console.warn = this.originalConsole.warn;\n console.error = this.originalConsole.error;\n\n if (this.originalFetch) {\n (window as unknown as Record<string, unknown>).fetch = this.originalFetch;\n }\n if (this.originalXhrOpen) {\n XMLHttpRequest.prototype.open = this.originalXhrOpen;\n }\n if (this.clickHandler) {\n document.removeEventListener('click', this.clickHandler, true);\n }\n }\n}\n","const DB_NAME = 'shellapps_experience';\nconst STORE_NAME = 'offline_queue';\nconst DB_VERSION = 1;\n\nfunction openDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { autoIncrement: true });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function enqueueOffline(data: { url: string; body: string }): Promise<void> {\n const db = await openDB();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).add(data);\n await new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n db.close();\n}\n\nexport async function drainOfflineQueue(sendFn: (url: string, body: string) => Promise<void>): Promise<void> {\n const db = await openDB();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n const request = store.getAll();\n\n await new Promise<void>((resolve, reject) => {\n request.onsuccess = async () => {\n const items = request.result as { url: string; body: string }[];\n for (const item of items) {\n try {\n await sendFn(item.url, item.body);\n } catch {\n // Will retry next time\n break;\n }\n }\n store.clear();\n resolve();\n };\n request.onerror = () => reject(request.error);\n });\n\n db.close();\n}\n","export function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getPageContext() {\n return {\n path: location.pathname,\n title: document.title,\n referrer: document.referrer,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any[]) => void>(fn: T, ms: number): T {\n let last = 0;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return ((...args: any[]) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n }) as T;\n}\n","import type { ExperienceConfig, ExperienceEvent, ErrorReport } from './types';\nimport { BreadcrumbManager } from './breadcrumbs';\nimport { enqueueOffline, drainOfflineQueue } from './offline';\nimport { generateUUID, getPageContext, throttle } from './utils';\n\nconst DEFAULT_CONFIG: Partial<ExperienceConfig> = {\n endpoint: '',\n enableTracking: true,\n enableErrorCapture: true,\n enableHeatmaps: false,\n enableBreadcrumbs: true,\n sampleRate: 1.0,\n batchIntervalMs: 5000,\n maxBatchSize: 50,\n debug: false,\n};\n\nexport class Experience {\n private config: Required<ExperienceConfig>;\n private sessionId: string;\n private profileId = '';\n private eventQueue: ExperienceEvent[] = [];\n private errorQueue: ErrorReport[] = [];\n private batchTimer: ReturnType<typeof setInterval> | null = null;\n private breadcrumbs: BreadcrumbManager;\n private flags: Record<string, unknown> = {};\n private flagsFetched = false;\n private teardownFns: Array<() => void> = [];\n private destroyed = false;\n\n private constructor(config: ExperienceConfig) {\n this.config = { ...DEFAULT_CONFIG, ...config } as Required<ExperienceConfig>;\n this.breadcrumbs = new BreadcrumbManager();\n\n // Session management\n const stored = typeof sessionStorage !== 'undefined' ? sessionStorage.getItem('exp_session_id') : null;\n if (stored) {\n this.sessionId = stored;\n } else {\n this.sessionId = generateUUID();\n if (typeof sessionStorage !== 'undefined') {\n sessionStorage.setItem('exp_session_id', this.sessionId);\n }\n }\n }\n\n static init(config: ExperienceConfig): Experience {\n const instance = new Experience(config);\n instance.setup();\n return instance;\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[Experience]', ...args);\n }\n }\n\n private setup(): void {\n // Check sample rate\n if (Math.random() > this.config.sampleRate) {\n this.log('Sampled out');\n return;\n }\n\n // Breadcrumbs\n if (this.config.enableBreadcrumbs) {\n this.breadcrumbs.install();\n }\n\n // Auto error capture\n if (this.config.enableErrorCapture) {\n this.setupErrorCapture();\n }\n\n // Auto page views\n if (this.config.enableTracking) {\n this.setupAutoPageViews();\n }\n\n // Heatmaps\n if (this.config.enableHeatmaps) {\n this.setupHeatmaps();\n }\n\n // Batch timer\n this.batchTimer = setInterval(() => this.flush(), this.config.batchIntervalMs);\n\n // Page unload\n const beforeUnload = () => this.flushSync();\n window.addEventListener('beforeunload', beforeUnload);\n this.teardownFns.push(() => window.removeEventListener('beforeunload', beforeUnload));\n\n // Offline resilience\n const onlineHandler = () => {\n this.log('Back online, draining queue');\n drainOfflineQueue((url, body) => this.sendRequest(url, body)).catch(() => {});\n };\n window.addEventListener('online', onlineHandler);\n this.teardownFns.push(() => window.removeEventListener('online', onlineHandler));\n\n // Fetch flags\n this.fetchFlags().catch(() => {});\n\n this.log('Initialized', this.config.appId);\n }\n\n // --- Public API ---\n\n track(eventName: string, metadata?: Record<string, unknown>): void {\n if (this.destroyed) return;\n this.enqueueEvent('custom', eventName, metadata);\n }\n\n trackPageView(): void {\n if (this.destroyed) return;\n this.enqueueEvent('page_view', 'page_view');\n this.breadcrumbs.add({ type: 'navigation', category: 'page_view', message: location.href });\n }\n\n captureError(error: Error, extra?: Record<string, unknown>): void {\n if (this.destroyed) return;\n this.enqueueError(error.message, error.stack || '', 'error', extra);\n }\n\n captureMessage(msg: string, severity = 'info'): void {\n if (this.destroyed) return;\n this.enqueueError(msg, '', severity);\n }\n\n getFlag<T>(name: string, defaultValue: T): T {\n if (!this.flagsFetched || !(name in this.flags)) return defaultValue;\n return this.flags[name] as T;\n }\n\n identify(profileId: string): void {\n this.profileId = profileId;\n this.log('Identified', profileId);\n }\n\n async shutdown(): Promise<void> {\n if (this.destroyed) return;\n this.destroyed = true;\n if (this.batchTimer) {\n clearInterval(this.batchTimer);\n this.batchTimer = null;\n }\n await this.flush();\n this.breadcrumbs.teardown();\n this.teardownFns.forEach((fn) => fn());\n this.teardownFns = [];\n this.log('Shutdown complete');\n }\n\n // --- Internal ---\n\n private enqueueEvent(eventType: string, eventName: string, metadata?: Record<string, unknown>): void {\n const event: ExperienceEvent = {\n eventId: generateUUID(),\n appId: this.config.appId,\n profileId: this.profileId,\n sessionId: this.sessionId,\n timestampMs: Date.now(),\n eventType,\n pageUrl: location.href,\n elementTid: metadata?.elementTid as string || '',\n metadata: { eventName, ...metadata },\n pageContext: getPageContext(),\n elementContext: null,\n };\n this.eventQueue.push(event);\n if (this.eventQueue.length >= this.config.maxBatchSize) {\n this.flush().catch(() => {});\n }\n }\n\n private enqueueError(message: string, stack: string, severity: string, extra?: Record<string, unknown>): void {\n const report: ErrorReport = {\n eventId: generateUUID(),\n appId: this.config.appId,\n profileId: this.profileId,\n sessionId: this.sessionId,\n timestampMs: Date.now(),\n message,\n stack,\n severity,\n extra: extra || {},\n pageContext: getPageContext(),\n breadcrumbs: this.breadcrumbs.getAll(),\n };\n this.errorQueue.push(report);\n }\n\n private async flush(): Promise<void> {\n if (this.eventQueue.length > 0) {\n const events = this.eventQueue.splice(0);\n const url = `${this.config.endpoint}/api/v1/ingest/events`;\n const body = JSON.stringify({ events });\n await this.sendOrQueue(url, body);\n }\n if (this.errorQueue.length > 0) {\n const errors = this.errorQueue.splice(0);\n const url = `${this.config.endpoint}/api/v1/ingest/errors`;\n const body = JSON.stringify({ errors });\n await this.sendOrQueue(url, body);\n }\n }\n\n private flushSync(): void {\n if (this.eventQueue.length > 0) {\n const url = `${this.config.endpoint}/api/v1/ingest/events`;\n const body = JSON.stringify({ events: this.eventQueue.splice(0) });\n if (typeof navigator.sendBeacon === 'function') {\n navigator.sendBeacon(url, body);\n }\n }\n if (this.errorQueue.length > 0) {\n const url = `${this.config.endpoint}/api/v1/ingest/errors`;\n const body = JSON.stringify({ errors: this.errorQueue.splice(0) });\n if (typeof navigator.sendBeacon === 'function') {\n navigator.sendBeacon(url, body);\n }\n }\n }\n\n private async sendOrQueue(url: string, body: string): Promise<void> {\n if (typeof navigator !== 'undefined' && !navigator.onLine) {\n await enqueueOffline({ url, body });\n return;\n }\n try {\n await this.sendRequest(url, body);\n } catch {\n await enqueueOffline({ url, body }).catch(() => {});\n }\n }\n\n private async sendRequest(url: string, body: string): Promise<void> {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body,\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n }\n\n private async fetchFlags(): Promise<void> {\n try {\n const url = `${this.config.endpoint}/api/v1/flags/${this.config.appId}`;\n const response = await fetch(url, {\n headers: { 'Authorization': `Bearer ${this.config.apiKey}` },\n });\n if (response.ok) {\n this.flags = await response.json();\n this.flagsFetched = true;\n this.log('Flags loaded', this.flags);\n }\n } catch {\n this.log('Failed to fetch flags');\n }\n }\n\n // --- Auto features ---\n\n private setupErrorCapture(): void {\n const onError = (event: ErrorEvent) => {\n this.enqueueError(\n event.message,\n event.error?.stack || '',\n 'error',\n { filename: event.filename, lineno: event.lineno, colno: event.colno },\n );\n };\n window.addEventListener('error', onError);\n this.teardownFns.push(() => window.removeEventListener('error', onError));\n\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n const msg = event.reason instanceof Error ? event.reason.message : String(event.reason);\n const stack = event.reason instanceof Error ? event.reason.stack || '' : '';\n this.enqueueError(msg, stack, 'error', { type: 'unhandledrejection' });\n };\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n this.teardownFns.push(() => window.removeEventListener('unhandledrejection', onUnhandledRejection));\n }\n\n private setupAutoPageViews(): void {\n // Intercept pushState / replaceState\n const originalPushState = history.pushState.bind(history);\n const originalReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n originalPushState(...args);\n this.trackPageView();\n };\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n originalReplaceState(...args);\n this.trackPageView();\n };\n\n this.teardownFns.push(() => {\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n });\n\n const onPopState = () => this.trackPageView();\n window.addEventListener('popstate', onPopState);\n this.teardownFns.push(() => window.removeEventListener('popstate', onPopState));\n\n // Track initial page view\n this.trackPageView();\n }\n\n private setupHeatmaps(): void {\n const handleMove = throttle((e: MouseEvent) => {\n this.enqueueEvent('heatmap_move', 'mousemove', {\n x: e.clientX,\n y: e.clientY,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n });\n }, 100);\n\n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n this.enqueueEvent('heatmap_click', 'click', {\n x: e.clientX,\n y: e.clientY,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n tag: target?.tagName?.toLowerCase() || '',\n text: (target?.textContent || '').slice(0, 100),\n });\n };\n\n document.addEventListener('mousemove', handleMove as EventListener);\n document.addEventListener('click', handleClick);\n this.teardownFns.push(() => {\n document.removeEventListener('mousemove', handleMove as EventListener);\n document.removeEventListener('click', handleClick);\n });\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/breadcrumbs.ts","../src/offline.ts","../src/utils.ts","../src/experience.ts"],"sourcesContent":["export { Experience } from './experience';\nexport type {\n ExperienceConfig,\n ExperienceEvent,\n ErrorReport,\n Breadcrumb,\n PageContext,\n ElementContext,\n HeatmapEntry,\n} from './types';\n","import type { Breadcrumb } from './types';\n\nconst MAX_BREADCRUMBS = 50;\n\nexport class BreadcrumbManager {\n private buffer: Breadcrumb[] = [];\n private originalConsole: Pick<Console, 'log' | 'warn' | 'error'>;\n private originalFetch: typeof fetch | null = null;\n private originalXhrOpen: typeof XMLHttpRequest.prototype.open | null = null;\n private clickHandler: ((e: MouseEvent) => void) | null = null;\n\n constructor() {\n this.originalConsole = {\n log: console.log,\n warn: console.warn,\n error: console.error,\n };\n }\n\n add(breadcrumb: Omit<Breadcrumb, 'timestampMs'>): void {\n this.buffer.push({ ...breadcrumb, timestampMs: Date.now() });\n if (this.buffer.length > MAX_BREADCRUMBS) {\n this.buffer.shift();\n }\n }\n\n getAll(): Breadcrumb[] {\n return [...this.buffer];\n }\n\n install(): void {\n (['log', 'warn', 'error'] as const).forEach((level) => {\n const original = this.originalConsole[level];\n console[level] = (...args: unknown[]) => {\n this.add({\n type: 'console',\n category: level,\n message: args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' '),\n });\n original.apply(console, args);\n };\n });\n\n if (typeof fetch !== 'undefined') {\n this.originalFetch = fetch;\n const self = this;\n (window as unknown as Record<string, unknown>).fetch = function (input: RequestInfo | URL, init?: RequestInit) {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;\n const method = init?.method || 'GET';\n self.add({ type: 'http', category: 'fetch', message: `${method} ${url}` });\n return self.originalFetch!.call(window, input, init);\n };\n }\n\n if (typeof XMLHttpRequest !== 'undefined') {\n this.originalXhrOpen = XMLHttpRequest.prototype.open;\n const self = this;\n XMLHttpRequest.prototype.open = function (method: string, url: string | URL) {\n self.add({ type: 'http', category: 'xhr', message: `${method} ${url}` });\n return self.originalXhrOpen!.apply(this, arguments as unknown as Parameters<typeof XMLHttpRequest.prototype.open>);\n };\n }\n\n this.clickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target) return;\n const tag = target.tagName?.toLowerCase() || '';\n const text = (target.textContent || '').slice(0, 100);\n this.add({ type: 'ui', category: 'click', message: `${tag}: ${text}` });\n };\n document.addEventListener('click', this.clickHandler, true);\n }\n\n teardown(): void {\n console.log = this.originalConsole.log;\n console.warn = this.originalConsole.warn;\n console.error = this.originalConsole.error;\n\n if (this.originalFetch) {\n (window as unknown as Record<string, unknown>).fetch = this.originalFetch;\n }\n if (this.originalXhrOpen) {\n XMLHttpRequest.prototype.open = this.originalXhrOpen;\n }\n if (this.clickHandler) {\n document.removeEventListener('click', this.clickHandler, true);\n }\n }\n}\n","const DB_NAME = 'shellapps_experience';\nconst STORE_NAME = 'offline_queue';\nconst DB_VERSION = 1;\n\nfunction openDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { autoIncrement: true });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function enqueueOffline(data: { url: string; body: string }): Promise<void> {\n const db = await openDB();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).add(data);\n await new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n db.close();\n}\n\nexport async function drainOfflineQueue(sendFn: (url: string, body: string) => Promise<void>): Promise<void> {\n const db = await openDB();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n const cursorReq = store.openCursor();\n\n await new Promise<void>((resolve, reject) => {\n cursorReq.onsuccess = async () => {\n const cursor = cursorReq.result;\n if (!cursor) {\n resolve();\n return;\n }\n const item = cursor.value as { url: string; body: string };\n try {\n await sendFn(item.url, item.body);\n cursor.delete();\n cursor.continue();\n } catch {\n // Stop draining on first failure; remaining items stay queued\n resolve();\n }\n };\n cursorReq.onerror = () => reject(cursorReq.error);\n });\n\n db.close();\n}\n","export function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getPageContext() {\n return {\n path: location.pathname,\n title: document.title,\n referrer: document.referrer,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any[]) => void>(fn: T, ms: number): T {\n let last = 0;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return ((...args: any[]) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n }) as T;\n}\n","import type { ExperienceConfig, ExperienceEvent, ErrorReport } from './types';\nimport { BreadcrumbManager } from './breadcrumbs';\nimport { enqueueOffline, drainOfflineQueue } from './offline';\nimport { generateUUID, getPageContext, throttle } from './utils';\n\nconst DEFAULT_CONFIG: Partial<ExperienceConfig> = {\n endpoint: '',\n enableTracking: true,\n enableErrorCapture: true,\n enableHeatmaps: false,\n enableBreadcrumbs: true,\n sampleRate: 1.0,\n batchIntervalMs: 5000,\n maxBatchSize: 50,\n debug: false,\n};\n\nexport class Experience {\n private config: Required<ExperienceConfig>;\n private sessionId: string;\n private profileId = '';\n private eventQueue: ExperienceEvent[] = [];\n private errorQueue: ErrorReport[] = [];\n private batchTimer: ReturnType<typeof setInterval> | null = null;\n private breadcrumbs: BreadcrumbManager;\n private flags: Record<string, unknown> = {};\n private flagsFetched = false;\n private teardownFns: Array<() => void> = [];\n private destroyed = false;\n\n private constructor(config: ExperienceConfig) {\n this.config = { ...DEFAULT_CONFIG, ...config } as Required<ExperienceConfig>;\n this.breadcrumbs = new BreadcrumbManager();\n\n // Session management\n const stored = typeof sessionStorage !== 'undefined' ? sessionStorage.getItem('exp_session_id') : null;\n if (stored) {\n this.sessionId = stored;\n } else {\n this.sessionId = generateUUID();\n if (typeof sessionStorage !== 'undefined') {\n sessionStorage.setItem('exp_session_id', this.sessionId);\n }\n }\n }\n\n static init(config: ExperienceConfig): Experience {\n const instance = new Experience(config);\n instance.setup();\n return instance;\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[Experience]', ...args);\n }\n }\n\n private setup(): void {\n // Check sample rate\n if (Math.random() > this.config.sampleRate) {\n this.log('Sampled out');\n return;\n }\n\n // Breadcrumbs\n if (this.config.enableBreadcrumbs) {\n this.breadcrumbs.install();\n }\n\n // Auto error capture\n if (this.config.enableErrorCapture) {\n this.setupErrorCapture();\n }\n\n // Auto page views\n if (this.config.enableTracking) {\n this.setupAutoPageViews();\n }\n\n // Heatmaps\n if (this.config.enableHeatmaps) {\n this.setupHeatmaps();\n }\n\n // Batch timer\n this.batchTimer = setInterval(() => this.flush(), this.config.batchIntervalMs);\n\n // Page unload\n const beforeUnload = () => this.flushSync();\n window.addEventListener('beforeunload', beforeUnload);\n this.teardownFns.push(() => window.removeEventListener('beforeunload', beforeUnload));\n\n // Offline resilience\n const onlineHandler = () => {\n this.log('Back online, draining queue');\n drainOfflineQueue((url, body) => this.sendRequest(url, body)).catch(() => {});\n };\n window.addEventListener('online', onlineHandler);\n this.teardownFns.push(() => window.removeEventListener('online', onlineHandler));\n\n // Fetch flags\n this.fetchFlags().catch(() => {});\n\n this.log('Initialized', this.config.appId);\n }\n\n // --- Public API ---\n\n track(eventName: string, metadata?: Record<string, unknown>): void {\n if (this.destroyed) return;\n this.enqueueEvent('custom', eventName, metadata);\n }\n\n trackPageView(): void {\n if (this.destroyed) return;\n this.enqueueEvent('page_view', 'page_view');\n this.breadcrumbs.add({ type: 'navigation', category: 'page_view', message: location.href });\n }\n\n captureError(error: Error, extra?: Record<string, unknown>): void {\n if (this.destroyed) return;\n this.enqueueError(error.message, error.stack || '', 'error', extra);\n }\n\n captureMessage(msg: string, severity = 'info'): void {\n if (this.destroyed) return;\n this.enqueueError(msg, '', severity);\n }\n\n getFlag<T>(name: string, defaultValue: T): T {\n if (!this.flagsFetched || !(name in this.flags)) return defaultValue;\n return this.flags[name] as T;\n }\n\n identify(profileId: string): void {\n this.profileId = profileId;\n this.log('Identified', profileId);\n }\n\n async shutdown(): Promise<void> {\n if (this.destroyed) return;\n this.destroyed = true;\n if (this.batchTimer) {\n clearInterval(this.batchTimer);\n this.batchTimer = null;\n }\n await this.flush();\n this.breadcrumbs.teardown();\n this.teardownFns.forEach((fn) => fn());\n this.teardownFns = [];\n this.log('Shutdown complete');\n }\n\n // --- Internal ---\n\n private enqueueEvent(eventType: string, eventName: string, metadata?: Record<string, unknown>): void {\n const event: ExperienceEvent = {\n eventId: generateUUID(),\n appId: this.config.appId,\n profileId: this.profileId,\n sessionId: this.sessionId,\n timestampMs: Date.now(),\n eventType,\n pageUrl: location.href,\n elementTid: metadata?.elementTid as string || '',\n metadata: { eventName, ...metadata },\n pageContext: getPageContext(),\n elementContext: null,\n };\n this.eventQueue.push(event);\n if (this.eventQueue.length >= this.config.maxBatchSize) {\n this.flush().catch(() => {});\n }\n }\n\n private enqueueError(message: string, stack: string, severity: string, extra?: Record<string, unknown>): void {\n const report: ErrorReport = {\n eventId: generateUUID(),\n appId: this.config.appId,\n profileId: this.profileId,\n sessionId: this.sessionId,\n timestampMs: Date.now(),\n message,\n stack,\n severity,\n extra: extra || {},\n pageContext: getPageContext(),\n breadcrumbs: this.breadcrumbs.getAll(),\n };\n this.errorQueue.push(report);\n }\n\n private async flush(): Promise<void> {\n if (this.eventQueue.length > 0) {\n const events = this.eventQueue.splice(0);\n const url = `${this.config.endpoint}/api/v1/ingest/events`;\n const body = JSON.stringify({ events });\n await this.sendOrQueue(url, body);\n }\n if (this.errorQueue.length > 0) {\n const errors = this.errorQueue.splice(0);\n const url = `${this.config.endpoint}/api/v1/ingest/errors`;\n const body = JSON.stringify({ errors });\n await this.sendOrQueue(url, body);\n }\n }\n\n private flushSync(): void {\n if (typeof navigator.sendBeacon !== 'function') return;\n if (this.eventQueue.length > 0) {\n const url = `${this.config.endpoint}/api/v1/ingest/events`;\n const blob = new Blob([JSON.stringify({ events: this.eventQueue.splice(0) })], { type: 'application/json' });\n navigator.sendBeacon(url, blob);\n }\n if (this.errorQueue.length > 0) {\n const url = `${this.config.endpoint}/api/v1/ingest/errors`;\n const blob = new Blob([JSON.stringify({ errors: this.errorQueue.splice(0) })], { type: 'application/json' });\n navigator.sendBeacon(url, blob);\n }\n }\n\n private async sendOrQueue(url: string, body: string): Promise<void> {\n if (typeof navigator !== 'undefined' && !navigator.onLine) {\n await enqueueOffline({ url, body });\n return;\n }\n try {\n await this.sendRequest(url, body);\n } catch {\n await enqueueOffline({ url, body }).catch(() => {});\n }\n }\n\n private async sendRequest(url: string, body: string): Promise<void> {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body,\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n }\n\n private async fetchFlags(): Promise<void> {\n try {\n const url = `${this.config.endpoint}/api/v1/flags/${this.config.appId}`;\n const response = await fetch(url, {\n headers: { 'Authorization': `Bearer ${this.config.apiKey}` },\n });\n if (response.ok) {\n this.flags = await response.json();\n this.flagsFetched = true;\n this.log('Flags loaded', this.flags);\n }\n } catch {\n this.log('Failed to fetch flags');\n }\n }\n\n // --- Auto features ---\n\n private setupErrorCapture(): void {\n const onError = (event: ErrorEvent) => {\n this.enqueueError(\n event.message,\n event.error?.stack || '',\n 'error',\n { filename: event.filename, lineno: event.lineno, colno: event.colno },\n );\n };\n window.addEventListener('error', onError);\n this.teardownFns.push(() => window.removeEventListener('error', onError));\n\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n const msg = event.reason instanceof Error ? event.reason.message : String(event.reason);\n const stack = event.reason instanceof Error ? event.reason.stack || '' : '';\n this.enqueueError(msg, stack, 'error', { type: 'unhandledrejection' });\n };\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n this.teardownFns.push(() => window.removeEventListener('unhandledrejection', onUnhandledRejection));\n }\n\n private setupAutoPageViews(): void {\n // Intercept pushState / replaceState\n const originalPushState = history.pushState.bind(history);\n const originalReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n originalPushState(...args);\n this.trackPageView();\n };\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n originalReplaceState(...args);\n this.trackPageView();\n };\n\n this.teardownFns.push(() => {\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n });\n\n const onPopState = () => this.trackPageView();\n window.addEventListener('popstate', onPopState);\n this.teardownFns.push(() => window.removeEventListener('popstate', onPopState));\n\n // Track initial page view\n this.trackPageView();\n }\n\n private setupHeatmaps(): void {\n const handleMove = throttle((e: MouseEvent) => {\n this.enqueueEvent('heatmap_move', 'mousemove', {\n x: e.clientX,\n y: e.clientY,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n });\n }, 100);\n\n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n this.enqueueEvent('heatmap_click', 'click', {\n x: e.clientX,\n y: e.clientY,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n tag: target?.tagName?.toLowerCase() || '',\n text: (target?.textContent || '').slice(0, 100),\n });\n };\n\n document.addEventListener('mousemove', handleMove as EventListener);\n document.addEventListener('click', handleClick);\n this.teardownFns.push(() => {\n document.removeEventListener('mousemove', handleMove as EventListener);\n document.removeEventListener('click', handleClick);\n });\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -107,21 +107,24 @@ async function drainOfflineQueue(sendFn) {
|
|
|
107
107
|
const db = await openDB();
|
|
108
108
|
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
109
109
|
const store = tx.objectStore(STORE_NAME);
|
|
110
|
-
const
|
|
110
|
+
const cursorReq = store.openCursor();
|
|
111
111
|
await new Promise((resolve, reject) => {
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
112
|
+
cursorReq.onsuccess = async () => {
|
|
113
|
+
const cursor = cursorReq.result;
|
|
114
|
+
if (!cursor) {
|
|
115
|
+
resolve();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const item = cursor.value;
|
|
119
|
+
try {
|
|
120
|
+
await sendFn(item.url, item.body);
|
|
121
|
+
cursor.delete();
|
|
122
|
+
cursor.continue();
|
|
123
|
+
} catch {
|
|
124
|
+
resolve();
|
|
120
125
|
}
|
|
121
|
-
store.clear();
|
|
122
|
-
resolve();
|
|
123
126
|
};
|
|
124
|
-
|
|
127
|
+
cursorReq.onerror = () => reject(cursorReq.error);
|
|
125
128
|
});
|
|
126
129
|
db.close();
|
|
127
130
|
}
|
|
@@ -324,19 +327,16 @@ var Experience = class _Experience {
|
|
|
324
327
|
}
|
|
325
328
|
}
|
|
326
329
|
flushSync() {
|
|
330
|
+
if (typeof navigator.sendBeacon !== "function") return;
|
|
327
331
|
if (this.eventQueue.length > 0) {
|
|
328
332
|
const url = `${this.config.endpoint}/api/v1/ingest/events`;
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
navigator.sendBeacon(url, body);
|
|
332
|
-
}
|
|
333
|
+
const blob = new Blob([JSON.stringify({ events: this.eventQueue.splice(0) })], { type: "application/json" });
|
|
334
|
+
navigator.sendBeacon(url, blob);
|
|
333
335
|
}
|
|
334
336
|
if (this.errorQueue.length > 0) {
|
|
335
337
|
const url = `${this.config.endpoint}/api/v1/ingest/errors`;
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
navigator.sendBeacon(url, body);
|
|
339
|
-
}
|
|
338
|
+
const blob = new Blob([JSON.stringify({ errors: this.errorQueue.splice(0) })], { type: "application/json" });
|
|
339
|
+
navigator.sendBeacon(url, blob);
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
async sendOrQueue(url, body) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/breadcrumbs.ts","../src/offline.ts","../src/utils.ts","../src/experience.ts"],"sourcesContent":["import type { Breadcrumb } from './types';\n\nconst MAX_BREADCRUMBS = 50;\n\nexport class BreadcrumbManager {\n private buffer: Breadcrumb[] = [];\n private originalConsole: Pick<Console, 'log' | 'warn' | 'error'>;\n private originalFetch: typeof fetch | null = null;\n private originalXhrOpen: typeof XMLHttpRequest.prototype.open | null = null;\n private clickHandler: ((e: MouseEvent) => void) | null = null;\n\n constructor() {\n this.originalConsole = {\n log: console.log,\n warn: console.warn,\n error: console.error,\n };\n }\n\n add(breadcrumb: Omit<Breadcrumb, 'timestampMs'>): void {\n this.buffer.push({ ...breadcrumb, timestampMs: Date.now() });\n if (this.buffer.length > MAX_BREADCRUMBS) {\n this.buffer.shift();\n }\n }\n\n getAll(): Breadcrumb[] {\n return [...this.buffer];\n }\n\n install(): void {\n (['log', 'warn', 'error'] as const).forEach((level) => {\n const original = this.originalConsole[level];\n console[level] = (...args: unknown[]) => {\n this.add({\n type: 'console',\n category: level,\n message: args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' '),\n });\n original.apply(console, args);\n };\n });\n\n if (typeof fetch !== 'undefined') {\n this.originalFetch = fetch;\n const self = this;\n (window as unknown as Record<string, unknown>).fetch = function (input: RequestInfo | URL, init?: RequestInit) {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;\n const method = init?.method || 'GET';\n self.add({ type: 'http', category: 'fetch', message: `${method} ${url}` });\n return self.originalFetch!.call(window, input, init);\n };\n }\n\n if (typeof XMLHttpRequest !== 'undefined') {\n this.originalXhrOpen = XMLHttpRequest.prototype.open;\n const self = this;\n XMLHttpRequest.prototype.open = function (method: string, url: string | URL) {\n self.add({ type: 'http', category: 'xhr', message: `${method} ${url}` });\n return self.originalXhrOpen!.apply(this, arguments as unknown as Parameters<typeof XMLHttpRequest.prototype.open>);\n };\n }\n\n this.clickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target) return;\n const tag = target.tagName?.toLowerCase() || '';\n const text = (target.textContent || '').slice(0, 100);\n this.add({ type: 'ui', category: 'click', message: `${tag}: ${text}` });\n };\n document.addEventListener('click', this.clickHandler, true);\n }\n\n teardown(): void {\n console.log = this.originalConsole.log;\n console.warn = this.originalConsole.warn;\n console.error = this.originalConsole.error;\n\n if (this.originalFetch) {\n (window as unknown as Record<string, unknown>).fetch = this.originalFetch;\n }\n if (this.originalXhrOpen) {\n XMLHttpRequest.prototype.open = this.originalXhrOpen;\n }\n if (this.clickHandler) {\n document.removeEventListener('click', this.clickHandler, true);\n }\n }\n}\n","const DB_NAME = 'shellapps_experience';\nconst STORE_NAME = 'offline_queue';\nconst DB_VERSION = 1;\n\nfunction openDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { autoIncrement: true });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function enqueueOffline(data: { url: string; body: string }): Promise<void> {\n const db = await openDB();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).add(data);\n await new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n db.close();\n}\n\nexport async function drainOfflineQueue(sendFn: (url: string, body: string) => Promise<void>): Promise<void> {\n const db = await openDB();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n const request = store.getAll();\n\n await new Promise<void>((resolve, reject) => {\n request.onsuccess = async () => {\n const items = request.result as { url: string; body: string }[];\n for (const item of items) {\n try {\n await sendFn(item.url, item.body);\n } catch {\n // Will retry next time\n break;\n }\n }\n store.clear();\n resolve();\n };\n request.onerror = () => reject(request.error);\n });\n\n db.close();\n}\n","export function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getPageContext() {\n return {\n path: location.pathname,\n title: document.title,\n referrer: document.referrer,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any[]) => void>(fn: T, ms: number): T {\n let last = 0;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return ((...args: any[]) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n }) as T;\n}\n","import type { ExperienceConfig, ExperienceEvent, ErrorReport } from './types';\nimport { BreadcrumbManager } from './breadcrumbs';\nimport { enqueueOffline, drainOfflineQueue } from './offline';\nimport { generateUUID, getPageContext, throttle } from './utils';\n\nconst DEFAULT_CONFIG: Partial<ExperienceConfig> = {\n endpoint: '',\n enableTracking: true,\n enableErrorCapture: true,\n enableHeatmaps: false,\n enableBreadcrumbs: true,\n sampleRate: 1.0,\n batchIntervalMs: 5000,\n maxBatchSize: 50,\n debug: false,\n};\n\nexport class Experience {\n private config: Required<ExperienceConfig>;\n private sessionId: string;\n private profileId = '';\n private eventQueue: ExperienceEvent[] = [];\n private errorQueue: ErrorReport[] = [];\n private batchTimer: ReturnType<typeof setInterval> | null = null;\n private breadcrumbs: BreadcrumbManager;\n private flags: Record<string, unknown> = {};\n private flagsFetched = false;\n private teardownFns: Array<() => void> = [];\n private destroyed = false;\n\n private constructor(config: ExperienceConfig) {\n this.config = { ...DEFAULT_CONFIG, ...config } as Required<ExperienceConfig>;\n this.breadcrumbs = new BreadcrumbManager();\n\n // Session management\n const stored = typeof sessionStorage !== 'undefined' ? sessionStorage.getItem('exp_session_id') : null;\n if (stored) {\n this.sessionId = stored;\n } else {\n this.sessionId = generateUUID();\n if (typeof sessionStorage !== 'undefined') {\n sessionStorage.setItem('exp_session_id', this.sessionId);\n }\n }\n }\n\n static init(config: ExperienceConfig): Experience {\n const instance = new Experience(config);\n instance.setup();\n return instance;\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[Experience]', ...args);\n }\n }\n\n private setup(): void {\n // Check sample rate\n if (Math.random() > this.config.sampleRate) {\n this.log('Sampled out');\n return;\n }\n\n // Breadcrumbs\n if (this.config.enableBreadcrumbs) {\n this.breadcrumbs.install();\n }\n\n // Auto error capture\n if (this.config.enableErrorCapture) {\n this.setupErrorCapture();\n }\n\n // Auto page views\n if (this.config.enableTracking) {\n this.setupAutoPageViews();\n }\n\n // Heatmaps\n if (this.config.enableHeatmaps) {\n this.setupHeatmaps();\n }\n\n // Batch timer\n this.batchTimer = setInterval(() => this.flush(), this.config.batchIntervalMs);\n\n // Page unload\n const beforeUnload = () => this.flushSync();\n window.addEventListener('beforeunload', beforeUnload);\n this.teardownFns.push(() => window.removeEventListener('beforeunload', beforeUnload));\n\n // Offline resilience\n const onlineHandler = () => {\n this.log('Back online, draining queue');\n drainOfflineQueue((url, body) => this.sendRequest(url, body)).catch(() => {});\n };\n window.addEventListener('online', onlineHandler);\n this.teardownFns.push(() => window.removeEventListener('online', onlineHandler));\n\n // Fetch flags\n this.fetchFlags().catch(() => {});\n\n this.log('Initialized', this.config.appId);\n }\n\n // --- Public API ---\n\n track(eventName: string, metadata?: Record<string, unknown>): void {\n if (this.destroyed) return;\n this.enqueueEvent('custom', eventName, metadata);\n }\n\n trackPageView(): void {\n if (this.destroyed) return;\n this.enqueueEvent('page_view', 'page_view');\n this.breadcrumbs.add({ type: 'navigation', category: 'page_view', message: location.href });\n }\n\n captureError(error: Error, extra?: Record<string, unknown>): void {\n if (this.destroyed) return;\n this.enqueueError(error.message, error.stack || '', 'error', extra);\n }\n\n captureMessage(msg: string, severity = 'info'): void {\n if (this.destroyed) return;\n this.enqueueError(msg, '', severity);\n }\n\n getFlag<T>(name: string, defaultValue: T): T {\n if (!this.flagsFetched || !(name in this.flags)) return defaultValue;\n return this.flags[name] as T;\n }\n\n identify(profileId: string): void {\n this.profileId = profileId;\n this.log('Identified', profileId);\n }\n\n async shutdown(): Promise<void> {\n if (this.destroyed) return;\n this.destroyed = true;\n if (this.batchTimer) {\n clearInterval(this.batchTimer);\n this.batchTimer = null;\n }\n await this.flush();\n this.breadcrumbs.teardown();\n this.teardownFns.forEach((fn) => fn());\n this.teardownFns = [];\n this.log('Shutdown complete');\n }\n\n // --- Internal ---\n\n private enqueueEvent(eventType: string, eventName: string, metadata?: Record<string, unknown>): void {\n const event: ExperienceEvent = {\n eventId: generateUUID(),\n appId: this.config.appId,\n profileId: this.profileId,\n sessionId: this.sessionId,\n timestampMs: Date.now(),\n eventType,\n pageUrl: location.href,\n elementTid: metadata?.elementTid as string || '',\n metadata: { eventName, ...metadata },\n pageContext: getPageContext(),\n elementContext: null,\n };\n this.eventQueue.push(event);\n if (this.eventQueue.length >= this.config.maxBatchSize) {\n this.flush().catch(() => {});\n }\n }\n\n private enqueueError(message: string, stack: string, severity: string, extra?: Record<string, unknown>): void {\n const report: ErrorReport = {\n eventId: generateUUID(),\n appId: this.config.appId,\n profileId: this.profileId,\n sessionId: this.sessionId,\n timestampMs: Date.now(),\n message,\n stack,\n severity,\n extra: extra || {},\n pageContext: getPageContext(),\n breadcrumbs: this.breadcrumbs.getAll(),\n };\n this.errorQueue.push(report);\n }\n\n private async flush(): Promise<void> {\n if (this.eventQueue.length > 0) {\n const events = this.eventQueue.splice(0);\n const url = `${this.config.endpoint}/api/v1/ingest/events`;\n const body = JSON.stringify({ events });\n await this.sendOrQueue(url, body);\n }\n if (this.errorQueue.length > 0) {\n const errors = this.errorQueue.splice(0);\n const url = `${this.config.endpoint}/api/v1/ingest/errors`;\n const body = JSON.stringify({ errors });\n await this.sendOrQueue(url, body);\n }\n }\n\n private flushSync(): void {\n if (this.eventQueue.length > 0) {\n const url = `${this.config.endpoint}/api/v1/ingest/events`;\n const body = JSON.stringify({ events: this.eventQueue.splice(0) });\n if (typeof navigator.sendBeacon === 'function') {\n navigator.sendBeacon(url, body);\n }\n }\n if (this.errorQueue.length > 0) {\n const url = `${this.config.endpoint}/api/v1/ingest/errors`;\n const body = JSON.stringify({ errors: this.errorQueue.splice(0) });\n if (typeof navigator.sendBeacon === 'function') {\n navigator.sendBeacon(url, body);\n }\n }\n }\n\n private async sendOrQueue(url: string, body: string): Promise<void> {\n if (typeof navigator !== 'undefined' && !navigator.onLine) {\n await enqueueOffline({ url, body });\n return;\n }\n try {\n await this.sendRequest(url, body);\n } catch {\n await enqueueOffline({ url, body }).catch(() => {});\n }\n }\n\n private async sendRequest(url: string, body: string): Promise<void> {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body,\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n }\n\n private async fetchFlags(): Promise<void> {\n try {\n const url = `${this.config.endpoint}/api/v1/flags/${this.config.appId}`;\n const response = await fetch(url, {\n headers: { 'Authorization': `Bearer ${this.config.apiKey}` },\n });\n if (response.ok) {\n this.flags = await response.json();\n this.flagsFetched = true;\n this.log('Flags loaded', this.flags);\n }\n } catch {\n this.log('Failed to fetch flags');\n }\n }\n\n // --- Auto features ---\n\n private setupErrorCapture(): void {\n const onError = (event: ErrorEvent) => {\n this.enqueueError(\n event.message,\n event.error?.stack || '',\n 'error',\n { filename: event.filename, lineno: event.lineno, colno: event.colno },\n );\n };\n window.addEventListener('error', onError);\n this.teardownFns.push(() => window.removeEventListener('error', onError));\n\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n const msg = event.reason instanceof Error ? event.reason.message : String(event.reason);\n const stack = event.reason instanceof Error ? event.reason.stack || '' : '';\n this.enqueueError(msg, stack, 'error', { type: 'unhandledrejection' });\n };\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n this.teardownFns.push(() => window.removeEventListener('unhandledrejection', onUnhandledRejection));\n }\n\n private setupAutoPageViews(): void {\n // Intercept pushState / replaceState\n const originalPushState = history.pushState.bind(history);\n const originalReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n originalPushState(...args);\n this.trackPageView();\n };\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n originalReplaceState(...args);\n this.trackPageView();\n };\n\n this.teardownFns.push(() => {\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n });\n\n const onPopState = () => this.trackPageView();\n window.addEventListener('popstate', onPopState);\n this.teardownFns.push(() => window.removeEventListener('popstate', onPopState));\n\n // Track initial page view\n this.trackPageView();\n }\n\n private setupHeatmaps(): void {\n const handleMove = throttle((e: MouseEvent) => {\n this.enqueueEvent('heatmap_move', 'mousemove', {\n x: e.clientX,\n y: e.clientY,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n });\n }, 100);\n\n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n this.enqueueEvent('heatmap_click', 'click', {\n x: e.clientX,\n y: e.clientY,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n tag: target?.tagName?.toLowerCase() || '',\n text: (target?.textContent || '').slice(0, 100),\n });\n };\n\n document.addEventListener('mousemove', handleMove as EventListener);\n document.addEventListener('click', handleClick);\n this.teardownFns.push(() => {\n document.removeEventListener('mousemove', handleMove as EventListener);\n document.removeEventListener('click', handleClick);\n });\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/breadcrumbs.ts","../src/offline.ts","../src/utils.ts","../src/experience.ts"],"sourcesContent":["import type { Breadcrumb } from './types';\n\nconst MAX_BREADCRUMBS = 50;\n\nexport class BreadcrumbManager {\n private buffer: Breadcrumb[] = [];\n private originalConsole: Pick<Console, 'log' | 'warn' | 'error'>;\n private originalFetch: typeof fetch | null = null;\n private originalXhrOpen: typeof XMLHttpRequest.prototype.open | null = null;\n private clickHandler: ((e: MouseEvent) => void) | null = null;\n\n constructor() {\n this.originalConsole = {\n log: console.log,\n warn: console.warn,\n error: console.error,\n };\n }\n\n add(breadcrumb: Omit<Breadcrumb, 'timestampMs'>): void {\n this.buffer.push({ ...breadcrumb, timestampMs: Date.now() });\n if (this.buffer.length > MAX_BREADCRUMBS) {\n this.buffer.shift();\n }\n }\n\n getAll(): Breadcrumb[] {\n return [...this.buffer];\n }\n\n install(): void {\n (['log', 'warn', 'error'] as const).forEach((level) => {\n const original = this.originalConsole[level];\n console[level] = (...args: unknown[]) => {\n this.add({\n type: 'console',\n category: level,\n message: args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' '),\n });\n original.apply(console, args);\n };\n });\n\n if (typeof fetch !== 'undefined') {\n this.originalFetch = fetch;\n const self = this;\n (window as unknown as Record<string, unknown>).fetch = function (input: RequestInfo | URL, init?: RequestInit) {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;\n const method = init?.method || 'GET';\n self.add({ type: 'http', category: 'fetch', message: `${method} ${url}` });\n return self.originalFetch!.call(window, input, init);\n };\n }\n\n if (typeof XMLHttpRequest !== 'undefined') {\n this.originalXhrOpen = XMLHttpRequest.prototype.open;\n const self = this;\n XMLHttpRequest.prototype.open = function (method: string, url: string | URL) {\n self.add({ type: 'http', category: 'xhr', message: `${method} ${url}` });\n return self.originalXhrOpen!.apply(this, arguments as unknown as Parameters<typeof XMLHttpRequest.prototype.open>);\n };\n }\n\n this.clickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target) return;\n const tag = target.tagName?.toLowerCase() || '';\n const text = (target.textContent || '').slice(0, 100);\n this.add({ type: 'ui', category: 'click', message: `${tag}: ${text}` });\n };\n document.addEventListener('click', this.clickHandler, true);\n }\n\n teardown(): void {\n console.log = this.originalConsole.log;\n console.warn = this.originalConsole.warn;\n console.error = this.originalConsole.error;\n\n if (this.originalFetch) {\n (window as unknown as Record<string, unknown>).fetch = this.originalFetch;\n }\n if (this.originalXhrOpen) {\n XMLHttpRequest.prototype.open = this.originalXhrOpen;\n }\n if (this.clickHandler) {\n document.removeEventListener('click', this.clickHandler, true);\n }\n }\n}\n","const DB_NAME = 'shellapps_experience';\nconst STORE_NAME = 'offline_queue';\nconst DB_VERSION = 1;\n\nfunction openDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { autoIncrement: true });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function enqueueOffline(data: { url: string; body: string }): Promise<void> {\n const db = await openDB();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).add(data);\n await new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n db.close();\n}\n\nexport async function drainOfflineQueue(sendFn: (url: string, body: string) => Promise<void>): Promise<void> {\n const db = await openDB();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n const cursorReq = store.openCursor();\n\n await new Promise<void>((resolve, reject) => {\n cursorReq.onsuccess = async () => {\n const cursor = cursorReq.result;\n if (!cursor) {\n resolve();\n return;\n }\n const item = cursor.value as { url: string; body: string };\n try {\n await sendFn(item.url, item.body);\n cursor.delete();\n cursor.continue();\n } catch {\n // Stop draining on first failure; remaining items stay queued\n resolve();\n }\n };\n cursorReq.onerror = () => reject(cursorReq.error);\n });\n\n db.close();\n}\n","export function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getPageContext() {\n return {\n path: location.pathname,\n title: document.title,\n referrer: document.referrer,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any[]) => void>(fn: T, ms: number): T {\n let last = 0;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return ((...args: any[]) => {\n const now = Date.now();\n if (now - last >= ms) {\n last = now;\n fn(...args);\n }\n }) as T;\n}\n","import type { ExperienceConfig, ExperienceEvent, ErrorReport } from './types';\nimport { BreadcrumbManager } from './breadcrumbs';\nimport { enqueueOffline, drainOfflineQueue } from './offline';\nimport { generateUUID, getPageContext, throttle } from './utils';\n\nconst DEFAULT_CONFIG: Partial<ExperienceConfig> = {\n endpoint: '',\n enableTracking: true,\n enableErrorCapture: true,\n enableHeatmaps: false,\n enableBreadcrumbs: true,\n sampleRate: 1.0,\n batchIntervalMs: 5000,\n maxBatchSize: 50,\n debug: false,\n};\n\nexport class Experience {\n private config: Required<ExperienceConfig>;\n private sessionId: string;\n private profileId = '';\n private eventQueue: ExperienceEvent[] = [];\n private errorQueue: ErrorReport[] = [];\n private batchTimer: ReturnType<typeof setInterval> | null = null;\n private breadcrumbs: BreadcrumbManager;\n private flags: Record<string, unknown> = {};\n private flagsFetched = false;\n private teardownFns: Array<() => void> = [];\n private destroyed = false;\n\n private constructor(config: ExperienceConfig) {\n this.config = { ...DEFAULT_CONFIG, ...config } as Required<ExperienceConfig>;\n this.breadcrumbs = new BreadcrumbManager();\n\n // Session management\n const stored = typeof sessionStorage !== 'undefined' ? sessionStorage.getItem('exp_session_id') : null;\n if (stored) {\n this.sessionId = stored;\n } else {\n this.sessionId = generateUUID();\n if (typeof sessionStorage !== 'undefined') {\n sessionStorage.setItem('exp_session_id', this.sessionId);\n }\n }\n }\n\n static init(config: ExperienceConfig): Experience {\n const instance = new Experience(config);\n instance.setup();\n return instance;\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[Experience]', ...args);\n }\n }\n\n private setup(): void {\n // Check sample rate\n if (Math.random() > this.config.sampleRate) {\n this.log('Sampled out');\n return;\n }\n\n // Breadcrumbs\n if (this.config.enableBreadcrumbs) {\n this.breadcrumbs.install();\n }\n\n // Auto error capture\n if (this.config.enableErrorCapture) {\n this.setupErrorCapture();\n }\n\n // Auto page views\n if (this.config.enableTracking) {\n this.setupAutoPageViews();\n }\n\n // Heatmaps\n if (this.config.enableHeatmaps) {\n this.setupHeatmaps();\n }\n\n // Batch timer\n this.batchTimer = setInterval(() => this.flush(), this.config.batchIntervalMs);\n\n // Page unload\n const beforeUnload = () => this.flushSync();\n window.addEventListener('beforeunload', beforeUnload);\n this.teardownFns.push(() => window.removeEventListener('beforeunload', beforeUnload));\n\n // Offline resilience\n const onlineHandler = () => {\n this.log('Back online, draining queue');\n drainOfflineQueue((url, body) => this.sendRequest(url, body)).catch(() => {});\n };\n window.addEventListener('online', onlineHandler);\n this.teardownFns.push(() => window.removeEventListener('online', onlineHandler));\n\n // Fetch flags\n this.fetchFlags().catch(() => {});\n\n this.log('Initialized', this.config.appId);\n }\n\n // --- Public API ---\n\n track(eventName: string, metadata?: Record<string, unknown>): void {\n if (this.destroyed) return;\n this.enqueueEvent('custom', eventName, metadata);\n }\n\n trackPageView(): void {\n if (this.destroyed) return;\n this.enqueueEvent('page_view', 'page_view');\n this.breadcrumbs.add({ type: 'navigation', category: 'page_view', message: location.href });\n }\n\n captureError(error: Error, extra?: Record<string, unknown>): void {\n if (this.destroyed) return;\n this.enqueueError(error.message, error.stack || '', 'error', extra);\n }\n\n captureMessage(msg: string, severity = 'info'): void {\n if (this.destroyed) return;\n this.enqueueError(msg, '', severity);\n }\n\n getFlag<T>(name: string, defaultValue: T): T {\n if (!this.flagsFetched || !(name in this.flags)) return defaultValue;\n return this.flags[name] as T;\n }\n\n identify(profileId: string): void {\n this.profileId = profileId;\n this.log('Identified', profileId);\n }\n\n async shutdown(): Promise<void> {\n if (this.destroyed) return;\n this.destroyed = true;\n if (this.batchTimer) {\n clearInterval(this.batchTimer);\n this.batchTimer = null;\n }\n await this.flush();\n this.breadcrumbs.teardown();\n this.teardownFns.forEach((fn) => fn());\n this.teardownFns = [];\n this.log('Shutdown complete');\n }\n\n // --- Internal ---\n\n private enqueueEvent(eventType: string, eventName: string, metadata?: Record<string, unknown>): void {\n const event: ExperienceEvent = {\n eventId: generateUUID(),\n appId: this.config.appId,\n profileId: this.profileId,\n sessionId: this.sessionId,\n timestampMs: Date.now(),\n eventType,\n pageUrl: location.href,\n elementTid: metadata?.elementTid as string || '',\n metadata: { eventName, ...metadata },\n pageContext: getPageContext(),\n elementContext: null,\n };\n this.eventQueue.push(event);\n if (this.eventQueue.length >= this.config.maxBatchSize) {\n this.flush().catch(() => {});\n }\n }\n\n private enqueueError(message: string, stack: string, severity: string, extra?: Record<string, unknown>): void {\n const report: ErrorReport = {\n eventId: generateUUID(),\n appId: this.config.appId,\n profileId: this.profileId,\n sessionId: this.sessionId,\n timestampMs: Date.now(),\n message,\n stack,\n severity,\n extra: extra || {},\n pageContext: getPageContext(),\n breadcrumbs: this.breadcrumbs.getAll(),\n };\n this.errorQueue.push(report);\n }\n\n private async flush(): Promise<void> {\n if (this.eventQueue.length > 0) {\n const events = this.eventQueue.splice(0);\n const url = `${this.config.endpoint}/api/v1/ingest/events`;\n const body = JSON.stringify({ events });\n await this.sendOrQueue(url, body);\n }\n if (this.errorQueue.length > 0) {\n const errors = this.errorQueue.splice(0);\n const url = `${this.config.endpoint}/api/v1/ingest/errors`;\n const body = JSON.stringify({ errors });\n await this.sendOrQueue(url, body);\n }\n }\n\n private flushSync(): void {\n if (typeof navigator.sendBeacon !== 'function') return;\n if (this.eventQueue.length > 0) {\n const url = `${this.config.endpoint}/api/v1/ingest/events`;\n const blob = new Blob([JSON.stringify({ events: this.eventQueue.splice(0) })], { type: 'application/json' });\n navigator.sendBeacon(url, blob);\n }\n if (this.errorQueue.length > 0) {\n const url = `${this.config.endpoint}/api/v1/ingest/errors`;\n const blob = new Blob([JSON.stringify({ errors: this.errorQueue.splice(0) })], { type: 'application/json' });\n navigator.sendBeacon(url, blob);\n }\n }\n\n private async sendOrQueue(url: string, body: string): Promise<void> {\n if (typeof navigator !== 'undefined' && !navigator.onLine) {\n await enqueueOffline({ url, body });\n return;\n }\n try {\n await this.sendRequest(url, body);\n } catch {\n await enqueueOffline({ url, body }).catch(() => {});\n }\n }\n\n private async sendRequest(url: string, body: string): Promise<void> {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body,\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n }\n\n private async fetchFlags(): Promise<void> {\n try {\n const url = `${this.config.endpoint}/api/v1/flags/${this.config.appId}`;\n const response = await fetch(url, {\n headers: { 'Authorization': `Bearer ${this.config.apiKey}` },\n });\n if (response.ok) {\n this.flags = await response.json();\n this.flagsFetched = true;\n this.log('Flags loaded', this.flags);\n }\n } catch {\n this.log('Failed to fetch flags');\n }\n }\n\n // --- Auto features ---\n\n private setupErrorCapture(): void {\n const onError = (event: ErrorEvent) => {\n this.enqueueError(\n event.message,\n event.error?.stack || '',\n 'error',\n { filename: event.filename, lineno: event.lineno, colno: event.colno },\n );\n };\n window.addEventListener('error', onError);\n this.teardownFns.push(() => window.removeEventListener('error', onError));\n\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n const msg = event.reason instanceof Error ? event.reason.message : String(event.reason);\n const stack = event.reason instanceof Error ? event.reason.stack || '' : '';\n this.enqueueError(msg, stack, 'error', { type: 'unhandledrejection' });\n };\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n this.teardownFns.push(() => window.removeEventListener('unhandledrejection', onUnhandledRejection));\n }\n\n private setupAutoPageViews(): void {\n // Intercept pushState / replaceState\n const originalPushState = history.pushState.bind(history);\n const originalReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n originalPushState(...args);\n this.trackPageView();\n };\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n originalReplaceState(...args);\n this.trackPageView();\n };\n\n this.teardownFns.push(() => {\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n });\n\n const onPopState = () => this.trackPageView();\n window.addEventListener('popstate', onPopState);\n this.teardownFns.push(() => window.removeEventListener('popstate', onPopState));\n\n // Track initial page view\n this.trackPageView();\n }\n\n private setupHeatmaps(): void {\n const handleMove = throttle((e: MouseEvent) => {\n this.enqueueEvent('heatmap_move', 'mousemove', {\n x: e.clientX,\n y: e.clientY,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n });\n }, 100);\n\n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n this.enqueueEvent('heatmap_click', 'click', {\n x: e.clientX,\n y: e.clientY,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n tag: target?.tagName?.toLowerCase() || '',\n text: (target?.textContent || '').slice(0, 100),\n });\n };\n\n document.addEventListener('mousemove', handleMove as EventListener);\n document.addEventListener('click', handleClick);\n this.teardownFns.push(() => {\n document.removeEventListener('mousemove', handleMove as EventListener);\n document.removeEventListener('click', handleClick);\n });\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shellapps/experience",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Browser event tracking, error capture, and feature flags SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"url": "git+https://github.com/ShellTechnology/shellapps-js.git",
|
|
38
38
|
"directory": "packages/experience"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "b7b3b29f4722dc1284df8239ea4ca7ec6afd0783"
|
|
41
41
|
}
|