@layers/client 1.2.0 → 1.3.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.
@@ -253,6 +253,8 @@ declare class LayersClient {
253
253
  screen(screenName: string, properties?: EventProperties): void;
254
254
  /** Set or update user-level properties that persist across sessions. */
255
255
  setUserProperties(properties: UserProperties): void;
256
+ /** Set user-level properties with "set once" semantics — only keys not previously set are applied. */
257
+ setUserPropertiesOnce(properties: UserProperties): void;
256
258
  /** Update the user's consent state for analytics and advertising data collection. */
257
259
  setConsent(consent: ConsentState): void;
258
260
  /** Associate all subsequent events with the given user ID, or clear it with `undefined`. */
@@ -302,4 +304,4 @@ declare class LayersClient {
302
304
  }
303
305
  //#endregion
304
306
  export { LayersError as _, getAttribution as a, ConsentPayload as c, SKANPostbackPayload as d, UserPropertiesPayload as f, EventProperties as g, Environment as h, AttributionData as i, EventsBatchPayload as l, DeviceContext as m, LayersClient as n, getAttributionProperties as o, ConsentState as p, LayersConfig as r, BaseEvent as s, ErrorListener as t, RemoteConfigResponse as u, UserProperties as v };
305
- //# sourceMappingURL=index-DGDLULwp.d.ts.map
307
+ //# sourceMappingURL=index-CJMJEjVd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CJMJEjVd.d.ts","names":[],"sources":["../../wasm/src/types.ts","../src/api-types.ts","../src/attribution.ts","../src/index.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as LayersError, a as getAttribution, c as ConsentPayload, d as SKANPostbackPayload, f as UserPropertiesPayload, g as EventProperties, h as Environment, i as AttributionData, l as EventsBatchPayload, m as DeviceContext, n as LayersClient, o as getAttributionProperties, p as ConsentState, r as LayersConfig, s as BaseEvent, t as ErrorListener, u as RemoteConfigResponse, v as UserProperties } from "./index-DGDLULwp.js";
1
+ import { _ as LayersError, a as getAttribution, c as ConsentPayload, d as SKANPostbackPayload, f as UserPropertiesPayload, g as EventProperties, h as Environment, i as AttributionData, l as EventsBatchPayload, m as DeviceContext, n as LayersClient, o as getAttributionProperties, p as ConsentState, r as LayersConfig, s as BaseEvent, t as ErrorListener, u as RemoteConfigResponse, v as UserProperties } from "./index-CJMJEjVd.js";
2
2
  export { AttributionData, BaseEvent, ConsentPayload, ConsentState, DeviceContext, Environment, ErrorListener, EventProperties, EventsBatchPayload, LayersClient, LayersConfig, LayersError, RemoteConfigResponse, SKANPostbackPayload, UserProperties, UserPropertiesPayload, getAttribution, getAttributionProperties };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { i as getAttributionProperties, n as LayersError, r as getAttribution, t as LayersClient } from "./src-DQ_-NO-4.js";
1
+ import { i as getAttributionProperties, n as LayersError, r as getAttribution, t as LayersClient } from "./src-CHAudwOt.js";
2
2
 
3
3
  export { LayersClient, LayersError, getAttribution, getAttributionProperties };
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { g as EventProperties, n as LayersClient, p as ConsentState, r as LayersConfig } from "./index-DGDLULwp.js";
1
+ import { g as EventProperties, n as LayersClient, p as ConsentState, r as LayersConfig } from "./index-CJMJEjVd.js";
2
2
  import { ReactNode } from "react";
3
3
  import * as react_jsx_runtime0 from "react/jsx-runtime";
4
4
 
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as LayersClient } from "./src-DQ_-NO-4.js";
1
+ import { t as LayersClient } from "./src-CHAudwOt.js";
2
2
  import { createContext, useCallback, useContext, useEffect, useRef } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
 
@@ -204,6 +204,10 @@ var LayersClient = class {
204
204
  setUserProperties(properties) {
205
205
  this.core.setUserProperties(properties);
206
206
  }
207
+ /** Set user-level properties with "set once" semantics — only keys not previously set are applied. */
208
+ setUserPropertiesOnce(properties) {
209
+ this.core.setUserPropertiesOnce(properties);
210
+ }
207
211
  /** Update the user's consent state for analytics and advertising data collection. */
208
212
  setConsent(consent) {
209
213
  this.core.setConsent(consent);
@@ -396,4 +400,4 @@ const SDK_VERSION = typeof __LAYERS_CLIENT_VERSION__ !== "undefined" ? __LAYERS_
396
400
 
397
401
  //#endregion
398
402
  export { getAttributionProperties as i, LayersError$1 as n, getAttribution as r, LayersClient as t };
399
- //# sourceMappingURL=src-DQ_-NO-4.js.map
403
+ //# sourceMappingURL=src-CHAudwOt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-CHAudwOt.js","names":["params: URLSearchParams","clickIdParam: string | undefined","clickIdValue: string | undefined","utms: Partial<Pick<AttributionData, (typeof UTM_PARAMS)[number]>>","data: AttributionData","props: Record<string, string>","context: DeviceContext","SDK_VERSION: string"],"sources":["../src/attribution.ts","../src/index.ts"],"sourcesContent":["const CLICK_ID_PARAMS = [\n 'fbclid',\n 'gclid',\n 'gbraid',\n 'wbraid',\n 'ttclid',\n 'msclkid',\n 'rclid'\n] as const;\nconst UTM_PARAMS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'] as const;\nconst STORAGE_KEY = 'layers_attribution';\nconst TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days\n\nexport interface AttributionData {\n click_id_param?: string;\n click_id_value?: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_content?: string;\n utm_term?: string;\n referrer_url?: string;\n captured_at: number;\n}\n\n/**\n * Capture attribution signals from the current page URL and referrer.\n * Persists to localStorage with a 30-day TTL. Click IDs take priority:\n * if a new click ID is present, the entire record is overwritten.\n */\nexport function captureAttribution(): void {\n if (typeof window === 'undefined' || typeof localStorage === 'undefined') return;\n\n let params: URLSearchParams;\n try {\n params = new URLSearchParams(window.location.search);\n } catch {\n return;\n }\n\n // Check for click IDs first — any click ID overwrites the stored record\n let clickIdParam: string | undefined;\n let clickIdValue: string | undefined;\n for (const param of CLICK_ID_PARAMS) {\n const value = params.get(param);\n if (value) {\n clickIdParam = param;\n clickIdValue = value;\n break; // first match wins\n }\n }\n\n // Collect UTM params\n const utms: Partial<Pick<AttributionData, (typeof UTM_PARAMS)[number]>> = {};\n let hasUtm = false;\n for (const param of UTM_PARAMS) {\n const value = params.get(param);\n if (value) {\n utms[param] = value;\n hasUtm = true;\n }\n }\n\n const referrer =\n typeof document !== 'undefined' && document.referrer ? document.referrer : undefined;\n\n // Nothing to capture\n if (!clickIdParam && !hasUtm && !referrer) return;\n\n const existing = getAttribution();\n\n // If a new click ID is present, overwrite entirely\n if (clickIdParam) {\n const data: AttributionData = {\n click_id_param: clickIdParam,\n ...(clickIdValue != null && { click_id_value: clickIdValue }),\n ...utms,\n ...(referrer != null && { referrer_url: referrer }),\n captured_at: Date.now()\n };\n writeAttribution(data);\n return;\n }\n\n // If UTMs are present, overwrite (fresh campaign visit)\n if (hasUtm) {\n const data: AttributionData = {\n // Preserve existing click ID if no new one\n ...(existing?.click_id_param != null && { click_id_param: existing.click_id_param }),\n ...(existing?.click_id_value != null && { click_id_value: existing.click_id_value }),\n ...utms,\n ...(referrer != null && { referrer_url: referrer }),\n captured_at: Date.now()\n };\n writeAttribution(data);\n return;\n }\n\n // Only referrer and no existing attribution — store it\n if (!existing) {\n const data: AttributionData = {\n ...(referrer != null && { referrer_url: referrer }),\n captured_at: Date.now()\n };\n writeAttribution(data);\n }\n}\n\n/**\n * Read stored attribution data, returning null if missing or expired.\n */\nexport function getAttribution(): AttributionData | null {\n if (typeof localStorage === 'undefined') return null;\n\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return null;\n\n const data: AttributionData = JSON.parse(raw);\n if (Date.now() - data.captured_at > TTL_MS) {\n localStorage.removeItem(STORAGE_KEY);\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\n/**\n * Return a flat property bag suitable for merging into event properties.\n * Keys are prefixed with `$attribution_` to avoid collisions.\n */\nexport function getAttributionProperties(): Record<string, string> {\n const data = getAttribution();\n if (!data) return {};\n\n const props: Record<string, string> = {};\n\n if (data.click_id_param) props['$attribution_click_id_param'] = data.click_id_param;\n if (data.click_id_value) props['$attribution_click_id_value'] = data.click_id_value;\n if (data.utm_source) props['$attribution_utm_source'] = data.utm_source;\n if (data.utm_medium) props['$attribution_utm_medium'] = data.utm_medium;\n if (data.utm_campaign) props['$attribution_utm_campaign'] = data.utm_campaign;\n if (data.utm_content) props['$attribution_utm_content'] = data.utm_content;\n if (data.utm_term) props['$attribution_utm_term'] = data.utm_term;\n if (data.referrer_url) props['$attribution_referrer_url'] = data.referrer_url;\n\n return props;\n}\n\nfunction writeAttribution(data: AttributionData): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n } catch {\n // localStorage full or unavailable — silently ignore\n }\n}\n","// @layers/client — Web browser SDK.\n// Thin wrapper over @layers/core-wasm. Owns only:\n// - localStorage persistence\n// - window online/offline detection\n// - navigator device info\n// - visibilitychange / beforeunload flush\nimport {\n FetchHttpClient,\n LayersCore,\n LayersError,\n createDefaultPersistence\n} from '@layers/core-wasm';\nimport type {\n ConsentState,\n DeviceContext,\n Environment,\n EventProperties,\n UserProperties\n} from '@layers/core-wasm';\n\nimport { captureAttribution, getAttributionProperties } from './attribution.js';\n\nexport type {\n ConsentState,\n DeviceContext,\n Environment,\n EventProperties,\n UserProperties\n} from '@layers/core-wasm';\n\nexport { LayersError } from '@layers/core-wasm';\n\nexport * from './api-types.js';\nexport type { AttributionData } from './attribution.js';\nexport { getAttribution, getAttributionProperties } from './attribution.js';\n\nexport interface LayersConfig {\n /** Unique application identifier issued by the Layers dashboard. */\n appId: string;\n /** Deployment environment label. @default \"production\" */\n environment: Environment;\n /** Optional user identifier to associate events with from the start. */\n appUserId?: string;\n /** Enable verbose debug logging to the console. @default false */\n enableDebug?: boolean;\n /** Base URL for the Layers ingest API. @default \"https://in.layers.com\" */\n baseUrl?: string;\n /** How often the event queue is flushed, in milliseconds. @default 30000 */\n flushIntervalMs?: number;\n /** Number of queued events that triggers an automatic flush. @default 10 */\n flushThreshold?: number;\n /** Maximum number of events to hold in the queue before dropping. @default 1000 */\n maxQueueSize?: number;\n}\n\nexport type ErrorListener = (error: Error) => void;\n\nexport class LayersClient {\n private core: LayersCore;\n private appUserId: string | undefined;\n private isOnline = true;\n private readonly enableDebug: boolean;\n private readonly baseUrl: string;\n\n // Stored listener references for cleanup on shutdown\n private onlineListener: (() => void) | null = null;\n private offlineListener: (() => void) | null = null;\n private visibilityListener: (() => void) | null = null;\n private beforeUnloadListener: (() => void) | null = null;\n\n // Error listeners\n private readonly errorListeners: Set<ErrorListener> = new Set();\n\n constructor(config: LayersConfig) {\n this.enableDebug = config.enableDebug ?? false;\n this.baseUrl = (config.baseUrl ?? 'https://in.layers.com').replace(/\\/$/, '');\n this.appUserId = config.appUserId;\n\n const persistence = createDefaultPersistence(config.appId);\n const httpClient = new FetchHttpClient();\n\n this.core = LayersCore.init({\n config: {\n appId: config.appId,\n environment: config.environment,\n ...(config.baseUrl != null && { baseUrl: config.baseUrl }),\n ...(config.enableDebug != null && { enableDebug: config.enableDebug }),\n ...(config.flushIntervalMs != null && { flushIntervalMs: config.flushIntervalMs }),\n ...(config.flushThreshold != null && { flushThreshold: config.flushThreshold }),\n ...(config.maxQueueSize != null && { maxQueueSize: config.maxQueueSize }),\n sdkVersion: `client/${SDK_VERSION}`\n },\n httpClient,\n persistence\n });\n\n if (this.appUserId) {\n this.core.identify(this.appUserId);\n }\n }\n\n /** Initialize the client: detects device info, attaches lifecycle listeners, and fetches remote config. */\n async init(): Promise<void> {\n this.initializeDeviceInfo();\n this.setupNetworkListener();\n this.setupLifecycleListeners();\n captureAttribution();\n await this.core.fetchRemoteConfig().catch(() => {\n // Remote config fetch is best-effort\n });\n }\n\n /**\n * Record a custom analytics event with an optional property bag.\n *\n * Events are batched and flushed automatically when the queue reaches\n * `flushThreshold` or the periodic flush timer fires.\n */\n track(eventName: string, properties?: EventProperties): void {\n if (this.enableDebug) {\n console.log(\n `[Layers] track(\"${eventName}\", ${Object.keys(properties ?? {}).length} properties)`\n );\n }\n try {\n const merged = { ...getAttributionProperties(), ...properties };\n this.core.track(eventName, merged, this.appUserId);\n } catch (e) {\n this.emitError(e);\n }\n }\n\n /**\n * Record a screen view event with an optional property bag.\n *\n * Events are batched and flushed automatically when the queue reaches\n * `flushThreshold` or the periodic flush timer fires.\n */\n screen(screenName: string, properties?: EventProperties): void {\n if (this.enableDebug) {\n console.log(\n `[Layers] screen(\"${screenName}\", ${Object.keys(properties ?? {}).length} properties)`\n );\n }\n try {\n const merged = { ...getAttributionProperties(), ...properties };\n this.core.screen(screenName, merged, this.appUserId);\n } catch (e) {\n this.emitError(e);\n }\n }\n\n /** Set or update user-level properties that persist across sessions. */\n setUserProperties(properties: UserProperties): void {\n this.core.setUserProperties(properties);\n }\n\n /** Set user-level properties with \"set once\" semantics — only keys not previously set are applied. */\n setUserPropertiesOnce(properties: UserProperties): void {\n this.core.setUserPropertiesOnce(properties);\n }\n\n /** Update the user's consent state for analytics and advertising data collection. */\n setConsent(consent: ConsentState): void {\n this.core.setConsent(consent);\n }\n\n /** Associate all subsequent events with the given user ID, or clear it with `undefined`. */\n setAppUserId(appUserId: string | undefined): void {\n if (this.enableDebug) {\n console.log(`[Layers] setAppUserId(${appUserId ? `\"${appUserId}\"` : 'undefined'})`);\n }\n this.appUserId = appUserId;\n if (appUserId) {\n this.core.identify(appUserId);\n } else {\n this.core.identify('');\n }\n }\n\n /** @deprecated Use setAppUserId instead */\n setUserId(userId: string): void {\n this.setAppUserId(userId);\n }\n\n /** Return the current app user ID, or `undefined` if not set. */\n getAppUserId(): string | undefined {\n return this.appUserId;\n }\n\n /** @deprecated Use getAppUserId instead */\n getUserId(): string | undefined {\n return this.appUserId;\n }\n\n /** Return the current anonymous session ID. */\n getSessionId(): string {\n return this.core.getSessionId();\n }\n\n /** Return the current consent state for analytics and advertising. */\n getConsentState(): ConsentState {\n return this.core.getConsentState();\n }\n\n /** Override device-level context fields (platform, OS, locale, etc.). */\n setDeviceInfo(deviceInfo: DeviceContext): void {\n this.core.setDeviceContext(deviceInfo);\n }\n\n /** Flush all queued events to the server. Falls back to synchronous persistence on failure. */\n async flush(): Promise<void> {\n try {\n await this.core.flushAsync();\n } catch (e) {\n this.emitError(e);\n this.core.flush();\n }\n }\n\n /** Immediately shut down the client, removing all event listeners. Queued events are persisted but not flushed. */\n shutdown(): void {\n this.cleanupListeners();\n this.core.shutdown();\n }\n\n /**\n * Async shutdown: flushes remaining events before shutting down.\n * @param timeoutMs Maximum time to wait for flush (default 3000ms).\n */\n async shutdownAsync(timeoutMs = 3000): Promise<void> {\n this.cleanupListeners();\n try {\n await Promise.race([\n this.core.flushAsync(),\n new Promise<void>((resolve) => setTimeout(resolve, timeoutMs))\n ]);\n } catch {\n // Best effort — proceed with shutdown\n }\n this.core.shutdown();\n }\n\n private cleanupListeners(): void {\n if (typeof window !== 'undefined') {\n if (this.onlineListener) {\n window.removeEventListener('online', this.onlineListener);\n this.onlineListener = null;\n }\n if (this.offlineListener) {\n window.removeEventListener('offline', this.offlineListener);\n this.offlineListener = null;\n }\n if (this.beforeUnloadListener) {\n window.removeEventListener('beforeunload', this.beforeUnloadListener);\n this.beforeUnloadListener = null;\n }\n }\n if (typeof document !== 'undefined' && this.visibilityListener) {\n document.removeEventListener('visibilitychange', this.visibilityListener);\n this.visibilityListener = null;\n }\n }\n\n /** End the current session and start a new one with a fresh session ID. */\n startNewSession(): void {\n this.core.startNewSession();\n }\n\n /**\n * Register an error listener. Errors from track/screen/flush\n * that would otherwise be silently dropped are forwarded here.\n */\n on(event: 'error', listener: ErrorListener): this {\n if (event === 'error') this.errorListeners.add(listener);\n return this;\n }\n\n /**\n * Remove a previously registered error listener.\n */\n off(event: 'error', listener: ErrorListener): this {\n if (event === 'error') this.errorListeners.delete(listener);\n return this;\n }\n\n private emitError(error: unknown): void {\n const err = error instanceof Error ? error : new Error(String(error));\n for (const listener of this.errorListeners) {\n try {\n listener(err);\n } catch {}\n }\n if (this.enableDebug && this.errorListeners.size === 0) {\n console.warn('[Layers]', err.message);\n }\n }\n\n // --- Platform-specific: browser device info ---\n\n private initializeDeviceInfo(): void {\n const context: DeviceContext = {\n platform: 'web',\n osVersion: this.detectOS(),\n appVersion: SDK_VERSION,\n deviceModel: this.detectDeviceModel(),\n locale: this.detectLocale(),\n screenSize: this.detectScreenSize(),\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone\n };\n this.core.setDeviceContext(context);\n }\n\n private detectOS(): string {\n if (typeof navigator === 'undefined') return 'unknown';\n const ua = navigator.userAgent;\n if (ua.includes('Windows')) return 'Windows';\n if (ua.includes('Mac OS')) return 'macOS';\n if (ua.includes('Linux')) return 'Linux';\n if (ua.includes('Android')) return 'Android';\n if (ua.includes('iPhone') || ua.includes('iPad')) return 'iOS';\n return 'unknown';\n }\n\n private detectDeviceModel(): string {\n if (typeof navigator === 'undefined') return 'unknown';\n if ('userAgentData' in navigator) {\n const uaData = (navigator as { userAgentData?: { platform?: string } }).userAgentData;\n if (uaData?.platform) return uaData.platform;\n }\n return navigator.platform ?? 'unknown';\n }\n\n private detectLocale(): string {\n if (typeof navigator === 'undefined') return 'en-US';\n return navigator.language ?? 'en-US';\n }\n\n private detectScreenSize(): string {\n if (typeof window === 'undefined' || typeof screen === 'undefined') return 'unknown';\n return `${screen.width}x${screen.height}`;\n }\n\n // --- Platform-specific: network listener ---\n\n private setupNetworkListener(): void {\n if (typeof window === 'undefined') return;\n\n this.isOnline = navigator?.onLine ?? true;\n\n this.onlineListener = () => {\n this.isOnline = true;\n void this.core.flushAsync().catch(() => {});\n };\n this.offlineListener = () => {\n this.isOnline = false;\n };\n\n window.addEventListener('online', this.onlineListener);\n window.addEventListener('offline', this.offlineListener);\n }\n\n // --- Platform-specific: lifecycle listeners ---\n\n private getBeaconUrl(): string {\n return `${this.baseUrl}/events`;\n }\n\n private setupLifecycleListeners(): void {\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n\n // Flush on page hide / visibility change.\n // Use sendBeacon for best-effort network delivery before the page is hidden.\n // Falls back to synchronous localStorage persistence if sendBeacon fails.\n this.visibilityListener = () => {\n if (document.visibilityState === 'hidden') {\n if (\n typeof navigator !== 'undefined' &&\n navigator.sendBeacon &&\n this.core.queueDepth() > 0\n ) {\n try {\n const batch = this.core.createBeaconPayload();\n if (batch) {\n const sent = navigator.sendBeacon(this.getBeaconUrl(), batch);\n if (sent) {\n this.core.clearBeaconEvents();\n return;\n }\n // sendBeacon failed — requeue events before falling back to persistence\n this.core.requeueBeaconEvents();\n this.core.flush();\n return;\n }\n } catch {\n // sendBeacon threw — requeue any drained events before sync flush\n this.core.requeueBeaconEvents();\n }\n }\n this.core.flush();\n }\n };\n document.addEventListener('visibilitychange', this.visibilityListener);\n\n // Flush on beforeunload — synchronous persistence as last resort\n this.beforeUnloadListener = () => {\n this.core.flush();\n };\n window.addEventListener('beforeunload', this.beforeUnloadListener);\n }\n}\n\n// SDK version injected at build time by tsdown define\ndeclare const __LAYERS_CLIENT_VERSION__: string;\nconst SDK_VERSION: string =\n typeof __LAYERS_CLIENT_VERSION__ !== 'undefined' ? __LAYERS_CLIENT_VERSION__ : '0.1.1-alpha.1';\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layers/client",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -33,7 +33,7 @@
33
33
  "dist"
34
34
  ],
35
35
  "dependencies": {
36
- "@layers/core-wasm": "1.2.0"
36
+ "@layers/core-wasm": "1.3.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react": ">=18"
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-DGDLULwp.d.ts","names":[],"sources":["../../wasm/src/types.ts","../src/api-types.ts","../src/attribution.ts","../src/index.ts"],"sourcesContent":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"src-DQ_-NO-4.js","names":["params: URLSearchParams","clickIdParam: string | undefined","clickIdValue: string | undefined","utms: Partial<Pick<AttributionData, (typeof UTM_PARAMS)[number]>>","data: AttributionData","props: Record<string, string>","context: DeviceContext","SDK_VERSION: string"],"sources":["../src/attribution.ts","../src/index.ts"],"sourcesContent":["const CLICK_ID_PARAMS = [\n 'fbclid',\n 'gclid',\n 'gbraid',\n 'wbraid',\n 'ttclid',\n 'msclkid',\n 'rclid'\n] as const;\nconst UTM_PARAMS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'] as const;\nconst STORAGE_KEY = 'layers_attribution';\nconst TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days\n\nexport interface AttributionData {\n click_id_param?: string;\n click_id_value?: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_content?: string;\n utm_term?: string;\n referrer_url?: string;\n captured_at: number;\n}\n\n/**\n * Capture attribution signals from the current page URL and referrer.\n * Persists to localStorage with a 30-day TTL. Click IDs take priority:\n * if a new click ID is present, the entire record is overwritten.\n */\nexport function captureAttribution(): void {\n if (typeof window === 'undefined' || typeof localStorage === 'undefined') return;\n\n let params: URLSearchParams;\n try {\n params = new URLSearchParams(window.location.search);\n } catch {\n return;\n }\n\n // Check for click IDs first — any click ID overwrites the stored record\n let clickIdParam: string | undefined;\n let clickIdValue: string | undefined;\n for (const param of CLICK_ID_PARAMS) {\n const value = params.get(param);\n if (value) {\n clickIdParam = param;\n clickIdValue = value;\n break; // first match wins\n }\n }\n\n // Collect UTM params\n const utms: Partial<Pick<AttributionData, (typeof UTM_PARAMS)[number]>> = {};\n let hasUtm = false;\n for (const param of UTM_PARAMS) {\n const value = params.get(param);\n if (value) {\n utms[param] = value;\n hasUtm = true;\n }\n }\n\n const referrer =\n typeof document !== 'undefined' && document.referrer ? document.referrer : undefined;\n\n // Nothing to capture\n if (!clickIdParam && !hasUtm && !referrer) return;\n\n const existing = getAttribution();\n\n // If a new click ID is present, overwrite entirely\n if (clickIdParam) {\n const data: AttributionData = {\n click_id_param: clickIdParam,\n ...(clickIdValue != null && { click_id_value: clickIdValue }),\n ...utms,\n ...(referrer != null && { referrer_url: referrer }),\n captured_at: Date.now()\n };\n writeAttribution(data);\n return;\n }\n\n // If UTMs are present, overwrite (fresh campaign visit)\n if (hasUtm) {\n const data: AttributionData = {\n // Preserve existing click ID if no new one\n ...(existing?.click_id_param != null && { click_id_param: existing.click_id_param }),\n ...(existing?.click_id_value != null && { click_id_value: existing.click_id_value }),\n ...utms,\n ...(referrer != null && { referrer_url: referrer }),\n captured_at: Date.now()\n };\n writeAttribution(data);\n return;\n }\n\n // Only referrer and no existing attribution — store it\n if (!existing) {\n const data: AttributionData = {\n ...(referrer != null && { referrer_url: referrer }),\n captured_at: Date.now()\n };\n writeAttribution(data);\n }\n}\n\n/**\n * Read stored attribution data, returning null if missing or expired.\n */\nexport function getAttribution(): AttributionData | null {\n if (typeof localStorage === 'undefined') return null;\n\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return null;\n\n const data: AttributionData = JSON.parse(raw);\n if (Date.now() - data.captured_at > TTL_MS) {\n localStorage.removeItem(STORAGE_KEY);\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\n/**\n * Return a flat property bag suitable for merging into event properties.\n * Keys are prefixed with `$attribution_` to avoid collisions.\n */\nexport function getAttributionProperties(): Record<string, string> {\n const data = getAttribution();\n if (!data) return {};\n\n const props: Record<string, string> = {};\n\n if (data.click_id_param) props['$attribution_click_id_param'] = data.click_id_param;\n if (data.click_id_value) props['$attribution_click_id_value'] = data.click_id_value;\n if (data.utm_source) props['$attribution_utm_source'] = data.utm_source;\n if (data.utm_medium) props['$attribution_utm_medium'] = data.utm_medium;\n if (data.utm_campaign) props['$attribution_utm_campaign'] = data.utm_campaign;\n if (data.utm_content) props['$attribution_utm_content'] = data.utm_content;\n if (data.utm_term) props['$attribution_utm_term'] = data.utm_term;\n if (data.referrer_url) props['$attribution_referrer_url'] = data.referrer_url;\n\n return props;\n}\n\nfunction writeAttribution(data: AttributionData): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n } catch {\n // localStorage full or unavailable — silently ignore\n }\n}\n","// @layers/client — Web browser SDK.\n// Thin wrapper over @layers/core-wasm. Owns only:\n// - localStorage persistence\n// - window online/offline detection\n// - navigator device info\n// - visibilitychange / beforeunload flush\nimport {\n FetchHttpClient,\n LayersCore,\n LayersError,\n createDefaultPersistence\n} from '@layers/core-wasm';\nimport type {\n ConsentState,\n DeviceContext,\n Environment,\n EventProperties,\n UserProperties\n} from '@layers/core-wasm';\n\nimport { captureAttribution, getAttributionProperties } from './attribution.js';\n\nexport type {\n ConsentState,\n DeviceContext,\n Environment,\n EventProperties,\n UserProperties\n} from '@layers/core-wasm';\n\nexport { LayersError } from '@layers/core-wasm';\n\nexport * from './api-types.js';\nexport type { AttributionData } from './attribution.js';\nexport { getAttribution, getAttributionProperties } from './attribution.js';\n\nexport interface LayersConfig {\n /** Unique application identifier issued by the Layers dashboard. */\n appId: string;\n /** Deployment environment label. @default \"production\" */\n environment: Environment;\n /** Optional user identifier to associate events with from the start. */\n appUserId?: string;\n /** Enable verbose debug logging to the console. @default false */\n enableDebug?: boolean;\n /** Base URL for the Layers ingest API. @default \"https://in.layers.com\" */\n baseUrl?: string;\n /** How often the event queue is flushed, in milliseconds. @default 30000 */\n flushIntervalMs?: number;\n /** Number of queued events that triggers an automatic flush. @default 10 */\n flushThreshold?: number;\n /** Maximum number of events to hold in the queue before dropping. @default 1000 */\n maxQueueSize?: number;\n}\n\nexport type ErrorListener = (error: Error) => void;\n\nexport class LayersClient {\n private core: LayersCore;\n private appUserId: string | undefined;\n private isOnline = true;\n private readonly enableDebug: boolean;\n private readonly baseUrl: string;\n\n // Stored listener references for cleanup on shutdown\n private onlineListener: (() => void) | null = null;\n private offlineListener: (() => void) | null = null;\n private visibilityListener: (() => void) | null = null;\n private beforeUnloadListener: (() => void) | null = null;\n\n // Error listeners\n private readonly errorListeners: Set<ErrorListener> = new Set();\n\n constructor(config: LayersConfig) {\n this.enableDebug = config.enableDebug ?? false;\n this.baseUrl = (config.baseUrl ?? 'https://in.layers.com').replace(/\\/$/, '');\n this.appUserId = config.appUserId;\n\n const persistence = createDefaultPersistence(config.appId);\n const httpClient = new FetchHttpClient();\n\n this.core = LayersCore.init({\n config: {\n appId: config.appId,\n environment: config.environment,\n ...(config.baseUrl != null && { baseUrl: config.baseUrl }),\n ...(config.enableDebug != null && { enableDebug: config.enableDebug }),\n ...(config.flushIntervalMs != null && { flushIntervalMs: config.flushIntervalMs }),\n ...(config.flushThreshold != null && { flushThreshold: config.flushThreshold }),\n ...(config.maxQueueSize != null && { maxQueueSize: config.maxQueueSize }),\n sdkVersion: `client/${SDK_VERSION}`\n },\n httpClient,\n persistence\n });\n\n if (this.appUserId) {\n this.core.identify(this.appUserId);\n }\n }\n\n /** Initialize the client: detects device info, attaches lifecycle listeners, and fetches remote config. */\n async init(): Promise<void> {\n this.initializeDeviceInfo();\n this.setupNetworkListener();\n this.setupLifecycleListeners();\n captureAttribution();\n await this.core.fetchRemoteConfig().catch(() => {\n // Remote config fetch is best-effort\n });\n }\n\n /**\n * Record a custom analytics event with an optional property bag.\n *\n * Events are batched and flushed automatically when the queue reaches\n * `flushThreshold` or the periodic flush timer fires.\n */\n track(eventName: string, properties?: EventProperties): void {\n if (this.enableDebug) {\n console.log(\n `[Layers] track(\"${eventName}\", ${Object.keys(properties ?? {}).length} properties)`\n );\n }\n try {\n const merged = { ...getAttributionProperties(), ...properties };\n this.core.track(eventName, merged, this.appUserId);\n } catch (e) {\n this.emitError(e);\n }\n }\n\n /**\n * Record a screen view event with an optional property bag.\n *\n * Events are batched and flushed automatically when the queue reaches\n * `flushThreshold` or the periodic flush timer fires.\n */\n screen(screenName: string, properties?: EventProperties): void {\n if (this.enableDebug) {\n console.log(\n `[Layers] screen(\"${screenName}\", ${Object.keys(properties ?? {}).length} properties)`\n );\n }\n try {\n const merged = { ...getAttributionProperties(), ...properties };\n this.core.screen(screenName, merged, this.appUserId);\n } catch (e) {\n this.emitError(e);\n }\n }\n\n /** Set or update user-level properties that persist across sessions. */\n setUserProperties(properties: UserProperties): void {\n this.core.setUserProperties(properties);\n }\n\n /** Update the user's consent state for analytics and advertising data collection. */\n setConsent(consent: ConsentState): void {\n this.core.setConsent(consent);\n }\n\n /** Associate all subsequent events with the given user ID, or clear it with `undefined`. */\n setAppUserId(appUserId: string | undefined): void {\n if (this.enableDebug) {\n console.log(`[Layers] setAppUserId(${appUserId ? `\"${appUserId}\"` : 'undefined'})`);\n }\n this.appUserId = appUserId;\n if (appUserId) {\n this.core.identify(appUserId);\n } else {\n this.core.identify('');\n }\n }\n\n /** @deprecated Use setAppUserId instead */\n setUserId(userId: string): void {\n this.setAppUserId(userId);\n }\n\n /** Return the current app user ID, or `undefined` if not set. */\n getAppUserId(): string | undefined {\n return this.appUserId;\n }\n\n /** @deprecated Use getAppUserId instead */\n getUserId(): string | undefined {\n return this.appUserId;\n }\n\n /** Return the current anonymous session ID. */\n getSessionId(): string {\n return this.core.getSessionId();\n }\n\n /** Return the current consent state for analytics and advertising. */\n getConsentState(): ConsentState {\n return this.core.getConsentState();\n }\n\n /** Override device-level context fields (platform, OS, locale, etc.). */\n setDeviceInfo(deviceInfo: DeviceContext): void {\n this.core.setDeviceContext(deviceInfo);\n }\n\n /** Flush all queued events to the server. Falls back to synchronous persistence on failure. */\n async flush(): Promise<void> {\n try {\n await this.core.flushAsync();\n } catch (e) {\n this.emitError(e);\n this.core.flush();\n }\n }\n\n /** Immediately shut down the client, removing all event listeners. Queued events are persisted but not flushed. */\n shutdown(): void {\n this.cleanupListeners();\n this.core.shutdown();\n }\n\n /**\n * Async shutdown: flushes remaining events before shutting down.\n * @param timeoutMs Maximum time to wait for flush (default 3000ms).\n */\n async shutdownAsync(timeoutMs = 3000): Promise<void> {\n this.cleanupListeners();\n try {\n await Promise.race([\n this.core.flushAsync(),\n new Promise<void>((resolve) => setTimeout(resolve, timeoutMs))\n ]);\n } catch {\n // Best effort — proceed with shutdown\n }\n this.core.shutdown();\n }\n\n private cleanupListeners(): void {\n if (typeof window !== 'undefined') {\n if (this.onlineListener) {\n window.removeEventListener('online', this.onlineListener);\n this.onlineListener = null;\n }\n if (this.offlineListener) {\n window.removeEventListener('offline', this.offlineListener);\n this.offlineListener = null;\n }\n if (this.beforeUnloadListener) {\n window.removeEventListener('beforeunload', this.beforeUnloadListener);\n this.beforeUnloadListener = null;\n }\n }\n if (typeof document !== 'undefined' && this.visibilityListener) {\n document.removeEventListener('visibilitychange', this.visibilityListener);\n this.visibilityListener = null;\n }\n }\n\n /** End the current session and start a new one with a fresh session ID. */\n startNewSession(): void {\n this.core.startNewSession();\n }\n\n /**\n * Register an error listener. Errors from track/screen/flush\n * that would otherwise be silently dropped are forwarded here.\n */\n on(event: 'error', listener: ErrorListener): this {\n if (event === 'error') this.errorListeners.add(listener);\n return this;\n }\n\n /**\n * Remove a previously registered error listener.\n */\n off(event: 'error', listener: ErrorListener): this {\n if (event === 'error') this.errorListeners.delete(listener);\n return this;\n }\n\n private emitError(error: unknown): void {\n const err = error instanceof Error ? error : new Error(String(error));\n for (const listener of this.errorListeners) {\n try {\n listener(err);\n } catch {}\n }\n if (this.enableDebug && this.errorListeners.size === 0) {\n console.warn('[Layers]', err.message);\n }\n }\n\n // --- Platform-specific: browser device info ---\n\n private initializeDeviceInfo(): void {\n const context: DeviceContext = {\n platform: 'web',\n osVersion: this.detectOS(),\n appVersion: SDK_VERSION,\n deviceModel: this.detectDeviceModel(),\n locale: this.detectLocale(),\n screenSize: this.detectScreenSize(),\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone\n };\n this.core.setDeviceContext(context);\n }\n\n private detectOS(): string {\n if (typeof navigator === 'undefined') return 'unknown';\n const ua = navigator.userAgent;\n if (ua.includes('Windows')) return 'Windows';\n if (ua.includes('Mac OS')) return 'macOS';\n if (ua.includes('Linux')) return 'Linux';\n if (ua.includes('Android')) return 'Android';\n if (ua.includes('iPhone') || ua.includes('iPad')) return 'iOS';\n return 'unknown';\n }\n\n private detectDeviceModel(): string {\n if (typeof navigator === 'undefined') return 'unknown';\n if ('userAgentData' in navigator) {\n const uaData = (navigator as { userAgentData?: { platform?: string } }).userAgentData;\n if (uaData?.platform) return uaData.platform;\n }\n return navigator.platform ?? 'unknown';\n }\n\n private detectLocale(): string {\n if (typeof navigator === 'undefined') return 'en-US';\n return navigator.language ?? 'en-US';\n }\n\n private detectScreenSize(): string {\n if (typeof window === 'undefined' || typeof screen === 'undefined') return 'unknown';\n return `${screen.width}x${screen.height}`;\n }\n\n // --- Platform-specific: network listener ---\n\n private setupNetworkListener(): void {\n if (typeof window === 'undefined') return;\n\n this.isOnline = navigator?.onLine ?? true;\n\n this.onlineListener = () => {\n this.isOnline = true;\n void this.core.flushAsync().catch(() => {});\n };\n this.offlineListener = () => {\n this.isOnline = false;\n };\n\n window.addEventListener('online', this.onlineListener);\n window.addEventListener('offline', this.offlineListener);\n }\n\n // --- Platform-specific: lifecycle listeners ---\n\n private getBeaconUrl(): string {\n return `${this.baseUrl}/events`;\n }\n\n private setupLifecycleListeners(): void {\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n\n // Flush on page hide / visibility change.\n // Use sendBeacon for best-effort network delivery before the page is hidden.\n // Falls back to synchronous localStorage persistence if sendBeacon fails.\n this.visibilityListener = () => {\n if (document.visibilityState === 'hidden') {\n if (\n typeof navigator !== 'undefined' &&\n navigator.sendBeacon &&\n this.core.queueDepth() > 0\n ) {\n try {\n const batch = this.core.createBeaconPayload();\n if (batch) {\n const sent = navigator.sendBeacon(this.getBeaconUrl(), batch);\n if (sent) {\n this.core.clearBeaconEvents();\n return;\n }\n // sendBeacon failed — requeue events before falling back to persistence\n this.core.requeueBeaconEvents();\n this.core.flush();\n return;\n }\n } catch {\n // sendBeacon threw — requeue any drained events before sync flush\n this.core.requeueBeaconEvents();\n }\n }\n this.core.flush();\n }\n };\n document.addEventListener('visibilitychange', this.visibilityListener);\n\n // Flush on beforeunload — synchronous persistence as last resort\n this.beforeUnloadListener = () => {\n this.core.flush();\n };\n window.addEventListener('beforeunload', this.beforeUnloadListener);\n }\n}\n\n// SDK version injected at build time by tsdown define\ndeclare const __LAYERS_CLIENT_VERSION__: string;\nconst SDK_VERSION: string =\n typeof __LAYERS_CLIENT_VERSION__ !== 'undefined' ? __LAYERS_CLIENT_VERSION__ : '0.1.1-alpha.1';\n"],"mappings":"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"}