@layers/client 1.0.1 → 1.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/README.md CHANGED
@@ -1,64 +1,289 @@
1
- # @layers/client
1
+ # Layers Web SDK
2
2
 
3
- Web browser SDK for Layers Analytics. Thin wrapper over the Rust/WASM core (`@layers/core-wasm`) that adds browser-specific features: localStorage persistence, network detection, page lifecycle flush via `sendBeacon`, and React integration.
3
+ `@layers/client` is the Layers analytics SDK for web browsers. It provides event tracking, screen tracking, user identification, automatic attribution capture (UTM parameters, click IDs, referrer), consent management, and lifecycle-aware event flushing with `sendBeacon` support.
4
4
 
5
- ## Install
5
+ ## Requirements
6
+
7
+ - Modern browser with ES module support
8
+ - React 18+ (for React hooks, optional)
9
+
10
+ ## Installation
6
11
 
7
12
  ```bash
8
13
  npm install @layers/client
9
14
  # or
15
+ yarn add @layers/client
16
+ # or
10
17
  pnpm add @layers/client
11
18
  ```
12
19
 
13
20
  ## Quick Start
14
21
 
15
- ```ts
22
+ ```typescript
16
23
  import { LayersClient } from '@layers/client';
17
24
 
18
25
  const layers = new LayersClient({
19
- apiKey: 'your-api-key',
20
26
  appId: 'your-app-id',
21
27
  environment: 'production'
22
28
  });
23
-
24
29
  await layers.init();
25
30
 
26
31
  // Track events
27
- await layers.track('button_click', { button: 'signup' });
28
-
29
- // Track screen views
30
- await layers.screen('home_page');
32
+ layers.track('button_click', { button_name: 'signup' });
31
33
 
32
- // Identify a user
33
- layers.setAppUserId('user-123');
34
+ // Track page views
35
+ layers.screen('Home');
34
36
 
35
- // Shut down gracefully
36
- await layers.shutdownAsync();
37
+ // Identify users
38
+ layers.setAppUserId('user_123');
37
39
  ```
38
40
 
39
41
  ## Configuration
40
42
 
41
- All fields for `LayersConfig`:
43
+ ### LayersConfig
44
+
45
+ ```typescript
46
+ interface LayersConfig {
47
+ appId: string;
48
+ environment: 'development' | 'staging' | 'production';
49
+ appUserId?: string;
50
+ enableDebug?: boolean;
51
+ baseUrl?: string;
52
+ flushIntervalMs?: number;
53
+ flushThreshold?: number;
54
+ maxQueueSize?: number;
55
+ }
56
+ ```
57
+
58
+ | Option | Type | Default | Description |
59
+ | ----------------- | ------------- | ------------------------- | ------------------------------------------------ |
60
+ | `appId` | `string` | _required_ | Your Layers application identifier. |
61
+ | `environment` | `Environment` | _required_ | `'development'`, `'staging'`, or `'production'`. |
62
+ | `appUserId` | `string` | `undefined` | Optional user ID to set at construction time. |
63
+ | `enableDebug` | `boolean` | `false` | Enable verbose console logging. |
64
+ | `baseUrl` | `string` | `"https://in.layers.com"` | Custom ingest API endpoint. |
65
+ | `flushIntervalMs` | `number` | `30000` | Automatic flush interval in milliseconds. |
66
+ | `flushThreshold` | `number` | `10` | Queue size that triggers an automatic flush. |
67
+ | `maxQueueSize` | `number` | `1000` | Maximum events in the queue before dropping. |
68
+
69
+ ```typescript
70
+ const layers = new LayersClient({
71
+ appId: 'your-app-id',
72
+ environment: 'development',
73
+ enableDebug: true,
74
+ flushIntervalMs: 15000,
75
+ flushThreshold: 5,
76
+ maxQueueSize: 5000
77
+ });
78
+ ```
79
+
80
+ ## Core API
42
81
 
43
- | Field | Type | Default | Description |
44
- | ----------------- | -------------------------------------------- | ----------------------- | ------------------------------------------ |
45
- | `apiKey` | `string` | _required_ | API key from the Layers dashboard |
46
- | `appId` | `string` | _required_ | Application identifier |
47
- | `environment` | `'development' \| 'staging' \| 'production'` | _required_ | Deployment environment |
48
- | `appUserId` | `string` | `undefined` | Pre-set user ID at init time |
49
- | `enableDebug` | `boolean` | `false` | Verbose console logging for all SDK calls |
50
- | `baseUrl` | `string` | `https://in.layers.com` | Override the ingest endpoint |
51
- | `flushIntervalMs` | `number` | `30000` | Periodic flush interval (ms) |
52
- | `flushThreshold` | `number` | `10` | Queue depth that triggers auto-flush |
53
- | `maxQueueSize` | `number` | `1000` | Max events in queue before dropping oldest |
82
+ ### Constructor & Initialization
54
83
 
55
- ## React Integration
84
+ ```typescript
85
+ const layers = new LayersClient(config: LayersConfig);
86
+ await layers.init();
87
+ ```
88
+
89
+ The constructor creates the SDK instance with localStorage-backed persistence. Calling `init()` detects device info, attaches lifecycle listeners (online/offline, visibility change, beforeunload), captures attribution signals, and fetches remote config.
90
+
91
+ You can call `track()` and `screen()` before `init()` completes -- events are queued.
56
92
 
57
- The SDK includes first-class React bindings via `@layers/client/react`.
93
+ ### Event Tracking
94
+
95
+ ```typescript
96
+ track(eventName: string, properties?: EventProperties): void
97
+ ```
98
+
99
+ Events are batched and flushed automatically. Attribution properties (UTM, click IDs, referrer) from the current session are automatically merged into every event.
100
+
101
+ ```typescript
102
+ layers.track('purchase_completed', {
103
+ product_id: 'sku_123',
104
+ price: 9.99,
105
+ currency: 'USD'
106
+ });
107
+ ```
108
+
109
+ ### Screen/Page Tracking
110
+
111
+ ```typescript
112
+ screen(screenName: string, properties?: EventProperties): void
113
+ ```
114
+
115
+ Attribution properties are automatically merged.
116
+
117
+ ```typescript
118
+ layers.screen('ProductDetail', { product_id: 'sku_123' });
119
+ ```
120
+
121
+ ### User Identity
122
+
123
+ ```typescript
124
+ // Set or clear the app user ID
125
+ setAppUserId(appUserId: string | undefined): void
126
+
127
+ // Get the current user ID
128
+ getAppUserId(): string | undefined
129
+
130
+ // Deprecated aliases
131
+ setUserId(userId: string): void
132
+ getUserId(): string | undefined
133
+ ```
58
134
 
59
- ### Provider
135
+ ```typescript
136
+ // After login
137
+ layers.setAppUserId('user_123');
60
138
 
61
- Wrap your app in `<LayersProvider>` to initialize the SDK and make it available to hooks:
139
+ // On logout
140
+ layers.setAppUserId(undefined);
141
+ ```
142
+
143
+ ### User Properties
144
+
145
+ ```typescript
146
+ setUserProperties(properties: UserProperties): void
147
+ ```
148
+
149
+ ```typescript
150
+ layers.setUserProperties({
151
+ email: 'user@example.com',
152
+ plan: 'premium',
153
+ signup_date: '2024-01-15'
154
+ });
155
+ ```
156
+
157
+ ### Consent Management
158
+
159
+ ```typescript
160
+ setConsent(consent: ConsentState): void
161
+ getConsentState(): ConsentState
162
+ ```
163
+
164
+ ```typescript
165
+ interface ConsentState {
166
+ analytics?: boolean;
167
+ advertising?: boolean;
168
+ }
169
+ ```
170
+
171
+ ```typescript
172
+ // User accepts analytics only
173
+ layers.setConsent({ analytics: true, advertising: false });
174
+
175
+ // Read current state
176
+ const consent = layers.getConsentState();
177
+ ```
178
+
179
+ ### Session Management
180
+
181
+ ```typescript
182
+ // Get the current session ID
183
+ getSessionId(): string
184
+
185
+ // End the current session and start a new one
186
+ startNewSession(): void
187
+ ```
188
+
189
+ ### Device Info
190
+
191
+ ```typescript
192
+ setDeviceInfo(deviceInfo: DeviceContext): void
193
+ ```
194
+
195
+ Override auto-detected device context fields.
196
+
197
+ ### Flush & Shutdown
198
+
199
+ ```typescript
200
+ // Flush all queued events to the server
201
+ async flush(): Promise<void>
202
+
203
+ // Shut down immediately (no flush, events persisted to localStorage)
204
+ shutdown(): void
205
+
206
+ // Shut down with a final flush (with timeout)
207
+ async shutdownAsync(timeoutMs?: number): Promise<void> // default: 3000ms
208
+ ```
209
+
210
+ ### Error Handling
211
+
212
+ ```typescript
213
+ on(event: 'error', listener: (error: Error) => void): this
214
+ off(event: 'error', listener: (error: Error) => void): this
215
+ ```
216
+
217
+ ```typescript
218
+ layers.on('error', (error) => {
219
+ console.error('Layers error:', error.message);
220
+ });
221
+ ```
222
+
223
+ ## Attribution
224
+
225
+ The SDK automatically captures and persists attribution signals from the current page URL and referrer.
226
+
227
+ ### Captured Signals
228
+
229
+ **Click IDs** (highest priority -- overwrites existing attribution):
230
+
231
+ - `fbclid` (Meta/Facebook)
232
+ - `gclid`, `gbraid`, `wbraid` (Google)
233
+ - `ttclid` (TikTok)
234
+ - `msclkid` (Microsoft/Bing)
235
+ - `rclid` (Reddit)
236
+
237
+ **UTM Parameters**:
238
+
239
+ - `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`
240
+
241
+ **Referrer**:
242
+
243
+ - `document.referrer`
244
+
245
+ ### How It Works
246
+
247
+ 1. On `init()`, the SDK reads the current URL's query parameters and `document.referrer`.
248
+ 2. Attribution data is persisted in `localStorage` with a 30-day TTL.
249
+ 3. Click IDs take priority -- a new click ID overwrites the entire stored record.
250
+ 4. UTM parameters overwrite on fresh campaign visits, but preserve existing click IDs.
251
+ 5. Attribution properties are automatically prefixed with `$attribution_` and merged into every `track()` and `screen()` call.
252
+
253
+ ### Manually Reading Attribution
254
+
255
+ ```typescript
256
+ import { getAttribution, getAttributionProperties } from '@layers/client';
257
+
258
+ // Get the full stored attribution data (or null if expired/missing)
259
+ const attribution = getAttribution();
260
+
261
+ // Get a flat property bag for merging into events
262
+ const props = getAttributionProperties();
263
+ // { '$attribution_utm_source': 'google', '$attribution_click_id_param': 'gclid', ... }
264
+ ```
265
+
266
+ ### AttributionData Type
267
+
268
+ ```typescript
269
+ interface AttributionData {
270
+ click_id_param?: string;
271
+ click_id_value?: string;
272
+ utm_source?: string;
273
+ utm_medium?: string;
274
+ utm_campaign?: string;
275
+ utm_content?: string;
276
+ utm_term?: string;
277
+ referrer_url?: string;
278
+ captured_at: number;
279
+ }
280
+ ```
281
+
282
+ ## React Integration
283
+
284
+ The SDK includes React hooks for idiomatic usage. Import from `@layers/client/react`.
285
+
286
+ ### LayersProvider
62
287
 
63
288
  ```tsx
64
289
  import { LayersProvider } from '@layers/client/react';
@@ -67,7 +292,6 @@ function App() {
67
292
  return (
68
293
  <LayersProvider
69
294
  config={{
70
- apiKey: 'your-api-key',
71
295
  appId: 'your-app-id',
72
296
  environment: 'production'
73
297
  }}
@@ -78,73 +302,87 @@ function App() {
78
302
  }
79
303
  ```
80
304
 
81
- The provider creates a `LayersClient` on mount, calls `init()`, and shuts it down on unmount.
305
+ Initializes the client on mount and shuts it down on unmount.
82
306
 
83
- ### Hooks
307
+ ### useLayers
84
308
 
85
- All hooks must be used inside a `<LayersProvider>`.
86
-
87
- #### `useTrack()`
309
+ ```typescript
310
+ function useLayers(): LayersClient;
311
+ ```
88
312
 
89
- Returns a stable, memoized function for tracking events:
313
+ Returns the `LayersClient` instance. Throws if used outside a `<LayersProvider>`.
90
314
 
91
315
  ```tsx
92
- import { useTrack } from '@layers/client/react';
316
+ function MyComponent() {
317
+ const layers = useLayers();
318
+ layers.track('component_viewed');
319
+ }
320
+ ```
321
+
322
+ ### useTrack
323
+
324
+ ```typescript
325
+ function useTrack(): (eventName: string, properties?: EventProperties) => void;
326
+ ```
93
327
 
328
+ Returns a stable, memoized track function.
329
+
330
+ ```tsx
94
331
  function SignupButton() {
95
332
  const track = useTrack();
96
333
 
97
- return <button onClick={() => track('signup_click', { source: 'hero' })}>Sign up</button>;
334
+ return <button onClick={() => track('signup_click', { source: 'hero' })}>Sign Up</button>;
98
335
  }
99
336
  ```
100
337
 
101
- #### `useScreen()`
338
+ ### useScreen
102
339
 
103
- Returns a stable, memoized function for tracking screen views:
340
+ ```typescript
341
+ function useScreen(): (screenName: string, properties?: EventProperties) => void;
342
+ ```
104
343
 
105
- ```tsx
106
- import { useScreen } from '@layers/client/react';
107
- import { useEffect } from 'react';
344
+ Returns a stable, memoized screen tracking function.
108
345
 
346
+ ```tsx
109
347
  function Dashboard() {
110
348
  const screen = useScreen();
111
349
  useEffect(() => {
112
- screen('dashboard');
350
+ screen('Dashboard');
113
351
  }, [screen]);
114
352
 
115
- return <div>...</div>;
353
+ return <div>Dashboard</div>;
116
354
  }
117
355
  ```
118
356
 
119
- #### `useIdentify()`
357
+ ### useIdentify
120
358
 
121
- Returns a function to set (or clear) the app user ID:
359
+ ```typescript
360
+ function useIdentify(): (userId: string | undefined) => void;
361
+ ```
122
362
 
123
- ```tsx
124
- import { useIdentify } from '@layers/client/react';
363
+ Returns a stable, memoized identify function. Pass `undefined` to clear.
125
364
 
365
+ ```tsx
126
366
  function LoginForm() {
127
367
  const identify = useIdentify();
128
368
 
129
- const onLogin = (userId: string) => {
130
- identify(userId);
131
- };
132
-
133
- const onLogout = () => {
134
- identify(undefined);
135
- };
369
+ const onLogin = (userId: string) => identify(userId);
370
+ const onLogout = () => identify(undefined);
136
371
  }
137
372
  ```
138
373
 
139
- #### `useConsent()`
374
+ ### useConsent
140
375
 
141
- Returns functions to get and set consent state:
376
+ ```typescript
377
+ function useConsent(): {
378
+ setConsent: (consent: ConsentState) => void;
379
+ getConsentState: () => ConsentState;
380
+ };
381
+ ```
142
382
 
143
383
  ```tsx
144
- import { useConsent } from '@layers/client/react';
145
-
146
384
  function ConsentBanner() {
147
- const { setConsent, getConsentState } = useConsent();
385
+ const { setConsent } = useConsent();
148
386
 
149
387
  return (
150
388
  <button onClick={() => setConsent({ analytics: true, advertising: false })}>
@@ -154,71 +392,84 @@ function ConsentBanner() {
154
392
  }
155
393
  ```
156
394
 
157
- #### `useLayers()`
395
+ ## Automatic Behaviors
158
396
 
159
- Returns the raw `LayersClient` instance for advanced usage:
160
-
161
- ```tsx
162
- import { useLayers } from '@layers/client/react';
397
+ - **Attribution capture**: UTM parameters, click IDs, and referrer are captured and persisted on init.
398
+ - **Attribution enrichment**: Stored attribution is merged into every `track()` and `screen()` call.
399
+ - **Online/offline detection**: Events are flushed when the browser reconnects.
400
+ - **Visibility change flush**: Events are flushed via `navigator.sendBeacon` when the page is hidden (tab switch, minimize).
401
+ - **Before unload flush**: Events are persisted to `localStorage` on page close.
402
+ - **Periodic flush**: Events are flushed on a timer (configurable).
403
+ - **Remote config**: Server configuration is fetched during init.
404
+ - **Device context**: OS, browser, locale, screen size, and timezone are detected automatically.
405
+ - **Event persistence**: Events are persisted in `localStorage` and rehydrated on page load.
163
406
 
164
- function Advanced() {
165
- const layers = useLayers();
166
- // layers.setUserProperties({ plan: 'pro' });
167
- }
168
- ```
407
+ ## SPA (Single Page App) Usage
169
408
 
170
- ## Error Handling
409
+ For single-page apps with client-side routing, call `screen()` on route changes:
171
410
 
172
- Register error listeners to catch errors from `track()`, `screen()`, and `flush()` that would otherwise be silently dropped:
411
+ ```typescript
412
+ // React Router
413
+ import { useLocation } from 'react-router-dom';
173
414
 
174
- ```ts
175
- const layers = new LayersClient({ ... });
415
+ function RouteTracker() {
416
+ const location = useLocation();
417
+ const screen = useScreen();
176
418
 
177
- layers.on('error', (err) => {
178
- console.error('Layers SDK error:', err.message);
179
- // Send to your error reporting service
180
- });
419
+ useEffect(() => {
420
+ screen(location.pathname, { search: location.search });
421
+ }, [location, screen]);
181
422
 
182
- // Remove a specific listener
183
- layers.off('error', myListener);
423
+ return null;
424
+ }
184
425
  ```
185
426
 
186
- When `enableDebug` is `true` and no error listeners are registered, errors are logged to `console.warn`.
427
+ ```typescript
428
+ 'use client';
187
429
 
188
- ## Consent Management
430
+ import { usePathname } from 'next/navigation';
189
431
 
190
- Control what data the SDK collects:
432
+ function PageTracker() {
433
+ const pathname = usePathname();
434
+ const screen = useScreen();
191
435
 
192
- ```ts
193
- // Allow analytics, deny advertising
194
- layers.setConsent({ analytics: true, advertising: false });
436
+ useEffect(() => {
437
+ screen(pathname);
438
+ }, [pathname, screen]);
195
439
 
196
- // Check current state
197
- const consent = layers.getConsentState();
440
+ return null;
441
+ }
198
442
  ```
199
443
 
200
- When `analytics` is `false`, `track()` and `screen()` calls are silently dropped.
201
-
202
- ## Page Lifecycle (sendBeacon)
203
-
204
- The SDK automatically flushes events when the page becomes hidden using `navigator.sendBeacon()` for reliable delivery. If `sendBeacon` fails, events are persisted to localStorage and retried on the next page load.
205
-
206
- On `beforeunload`, events are synchronously written to localStorage as a last resort.
207
-
208
- ## Debug Mode
209
-
210
- Enable `enableDebug: true` to see detailed logs for every SDK operation:
211
-
212
- ```
213
- [Layers] track("button_click", 2 properties)
214
- [Layers] screen("home_page", 0 properties)
215
- [Layers] setAppUserId("user-123")
444
+ ## TypeScript Types
445
+
446
+ ```typescript
447
+ import type {
448
+ AttributionData,
449
+ BaseEvent,
450
+ ConsentState,
451
+ DeviceContext,
452
+ Environment,
453
+ ErrorListener,
454
+ EventProperties,
455
+ EventsBatchPayload,
456
+ LayersConfig,
457
+ RemoteConfigResponse,
458
+ UserProperties
459
+ } from '@layers/client';
216
460
  ```
217
461
 
218
- ## Server-Side Rendering
462
+ ## Wire Protocol Types
219
463
 
220
- The SDK safely handles SSR environments where `window`, `document`, and `navigator` are unavailable. Device detection and lifecycle listeners are skipped in SSR. For server-side tracking, use [@layers/node](../node) instead.
464
+ The package also exports TypeScript interfaces for the Layers wire protocol, useful for building custom integrations:
221
465
 
222
- ## License
223
-
224
- MIT
466
+ ```typescript
467
+ import type {
468
+ BaseEvent,
469
+ ConsentPayload,
470
+ EventsBatchPayload,
471
+ RemoteConfigResponse,
472
+ SKANPostbackPayload,
473
+ UserPropertiesPayload
474
+ } from '@layers/client';
475
+ ```
@@ -13,6 +13,7 @@ interface DeviceContext {
13
13
  idfa?: string;
14
14
  idfv?: string;
15
15
  attStatus?: string;
16
+ timezone?: string;
16
17
  }
17
18
  interface ConsentState {
18
19
  analytics?: boolean | null;
@@ -301,4 +302,4 @@ declare class LayersClient {
301
302
  }
302
303
  //#endregion
303
304
  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 };
304
- //# sourceMappingURL=index-BCpCaNor.d.ts.map
305
+ //# sourceMappingURL=index-DGDLULwp.d.ts.map
@@ -0,0 +1 @@
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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"}
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-BCpCaNor.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-DGDLULwp.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-CDTj2A6Q.js";
1
+ import { i as getAttributionProperties, n as LayersError, r as getAttribution, t as LayersClient } from "./src-DQ_-NO-4.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-BCpCaNor.js";
1
+ import { g as EventProperties, n as LayersClient, p as ConsentState, r as LayersConfig } from "./index-DGDLULwp.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-CDTj2A6Q.js";
1
+ import { t as LayersClient } from "./src-DQ_-NO-4.js";
2
2
  import { createContext, useCallback, useContext, useEffect, useRef } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
 
@@ -317,7 +317,8 @@ var LayersClient = class {
317
317
  appVersion: SDK_VERSION,
318
318
  deviceModel: this.detectDeviceModel(),
319
319
  locale: this.detectLocale(),
320
- screenSize: this.detectScreenSize()
320
+ screenSize: this.detectScreenSize(),
321
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
321
322
  };
322
323
  this.core.setDeviceContext(context);
323
324
  }
@@ -395,4 +396,4 @@ const SDK_VERSION = typeof __LAYERS_CLIENT_VERSION__ !== "undefined" ? __LAYERS_
395
396
 
396
397
  //#endregion
397
398
  export { getAttributionProperties as i, LayersError$1 as n, getAttribution as r, LayersClient as t };
398
- //# sourceMappingURL=src-CDTj2A6Q.js.map
399
+ //# sourceMappingURL=src-DQ_-NO-4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src-CDTj2A6Q.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 };\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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"}
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layers/client",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
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.0.1"
36
+ "@layers/core-wasm": "1.2.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react": ">=18"
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-BCpCaNor.d.ts","names":[],"sources":["../../wasm/src/types.ts","../src/api-types.ts","../src/attribution.ts","../src/index.ts"],"sourcesContent":[],"mappings":"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"}