@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 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 request = store.getAll();
136
+ const cursorReq = store.openCursor();
137
137
  await new Promise((resolve, reject) => {
138
- request.onsuccess = async () => {
139
- const items = request.result;
140
- for (const item of items) {
141
- try {
142
- await sendFn(item.url, item.body);
143
- } catch {
144
- break;
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
- request.onerror = () => reject(request.error);
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 body = JSON.stringify({ events: this.eventQueue.splice(0) });
356
- if (typeof navigator.sendBeacon === "function") {
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 body = JSON.stringify({ errors: this.errorQueue.splice(0) });
363
- if (typeof navigator.sendBeacon === "function") {
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 request = store.getAll();
110
+ const cursorReq = store.openCursor();
111
111
  await new Promise((resolve, reject) => {
112
- request.onsuccess = async () => {
113
- const items = request.result;
114
- for (const item of items) {
115
- try {
116
- await sendFn(item.url, item.body);
117
- } catch {
118
- break;
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
- request.onerror = () => reject(request.error);
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 body = JSON.stringify({ events: this.eventQueue.splice(0) });
330
- if (typeof navigator.sendBeacon === "function") {
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 body = JSON.stringify({ errors: this.errorQueue.splice(0) });
337
- if (typeof navigator.sendBeacon === "function") {
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) {
@@ -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.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": "97840ec6e98bfb5289b83abbe5f618ef3c4c663f"
40
+ "gitHead": "b7b3b29f4722dc1284df8239ea4ca7ec6afd0783"
41
41
  }