@snovasys/usage-analytics-sdk 1.0.0
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/README.md +638 -0
- package/dist/clarity.cjs +91 -0
- package/dist/clarity.cjs.map +1 -0
- package/dist/clarity.d.cts +19 -0
- package/dist/clarity.d.ts +19 -0
- package/dist/clarity.js +64 -0
- package/dist/clarity.js.map +1 -0
- package/dist/custom-api.cjs +98 -0
- package/dist/custom-api.cjs.map +1 -0
- package/dist/custom-api.d.cts +20 -0
- package/dist/custom-api.d.ts +20 -0
- package/dist/custom-api.js +71 -0
- package/dist/custom-api.js.map +1 -0
- package/dist/ga.cjs +96 -0
- package/dist/ga.cjs.map +1 -0
- package/dist/ga.d.cts +20 -0
- package/dist/ga.d.ts +20 -0
- package/dist/ga.js +69 -0
- package/dist/ga.js.map +1 -0
- package/dist/index.cjs +729 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +93 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +697 -0
- package/dist/index.js.map +1 -0
- package/dist/listener-CrNaKh1a.d.cts +58 -0
- package/dist/listener-CrNaKh1a.d.ts +58 -0
- package/dist/noop.cjs +43 -0
- package/dist/noop.cjs.map +1 -0
- package/dist/noop.d.cts +12 -0
- package/dist/noop.d.ts +12 -0
- package/dist/noop.js +15 -0
- package/dist/noop.js.map +1 -0
- package/dist/usage-analytics.min.js +2 -0
- package/dist/usage-analytics.min.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/buffer/pre-init-buffer.ts","../src/dispatcher/registry.ts","../src/enricher/session.ts","../src/enricher/enricher.ts","../src/dispatcher/dispatcher.ts","../src/listeners/noop.ts","../src/listeners/clarity.ts","../src/listeners/ga.ts","../src/listeners/custom-api.ts","../src/listeners/registry.ts","../src/validate-config.ts","../src/version.ts","../src/facade.ts"],"sourcesContent":["export { init, track, identify, flush, reset, isInitialized } from './facade.js';\nexport type { AnalyticsInitConfig, AnalyticsListener, EventEnvelope, ListenerEntry, OnErrorContext, PreInitBehavior } from './types/index.js';\n","import type { BufferedItem, BufferedTrack, BufferedIdentify } from './types.js';\n\nexport interface PreInitBufferOptions {\n /** 'drop' = no-op; 'queue' = FIFO queue. In SSR (no window) always drop. */\n mode: 'drop' | 'queue';\n maxSize: number;\n ttlMs: number;\n /** For testing: override browser check so queue works in Node. */\n isBrowserOverride?: boolean;\n}\n\nexport type FlushTrackHandler = (payload: { name: string; properties?: Record<string, unknown>; timestamp?: string }) => void;\nexport type FlushIdentifyHandler = (userId: string, traits?: Record<string, unknown>) => void;\n\n/**\n * Pre-init buffer: either drops events or queues them (FIFO) until flush.\n * In Node/SSR (typeof window === 'undefined') always behaves as drop.\n */\nexport class PreInitBuffer {\n private readonly options: PreInitBufferOptions;\n private readonly queue: BufferedItem[] = [];\n private readonly isBrowser: boolean;\n\n constructor(options: PreInitBufferOptions) {\n this.options = options;\n this.isBrowser =\n options.isBrowserOverride !== undefined ? options.isBrowserOverride : typeof window !== 'undefined';\n }\n\n /**\n * Push a track call. No-op if mode is drop or not browser (SSR).\n */\n pushTrack(name: string, properties?: Record<string, unknown>, timestamp?: string): void {\n if (this.options.mode === 'drop' || !this.isBrowser) return;\n const item: BufferedTrack = {\n type: 'track',\n name,\n properties,\n timestamp,\n createdAt: Date.now(),\n };\n this.push(item);\n }\n\n /**\n * Push an identify call. No-op if mode is drop or not browser (SSR).\n */\n pushIdentify(userId: string, traits?: Record<string, unknown>): void {\n if (this.options.mode === 'drop' || !this.isBrowser) return;\n const item: BufferedIdentify = {\n type: 'identify',\n userId,\n traits,\n createdAt: Date.now(),\n };\n this.push(item);\n }\n\n private push(item: BufferedItem): void {\n while (this.queue.length >= this.options.maxSize && this.queue.length > 0) {\n this.queue.shift(); // drop oldest (FIFO)\n }\n this.queue.push(item);\n }\n\n /**\n * Replay queued items: all identify first (order), then all track (order).\n * Items older than ttlMs are dropped. Then clear the queue.\n */\n flush(\n onTrack: FlushTrackHandler,\n onIdentify: FlushIdentifyHandler\n ): void {\n if (!this.isBrowser || this.queue.length === 0) {\n this.queue.length = 0;\n return;\n }\n const now = Date.now();\n const cutoff = now - this.options.ttlMs;\n const identifyItems = this.queue.filter(\n (item): item is BufferedIdentify => item.type === 'identify' && item.createdAt >= cutoff\n );\n const trackItems = this.queue.filter(\n (item): item is BufferedTrack => item.type === 'track' && item.createdAt >= cutoff\n );\n for (const item of identifyItems) {\n onIdentify(item.userId, item.traits);\n }\n for (const item of trackItems) {\n onTrack({\n name: item.name,\n properties: item.properties,\n timestamp: item.timestamp,\n });\n }\n this.queue.length = 0;\n }\n\n /** Number of items currently queued (for tests). */\n get length(): number {\n return this.queue.length;\n }\n}\n","import type { AnalyticsListener } from '../types/listener.js';\n\nexport interface RegisteredListener {\n id?: string;\n listener: AnalyticsListener;\n}\n\n/**\n * Holds enabled listener instances. Populated at init.\n */\nexport class ListenerRegistry {\n private readonly listeners: RegisteredListener[] = [];\n\n add(id: string | undefined, listener: AnalyticsListener): void {\n this.listeners.push({ id, listener });\n }\n\n getAll(): RegisteredListener[] {\n return [...this.listeners];\n }\n\n clear(): void {\n this.listeners.length = 0;\n }\n}\n","const STORAGE_KEY_PREFIX = 'snovasys_usage_analytics_session_';\n\n/**\n * Generate a UUID v4 (uses crypto.randomUUID when available, else fallback).\n */\nexport function generateId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return fallbackUuidV4();\n}\n\nfunction fallbackUuidV4(): string {\n const hex = '0123456789abcdef';\n let result = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';\n result = result.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return hex[v];\n });\n return result;\n}\n\n/**\n * Get or create session id. Optionally persist in sessionStorage keyed by appId.\n */\nexport function getOrCreateSessionId(appId: string, providedSessionId?: string): string {\n if (providedSessionId) return providedSessionId;\n const key = `${STORAGE_KEY_PREFIX}${appId}`;\n if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {\n try {\n const existing = sessionStorage.getItem(key);\n if (existing) return existing;\n const newId = generateId();\n sessionStorage.setItem(key, newId);\n return newId;\n } catch {\n return generateId();\n }\n }\n return generateId();\n}\n","import type { EventEnvelope } from '../types/envelope.js';\nimport { generateId, getOrCreateSessionId } from './session.js';\n\n/** Raw track payload from app (before enrichment). */\nexport interface TrackPayload {\n name: string;\n properties?: Record<string, unknown>;\n timestamp?: string;\n}\n\nexport interface EnricherState {\n appId: string;\n environment: string;\n sdkVersion: string;\n sessionId?: string;\n userId?: string;\n /** Provided at init or generated per session. */\n resolvedSessionId?: string;\n}\n\nconst ENVELOPE_VERSION = 1;\n\n/**\n * Creates enricher state from init config. Call once at init.\n */\nexport function createEnricherState(\n appId: string,\n environment: string,\n sdkVersion: string,\n sessionId?: string\n): EnricherState {\n const resolvedSessionId = getOrCreateSessionId(appId, sessionId);\n return {\n appId,\n environment,\n sdkVersion,\n sessionId,\n resolvedSessionId,\n };\n}\n\n/**\n * Enrich a raw track payload into a full EventEnvelope.\n */\nexport function enrich(\n payload: TrackPayload,\n state: EnricherState\n): EventEnvelope {\n const timestamp = payload.timestamp ?? new Date().toISOString();\n const envelope: EventEnvelope = {\n name: payload.name,\n timestamp,\n eventId: generateId(),\n appId: state.appId,\n environment: state.environment,\n sdkVersion: state.sdkVersion,\n version: ENVELOPE_VERSION,\n };\n if (payload.properties != null) envelope.properties = payload.properties;\n if (state.resolvedSessionId) envelope.sessionId = state.resolvedSessionId;\n if (state.userId) envelope.userId = state.userId;\n return envelope;\n}\n\n/**\n * Set userId (and optional traits) on state after identify. Cleared on reset.\n */\nexport function setUserId(state: EnricherState, userId: string): void {\n state.userId = userId;\n}\n\n/**\n * Clear userId from state (e.g. on reset).\n */\nexport function clearUserId(state: EnricherState): void {\n state.userId = undefined;\n}\n","import type { EventEnvelope } from '../types/envelope.js';\nimport type { OnErrorContext } from '../types/config.js';\nimport type { ListenerRegistry } from './registry.js';\nimport type { EnricherState } from '../enricher/enricher.js';\nimport { enrich, type TrackPayload } from '../enricher/enricher.js';\n\nexport interface DispatcherDeps {\n registry: ListenerRegistry;\n getEnricherState: () => EnricherState;\n onError?: (error: Error, context?: OnErrorContext) => void;\n}\n\n/**\n * Normalize payload → enrich → dispatch to all listeners (try/catch per listener).\n */\nexport function dispatchTrack(\n deps: DispatcherDeps,\n payload: TrackPayload\n): void {\n const state = deps.getEnricherState();\n const envelope = enrich(payload, state);\n dispatchEnvelope(deps, envelope, 'track');\n}\n\n/**\n * Dispatch a pre-built envelope to all listeners (e.g. after enrich).\n */\nfunction dispatchEnvelope(\n deps: DispatcherDeps,\n envelope: EventEnvelope,\n kind: 'track'\n): void {\n const { registry, onError } = deps;\n for (const { id, listener } of registry.getAll()) {\n try {\n listener.track(envelope);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error, { listenerId: id });\n }\n }\n}\n\n/**\n * Call identify on all listeners that implement it (try/catch per listener).\n */\nexport function dispatchIdentify(\n deps: DispatcherDeps,\n userId: string,\n traits?: Record<string, unknown>\n): void {\n const { registry, onError } = deps;\n for (const { id, listener } of registry.getAll()) {\n if (typeof listener.identify !== 'function') continue;\n try {\n listener.identify(userId, traits);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error, { listenerId: id });\n }\n }\n}\n","import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\n/**\n * No-op listener: implements the interface with no side effects.\n * Use when analytics is disabled or in tests.\n */\nexport function createNoopListener(): AnalyticsListener {\n return {\n init(_config: unknown): void {\n // no-op\n },\n track(_envelope: EventEnvelope): void {\n // no-op\n },\n };\n}\n\n/** Singleton no-op listener instance. */\nexport const noopListener: AnalyticsListener = createNoopListener();\n","import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\nexport interface ClarityListenerConfig {\n projectId: string;\n}\n\nconst CLARITY_SCRIPT_BASE = 'https://www.clarity.ms/tag/';\n\ndeclare global {\n interface Window {\n clarity?: (cmd: string, ...args: unknown[]) => void;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\nfunction loadClarityScript(projectId: string): Promise<void> {\n return new Promise((resolve) => {\n if (!isBrowser()) {\n resolve();\n return;\n }\n if (typeof window.clarity === 'function') {\n resolve();\n return;\n }\n const script = document.createElement('script');\n script.async = true;\n script.src = `${CLARITY_SCRIPT_BASE}${encodeURIComponent(projectId)}`;\n script.onload = () => resolve();\n script.onerror = () => resolve();\n document.head.appendChild(script);\n });\n}\n\n/**\n * Listener that sends events to Microsoft Clarity via script injection.\n * Loads Clarity script with projectId; track → clarity(\"event\", name); identify → clarity(\"identify\", userId, ...).\n * No-op when typeof window === 'undefined' (SSR).\n */\nexport function createClarityListener(config: ClarityListenerConfig): AnalyticsListener {\n const projectId = config.projectId;\n let ready = false;\n\n return {\n async init(cfg: unknown): Promise<void> {\n try {\n const c = (cfg ?? config) as ClarityListenerConfig;\n const id = c.projectId;\n if (!id || !isBrowser()) return;\n await loadClarityScript(id);\n ready = true;\n } catch {\n // swallow\n }\n },\n track(envelope: EventEnvelope): void {\n try {\n if (!isBrowser() || !ready || typeof window.clarity !== 'function') return;\n window.clarity('event', envelope.name);\n if (envelope.properties && typeof window.clarity === 'function') {\n for (const [key, value] of Object.entries(envelope.properties)) {\n if (typeof value === 'string' || Array.isArray(value)) {\n window.clarity('set', key, value);\n }\n }\n }\n } catch {\n // swallow\n }\n },\n identify(userId: string, _traits?: Record<string, unknown>): void {\n try {\n if (!isBrowser() || !ready || typeof window.clarity !== 'function') return;\n window.clarity('identify', userId, undefined, undefined, undefined);\n } catch {\n // swallow\n }\n },\n };\n}\n","import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\nexport interface GAListenerConfig {\n measurementId: string;\n}\n\nconst GTAG_SCRIPT_URL = 'https://www.googletagmanager.com/gtag/js';\n\ndeclare global {\n interface Window {\n dataLayer?: unknown[];\n gtag?: (...args: unknown[]) => void;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\nfunction loadGtagScript(measurementId: string): Promise<void> {\n return new Promise((resolve) => {\n if (!isBrowser()) {\n resolve();\n return;\n }\n if (window.gtag) {\n window.gtag('config', measurementId);\n resolve();\n return;\n }\n window.dataLayer = window.dataLayer ?? [];\n const gtag = (...args: unknown[]) => {\n window.dataLayer!.push(args);\n };\n window.gtag = gtag;\n gtag('js', new Date());\n const script = document.createElement('script');\n script.async = true;\n script.src = `${GTAG_SCRIPT_URL}?id=${encodeURIComponent(measurementId)}`;\n script.onload = () => {\n gtag('config', measurementId);\n resolve();\n };\n script.onerror = () => resolve();\n document.head.appendChild(script);\n });\n}\n\n/**\n * Listener that sends events to Google Analytics 4 via gtag.\n * Loads gtag script with measurementId; track → gtag('event', name, properties).\n * No-op when typeof window === 'undefined' (SSR).\n */\nexport function createGAListener(config: GAListenerConfig): AnalyticsListener {\n const measurementId = config.measurementId;\n let ready = false;\n\n return {\n async init(cfg: unknown): Promise<void> {\n try {\n const c = (cfg ?? config) as GAListenerConfig;\n const id = c.measurementId;\n if (!id || !isBrowser()) return;\n await loadGtagScript(id);\n ready = true;\n } catch {\n // swallow\n }\n },\n track(envelope: EventEnvelope): void {\n try {\n if (!isBrowser() || !ready || typeof window.gtag !== 'function') return;\n const params = envelope.properties ?? {};\n if (envelope.userId) (params as Record<string, unknown>)['user_id'] = envelope.userId;\n window.gtag('event', envelope.name, params);\n } catch {\n // swallow\n }\n },\n identify(userId: string, traits?: Record<string, unknown>): void {\n try {\n if (!isBrowser() || typeof window.gtag !== 'function') return;\n window.gtag('set', 'user_properties', { user_id: userId, ...traits });\n } catch {\n // swallow\n }\n },\n };\n}\n","import type { AnalyticsListener } from '../types/listener.js';\nimport type { EventEnvelope } from '../types/envelope.js';\n\nexport interface CustomApiListenerConfig {\n /** Endpoint URL for POST (e.g. https://api.example.com/analytics/events). */\n endpoint: string;\n /** Optional API key or bearer token. */\n apiKey?: string;\n /** Optional: batch size before sending. Default 1 (no batching). */\n batchSize?: number;\n /** Optional: max ms to wait before sending a partial batch. Default 5000. */\n flushIntervalMs?: number;\n}\n\nconst DEFAULT_BATCH_SIZE = 1;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5000;\n\n/**\n * Listener that POSTs events to a configurable endpoint.\n * Optional batching: accumulates events and sends when batchSize or flushIntervalMs is reached.\n */\nexport function createCustomApiListener(config: CustomApiListenerConfig): AnalyticsListener {\n const endpoint = config.endpoint;\n const apiKey = config.apiKey;\n const batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;\n const flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n\n let batch: EventEnvelope[] = [];\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n function scheduleFlush(): void {\n if (flushTimer != null) return;\n flushTimer = setTimeout(() => {\n flushTimer = null;\n sendBatch();\n }, flushIntervalMs);\n }\n\n function sendBatch(): void {\n if (batch.length === 0) return;\n const toSend = [...batch];\n batch = [];\n const body = JSON.stringify(toSend.length === 1 ? toSend[0] : { events: toSend });\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;\n if (typeof fetch !== 'undefined') {\n fetch(endpoint, {\n method: 'POST',\n headers,\n body,\n keepalive: true,\n }).catch(() => {});\n }\n }\n\n return {\n init(_config: unknown): void {\n // config was passed at createCustomApiListener\n },\n track(envelope: EventEnvelope): void {\n try {\n batch.push(envelope);\n if (batch.length >= batchSize) {\n sendBatch();\n } else if (flushIntervalMs > 0) {\n scheduleFlush();\n }\n } catch {\n // swallow\n }\n },\n flush(): Promise<void> {\n if (flushTimer != null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n sendBatch();\n return Promise.resolve();\n },\n teardown(): void {\n if (flushTimer != null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n batch.length = 0;\n },\n };\n}\n","import type { ListenerEntry, ListenerFactory, RemoteAnalyticsConfig } from '../types/config.js';\nimport type { AnalyticsListener } from '../types/listener.js';\nimport { createNoopListener } from './noop.js';\nimport { createClarityListener } from './clarity.js';\nimport { createGAListener } from './ga.js';\nimport { createCustomApiListener } from './custom-api.js';\n\n/** Built-in listener IDs supported by the SDK (noop, clarity, ga, custom-api). */\nexport const BUILT_IN_LISTENER_IDS = ['noop', 'clarity', 'ga', 'custom-api'] as const;\n\nconst BUILT_IN_FACTORIES: Record<string, ListenerFactory> = {\n noop: () => createNoopListener(),\n clarity: (config) => createClarityListener(config as { projectId: string }),\n ga: (config) => createGAListener(config as { measurementId: string }),\n 'custom-api': (config) => createCustomApiListener(config as Parameters<typeof createCustomApiListener>[0]),\n};\n\n/**\n * Returns the built-in listener factory for the given id, or undefined if unknown.\n */\nexport function getBuiltInListenerFactory(id: string): ListenerFactory | undefined {\n return BUILT_IN_FACTORIES[id];\n}\n\nexport interface BuildListenersFromRemoteConfigOptions {\n /** App override: map listener id to factory. When omitted, built-in registry is used. */\n factories?: Record<string, ListenerFactory>;\n /** Called when a remote listener id has no factory (unknown id). */\n onError?: (error: Error, context?: { listenerId?: string }) => void;\n}\n\n/**\n * Builds ListenerEntry[] from remote config. Uses options.factories when provided,\n * otherwise the built-in registry. Skips entries with enabled === false or unknown id.\n */\nexport function buildListenersFromRemoteConfig(\n remote: RemoteAnalyticsConfig,\n options?: BuildListenersFromRemoteConfigOptions\n): ListenerEntry[] {\n const factories = options?.factories ?? BUILT_IN_FACTORIES;\n const onError = options?.onError;\n const entries: ListenerEntry[] = [];\n\n if (!Array.isArray(remote.listeners)) {\n return entries;\n }\n\n for (const entry of remote.listeners) {\n if (entry.enabled === false) continue;\n const id = entry.id;\n if (id == null || typeof id !== 'string') continue;\n\n const factory = factories[id];\n if (factory == null) {\n onError?.(new Error(`Unknown listener id: ${id}`), { listenerId: id });\n continue;\n }\n\n let listener: AnalyticsListener;\n try {\n listener = factory(entry.config);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error, { listenerId: id });\n continue;\n }\n\n entries.push({\n id,\n enabled: entry.enabled,\n listener,\n config: entry.config,\n });\n }\n\n return entries;\n}\n","import type {\n AnalyticsInitConfig,\n ListenerEntry,\n PreInitBehavior,\n RemoteListenerEntry,\n} from './types/config.js';\nimport type { AnalyticsListener } from './types/listener.js';\n\nconst VALID_PRE_INIT_BEHAVIORS: PreInitBehavior[] = ['drop', 'queue'];\n\nfunction isRemoteListenerEntry(entry: unknown): entry is RemoteListenerEntry {\n if (entry == null || typeof entry !== 'object') return false;\n const o = entry as Record<string, unknown>;\n return (\n typeof o.id === 'string' &&\n o.id.trim() !== '' &&\n 'config' in o &&\n !('listener' in o && o.listener != null)\n );\n}\n\n/**\n * Validate init config. Throws with clear message on invalid config.\n * appId and environment are always taken from init options (e.g. from env files); when configUrl/getConfig is set, only listener details come from the remote source.\n */\nexport function validateConfig(options: AnalyticsInitConfig): void {\n const useRemoteConfig = Boolean(options.configUrl ?? options.getConfig);\n if (typeof options.appId !== 'string' || options.appId.trim() === '') {\n throw new Error('Analytics init failed: appId is required and must be a non-empty string (e.g. from environment variables).');\n }\n if (options.listeners != null && !Array.isArray(options.listeners)) {\n throw new Error('Analytics init failed: listeners must be an array.');\n }\n const behavior = options.preInitBehavior ?? 'drop';\n if (!VALID_PRE_INIT_BEHAVIORS.includes(behavior)) {\n throw new Error(\n `Analytics init failed: preInitBehavior must be 'queue' or 'drop', got '${behavior}'.`\n );\n }\n if (behavior === 'queue') {\n const maxSize = options.queueMaxSize ?? 100;\n const ttlMs = options.queueTtlMs ?? 5000;\n if (typeof maxSize !== 'number' || maxSize <= 0) {\n throw new Error('Analytics init failed: queueMaxSize must be a positive number.');\n }\n if (typeof ttlMs !== 'number' || ttlMs <= 0) {\n throw new Error('Analytics init failed: queueTtlMs must be a positive number.');\n }\n }\n if (useRemoteConfig) {\n return;\n }\n const listeners = options.listeners ?? [];\n const isRemoteShape = listeners.length > 0 && listeners.every(isRemoteListenerEntry);\n if (isRemoteShape) {\n for (let i = 0; i < listeners.length; i++) {\n const entry = listeners[i] as RemoteListenerEntry;\n if (entry.enabled === false) continue;\n if (typeof entry.id !== 'string' || entry.id.trim() === '') {\n throw new Error(`Analytics init failed: listeners[${i}].id is required and must be a non-empty string.`);\n }\n }\n return;\n }\n for (let i = 0; i < listeners.length; i++) {\n const entry = listeners[i] as ListenerEntry;\n if (entry.enabled === false) continue;\n if (entry.listener == null || typeof entry.listener !== 'object') {\n throw new Error(`Analytics init failed: listeners[${i}].listener is required.`);\n }\n const listener = entry.listener as AnalyticsListener;\n if (typeof listener.track !== 'function') {\n throw new Error(`Analytics init failed: listeners[${i}].listener must have a track method.`);\n }\n }\n}\n","/** SDK version; set at build time or from package.json. */\nexport const SDK_VERSION = '1.0.0';\n","import type {\n AnalyticsInitConfig,\n ListenerEntry,\n OnErrorContext,\n RemoteAnalyticsConfig,\n RemoteListenerEntry,\n} from './types/config.js';\nimport { PreInitBuffer } from './buffer/pre-init-buffer.js';\nimport { ListenerRegistry } from './dispatcher/registry.js';\nimport { dispatchTrack, dispatchIdentify } from './dispatcher/dispatcher.js';\nimport type { DispatcherDeps } from './dispatcher/dispatcher.js';\nimport {\n createEnricherState,\n setUserId,\n clearUserId,\n type EnricherState,\n} from './enricher/enricher.js';\nimport { buildListenersFromRemoteConfig } from './listeners/registry.js';\nimport { validateConfig } from './validate-config.js';\nimport { SDK_VERSION } from './version.js';\n\nlet enricherState: EnricherState | null = null;\nlet registry: ListenerRegistry | null = null;\n/** Pre-init buffer. Lazy-created on first track/identify (queue mode, defaults); replaced at init() with user options, then flushed and set null after init. */\nlet preInitBuffer: PreInitBuffer | null = null;\nlet onError: ((error: Error, context?: OnErrorContext) => void) | undefined;\nlet initialized = false;\n\n/** Default buffer before init: queue mode so events before init can be replayed. */\nfunction getOrCreatePreInitBuffer(): PreInitBuffer {\n if (preInitBuffer == null) {\n preInitBuffer = new PreInitBuffer({\n mode: 'queue',\n maxSize: 100,\n ttlMs: 5000,\n });\n }\n return preInitBuffer;\n}\n\nfunction getEnricherState(): EnricherState {\n if (enricherState == null) {\n throw new Error('Analytics not initialized.');\n }\n return enricherState;\n}\n\nasync function fetchRemoteConfig(options: AnalyticsInitConfig): Promise<RemoteAnalyticsConfig | null> {\n if (options.getConfig) {\n return options.getConfig();\n }\n if (options.configUrl) {\n const fetchFn = options.fetch ?? globalThis.fetch;\n const res = await fetchFn(options.configUrl);\n if (!res.ok) {\n throw new Error(`Analytics config fetch failed: ${res.status} ${res.statusText}`);\n }\n const json = await res.json();\n if (json == null || typeof json !== 'object') {\n throw new Error('Analytics config response must be a JSON object.');\n }\n return json as RemoteAnalyticsConfig;\n }\n return null;\n}\n\nfunction isInlineRemoteShape(listeners: unknown): listeners is RemoteListenerEntry[] {\n if (!Array.isArray(listeners) || listeners.length === 0) return false;\n return listeners.every(\n (entry): entry is RemoteListenerEntry =>\n entry != null &&\n typeof entry === 'object' &&\n typeof (entry as RemoteListenerEntry).id === 'string' &&\n 'config' in entry &&\n !('listener' in entry && (entry as ListenerEntry).listener != null)\n );\n}\n\n/**\n * Initialize the SDK. Idempotent; calling again re-applies config.\n * Pre-queued events (if queue mode) are flushed after listeners are ready.\n * When configUrl or getConfig is set, SDK fetches config and auto-configures listeners from the built-in registry (or listenerFactories).\n */\nexport async function init(options: AnalyticsInitConfig): Promise<void> {\n validateConfig(options);\n\n let appId: string;\n let environment: string;\n let listeners: ListenerEntry[];\n\n const remote = await fetchRemoteConfig(options);\n if (remote != null) {\n appId = (options.appId ?? '').toString().trim();\n environment = options.environment ?? 'production';\n if (!appId) {\n throw new Error('Analytics init failed: appId is required (set in init options, e.g. from environment variables).');\n }\n listeners = buildListenersFromRemoteConfig(remote, {\n factories: options.listenerFactories,\n onError: options.onError,\n });\n } else {\n appId = options.appId.trim();\n environment = options.environment ?? 'production';\n const rawListeners = options.listeners ?? [];\n if (isInlineRemoteShape(rawListeners)) {\n listeners = buildListenersFromRemoteConfig(\n { listeners: rawListeners },\n {\n factories: options.listenerFactories,\n onError: options.onError,\n }\n );\n } else {\n listeners = rawListeners as ListenerEntry[];\n }\n }\n\n const preInitBehavior = options.preInitBehavior ?? 'drop';\n const queueMaxSize = options.queueMaxSize ?? 100;\n const queueTtlMs = options.queueTtlMs ?? 5000;\n onError = options.onError;\n\n const mode = preInitBehavior === 'queue' ? 'queue' : 'drop';\n preInitBuffer = new PreInitBuffer({ mode, maxSize: queueMaxSize, ttlMs: queueTtlMs });\n\n enricherState = createEnricherState(appId, environment, SDK_VERSION, options.sessionId);\n registry = new ListenerRegistry();\n\n for (const entry of listeners) {\n if (entry.enabled === false) continue;\n try {\n const initResult = entry.listener.init(entry.config);\n if (initResult instanceof Promise) {\n await initResult;\n }\n registry.add(entry.id, entry.listener);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error, { listenerId: entry.id });\n }\n }\n\n const deps: DispatcherDeps = {\n registry,\n getEnricherState,\n onError,\n };\n\n if (preInitBuffer) {\n if (preInitBehavior === 'queue') {\n preInitBuffer.flush(\n (payload) => dispatchTrack(deps, payload),\n (userId, traits) => {\n setUserId(enricherState!, userId);\n dispatchIdentify(deps, userId, traits);\n }\n );\n } else {\n preInitBuffer.flush(() => {}, () => {});\n }\n preInitBuffer = null;\n }\n\n initialized = true;\n}\n\n/**\n * Track an event. Fire-and-forget. Safe before init (queued or dropped per config).\n */\nexport function track(event: { name: string; properties?: Record<string, unknown>; timestamp?: string }): void {\n if (!initialized) {\n getOrCreatePreInitBuffer().pushTrack(event.name, event.properties, event.timestamp);\n return;\n }\n const deps: DispatcherDeps = {\n registry: registry!,\n getEnricherState,\n onError,\n };\n dispatchTrack(deps, event);\n}\n\n/**\n * Identify the user. Fire-and-forget. Safe before init (queued or dropped per config).\n */\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n if (!initialized) {\n getOrCreatePreInitBuffer().pushIdentify(userId, traits);\n return;\n }\n if (enricherState) setUserId(enricherState, userId);\n const deps: DispatcherDeps = {\n registry: registry!,\n getEnricherState,\n onError,\n };\n dispatchIdentify(deps, userId, traits);\n}\n\n/**\n * Flush listeners that batch (e.g. before page unload).\n */\nexport async function flush(): Promise<void> {\n if (!initialized || registry == null) return;\n const promises: Promise<void>[] = [];\n for (const { listener } of registry.getAll()) {\n if (typeof listener.flush === 'function') {\n const result = listener.flush();\n if (result instanceof Promise) promises.push(result);\n }\n }\n await Promise.all(promises);\n}\n\n/**\n * Clear queue and teardown listeners. Useful in tests or when identity changes.\n */\nexport async function reset(): Promise<void> {\n if (preInitBuffer) {\n preInitBuffer.flush(() => {}, () => {});\n }\n if (enricherState) clearUserId(enricherState);\n if (registry) {\n for (const { listener } of registry.getAll()) {\n if (typeof listener.teardown === 'function') {\n try {\n const result = listener.teardown();\n if (result instanceof Promise) await result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error, {});\n }\n }\n }\n registry.clear();\n }\n preInitBuffer = null;\n enricherState = null;\n registry = null;\n onError = undefined;\n initialized = false;\n}\n\nexport function isInitialized(): boolean {\n return initialized;\n}\n"],"mappings":"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","names":["registry","onError","isBrowser","onError"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { A as AnalyticsListener } from './listener-CrNaKh1a.cjs';
|
|
2
|
+
export { E as EventEnvelope } from './listener-CrNaKh1a.cjs';
|
|
3
|
+
|
|
4
|
+
/** Pre-init behavior: drop events or queue them until init. */
|
|
5
|
+
type PreInitBehavior = 'drop' | 'queue';
|
|
6
|
+
/** Single listener entry passed at init. */
|
|
7
|
+
interface ListenerEntry {
|
|
8
|
+
/** Identifier for logging and onError. */
|
|
9
|
+
id?: string;
|
|
10
|
+
/** If false, listener is not registered. Default true. */
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
/** Listener instance (pass instances at init). */
|
|
13
|
+
listener: AnalyticsListener;
|
|
14
|
+
/** Opaque config passed to listener.init(config). */
|
|
15
|
+
config: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Factory that creates an AnalyticsListener from opaque config (for remote config). */
|
|
18
|
+
type ListenerFactory = (config: unknown) => AnalyticsListener;
|
|
19
|
+
/** Single listener entry in remote config (from configUrl or getConfig). */
|
|
20
|
+
interface RemoteListenerEntry {
|
|
21
|
+
id: string;
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
config: unknown;
|
|
24
|
+
}
|
|
25
|
+
/** Shape returned by config API (configUrl or getConfig). Only listeners are used by the SDK; appId and environment are taken from init options (e.g. env files). */
|
|
26
|
+
interface RemoteAnalyticsConfig {
|
|
27
|
+
/** Ignored by SDK; appId comes from init options (e.g. environment variables). */
|
|
28
|
+
appId?: string;
|
|
29
|
+
/** Ignored by SDK; environment comes from init options (e.g. environment variables). */
|
|
30
|
+
environment?: string;
|
|
31
|
+
listeners: RemoteListenerEntry[];
|
|
32
|
+
}
|
|
33
|
+
/** Error callback context when a listener fails. */
|
|
34
|
+
interface OnErrorContext {
|
|
35
|
+
listenerId?: string;
|
|
36
|
+
}
|
|
37
|
+
/** Init options for the SDK. */
|
|
38
|
+
interface AnalyticsInitConfig {
|
|
39
|
+
/** Application identifier. Required. */
|
|
40
|
+
appId: string;
|
|
41
|
+
/** Environment (e.g. production, staging, dev). Default 'production'. */
|
|
42
|
+
environment?: string;
|
|
43
|
+
/** Listeners to register. Default []. Ignored when configUrl or getConfig is set. When neither configUrl nor getConfig is set, can be ListenerEntry[] (with listener instances) or RemoteListenerEntry[] (id + config only; SDK builds listeners from built-in registry). */
|
|
44
|
+
listeners?: ListenerEntry[] | RemoteListenerEntry[];
|
|
45
|
+
/** Behavior before init: drop or queue. Default 'drop'. */
|
|
46
|
+
preInitBehavior?: PreInitBehavior;
|
|
47
|
+
/** Max queue size when preInitBehavior is 'queue'. Default 100. */
|
|
48
|
+
queueMaxSize?: number;
|
|
49
|
+
/** Queue TTL in ms when preInitBehavior is 'queue'. Default 5000. */
|
|
50
|
+
queueTtlMs?: number;
|
|
51
|
+
/** Called when a listener throws or rejects. */
|
|
52
|
+
onError?: (error: Error, context?: OnErrorContext) => void;
|
|
53
|
+
/** Optional session id; if not set, enricher generates one. */
|
|
54
|
+
sessionId?: string;
|
|
55
|
+
/** URL to fetch remote config (GET). When set with listenerFactories or built-in registry, SDK fetches and auto-configures listeners. */
|
|
56
|
+
configUrl?: string;
|
|
57
|
+
/** Alternative to configUrl: app provides config (e.g. from feature flags or authenticated API). */
|
|
58
|
+
getConfig?: () => Promise<RemoteAnalyticsConfig>;
|
|
59
|
+
/** Map listener id to factory. When configUrl/getConfig is used without this, SDK uses built-in registry (noop, clarity, ga, custom-api). */
|
|
60
|
+
listenerFactories?: Record<string, ListenerFactory>;
|
|
61
|
+
/** Optional fetch implementation (for tests or custom behavior). */
|
|
62
|
+
fetch?: typeof globalThis.fetch;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Initialize the SDK. Idempotent; calling again re-applies config.
|
|
67
|
+
* Pre-queued events (if queue mode) are flushed after listeners are ready.
|
|
68
|
+
* When configUrl or getConfig is set, SDK fetches config and auto-configures listeners from the built-in registry (or listenerFactories).
|
|
69
|
+
*/
|
|
70
|
+
declare function init(options: AnalyticsInitConfig): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Track an event. Fire-and-forget. Safe before init (queued or dropped per config).
|
|
73
|
+
*/
|
|
74
|
+
declare function track(event: {
|
|
75
|
+
name: string;
|
|
76
|
+
properties?: Record<string, unknown>;
|
|
77
|
+
timestamp?: string;
|
|
78
|
+
}): void;
|
|
79
|
+
/**
|
|
80
|
+
* Identify the user. Fire-and-forget. Safe before init (queued or dropped per config).
|
|
81
|
+
*/
|
|
82
|
+
declare function identify(userId: string, traits?: Record<string, unknown>): void;
|
|
83
|
+
/**
|
|
84
|
+
* Flush listeners that batch (e.g. before page unload).
|
|
85
|
+
*/
|
|
86
|
+
declare function flush(): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Clear queue and teardown listeners. Useful in tests or when identity changes.
|
|
89
|
+
*/
|
|
90
|
+
declare function reset(): Promise<void>;
|
|
91
|
+
declare function isInitialized(): boolean;
|
|
92
|
+
|
|
93
|
+
export { type AnalyticsInitConfig, AnalyticsListener, type ListenerEntry, type OnErrorContext, type PreInitBehavior, flush, identify, init, isInitialized, reset, track };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { A as AnalyticsListener } from './listener-CrNaKh1a.js';
|
|
2
|
+
export { E as EventEnvelope } from './listener-CrNaKh1a.js';
|
|
3
|
+
|
|
4
|
+
/** Pre-init behavior: drop events or queue them until init. */
|
|
5
|
+
type PreInitBehavior = 'drop' | 'queue';
|
|
6
|
+
/** Single listener entry passed at init. */
|
|
7
|
+
interface ListenerEntry {
|
|
8
|
+
/** Identifier for logging and onError. */
|
|
9
|
+
id?: string;
|
|
10
|
+
/** If false, listener is not registered. Default true. */
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
/** Listener instance (pass instances at init). */
|
|
13
|
+
listener: AnalyticsListener;
|
|
14
|
+
/** Opaque config passed to listener.init(config). */
|
|
15
|
+
config: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Factory that creates an AnalyticsListener from opaque config (for remote config). */
|
|
18
|
+
type ListenerFactory = (config: unknown) => AnalyticsListener;
|
|
19
|
+
/** Single listener entry in remote config (from configUrl or getConfig). */
|
|
20
|
+
interface RemoteListenerEntry {
|
|
21
|
+
id: string;
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
config: unknown;
|
|
24
|
+
}
|
|
25
|
+
/** Shape returned by config API (configUrl or getConfig). Only listeners are used by the SDK; appId and environment are taken from init options (e.g. env files). */
|
|
26
|
+
interface RemoteAnalyticsConfig {
|
|
27
|
+
/** Ignored by SDK; appId comes from init options (e.g. environment variables). */
|
|
28
|
+
appId?: string;
|
|
29
|
+
/** Ignored by SDK; environment comes from init options (e.g. environment variables). */
|
|
30
|
+
environment?: string;
|
|
31
|
+
listeners: RemoteListenerEntry[];
|
|
32
|
+
}
|
|
33
|
+
/** Error callback context when a listener fails. */
|
|
34
|
+
interface OnErrorContext {
|
|
35
|
+
listenerId?: string;
|
|
36
|
+
}
|
|
37
|
+
/** Init options for the SDK. */
|
|
38
|
+
interface AnalyticsInitConfig {
|
|
39
|
+
/** Application identifier. Required. */
|
|
40
|
+
appId: string;
|
|
41
|
+
/** Environment (e.g. production, staging, dev). Default 'production'. */
|
|
42
|
+
environment?: string;
|
|
43
|
+
/** Listeners to register. Default []. Ignored when configUrl or getConfig is set. When neither configUrl nor getConfig is set, can be ListenerEntry[] (with listener instances) or RemoteListenerEntry[] (id + config only; SDK builds listeners from built-in registry). */
|
|
44
|
+
listeners?: ListenerEntry[] | RemoteListenerEntry[];
|
|
45
|
+
/** Behavior before init: drop or queue. Default 'drop'. */
|
|
46
|
+
preInitBehavior?: PreInitBehavior;
|
|
47
|
+
/** Max queue size when preInitBehavior is 'queue'. Default 100. */
|
|
48
|
+
queueMaxSize?: number;
|
|
49
|
+
/** Queue TTL in ms when preInitBehavior is 'queue'. Default 5000. */
|
|
50
|
+
queueTtlMs?: number;
|
|
51
|
+
/** Called when a listener throws or rejects. */
|
|
52
|
+
onError?: (error: Error, context?: OnErrorContext) => void;
|
|
53
|
+
/** Optional session id; if not set, enricher generates one. */
|
|
54
|
+
sessionId?: string;
|
|
55
|
+
/** URL to fetch remote config (GET). When set with listenerFactories or built-in registry, SDK fetches and auto-configures listeners. */
|
|
56
|
+
configUrl?: string;
|
|
57
|
+
/** Alternative to configUrl: app provides config (e.g. from feature flags or authenticated API). */
|
|
58
|
+
getConfig?: () => Promise<RemoteAnalyticsConfig>;
|
|
59
|
+
/** Map listener id to factory. When configUrl/getConfig is used without this, SDK uses built-in registry (noop, clarity, ga, custom-api). */
|
|
60
|
+
listenerFactories?: Record<string, ListenerFactory>;
|
|
61
|
+
/** Optional fetch implementation (for tests or custom behavior). */
|
|
62
|
+
fetch?: typeof globalThis.fetch;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Initialize the SDK. Idempotent; calling again re-applies config.
|
|
67
|
+
* Pre-queued events (if queue mode) are flushed after listeners are ready.
|
|
68
|
+
* When configUrl or getConfig is set, SDK fetches config and auto-configures listeners from the built-in registry (or listenerFactories).
|
|
69
|
+
*/
|
|
70
|
+
declare function init(options: AnalyticsInitConfig): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Track an event. Fire-and-forget. Safe before init (queued or dropped per config).
|
|
73
|
+
*/
|
|
74
|
+
declare function track(event: {
|
|
75
|
+
name: string;
|
|
76
|
+
properties?: Record<string, unknown>;
|
|
77
|
+
timestamp?: string;
|
|
78
|
+
}): void;
|
|
79
|
+
/**
|
|
80
|
+
* Identify the user. Fire-and-forget. Safe before init (queued or dropped per config).
|
|
81
|
+
*/
|
|
82
|
+
declare function identify(userId: string, traits?: Record<string, unknown>): void;
|
|
83
|
+
/**
|
|
84
|
+
* Flush listeners that batch (e.g. before page unload).
|
|
85
|
+
*/
|
|
86
|
+
declare function flush(): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Clear queue and teardown listeners. Useful in tests or when identity changes.
|
|
89
|
+
*/
|
|
90
|
+
declare function reset(): Promise<void>;
|
|
91
|
+
declare function isInitialized(): boolean;
|
|
92
|
+
|
|
93
|
+
export { type AnalyticsInitConfig, AnalyticsListener, type ListenerEntry, type OnErrorContext, type PreInitBehavior, flush, identify, init, isInitialized, reset, track };
|