@levo-so/insights 0.1.64 → 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.
- package/dist/S_TwsxGkG8z9.js +857 -0
- package/dist/constants/storageKeys.d.ts +22 -0
- package/dist/index.d.ts +4 -304
- package/dist/index.js +582 -856
- package/dist/legacy/index.d.ts +71 -0
- package/dist/lib/analytics.d.ts +10 -0
- package/dist/lib/insights.d.ts +24 -0
- package/dist/stores/config.d.ts +11 -0
- package/dist/stores/events.d.ts +45 -0
- package/dist/stores/session.d.ts +21 -0
- package/dist/stores.d.ts +8 -0
- package/dist/stores.js +14 -0
- package/dist/tracking/activity.d.ts +21 -0
- package/dist/tracking/bounce.d.ts +24 -0
- package/dist/tracking/clicks.d.ts +9 -0
- package/dist/tracking/clipboard.d.ts +8 -0
- package/dist/tracking/currentTab.d.ts +16 -0
- package/dist/tracking/forms.d.ts +8 -0
- package/dist/tracking/page.d.ts +8 -0
- package/dist/tracking/scrollBehavior.d.ts +21 -0
- package/dist/tracking/textSelection.d.ts +13 -0
- package/dist/types/analytics.d.ts +4 -0
- package/dist/types/identity.d.ts +12 -0
- package/dist/types/options.d.ts +14 -0
- package/dist/utils/autocapture.d.ts +22 -0
- package/dist/utils/checkLocalStorage.d.ts +4 -0
- package/dist/utils/createPlugin.d.ts +66 -0
- package/dist/utils/detectMode.d.ts +10 -0
- package/dist/utils/getAuthHeaders.d.ts +9 -0
- package/dist/utils/getReferrer.d.ts +24 -0
- package/dist/utils/getUserProperties.d.ts +7 -0
- package/dist/utils/isIncognito.d.ts +8 -0
- package/dist/utils/lock.d.ts +20 -0
- package/dist/utils/pingEndpoint.d.ts +4 -0
- package/dist/utils/rageclick.d.ts +20 -0
- package/package.json +14 -8
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ILevoClient } from '@levo-so/core';
|
|
2
|
+
import { AnalyticsInstance } from 'analytics';
|
|
3
|
+
import { AnalyticsEventType, ILevoAudience } from '../types/analytics';
|
|
4
|
+
import { IInsightOptions } from '../types/options';
|
|
5
|
+
/**
|
|
6
|
+
* Creates the Levo Audience analytics module.
|
|
7
|
+
*
|
|
8
|
+
* This factory function creates a new audience module instance tied to
|
|
9
|
+
* a specific Levo control instance and HTTP client. The module manages
|
|
10
|
+
* all analytics tracking for the page.
|
|
11
|
+
*
|
|
12
|
+
* @param core - The Levo control instance containing workspace config
|
|
13
|
+
* @param httpClient - HTTP client for making API requests
|
|
14
|
+
* @returns The audience module with tracking methods
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const audience = createLevoAudienceModule(levoControl, httpClient);
|
|
19
|
+
*
|
|
20
|
+
* // Initialize on page load
|
|
21
|
+
* await audience.initiate({ id: 'page-123' });
|
|
22
|
+
*
|
|
23
|
+
* // Track custom events
|
|
24
|
+
* audience.track('button.click', { buttonId: 'cta-signup' });
|
|
25
|
+
*
|
|
26
|
+
* // Cleanup on unmount (optional, for SPAs)
|
|
27
|
+
* audience.destroy();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare const createLevoInsights: (client: ILevoClient, options: IInsightOptions) => {
|
|
31
|
+
/** Get the underlying analytics instance (read-only) */
|
|
32
|
+
readonly instance: AnalyticsInstance | null;
|
|
33
|
+
/** Check if session has been established (read-only) */
|
|
34
|
+
readonly is_identified: boolean;
|
|
35
|
+
/** Storage keys used by the module */
|
|
36
|
+
storage_keys: {
|
|
37
|
+
readonly identify: "lock:lv_aud_identify";
|
|
38
|
+
readonly open_tabs: "lv_insights_ot";
|
|
39
|
+
readonly current_tab: "lv_insights_ct";
|
|
40
|
+
readonly all_tabs: "lv_insights_at";
|
|
41
|
+
readonly device_token: "lv_aud_device";
|
|
42
|
+
readonly session_token: "lv_aud_session";
|
|
43
|
+
readonly mode: "lv_aud_mode";
|
|
44
|
+
readonly session: "lv_insights_session";
|
|
45
|
+
};
|
|
46
|
+
/** Initialize the module for a page */
|
|
47
|
+
initiate: (properties: ILevoAudience.Properties) => Promise<any>;
|
|
48
|
+
/** Identify/establish session */
|
|
49
|
+
identify: (options?: {
|
|
50
|
+
withLock?: boolean;
|
|
51
|
+
}) => Promise<void>;
|
|
52
|
+
/** Track a custom event */
|
|
53
|
+
track: <T extends ILevoAudience.Properties>(event: AnalyticsEventType, properties: T & ILevoAudience.Properties) => Promise<any>;
|
|
54
|
+
/** Track a bounce event */
|
|
55
|
+
bounce: (properties: ILevoAudience.Properties) => Promise<void>;
|
|
56
|
+
/** Cleanup the module */
|
|
57
|
+
destroy: () => void;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Type representing the audience module instance.
|
|
61
|
+
* Use this when you need to type a variable holding the module.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* let audience: ILevoAudienceModule;
|
|
66
|
+
* audience = createLevoAudienceModule(core, httpClient);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export type ILevoInsights = ReturnType<typeof createLevoInsights>;
|
|
70
|
+
export * from '../types/analytics';
|
|
71
|
+
export * from '../types/options';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ILevoClient } from '@levo-so/core';
|
|
2
|
+
import { TrackFn } from '../types/analytics';
|
|
3
|
+
/**
|
|
4
|
+
* Creates the analytics instance with our custom plugin.
|
|
5
|
+
*
|
|
6
|
+
* @param client - The Levo client instance
|
|
7
|
+
* @param sendEvent - Function to handle event tracking
|
|
8
|
+
* @param isValid - Function to check if the current instance is still valid/active
|
|
9
|
+
*/
|
|
10
|
+
export declare const createAnalytics: (client: ILevoClient, sendEvent: TrackFn, isValid: () => boolean) => import('analytics').AnalyticsInstance | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ILevoClient } from '@levo-so/core';
|
|
2
|
+
import { TrackFn } from '../types/analytics';
|
|
3
|
+
import { IInsightOptions } from '../types/options';
|
|
4
|
+
/**
|
|
5
|
+
* Creates the Levo Audience analytics module.
|
|
6
|
+
*
|
|
7
|
+
* This factory function creates a new audience module instance tied to
|
|
8
|
+
* a specific Levo control instance and HTTP client. The module manages
|
|
9
|
+
* all analytics tracking for the page.
|
|
10
|
+
*
|
|
11
|
+
* @param client - The Levo control instance containing workspace config
|
|
12
|
+
* @param options - Configuration options for the insights module
|
|
13
|
+
* @returns The audience module with tracking methods
|
|
14
|
+
*/
|
|
15
|
+
declare const createLevoInsights: (client: ILevoClient, options: IInsightOptions) => {
|
|
16
|
+
init: (initOptions?: {
|
|
17
|
+
pageId?: string | null;
|
|
18
|
+
}) => void;
|
|
19
|
+
destroy: () => void;
|
|
20
|
+
track: TrackFn;
|
|
21
|
+
readonly instance: import('analytics').AnalyticsInstance | null;
|
|
22
|
+
};
|
|
23
|
+
type ILevoInsights = ReturnType<typeof createLevoInsights>;
|
|
24
|
+
export { createLevoInsights, type ILevoInsights };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface IInsightsConfig {
|
|
2
|
+
workspace: string | null;
|
|
3
|
+
page_id: string | null;
|
|
4
|
+
site_id: string | null;
|
|
5
|
+
debug: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare const $config: import('nanostores').PreinitializedMapStore<IInsightsConfig> & object;
|
|
8
|
+
declare const getConfig: () => IInsightsConfig;
|
|
9
|
+
declare const setConfig: (v: Partial<IInsightsConfig>) => void;
|
|
10
|
+
declare const updateConfigKey: <T extends keyof IInsightsConfig>(key: T, value: IInsightsConfig[T]) => void;
|
|
11
|
+
export { $config, getConfig, setConfig, updateConfigKey, type IInsightsConfig };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ILevoAudience } from '../types/analytics';
|
|
2
|
+
type IQueuedEvent = Partial<ILevoAudience.CollectInput> & {
|
|
3
|
+
event: string;
|
|
4
|
+
created_at: string;
|
|
5
|
+
};
|
|
6
|
+
declare const $eventQueue: import('nanostores').PreinitializedWritableAtom<IQueuedEvent[]> & object;
|
|
7
|
+
declare const $lifetimePageCount: import('nanostores').PreinitializedWritableAtom<number> & object;
|
|
8
|
+
declare const $totalEventCount: import('nanostores').ReadableAtom<number>;
|
|
9
|
+
/**
|
|
10
|
+
* Initialize a listener that flushes the event queue immediately
|
|
11
|
+
* when the session becomes identified.
|
|
12
|
+
*
|
|
13
|
+
* @returns Unsubscribe function
|
|
14
|
+
*/
|
|
15
|
+
declare const initSessionFlushListener: () => () => void;
|
|
16
|
+
declare const getEventQueue: () => IQueuedEvent[];
|
|
17
|
+
/**
|
|
18
|
+
* Flush all queued events to the server.
|
|
19
|
+
*
|
|
20
|
+
* This function:
|
|
21
|
+
* 1. Takes all events from the queue
|
|
22
|
+
* 2. Merges context from stores (workspace, session, tab info)
|
|
23
|
+
* 3. Sends to /v1/insights/event/bulk via sendBeacon (preferred) or fetch
|
|
24
|
+
*
|
|
25
|
+
* sendBeacon is preferred because:
|
|
26
|
+
* - It survives page unload (critical for page exit events)
|
|
27
|
+
* - It doesn't block the main thread
|
|
28
|
+
* - Browser queues it and sends when convenient
|
|
29
|
+
*
|
|
30
|
+
* fetch with keepalive is the fallback for when sendBeacon fails or
|
|
31
|
+
* isn't available.
|
|
32
|
+
*/
|
|
33
|
+
declare const flushEventQueue: (_eventQueue: IQueuedEvent[]) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Add an event to the queue for batched sending.
|
|
36
|
+
* Only stores in-time data (event, properties, page context).
|
|
37
|
+
* Context from stores is merged at flush time.
|
|
38
|
+
*/
|
|
39
|
+
declare const queueEvent: (event: IQueuedEvent) => void;
|
|
40
|
+
declare const resetRateLimit: () => void;
|
|
41
|
+
/**
|
|
42
|
+
* Clear all pending events and reset state.
|
|
43
|
+
*/
|
|
44
|
+
export declare const clearEventQueue: () => void;
|
|
45
|
+
export { $eventQueue, $lifetimePageCount, $totalEventCount, queueEvent, resetRateLimit, initSessionFlushListener, getEventQueue, flushEventQueue, type IQueuedEvent, };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { IIdentity } from '../types/identity';
|
|
2
|
+
interface ISession {
|
|
3
|
+
isIdentified: boolean;
|
|
4
|
+
isIdentifying: boolean;
|
|
5
|
+
sessionId: string | null;
|
|
6
|
+
deviceId: string | null;
|
|
7
|
+
deviceToken: string | null;
|
|
8
|
+
sessionToken: string | null;
|
|
9
|
+
allTabs: string[];
|
|
10
|
+
mode: "proxy" | "direct";
|
|
11
|
+
insightsBaseUrl: string | null;
|
|
12
|
+
identity: IIdentity | null;
|
|
13
|
+
}
|
|
14
|
+
declare const $session: import('nanostores').PreinitializedWritableAtom<ISession> & object;
|
|
15
|
+
declare const onSessionReady: (cb: () => void) => void;
|
|
16
|
+
declare const isSessionReady: () => boolean;
|
|
17
|
+
declare const getSession: () => ISession;
|
|
18
|
+
declare const updateSession: (v: Partial<ISession>) => void;
|
|
19
|
+
export { $session, getSession, updateSession, onSessionReady, isSessionReady, type ISession };
|
|
20
|
+
declare const $isContextReady: import('nanostores').ReadableAtom<boolean>;
|
|
21
|
+
export { $isContextReady };
|
package/dist/stores.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { $config } from './stores/config';
|
|
2
|
+
export { $eventQueue, $lifetimePageCount, $totalEventCount } from './stores/events';
|
|
3
|
+
export { $isContextReady, $session } from './stores/session';
|
|
4
|
+
export { $activity } from './tracking/activity';
|
|
5
|
+
export { $pageLifecycle } from './tracking/bounce';
|
|
6
|
+
export { $currentTab } from './tracking/currentTab';
|
|
7
|
+
export { $scrollBehavior } from './tracking/scrollBehavior';
|
|
8
|
+
export { $selectedText } from './tracking/textSelection';
|
package/dist/stores.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { f as s, $ as t, h as $, a as i, d as o, b as c, g as n, i as l, j as r, e as f, c as u } from "./S_TwsxGkG8z9.js";
|
|
2
|
+
export {
|
|
3
|
+
s as $activity,
|
|
4
|
+
t as $config,
|
|
5
|
+
$ as $currentTab,
|
|
6
|
+
i as $eventQueue,
|
|
7
|
+
o as $isContextReady,
|
|
8
|
+
c as $lifetimePageCount,
|
|
9
|
+
n as $pageLifecycle,
|
|
10
|
+
l as $scrollBehavior,
|
|
11
|
+
r as $selectedText,
|
|
12
|
+
f as $session,
|
|
13
|
+
u as $totalEventCount
|
|
14
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AnalyticsInstance } from 'analytics';
|
|
2
|
+
/**
|
|
3
|
+
* Activity state interface.
|
|
4
|
+
*/
|
|
5
|
+
interface IActivityState {
|
|
6
|
+
status: "active" | "idle";
|
|
7
|
+
seconds: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Reactive store for user activity.
|
|
11
|
+
*/
|
|
12
|
+
declare const $activity: import('nanostores').PreinitializedMapStore<IActivityState> & object;
|
|
13
|
+
/**
|
|
14
|
+
* Initialize activity tracking.
|
|
15
|
+
*
|
|
16
|
+
* @param instance - Analytics instance
|
|
17
|
+
* @returns Cleanup function
|
|
18
|
+
*/
|
|
19
|
+
declare const initActivityTracker: (instance: AnalyticsInstance) => () => void;
|
|
20
|
+
declare const getActivityStatus: () => IActivityState;
|
|
21
|
+
export { $activity, initActivityTracker, getActivityStatus };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AnalyticsInstance } from 'analytics';
|
|
2
|
+
/**
|
|
3
|
+
* Page lifecycle states.
|
|
4
|
+
*/
|
|
5
|
+
declare enum LifecycleState {
|
|
6
|
+
ACTIVE = "active",
|
|
7
|
+
PASSIVE = "passive",
|
|
8
|
+
HIDDEN = "hidden",
|
|
9
|
+
FROZEN = "frozen",
|
|
10
|
+
TERMINATED = "terminated"
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Reactive store for the current page lifecycle state.
|
|
14
|
+
*/
|
|
15
|
+
declare const $pageLifecycle: import('nanostores').PreinitializedWritableAtom<LifecycleState> & object;
|
|
16
|
+
/**
|
|
17
|
+
* Initialize bounce tracking.
|
|
18
|
+
*
|
|
19
|
+
* @param instance - Analytics instance
|
|
20
|
+
* @param options - Configuration options (e.g., page ID)
|
|
21
|
+
* @returns Cleanup function
|
|
22
|
+
*/
|
|
23
|
+
declare const initBounceTracker: (instance: AnalyticsInstance) => () => void;
|
|
24
|
+
export { $pageLifecycle, initBounceTracker, LifecycleState };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AnalyticsInstance } from 'analytics';
|
|
2
|
+
/**
|
|
3
|
+
* Create a clicks tracker instance.
|
|
4
|
+
*
|
|
5
|
+
* @param instance - Analytics instance for tracking events
|
|
6
|
+
* @returns Cleanup function
|
|
7
|
+
*/
|
|
8
|
+
declare const initClicksTracker: (instance: AnalyticsInstance) => () => void;
|
|
9
|
+
export { initClicksTracker };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AnalyticsInstance } from 'analytics';
|
|
2
|
+
/**
|
|
3
|
+
* Reactive store for the local unique tab ID.
|
|
4
|
+
* This ID is NOT shared across tabs (unlike the session store).
|
|
5
|
+
*/
|
|
6
|
+
declare const $currentTab: import('nanostores').PreinitializedWritableAtom<string | null> & object;
|
|
7
|
+
/**
|
|
8
|
+
* Initialize current tab tracking.
|
|
9
|
+
* Assumes the session store is already synchronized (isReady).
|
|
10
|
+
*
|
|
11
|
+
* @param _instance - Analytics instance
|
|
12
|
+
* @returns Cleanup function
|
|
13
|
+
*/
|
|
14
|
+
declare const initCurrentTabTracker: (_instance: AnalyticsInstance) => () => void;
|
|
15
|
+
declare const getCurrentTab: () => string | null;
|
|
16
|
+
export { $currentTab, initCurrentTabTracker, getCurrentTab };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AnalyticsInstance } from 'analytics';
|
|
2
|
+
/**
|
|
3
|
+
* Scroll state interface.
|
|
4
|
+
*/
|
|
5
|
+
interface IScrollState {
|
|
6
|
+
depth: number;
|
|
7
|
+
speedCategory: "read" | "scan";
|
|
8
|
+
direction: "down" | "up";
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Reactive store for scroll behavior.
|
|
12
|
+
*/
|
|
13
|
+
declare const $scrollBehavior: import('nanostores').PreinitializedMapStore<IScrollState> & object;
|
|
14
|
+
/**
|
|
15
|
+
* Initialize scroll behavior tracking.
|
|
16
|
+
*
|
|
17
|
+
* @param instance - Analytics instance
|
|
18
|
+
* @returns Cleanup function
|
|
19
|
+
*/
|
|
20
|
+
declare const initScrollBehaviorTracker: (instance: AnalyticsInstance) => () => void;
|
|
21
|
+
export { $scrollBehavior, initScrollBehaviorTracker };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AnalyticsInstance } from 'analytics';
|
|
2
|
+
/**
|
|
3
|
+
* Reactive store for the currently selected text.
|
|
4
|
+
*/
|
|
5
|
+
declare const $selectedText: import('nanostores').PreinitializedWritableAtom<string | null> & object;
|
|
6
|
+
/**
|
|
7
|
+
* Initialize text selection tracking.
|
|
8
|
+
*
|
|
9
|
+
* @param instance - Analytics instance
|
|
10
|
+
* @returns Cleanup function
|
|
11
|
+
*/
|
|
12
|
+
declare const initTextSelectionTracker: (instance: AnalyticsInstance) => () => void;
|
|
13
|
+
export { $selectedText, initTextSelectionTracker };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ILevoAudience } from '@levo-so/core';
|
|
2
|
+
export type { AnalyticsEventType, ILevoAudience } from '@levo-so/core';
|
|
3
|
+
export { AnalyticsEvents } from '@levo-so/core';
|
|
4
|
+
export type TrackFn = <T extends ILevoAudience.Properties>(event: ILevoAudience.Properties["event"] & string, properties: T & ILevoAudience.Properties) => Promise<void>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ILevoAudience } from '@levo-so/core';
|
|
2
|
+
export type IIdentityReferrer = ILevoAudience.Traits["referrer"] & {
|
|
3
|
+
raw: string;
|
|
4
|
+
};
|
|
5
|
+
export interface IIdentity {
|
|
6
|
+
locale: ILevoAudience.Traits["locale"] | null;
|
|
7
|
+
timezone: ILevoAudience.Traits["timezone"] | null;
|
|
8
|
+
darkMode: ILevoAudience.Traits["dark_mode"] | null;
|
|
9
|
+
privateMode: ILevoAudience.Traits["private_mode"] | null;
|
|
10
|
+
referrer: IIdentityReferrer | null;
|
|
11
|
+
properties: ILevoAudience.Traits["properties"] | null;
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface IInsightOptions {
|
|
2
|
+
insightsUrl: string;
|
|
3
|
+
/** Site ID for analytics tracking */
|
|
4
|
+
site?: string | null;
|
|
5
|
+
/** Page ID for analytics tracking */
|
|
6
|
+
pageId?: string | null;
|
|
7
|
+
/** Direct insights API URL for third-party mode (when reverse proxy unavailable) */
|
|
8
|
+
directInsightsUrl?: string;
|
|
9
|
+
/** Insights mode: 'auto' (default) detects via ping, 'proxy' forces reverse proxy, 'direct' forces direct API */
|
|
10
|
+
mode?: "auto" | "proxy" | "direct";
|
|
11
|
+
/** Timeout for proxy ping detection in ms (default: 3000) */
|
|
12
|
+
pingTimeout?: number;
|
|
13
|
+
debug?: boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const isTextNode: (el: Element | undefined | null) => el is HTMLElement;
|
|
2
|
+
export declare const makeSafeText: (s: string | null | undefined, length?: number) => string;
|
|
3
|
+
export declare const getSafeText: (el: Element) => string;
|
|
4
|
+
export declare const getEventTarget: (e: Event) => Element | null;
|
|
5
|
+
export declare const shouldCaptureDomEvent: (el: Element, event: Event) => boolean;
|
|
6
|
+
export declare const shouldCaptureValue: (value: string, anchorRegexes?: boolean) => boolean;
|
|
7
|
+
export declare const isAngularStyleAttr: (attributeName: string) => boolean;
|
|
8
|
+
export declare const getDirectAndNestedSpanText: (target: Element) => string;
|
|
9
|
+
export type Property = any;
|
|
10
|
+
export type Properties = Record<string, Property>;
|
|
11
|
+
/** Text source indicates where the text was found */
|
|
12
|
+
export type TextSource = "text" | "aria-label" | "title" | "data-track-label" | "alt" | "placeholder" | "innerText" | "none";
|
|
13
|
+
/**
|
|
14
|
+
* Get element text with comprehensive fallback chain.
|
|
15
|
+
* Priority: direct text → aria-label → title → data-track-label → alt (for images) → placeholder → innerText
|
|
16
|
+
*/
|
|
17
|
+
export declare const getElementTextWithFallback: (el: Element) => {
|
|
18
|
+
text: string;
|
|
19
|
+
source: TextSource;
|
|
20
|
+
};
|
|
21
|
+
export declare const getAttributes: (element: Element) => Properties;
|
|
22
|
+
export declare const getPropertiesFromEvent: (e: Event, eventName: string) => Properties | null;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { STORAGE_KEYS } from '../constants/storageKeys';
|
|
2
|
+
import { AnalyticsEventType, ILevoAudience } from '../types/analytics';
|
|
3
|
+
export interface PluginContext {
|
|
4
|
+
workspace: string;
|
|
5
|
+
insightsUrl: string;
|
|
6
|
+
site?: string | null;
|
|
7
|
+
session: {
|
|
8
|
+
get: () => string;
|
|
9
|
+
set: (v: string) => void;
|
|
10
|
+
};
|
|
11
|
+
device: {
|
|
12
|
+
get: () => string;
|
|
13
|
+
set: (v: string) => void;
|
|
14
|
+
};
|
|
15
|
+
isIdentified: {
|
|
16
|
+
get: () => boolean;
|
|
17
|
+
set: (v: boolean) => void;
|
|
18
|
+
};
|
|
19
|
+
pendingIdentify: {
|
|
20
|
+
get: () => boolean;
|
|
21
|
+
set: (v: boolean) => void;
|
|
22
|
+
};
|
|
23
|
+
insightsMode: {
|
|
24
|
+
get: () => "proxy" | "direct";
|
|
25
|
+
};
|
|
26
|
+
getCurrentTabId: () => string;
|
|
27
|
+
getTabCount: () => number;
|
|
28
|
+
queueEvent: (event: ILevoAudience.CollectInput) => void;
|
|
29
|
+
broadcastSession: () => void;
|
|
30
|
+
request: <R, T>(url: string, data: T) => Promise<R | null>;
|
|
31
|
+
setInStorage: (key: string, value: string) => void;
|
|
32
|
+
resetEventCount: () => void;
|
|
33
|
+
storage_keys: typeof STORAGE_KEYS;
|
|
34
|
+
properties: ILevoAudience.Properties;
|
|
35
|
+
track: (event: AnalyticsEventType, props: any) => void;
|
|
36
|
+
debugEvents?: {
|
|
37
|
+
input: Partial<ILevoAudience.CollectInput>;
|
|
38
|
+
payload: ILevoAudience.CollectInput;
|
|
39
|
+
queued: boolean;
|
|
40
|
+
}[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Factory function to create the analytics plugin.
|
|
44
|
+
* Extracted from initiate() to improve maintainability.
|
|
45
|
+
*/
|
|
46
|
+
export declare const createPlugin: (context: PluginContext) => {
|
|
47
|
+
name: string;
|
|
48
|
+
/**
|
|
49
|
+
* Handle track events (custom events like clicks, scrolls, etc.)
|
|
50
|
+
*/
|
|
51
|
+
track: ({ payload }: {
|
|
52
|
+
payload: ILevoAudience.Properties;
|
|
53
|
+
}) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Handle page view events.
|
|
56
|
+
*/
|
|
57
|
+
page: ({ payload }: {
|
|
58
|
+
payload: ILevoAudience.EventProperties;
|
|
59
|
+
}) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Handle identify events (session establishment).
|
|
62
|
+
*/
|
|
63
|
+
identify: ({ payload }: {
|
|
64
|
+
payload: ILevoAudience.EventProperties;
|
|
65
|
+
}) => void;
|
|
66
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IInsightOptions } from '../types/options';
|
|
2
|
+
type DetectionResult = {
|
|
3
|
+
mode: "proxy" | "direct";
|
|
4
|
+
url: string | null;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Detect the insights mode (proxy vs direct).
|
|
8
|
+
*/
|
|
9
|
+
export declare const detectMode: (options: IInsightOptions) => Promise<DetectionResult>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get authentication headers for direct mode.
|
|
3
|
+
* Returns empty object in proxy mode (cookies handle auth).
|
|
4
|
+
*/
|
|
5
|
+
export declare const getAuthHeaders: ({ deviceToken, sessionToken, mode, }: {
|
|
6
|
+
deviceToken?: string | null;
|
|
7
|
+
sessionToken?: string | null;
|
|
8
|
+
mode?: string | null;
|
|
9
|
+
}) => Record<string, string>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract referrer information for the current page.
|
|
3
|
+
*
|
|
4
|
+
* Uses @analytics/visitor-source to parse:
|
|
5
|
+
* - Referrer type (direct, organic, paid, social, etc.)
|
|
6
|
+
* - UTM parameters (source, medium, campaign, content, term)
|
|
7
|
+
* - Raw referrer URL
|
|
8
|
+
*
|
|
9
|
+
* Handles array-to-string conversion for UTM params that may come
|
|
10
|
+
* as arrays from the parser.
|
|
11
|
+
*
|
|
12
|
+
* @returns Referrer information object
|
|
13
|
+
*/
|
|
14
|
+
export declare const getReferrer: () => {
|
|
15
|
+
type?: undefined;
|
|
16
|
+
referrer?: undefined;
|
|
17
|
+
data?: undefined;
|
|
18
|
+
raw?: undefined;
|
|
19
|
+
} | {
|
|
20
|
+
type: string;
|
|
21
|
+
referrer: Record<string, string>;
|
|
22
|
+
data: Record<string, string>;
|
|
23
|
+
raw: string;
|
|
24
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @example
|
|
3
|
+
*
|
|
4
|
+
* const lock = new LocalStorageLock("myResource");
|
|
5
|
+
* if (lock.acquireLock()) {
|
|
6
|
+
* console.log("Lock acquired");
|
|
7
|
+
* // Do some work...
|
|
8
|
+
* lock.releaseLock();
|
|
9
|
+
* } else {
|
|
10
|
+
* console.log("Lock is already held by another instance");
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
export declare class LocalStorageLock {
|
|
15
|
+
private key;
|
|
16
|
+
constructor(lockKey: string);
|
|
17
|
+
acquireLock(expiryMs?: number): boolean;
|
|
18
|
+
releaseLock(): void;
|
|
19
|
+
isLocked(expiryMs?: number): boolean;
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rage click detection: If mouse has not moved further than RAGE_CLICK_THRESHOLD_PX
|
|
3
|
+
* over RAGE_CLICK_CLICK_COUNT+ clicks with max RAGE_CLICK_TIMEOUT_MS between clicks,
|
|
4
|
+
* it's counted as a rage click.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Check if the current click is part of a rage click sequence.
|
|
8
|
+
* Returns true for 3+ consecutive clicks within threshold.
|
|
9
|
+
*
|
|
10
|
+
* @param x - Click X coordinate
|
|
11
|
+
* @param y - Click Y coordinate
|
|
12
|
+
* @param timestamp - Click timestamp
|
|
13
|
+
* @returns True if this click completes a rage click sequence
|
|
14
|
+
*/
|
|
15
|
+
declare const isRageClick: (x: number, y: number, timestamp: number) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Reset the click sequence (useful for testing)
|
|
18
|
+
*/
|
|
19
|
+
declare const reset: () => void;
|
|
20
|
+
export { isRageClick, reset };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@levo-so/insights",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.71",
|
|
4
4
|
"author": "Levo Engineering <devs@theinternetfolks.com>",
|
|
5
5
|
"description": "Levo analytics",
|
|
6
6
|
"type": "module",
|
|
@@ -17,15 +17,18 @@
|
|
|
17
17
|
"@analytics/visitor-source": "0.0.7",
|
|
18
18
|
"analytics": "0.8.14",
|
|
19
19
|
"get-user-locale": "2.3.2",
|
|
20
|
-
"lodash-es": "4.17.21"
|
|
20
|
+
"lodash-es": "4.17.21",
|
|
21
|
+
"nanostores": "0.11.4"
|
|
21
22
|
},
|
|
22
23
|
"peerDependencies": {
|
|
23
|
-
"@levo-so/core": "0.1.
|
|
24
|
+
"@levo-so/core": "0.1.71"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
27
|
+
"@playwright/test": "1.58.2",
|
|
26
28
|
"@types/lodash-es": "4.17.12",
|
|
27
|
-
"tsup": "8.2.4",
|
|
28
29
|
"typescript": "5.9.3",
|
|
30
|
+
"vite": "7.2.4",
|
|
31
|
+
"vite-plugin-dts": "4.1.0",
|
|
29
32
|
"@levo/ts-config": "0.0.0"
|
|
30
33
|
},
|
|
31
34
|
"main": "./dist/index.js",
|
|
@@ -35,14 +38,17 @@
|
|
|
35
38
|
".": {
|
|
36
39
|
"types": "./dist/index.d.ts",
|
|
37
40
|
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./stores": {
|
|
43
|
+
"types": "./dist/stores.d.ts",
|
|
44
|
+
"default": "./dist/stores.js"
|
|
38
45
|
}
|
|
39
46
|
},
|
|
40
47
|
"scripts": {
|
|
41
48
|
"clean": "rimraf dist node_modules .turbo",
|
|
42
49
|
"check-types": "tsc --noEmit",
|
|
43
|
-
"build": "
|
|
44
|
-
"dev": "
|
|
45
|
-
"
|
|
46
|
-
"demo": "pnpm build && pnpm demo:serve"
|
|
50
|
+
"build": "vite build",
|
|
51
|
+
"dev": "vite build --watch",
|
|
52
|
+
"test:e2e": "playwright test"
|
|
47
53
|
}
|
|
48
54
|
}
|