@scoperat/tracker 0.1.1 → 0.2.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,aAAa,CAAC;AAEnC,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"sources":["../src/breadcrumbs.ts","../src/context.ts","../src/errors.ts","../src/flag-client.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["export interface Breadcrumb {\n type: string;\n category: string;\n message: string;\n timestamp: number;\n data?: Record<string, unknown>;\n}\n\nconst MAX_BREADCRUMBS = 20;\nconst MAX_TEXT_LENGTH = 120;\n\nlet buffer: Breadcrumb[] = [];\nlet installed = false;\n\nfunction push(crumb: Breadcrumb): void {\n buffer.push(crumb);\n if (buffer.length > MAX_BREADCRUMBS) {\n buffer = buffer.slice(-MAX_BREADCRUMBS);\n }\n}\n\nfunction truncate(str: string, max = MAX_TEXT_LENGTH): string {\n return str.length > max ? str.slice(0, max) + \"…\" : str;\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...buffer];\n}\n\nexport function addBreadcrumb(crumb: Breadcrumb): void {\n push(crumb);\n}\n\nexport function startBreadcrumbCollection(): void {\n if (installed || typeof window === \"undefined\") return;\n installed = true;\n\n document.addEventListener(\n \"click\",\n (e) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n const text =\n target.textContent?.trim() || target.getAttribute(\"aria-label\") || \"\";\n push({\n type: \"user\",\n category: \"click\",\n message: truncate(\n `${target.tagName.toLowerCase()}${text ? ` \"${text}\"` : \"\"}`,\n ),\n timestamp: Date.now(),\n data: {\n tagName: target.tagName.toLowerCase(),\n className: target.className\n ? truncate(target.className, 80)\n : undefined,\n },\n });\n },\n { capture: true },\n );\n\n const origPushState = history.pushState;\n history.pushState = function (...args) {\n const from = location.pathname;\n origPushState.apply(this, args);\n push({\n type: \"navigation\",\n category: \"navigation\",\n message: `${from} → ${location.pathname}`,\n timestamp: Date.now(),\n });\n };\n\n window.addEventListener(\"popstate\", () => {\n push({\n type: \"navigation\",\n category: \"navigation\",\n message: `popstate → ${location.pathname}`,\n timestamp: Date.now(),\n });\n });\n\n const wrapConsole = (level: \"error\" | \"warn\") => {\n const orig = console[level];\n console[level] = (...args: unknown[]) => {\n push({\n type: \"console\",\n category: `console.${level}`,\n message: truncate(\n args.map((a) => (typeof a === \"string\" ? a : String(a))).join(\" \"),\n ),\n timestamp: Date.now(),\n });\n orig.apply(console, args);\n };\n };\n\n wrapConsole(\"error\");\n wrapConsole(\"warn\");\n}\n","/**\n * Auto-capture browser context: page, referrer, screen, locale, user agent.\n */\nexport function getBrowserContext(): Record<string, unknown> {\n if (typeof window === \"undefined\") {\n return {};\n }\n\n return {\n page: {\n url: window.location.href,\n path: window.location.pathname,\n title: document.title,\n referrer: document.referrer || undefined,\n },\n screen: {\n width: window.screen.width,\n height: window.screen.height,\n },\n locale: navigator.language,\n userAgent: navigator.userAgent,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n };\n}\n","interface TrackerLike {\n track(event: string, properties?: Record<string, unknown>): void;\n}\n\ninterface ErrorProperties {\n type: string;\n message: string;\n stack: string | undefined;\n handled: boolean;\n mechanism: string;\n source: \"browser\";\n filename?: string;\n lineno?: number;\n colno?: number;\n}\n\ntype BreadcrumbGetter = () => Array<{\n type: string;\n category: string;\n message: string;\n timestamp: number;\n data?: Record<string, unknown>;\n}>;\n\nconst DEDUP_COOLDOWN_MS = 60_000;\nconst dedupMap = new Map<string, number>();\n\nfunction simpleFingerprint(type: string, stack?: string): string {\n const firstFrame = stack?.split(\"\\n\")[1]?.trim() ?? \"\";\n return `${type}:${firstFrame}`;\n}\n\nfunction isDuplicate(fingerprint: string): boolean {\n const lastSent = dedupMap.get(fingerprint);\n if (lastSent && Date.now() - lastSent < DEDUP_COOLDOWN_MS) return true;\n dedupMap.set(fingerprint, Date.now());\n return false;\n}\n\nfunction sendException(\n tracker: TrackerLike,\n props: ErrorProperties,\n getBreadcrumbs: BreadcrumbGetter,\n): void {\n const fp = simpleFingerprint(props.type, props.stack);\n if (isDuplicate(fp)) return;\n\n tracker.track(\"$exception\", {\n ...props,\n context: { breadcrumbs: getBreadcrumbs() as unknown[] },\n });\n}\n\nexport function installGlobalHandlers(\n tracker: TrackerLike,\n getBreadcrumbs: BreadcrumbGetter,\n): void {\n if (typeof window === \"undefined\") return;\n\n window.onerror = (\n _message: string | Event,\n filename?: string,\n lineno?: number,\n colno?: number,\n error?: Error,\n ) => {\n const err = error ?? new Error(String(_message));\n sendException(\n tracker,\n {\n type: err.name || \"Error\",\n message: err.message || String(_message),\n stack: err.stack,\n handled: false,\n mechanism: \"onerror\",\n source: \"browser\",\n filename,\n lineno,\n colno,\n },\n getBreadcrumbs,\n );\n };\n\n window.onunhandledrejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const err = reason instanceof Error ? reason : new Error(String(reason));\n sendException(\n tracker,\n {\n type: err.name || \"UnhandledRejection\",\n message: err.message,\n stack: err.stack,\n handled: false,\n mechanism: \"onunhandledrejection\",\n source: \"browser\",\n },\n getBreadcrumbs,\n );\n };\n}\n","import type { EvaluatedFlag } from \"./types.js\";\n\nconst DEFAULT_FLAG_POLL_INTERVAL = 60_000;\n\nexport interface FlagClientConfig {\n endpoint: string;\n writeKey: string;\n timeout?: number;\n environment?: string;\n pollInterval?: number;\n getIdentity: () => {\n userId?: string;\n anonymousId?: string;\n orgId?: string;\n };\n /** Called when a flag is first evaluated (for impression tracking). */\n onEvaluation?: (key: string, flag: EvaluatedFlag) => void;\n}\n\nexport class FlagClient {\n private endpoint: string;\n private writeKey: string;\n private timeout: number;\n private environment: string | undefined;\n private getIdentity: FlagClientConfig[\"getIdentity\"];\n private onEvaluation: FlagClientConfig[\"onEvaluation\"];\n\n private cache = new Map<string, EvaluatedFlag>();\n private ready = false;\n private readyCallbacks: Array<() => void> = [];\n private changeListeners = new Set<() => void>();\n private evalTracked = new Set<string>();\n private timer: ReturnType<typeof setInterval> | null = null;\n\n constructor(config: FlagClientConfig) {\n this.endpoint = config.endpoint;\n this.writeKey = config.writeKey;\n this.timeout = config.timeout ?? 10_000;\n this.environment = config.environment;\n this.getIdentity = config.getIdentity;\n this.onEvaluation = config.onEvaluation;\n\n const interval = config.pollInterval ?? DEFAULT_FLAG_POLL_INTERVAL;\n this.fetch();\n this.timer = setInterval(() => this.fetch(), interval);\n }\n\n getFlag<T = unknown>(key: string, defaultValue: T): T {\n const flag = this.cache.get(key);\n if (!flag) return defaultValue;\n\n if (!this.evalTracked.has(key)) {\n this.evalTracked.add(key);\n this.onEvaluation?.(key, flag);\n }\n\n return flag.value as T;\n }\n\n onFlagsReady(callback: () => void): void {\n if (this.ready) {\n callback();\n } else {\n this.readyCallbacks.push(callback);\n }\n }\n\n onFlagChange(listener: () => void): () => void {\n this.changeListeners.add(listener);\n return () => this.changeListeners.delete(listener);\n }\n\n async refresh(): Promise<void> {\n await this.fetch();\n }\n\n destroy(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n private async fetch(): Promise<void> {\n if (!this.writeKey || !this.endpoint) return;\n\n const params = new URLSearchParams();\n if (this.environment) params.set(\"environment\", this.environment);\n const identity = this.getIdentity();\n const identifier = identity.userId ?? identity.anonymousId;\n if (identifier) params.set(\"identifier\", identifier);\n if (identity.orgId) params.set(\"orgId\", identity.orgId);\n\n const qs = params.toString();\n const url = `${this.endpoint}/api/flags${qs ? `?${qs}` : \"\"}`;\n\n try {\n const res = await globalThis.fetch(url, {\n headers: { Authorization: `Bearer ${this.writeKey}` },\n signal: AbortSignal.timeout(this.timeout),\n });\n if (!res.ok) return;\n\n const json = (await res.json()) as {\n flags: Record<string, EvaluatedFlag>;\n };\n\n this.cache.clear();\n for (const [key, flag] of Object.entries(json.flags)) {\n this.cache.set(key, flag);\n }\n\n if (!this.ready) {\n this.ready = true;\n for (const cb of this.readyCallbacks) {\n try {\n cb();\n } catch {\n // ignore callback errors\n }\n }\n this.readyCallbacks = [];\n }\n\n for (const listener of this.changeListeners) {\n try {\n listener();\n } catch {\n // ignore listener errors\n }\n }\n } catch {\n // Silently fail — flags use cached values or defaults\n }\n }\n}\n","import {\n addBreadcrumb,\n getBreadcrumbs,\n startBreadcrumbCollection,\n} from \"./breadcrumbs.js\";\nimport { getBrowserContext } from \"./context.js\";\nimport { installGlobalHandlers } from \"./errors.js\";\nimport { FlagClient } from \"./flag-client.js\";\nimport type {\n FlushResult,\n IdentifyOptions,\n IdentifyTraits,\n InitOptions,\n TrackEvent,\n} from \"./types.js\";\n\nconst DEFAULT_FLUSH_AT = 10;\nconst DEFAULT_FLUSH_INTERVAL = 3_000;\nconst DEFAULT_TIMEOUT = 10_000;\nconst DEFAULT_SESSION_TIMEOUT = 30 * 60 * 1_000; // 30 minutes\nconst MAX_BATCH_SIZE = 100;\nconst ANON_ID_KEY = \"__scoperat_anon_id\";\nconst SESSION_ID_KEY = \"__scoperat_session_id\";\nconst LAST_ACTIVITY_KEY = \"__scoperat_last_activity\";\n/**\n * Storage key for the anonymous support-ticket session token minted\n * by the server via `POST /ticket/session`. Stored as\n * `{ anonymousId, token, expiresAt }` JSON. The widget replays this\n * token on every ticket call so the server never has to trust a\n * client-supplied anonymous id (see `lib/ticket-session.ts` in the\n * API).\n */\nconst TICKET_SESSION_KEY = \"__scoperat_ticket_session\";\n\ninterface StoredTicketSession {\n anonymousId: string;\n token: string;\n expiresAt: number;\n}\n\nfunction generateAnonId(): 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\nfunction getOrCreateAnonId(): string | undefined {\n if (typeof window === \"undefined\" || typeof localStorage === \"undefined\") {\n return undefined;\n }\n\n try {\n let id = localStorage.getItem(ANON_ID_KEY);\n if (!id) {\n id = generateAnonId();\n localStorage.setItem(ANON_ID_KEY, id);\n }\n return id;\n } catch {\n return generateAnonId();\n }\n}\n\nclass TrackerImpl {\n private writeKey: string | null = null;\n private endpoint: string = \"\";\n private flushAt: number = DEFAULT_FLUSH_AT;\n private flushInterval: number = DEFAULT_FLUSH_INTERVAL;\n private timeout: number = DEFAULT_TIMEOUT;\n private onError?: (error: Error, events: TrackEvent[]) => void;\n\n private buffer: TrackEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private visibilityHandler: (() => void) | null = null;\n private userId: string | undefined;\n private orgId: string | undefined;\n private traits: IdentifyTraits = {};\n private userHash: string | undefined;\n private anonymousId: string | undefined;\n private sessionTimeout: number = DEFAULT_SESSION_TIMEOUT;\n private ticketSessionFetch: Promise<StoredTicketSession | null> | null = null;\n\n private _flagClient: FlagClient | null = null;\n\n init(writeKey: string, options: InitOptions = {}): void {\n this.writeKey = writeKey;\n this.endpoint = (\n options.endpoint ??\n globalThis.location?.origin ??\n \"\"\n ).replace(/\\/+$/, \"\");\n this.flushAt = options.flushAt ?? DEFAULT_FLUSH_AT;\n this.flushInterval = options.flushInterval ?? DEFAULT_FLUSH_INTERVAL;\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n this.onError = options.onError;\n this.sessionTimeout = options.sessionTimeout ?? DEFAULT_SESSION_TIMEOUT;\n\n this.anonymousId = getOrCreateAnonId();\n\n if (this.timer) clearInterval(this.timer);\n this.timer = setInterval(() => {\n if (this.buffer.length > 0) {\n this.flush().catch(() => {});\n }\n }, this.flushInterval);\n\n if (typeof window !== \"undefined\") {\n if (this.visibilityHandler) {\n window.removeEventListener(\"visibilitychange\", this.visibilityHandler);\n }\n this.visibilityHandler = () => {\n if (document.visibilityState === \"hidden\" && this.buffer.length > 0) {\n this.flushSync();\n }\n };\n window.addEventListener(\"visibilitychange\", this.visibilityHandler);\n }\n\n if (options.captureErrors) {\n installGlobalHandlers(this, getBreadcrumbs);\n startBreadcrumbCollection();\n }\n\n this._flagClient?.destroy();\n this._flagClient = new FlagClient({\n endpoint: this.endpoint,\n writeKey,\n timeout: this.timeout,\n environment: options.environment,\n pollInterval: options.flagPollInterval,\n getIdentity: () => ({\n userId: this.userId,\n anonymousId: this.anonymousId,\n orgId: this.orgId,\n }),\n onEvaluation: (key, flag) =>\n this.track(\"$flag_evaluation\", {\n flag_key: key,\n flag_value: flag.value,\n flag_type: flag.type,\n flag_source: flag.source,\n }),\n });\n }\n\n /** The underlying flag evaluation client. Use for direct SDK integration. */\n get flags(): FlagClient {\n if (!this._flagClient) {\n throw new Error(\"Tracker not initialized. Call init() first.\");\n }\n return this._flagClient;\n }\n\n identify(\n userId: string,\n traits?: IdentifyTraits,\n options?: IdentifyOptions,\n ): void {\n this.userId = userId;\n if (traits) {\n this.traits = { ...traits };\n if (traits.orgId) this.orgId = traits.orgId;\n }\n // Switching from one identified user to another invalidates the\n // prior userHash — callers must either pass a new one or accept\n // that ticket calls degrade to the anonymous session channel.\n this.userHash = options?.userHash;\n\n for (const evt of this.buffer) {\n if (!evt.user_id) evt.user_id = userId;\n if (!evt.org_id && this.orgId) evt.org_id = this.orgId;\n }\n\n this._flagClient?.refresh();\n }\n\n reset(): void {\n this.userId = undefined;\n this.orgId = undefined;\n this.traits = {};\n this.userHash = undefined;\n this.anonymousId = getOrCreateAnonId();\n this.clearSession();\n this.clearTicketSession();\n }\n\n private clearTicketSession(): void {\n this.ticketSessionFetch = null;\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.removeItem(TICKET_SESSION_KEY);\n } catch {\n // ignore storage errors\n }\n }\n\n private readStoredTicketSession(): StoredTicketSession | null {\n if (typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(TICKET_SESSION_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as Partial<StoredTicketSession>;\n if (\n typeof parsed.anonymousId === \"string\" &&\n typeof parsed.token === \"string\" &&\n typeof parsed.expiresAt === \"number\" &&\n parsed.expiresAt > Date.now() + 60_000\n ) {\n return parsed as StoredTicketSession;\n }\n localStorage.removeItem(TICKET_SESSION_KEY);\n } catch {\n // fall through to network fetch\n }\n return null;\n }\n\n /**\n * @internal Used by the widget API helpers. Returns a cached or\n * newly-minted anonymous session token, or `null` if the server\n * has anonymous sessions disabled. Coalesces concurrent callers\n * onto a single in-flight network request so mount-time parallel\n * API calls don't each trigger a `POST /ticket/session`.\n */\n _ensureTicketSession(): Promise<StoredTicketSession | null> {\n const cached = this.readStoredTicketSession();\n if (cached) return Promise.resolve(cached);\n\n if (this.ticketSessionFetch) return this.ticketSessionFetch;\n if (!this.writeKey) return Promise.resolve(null);\n\n this.ticketSessionFetch = (async () => {\n try {\n const res = await fetch(`${this.endpoint}/api/ingest/ticket/session`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.writeKey}`,\n },\n body: \"{}\",\n signal: AbortSignal.timeout(this.timeout),\n });\n if (!res.ok) return null;\n const json = (await res.json()) as StoredTicketSession;\n if (\n typeof json?.anonymousId === \"string\" &&\n typeof json?.token === \"string\" &&\n typeof json?.expiresAt === \"number\"\n ) {\n try {\n localStorage?.setItem(TICKET_SESSION_KEY, JSON.stringify(json));\n } catch {\n // ignore storage errors\n }\n // Keep our in-memory anonymousId in sync with the\n // server-issued one so any code that reads `_getIdentity`\n // outside the ticket flow (e.g. analytics) sees a\n // consistent value.\n this.anonymousId = json.anonymousId;\n return json;\n }\n return null;\n } catch {\n return null;\n } finally {\n this.ticketSessionFetch = null;\n }\n })();\n\n return this.ticketSessionFetch;\n }\n\n private getOrCreateSessionId(): string | undefined {\n if (typeof window === \"undefined\") return undefined;\n\n try {\n const now = Date.now();\n const lastActivity = localStorage.getItem(LAST_ACTIVITY_KEY);\n const existingId = sessionStorage.getItem(SESSION_ID_KEY);\n\n const expired =\n !lastActivity || now - Number(lastActivity) > this.sessionTimeout;\n\n if (existingId && !expired) {\n localStorage.setItem(LAST_ACTIVITY_KEY, String(now));\n return existingId;\n }\n\n const newId = generateAnonId();\n sessionStorage.setItem(SESSION_ID_KEY, newId);\n localStorage.setItem(LAST_ACTIVITY_KEY, String(now));\n return newId;\n } catch {\n return generateAnonId();\n }\n }\n\n private clearSession(): void {\n if (typeof window === \"undefined\") return;\n try {\n sessionStorage.removeItem(SESSION_ID_KEY);\n localStorage.removeItem(LAST_ACTIVITY_KEY);\n } catch {\n // Ignore storage errors\n }\n }\n\n getSessionId(): string | undefined {\n return this.getOrCreateSessionId();\n }\n\n /** @internal Used by the widget to read tracker config. */\n _getEndpoint(): string {\n return this.endpoint;\n }\n\n /** @internal Used by the widget to read the write key. */\n _getWriteKey(): string | null {\n return this.writeKey;\n }\n\n /** @internal Used by the widget to read the current user identity. */\n _getIdentity(): {\n userId?: string;\n anonymousId?: string;\n email?: string;\n name?: string;\n userHash?: string;\n } {\n return {\n userId: this.userId,\n anonymousId: this.anonymousId,\n email: this.traits.email as string | undefined,\n name: this.traits.name as string | undefined,\n userHash: this.userHash,\n };\n }\n\n captureException(error: Error, context?: Record<string, unknown>): void {\n if (!this.writeKey) return;\n\n const breadcrumbs = getBreadcrumbs();\n this.track(\"$exception\", {\n type: error.name || \"Error\",\n message: error.message,\n stack: error.stack,\n handled: true,\n mechanism: (context?.mechanism as string) ?? \"manual\",\n source: \"browser\",\n ...context,\n context: { breadcrumbs: breadcrumbs as unknown[] },\n });\n }\n\n addBreadcrumb(\n category: string,\n message: string,\n data?: Record<string, unknown>,\n ): void {\n addBreadcrumb({\n type: \"custom\",\n category,\n message,\n timestamp: Date.now(),\n data,\n });\n }\n\n track(event: string, properties?: Record<string, unknown>): void;\n track(event: TrackEvent): void;\n track(\n eventOrName: string | TrackEvent,\n properties?: Record<string, unknown>,\n ): void {\n if (!this.writeKey) return;\n\n const evt: TrackEvent =\n typeof eventOrName === \"string\"\n ? { event: eventOrName, properties }\n : eventOrName;\n\n const traitsContext =\n Object.keys(this.traits).length > 0 ? { traits: this.traits } : {};\n\n const enriched: TrackEvent = {\n ...evt,\n occurred_at: evt.occurred_at ?? new Date().toISOString(),\n source: evt.source ?? \"browser\",\n org_id: evt.org_id ?? this.orgId,\n user_id: evt.user_id ?? this.userId,\n anonymous_id: evt.anonymous_id ?? this.anonymousId,\n session_id: evt.session_id ?? this.getOrCreateSessionId(),\n context: {\n ...getBrowserContext(),\n ...traitsContext,\n ...evt.context,\n },\n };\n\n this.buffer.push(enriched);\n\n if (this.buffer.length >= this.flushAt) {\n this.flush().catch(() => {});\n }\n }\n\n async flush(): Promise<FlushResult> {\n if (!this.writeKey || this.buffer.length === 0) {\n return { success: true, ingested: 0 };\n }\n\n const batch = this.buffer.splice(0, MAX_BATCH_SIZE);\n\n try {\n const res = await fetch(`${this.endpoint}/api/ingest/track`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.writeKey}`,\n },\n body: JSON.stringify({ events: batch }),\n signal: AbortSignal.timeout(this.timeout),\n });\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`API returned ${res.status}: ${body}`);\n }\n\n const json = (await res.json()) as { ingested: number };\n return { success: true, ingested: json.ingested };\n } catch (error) {\n this.buffer.unshift(...batch);\n const err = error instanceof Error ? error : new Error(String(error));\n this.onError?.(err, batch);\n return { success: false, ingested: 0 };\n }\n }\n\n private flushSync(): void {\n if (!this.writeKey) return;\n if (typeof navigator === \"undefined\" || !navigator.sendBeacon) return;\n if (this.buffer.length === 0) return;\n\n const batch = this.buffer.splice(0, MAX_BATCH_SIZE);\n const payload = JSON.stringify({ events: batch });\n const url = `${this.endpoint}/api/ingest/track?key=${encodeURIComponent(this.writeKey)}`;\n\n try {\n const blob = new Blob([payload], { type: \"application/json\" });\n navigator.sendBeacon(url, blob);\n } catch {\n // Best effort on unload\n }\n }\n\n getFlag<T = unknown>(key: string, defaultValue: T): T {\n return this._flagClient?.getFlag(key, defaultValue) ?? defaultValue;\n }\n\n onFlagsReady(callback: () => void): void {\n this._flagClient?.onFlagsReady(callback);\n }\n\n onFlagChange(listener: () => void): () => void {\n return this._flagClient?.onFlagChange(listener) ?? (() => {});\n }\n\n async refreshFlags(): Promise<void> {\n await this._flagClient?.refresh();\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n\n this._flagClient?.destroy();\n this._flagClient = null;\n\n if (typeof window !== \"undefined\" && this.visibilityHandler) {\n window.removeEventListener(\"visibilitychange\", this.visibilityHandler);\n this.visibilityHandler = null;\n }\n\n while (this.buffer.length > 0) {\n await this.flush();\n }\n }\n}\n\nconst scoperat = new TrackerImpl();\nexport default scoperat;\n","import scoperat from \"./client.js\";\n\nexport default scoperat;\nexport { FlagClient } from \"./flag-client.js\";\nexport type {\n EvaluatedFlag,\n EventSource,\n FlushResult,\n IdentifyOptions,\n IdentifyTraits,\n InitOptions,\n TrackEvent,\n} from \"./types.js\";\n"],"mappings":"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","names":["getBreadcrumbs"]}
@@ -0,0 +1,41 @@
1
+ interface WidgetOptions {
2
+ position?: "bottom-right" | "bottom-left";
3
+ darkMode?: boolean;
4
+ theme?: WidgetTheme;
5
+ labels?: {
6
+ title?: string;
7
+ newTicket?: string;
8
+ placeholder?: string;
9
+ };
10
+ }
11
+ interface WidgetTheme {
12
+ primaryColor?: string;
13
+ textColor?: string;
14
+ backgroundColor?: string;
15
+ fontFamily?: string;
16
+ }
17
+ type TicketCategoryValue = "bug" | "feature_request" | "question" | "access_issue" | "performance" | "billing" | "documentation" | "other";
18
+
19
+ /**
20
+ * Initialize and render the support widget.
21
+ * Mounts inside a Shadow DOM for style isolation.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import scoperat from '@scoperat/tracker';
26
+ * import { initWidget } from '@scoperat/tracker/widget';
27
+ *
28
+ * scoperat.init('tk_live_...', { endpoint: 'https://app.scoperat.ai' });
29
+ * scoperat.identify('user-123', { email: 'user@co.com', name: 'Jane' });
30
+ *
31
+ * initWidget({ position: 'bottom-right' });
32
+ * ```
33
+ */
34
+ declare function initWidget(options?: WidgetOptions): void;
35
+ /**
36
+ * Unmount and remove the support widget from the DOM.
37
+ * After calling this, `initWidget` can be called again to re-mount.
38
+ */
39
+ declare function destroyWidget(): void;
40
+
41
+ export { type TicketCategoryValue, type WidgetOptions, type WidgetTheme, destroyWidget, initWidget };