@levo-so/insights 0.1.65 → 0.1.71

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.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Storage keys used by the insights module.
3
+ * These are the same keys used in createLevoInsights.
4
+ */
5
+ export declare const STORAGE_KEYS: {
6
+ /** Legacy: Lock key for identify operation (no longer used internally) */
7
+ readonly identify: "lock:lv_aud_identify";
8
+ /** Key for tracking open tab count */
9
+ readonly open_tabs: "lv_insights_ot";
10
+ /** Key for current tab ID (sessionStorage) */
11
+ readonly current_tab: "lv_insights_ct";
12
+ /** Key for all tabs registry */
13
+ readonly all_tabs: "lv_insights_at";
14
+ /** Device JWT for direct mode (1yr expiry, rotated on /welcome, analytics-only scope) */
15
+ readonly device_token: "lv_aud_device";
16
+ /** Session JWT for direct mode (1yr expiry, rotated on /welcome, analytics-only scope) */
17
+ readonly session_token: "lv_aud_session";
18
+ /** Cached insights mode ('proxy' | 'direct') */
19
+ readonly mode: "lv_aud_mode";
20
+ /** Key to store session data **/
21
+ readonly session: "lv_insights_session";
22
+ };
package/dist/index.d.ts CHANGED
@@ -1,305 +1,4 @@
1
- import { ILevoClient } from '@levo-so/core';
2
- import { AnalyticsInstance } from 'analytics';
3
-
4
- declare const AnalyticsEventsList: readonly ["bevy.collection.filled", "bevy.collection.submitted", "bevy.collection.view", "block.view", "blog.post.view", "event.booking.confirmed", "event.booking.initiated", "event.booking.pending", "event.coupon.applied", "event.event.view", "form.change", "form.submit", "membership.account.signin", "membership.account.signout", "membership.account.signup", "button.click", "page.bounce", "page.click", "page.copy", "page.impression", "page.scroll", "page.view", "page.selection", "user.active", "user.idle"];
5
- type AnalyticsEventType = (typeof AnalyticsEventsList)[number];
6
- declare const AnalyticsEvents: {
7
- "bevy.collection.filled": "bevy.collection.filled";
8
- "bevy.collection.submitted": "bevy.collection.submitted";
9
- "bevy.collection.view": "bevy.collection.view";
10
- "block.view": "block.view";
11
- "blog.post.view": "blog.post.view";
12
- "event.booking.confirmed": "event.booking.confirmed";
13
- "event.booking.initiated": "event.booking.initiated";
14
- "event.booking.pending": "event.booking.pending";
15
- "event.coupon.applied": "event.coupon.applied";
16
- "event.event.view": "event.event.view";
17
- "form.change": "form.change";
18
- "form.submit": "form.submit";
19
- "membership.account.signin": "membership.account.signin";
20
- "membership.account.signout": "membership.account.signout";
21
- "membership.account.signup": "membership.account.signup";
22
- "button.click": "button.click";
23
- "page.bounce": "page.bounce";
24
- "page.click": "page.click";
25
- "page.copy": "page.copy";
26
- "page.impression": "page.impression";
27
- "page.scroll": "page.scroll";
28
- "page.view": "page.view";
29
- "page.selection": "page.selection";
30
- "user.active": "user.active";
31
- "user.idle": "user.idle";
32
- };
33
- declare namespace ILevoAudience {
34
- interface Traits {
35
- private_mode: boolean;
36
- dark_mode: boolean;
37
- locale: string;
38
- timezone: string;
39
- referrer: {
40
- type: string;
41
- referrer: Record<string, string>;
42
- data: Record<string, string>;
43
- };
44
- properties: Record<string, any>;
45
- withLock?: boolean;
46
- }
47
- type BaseProperties = Traits & {
48
- resource: string;
49
- identifier: string;
50
- };
51
- interface BlockProperties {
52
- id: string;
53
- }
54
- interface ActivityProperties {
55
- seconds_idle?: number;
56
- seconds_active?: number;
57
- }
58
- interface ScrollProperties {
59
- percent: number;
60
- }
61
- type Properties = Partial<BaseProperties & BlockProperties & ActivityProperties & ScrollProperties> & Partial<Omit<BaseInput, "workspace_id" | "tab_count" | "tab_id">> & Record<string, any>;
62
- type EventProperties = {
63
- properties: Properties;
64
- traits: Traits;
65
- event: AnalyticsEventType;
66
- type: "track" | "page" | "identify";
67
- userId: string | null;
68
- };
69
- type BaseInput = {
70
- workspace_id: string;
71
- site_id?: string;
72
- hostname: string;
73
- pathname: string;
74
- page_title: string;
75
- url: string;
76
- created_at: string;
77
- tab_id: string;
78
- tab_count: number;
79
- };
80
- type WelcomeInput = Traits & BaseInput;
81
- type WelcomeResponse = {
82
- session: string;
83
- device: string;
84
- };
85
- type CollectInput = BaseInput & {
86
- session_id?: string;
87
- device_id?: string;
88
- event: AnalyticsEventType;
89
- version?: number;
90
- properties: Properties;
91
- resource: string;
92
- identifier: string | undefined;
93
- };
94
- type ActivityStatus = {
95
- isIdle: boolean;
96
- isDisabled: boolean;
97
- active: number;
98
- idle: number;
99
- };
100
- }
101
-
102
- interface IInsightOptions {
103
- /** Site ID for analytics tracking */
104
- site?: string | null;
105
- insightsUrl?: string;
106
- /** Direct insights API URL for third-party mode (when reverse proxy unavailable) */
107
- directInsightsUrl?: string;
108
- /** Insights mode: 'auto' (default) detects via ping, 'proxy' forces reverse proxy, 'direct' forces direct API */
109
- insightsMode?: "auto" | "proxy" | "direct";
110
- /** Timeout for proxy ping detection in ms (default: 3000) */
111
- pingTimeout?: number;
112
- }
113
-
114
- /**
115
- * @fileoverview Levo Audience Analytics Module
116
- *
117
- * This module provides client-side analytics tracking for Levo-powered websites.
118
- * It handles event collection, batching, cross-tab synchronization, and reliable
119
- * delivery of analytics data to the Levo Insights API.
120
- *
121
- * ## Architecture Overview
122
- *
123
- * ```
124
- * ┌────────────────────────────────────────────────────────────────────────┐
125
- * │ Browser Tab │
126
- * │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
127
- * │ │ track() │───▶│ EventQueue │───▶│ /v1/insights/event/bulk │ │
128
- * │ │ page() │ │ (batching) │ │ (sendBeacon / fetch) │ │
129
- * │ │ identify() │ └──────────────┘ └──────────────────────────┘ │
130
- * │ └──────────────┘ │ │
131
- * │ │ │ flush on: │
132
- * │ │ │ - 50 events (BATCH_SIZE) │
133
- * │ │ │ - 5s interval (BATCH_INTERVAL_MS) │
134
- * │ │ │ - page exit (visibilitychange) │
135
- * │ │ │ - beforeunload / pagehide │
136
- * │ ▼ │ │
137
- * │ ┌──────────────┐ │ │
138
- * │ │ Rate Limiter │───────────┘ │
139
- * │ │ (500/page) │ │
140
- * │ └──────────────┘ │
141
- * └────────────────────────────────────────────────────────────────────────┘
142
- * │
143
- * │ BroadcastChannel
144
- * │ (SESSION_SYNC, SESSION_REQUEST)
145
- * ▼
146
- * ┌────────────────────────────────────────────────────────────────────────┐
147
- * │ Other Browser Tabs │
148
- * │ - Receive session/device IDs from first tab │
149
- * │ - Skip /welcome API call if session already established │
150
- * └────────────────────────────────────────────────────────────────────────┘
151
- * ```
152
- *
153
- * ## Key Features
154
- *
155
- * ### 1. Event Batching
156
- * Instead of sending each event immediately (which caused 100+ requests per page),
157
- * events are queued and sent in batches. This reduces:
158
- * - Network requests by 50-100x
159
- * - Server load
160
- * - Bandwidth usage
161
- *
162
- * ### 2. Cross-Tab Session Synchronization
163
- * Uses BroadcastChannel API to share session/device IDs across tabs:
164
- * - First tab to complete /welcome broadcasts session to others
165
- * - Other tabs skip /welcome API call, reducing duplicate sessions
166
- * - Solves "Open in New Tab" race condition where multiple tabs would
167
- * each create separate sessions
168
- *
169
- * ### 3. Reliable Page Exit Handling
170
- * Uses multiple mechanisms to ensure events are sent before page unload:
171
- * - visibilitychange (most reliable, fires when tab hidden)
172
- * - beforeunload (backup for navigation)
173
- * - pagehide (backup for bfcache scenarios)
174
- * - sendBeacon API (survives page unload)
175
- *
176
- * ### 4. Rate Limiting
177
- * Prevents runaway loops or malicious spam:
178
- * - Max 500 events per page
179
- * - Counter resets on page navigation
180
- *
181
- * ## Session Flow
182
- *
183
- * ```
184
- * Page Load
185
- * │
186
- * ▼
187
- * initiate() called
188
- * │
189
- * ├── Initialize BroadcastChannel
190
- * │
191
- * ├── Request session from other tabs (SESSION_REQUEST)
192
- * │
193
- * ├── Wait 50ms for response
194
- * │ │
195
- * │ ├── If SESSION_SYNC received: Use shared session, skip /welcome
196
- * │ │
197
- * │ └── If no response: Call /welcome API
198
- * │ │
199
- * │ └── On success: Broadcast SESSION_SYNC to other tabs
200
- * │
201
- * └── Start tracking events
202
- * ```
203
- *
204
- * ## API Endpoints Used
205
- *
206
- * - `POST /v1/insights/event/welcome` - Initial session establishment
207
- * - Called once per session (first tab only, thanks to BroadcastChannel)
208
- * - Returns session_id and device_id from HttpOnly cookies
209
- *
210
- * - `POST /v1/insights/event/bulk` - Batch event submission
211
- * - Receives array of CollectInput events
212
- * - Used for all event tracking (replaces individual /collect calls)
213
- *
214
- * ## Configuration Constants
215
- *
216
- * - BATCH_SIZE (50): Flush queue when this many events accumulated
217
- * - BATCH_INTERVAL_MS (5000): Flush queue every 5 seconds regardless of size
218
- * - MAX_EVENTS_PER_PAGE (500): Rate limit per page to prevent abuse
219
- * - BROADCAST_CHANNEL_NAME ("levo_analytics"): Channel for cross-tab sync
220
- *
221
- * ## Browser Compatibility
222
- *
223
- * - BroadcastChannel: Modern browsers (Chrome 54+, Firefox 38+, Safari 15.4+)
224
- * - Gracefully degrades: If unavailable, each tab calls /welcome independently
225
- *
226
- * - sendBeacon: Universal support (Chrome 39+, Firefox 31+, Safari 11.1+)
227
- * - Fallback: fetch() with keepalive option
228
- *
229
- * @module @levo-so/core/control/audience
230
- */
231
-
232
- /**
233
- * Creates the Levo Audience analytics module.
234
- *
235
- * This factory function creates a new audience module instance tied to
236
- * a specific Levo control instance and HTTP client. The module manages
237
- * all analytics tracking for the page.
238
- *
239
- * @param core - The Levo control instance containing workspace config
240
- * @param httpClient - HTTP client for making API requests
241
- * @returns The audience module with tracking methods
242
- *
243
- * @example
244
- * ```typescript
245
- * const audience = createLevoAudienceModule(levoControl, httpClient);
246
- *
247
- * // Initialize on page load
248
- * await audience.initiate({ id: 'page-123' });
249
- *
250
- * // Track custom events
251
- * audience.track('button.click', { buttonId: 'cta-signup' });
252
- *
253
- * // Cleanup on unmount (optional, for SPAs)
254
- * audience.destroy();
255
- * ```
256
- */
257
- declare const createLevoInsights: (client: ILevoClient, options?: IInsightOptions) => {
258
- readonly insightsUrl: string;
259
- /** Get the underlying analytics instance (read-only) */
260
- readonly instance: AnalyticsInstance | null;
261
- /** Check if session has been established (read-only) */
262
- readonly is_identified: boolean;
263
- /** Storage keys used by the module */
264
- storage_keys: {
265
- /** Legacy: Lock key for identify operation (no longer used internally) */
266
- identify: string;
267
- /** Key for tracking open tab count */
268
- open_tabs: string;
269
- /** Key for current tab ID (sessionStorage) */
270
- current_tab: string;
271
- /** Key for all tabs registry */
272
- all_tabs: string;
273
- /** Device JWT for direct mode (1yr expiry, rotated on /welcome, analytics-only scope) */
274
- device_token: string;
275
- /** Session JWT for direct mode (1yr expiry, rotated on /welcome, analytics-only scope) */
276
- session_token: string;
277
- /** Cached insights mode ('proxy' | 'direct') */
278
- mode: string;
279
- };
280
- /** Initialize the module for a page */
281
- initiate: (properties: ILevoAudience.Properties) => Promise<any>;
282
- /** Identify/establish session */
283
- identify: (options?: {
284
- withLock?: boolean;
285
- }) => Promise<void>;
286
- /** Track a custom event */
287
- track: <T extends ILevoAudience.Properties>(event: AnalyticsEventType, properties: T & ILevoAudience.Properties) => Promise<any>;
288
- /** Track a bounce event */
289
- bounce: (properties: ILevoAudience.Properties) => Promise<void>;
290
- /** Cleanup the module */
291
- destroy: () => void;
292
- };
293
- /**
294
- * Type representing the audience module instance.
295
- * Use this when you need to type a variable holding the module.
296
- *
297
- * @example
298
- * ```typescript
299
- * let audience: ILevoAudienceModule;
300
- * audience = createLevoAudienceModule(core, httpClient);
301
- * ```
302
- */
303
- type ILevoInsights = ReturnType<typeof createLevoInsights>;
304
-
305
- export { type AnalyticsEventType, AnalyticsEvents, AnalyticsEventsList, type IInsightOptions, ILevoAudience, type ILevoInsights, createLevoInsights };
1
+ export * from './lib/insights';
2
+ export * from './types/analytics';
3
+ export * from './types/identity';
4
+ export * from './types/options';