@usermaven/sdk-js 1.4.4 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +149 -36
- package/dist/core/client.d.ts +54 -0
- package/dist/core/config.d.ts +3 -0
- package/dist/core/types.d.ts +128 -0
- package/dist/extensions/rage-click.d.ts +15 -0
- package/dist/extensions/scroll-depth.d.ts +19 -0
- package/dist/index.d.ts +5 -0
- package/dist/lib.js +2 -0
- package/dist/persistence/local-storage.d.ts +13 -0
- package/dist/persistence/memory.d.ts +8 -0
- package/dist/tracking/autocapture.d.ts +25 -0
- package/dist/tracking/form-tracking.d.ts +27 -0
- package/dist/tracking/pageviews.d.ts +11 -0
- package/dist/transport/beacon.d.ts +9 -0
- package/dist/transport/fetch.d.ts +12 -0
- package/dist/transport/https.d.ts +10 -0
- package/dist/transport/transport.d.ts +3 -0
- package/dist/transport/xhr.d.ts +11 -0
- package/dist/usermaven.cjs.js +2 -0
- package/dist/usermaven.es.js +1305 -0
- package/dist/utils/autocapture-utils.d.ts +13 -0
- package/dist/utils/common.d.ts +27 -0
- package/dist/utils/cookie.d.ts +14 -0
- package/dist/utils/helpers.d.ts +9 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/queue.d.ts +23 -0
- package/package.json +58 -49
- package/LICENSE +0 -23
- package/dist/npm/usermaven.cjs.js +0 -2696
- package/dist/npm/usermaven.d.ts +0 -546
- package/dist/npm/usermaven.es.js +0 -2689
- package/dist/web/lib.js +0 -1
package/README.md
CHANGED
|
@@ -1,51 +1,164 @@
|
|
|
1
|
-
# Usermaven
|
|
1
|
+
# Usermaven SDK
|
|
2
2
|
|
|
3
|
-
Usermaven
|
|
3
|
+
Usermaven SDK is a powerful and flexible JavaScript/TypeScript library for tracking user behavior and events in web applications. It supports both client-side and server-side usage, with a focus on privacy, configurability, and robustness.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- Cross-platform compatibility (browser and server-side)
|
|
8
|
+
- Flexible event tracking with custom payloads
|
|
9
|
+
- Automatic tracking of page views, form submissions, and user interactions
|
|
10
|
+
- Privacy-focused with configurable data sanitization
|
|
11
|
+
- Robust error handling and retry mechanisms
|
|
12
|
+
- Extensible architecture for custom tracking features
|
|
13
|
+
- Performance optimizations including event batching and debouncing
|
|
8
14
|
|
|
9
|
-
##
|
|
15
|
+
## Installation
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
### NPM or Yarn
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
You can install the Usermaven SDK using npm:
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
usermaven in action
|
|
19
|
-
* http://localhost:8081/test-case/embed.html - embedded Usermaven
|
|
20
|
-
- * <http://localhost:8081/test-case/embed_strict_mode.html> - embedded strict mode for Usermaven
|
|
21
|
-
* http://localhost:8081/test-case/autocapture.html - embedded Usermaven with autocapturing events
|
|
22
|
-
* `yarn test` runs [Playwright](https://playwright.dev/) test
|
|
23
|
-
* `yarn build` builds both npm package and `lib.js` browser bundle
|
|
24
|
-
* `npm publish --public` to publish the package (change version in `package.json` manually). You need to run `npm login` with your personal
|
|
25
|
-
npmjs account beforehand (make sure you have access to Usermaven team)
|
|
26
|
-
* In order to check usermaven sdk locally.
|
|
27
|
-
* `cd dist/npm` --- navigate to npm directory
|
|
28
|
-
* `npm link` --- creates a symbolic link to be accessed globally
|
|
29
|
-
* `cd ../../__tests__/sdk/` --- navigate to sdk test project
|
|
30
|
-
* `npm i` --- install npm dependencies
|
|
31
|
-
* `npm link @usermaven/sdk-js` --- use npm package locally whose symlink is just published
|
|
32
|
-
* `npm start` --- start the application and monitor events
|
|
21
|
+
```bash
|
|
22
|
+
npm install @usermaven/sdk-js
|
|
23
|
+
```
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
Setup a custom domain and sub-domain locally to test cross domain session persistence.
|
|
25
|
+
Or using yarn:
|
|
36
26
|
|
|
37
27
|
```bash
|
|
38
|
-
|
|
28
|
+
yarn add @usermaven/sdk-js
|
|
39
29
|
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
|
|
31
|
+
### UMD (Universal Module Definition)
|
|
32
|
+
|
|
33
|
+
For quick integration without a module bundler, you can include the SDK directly in your HTML using a script tag:
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<script src="https://cdn.usermaven.com/sdk/v1/lib.js"
|
|
37
|
+
data-key="your-api-key"
|
|
38
|
+
data-tracking-host="https://events.yourdomain.com"
|
|
39
|
+
data-log-level="debug"
|
|
40
|
+
data-autocapture="true"
|
|
41
|
+
data-form-tracking="true"
|
|
42
|
+
data-auto-pageview="true"></script>
|
|
44
43
|
```
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
Replace `https://cdn.usermaven.com/sdk/v1/lib.js` with the actual URL where the Usermaven SDK is hosted.
|
|
46
|
+
|
|
47
|
+
## Basic Usage
|
|
48
|
+
|
|
49
|
+
### Using as a module
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
import { usermavenClient } from '@usermaven/sdk-js';
|
|
53
|
+
|
|
54
|
+
const client = usermavenClient({
|
|
55
|
+
apiKey: 'your-api-key',
|
|
56
|
+
trackingHost: 'https://events.yourdomain.com',
|
|
57
|
+
// Add other configuration options as needed
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Track an event
|
|
61
|
+
client.track('button_click', {
|
|
62
|
+
buttonId: 'submit-form',
|
|
63
|
+
pageUrl: window.location.href
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Identify a user
|
|
67
|
+
client.id({
|
|
68
|
+
id: 'user123',
|
|
69
|
+
email: 'user@example.com',
|
|
70
|
+
name: 'John Doe'
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Track a page view
|
|
74
|
+
client.pageview();
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Using via UMD
|
|
78
|
+
|
|
79
|
+
When you include the SDK via a script tag, it automatically initializes with the configuration provided in the data attributes. You can then use the global `usermaven` function to interact with the SDK:
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<script>
|
|
83
|
+
// Track an event
|
|
84
|
+
usermaven('track', 'button_click', {
|
|
85
|
+
buttonId: 'submit-form',
|
|
86
|
+
pageUrl: window.location.href
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Identify a user
|
|
90
|
+
usermaven('id', {
|
|
91
|
+
id: 'user123',
|
|
92
|
+
email: 'user@example.com',
|
|
93
|
+
name: 'John Doe'
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Track a page view (if not set to automatic in the script tag)
|
|
97
|
+
usermaven('pageview');
|
|
98
|
+
</script>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Advanced Configuration
|
|
102
|
+
|
|
103
|
+
The SDK supports various configuration options to customize its behavior. When using as a module:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
const client = usermavenClient({
|
|
107
|
+
apiKey: 'your-api-key',
|
|
108
|
+
trackingHost: 'https://events.yourdomain.com',
|
|
109
|
+
cookieDomain: '.yourdomain.com',
|
|
110
|
+
logLevel: 'DEBUG',
|
|
111
|
+
useBeaconApi: true,
|
|
112
|
+
autocapture: true,
|
|
113
|
+
formTracking: 'all',
|
|
114
|
+
autoPageview: true,
|
|
115
|
+
// ... other options
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
When using via UMD, you can set these options using data attributes on the script tag:
|
|
120
|
+
|
|
121
|
+
```html
|
|
122
|
+
<script src="https://cdn.usermaven.com/sdk/v1/lib.js"
|
|
123
|
+
data-key="your-api-key"
|
|
124
|
+
data-tracking-host="https://events.yourdomain.com"
|
|
125
|
+
data-log-level="debug"
|
|
126
|
+
data-autocapture="true"
|
|
127
|
+
data-form-tracking="all"
|
|
128
|
+
data-auto-pageview="true"
|
|
129
|
+
data-use-beacon-api="true"
|
|
130
|
+
data-cookie-domain=".yourdomain.com"></script>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Refer to the `Config` interface in `src/core/config.ts` for a full list of configuration options.
|
|
134
|
+
|
|
135
|
+
## Server-Side Usage
|
|
136
|
+
|
|
137
|
+
The SDK can also be used in server-side environments:
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
const { usermavenClient } = require('@usermaven/sdk-js');
|
|
141
|
+
|
|
142
|
+
const client = usermavenClient({
|
|
143
|
+
apiKey: 'your-api-key',
|
|
144
|
+
trackingHost: 'https://events.yourdomain.com'
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
client.track('server_event', {
|
|
148
|
+
userId: 'user123',
|
|
149
|
+
action: 'item_purchased'
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Development
|
|
154
|
+
|
|
155
|
+
To set up the project for development:
|
|
156
|
+
|
|
157
|
+
1. Clone the repository
|
|
158
|
+
2. Install dependencies: `npm install`
|
|
159
|
+
3. Run tests: `npm test`
|
|
160
|
+
4. Build the project: `npm run build`
|
|
47
161
|
|
|
48
|
-
|
|
162
|
+
## Contributing
|
|
49
163
|
|
|
50
|
-
|
|
51
|
-
* Run `yarn install && yarn build && yarn test && npm publish --access public`
|
|
164
|
+
Contributions are welcome! Please read our contributing guidelines and code of conduct before submitting pull requests.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Config, CompanyProps, EventPayload, UserProps } from './types';
|
|
2
|
+
import { Logger } from '../utils/logger';
|
|
3
|
+
export declare class UsermavenClient {
|
|
4
|
+
private config;
|
|
5
|
+
private logger;
|
|
6
|
+
private cookieManager?;
|
|
7
|
+
private transport;
|
|
8
|
+
private persistence;
|
|
9
|
+
private autoCapture?;
|
|
10
|
+
private formTracking?;
|
|
11
|
+
private pageviewTracking?;
|
|
12
|
+
private retryQueue;
|
|
13
|
+
private anonymousId;
|
|
14
|
+
private namespace;
|
|
15
|
+
private rageClick?;
|
|
16
|
+
constructor(config: Config);
|
|
17
|
+
private initializeBrowserFeatures;
|
|
18
|
+
/**
|
|
19
|
+
* Recursively merge the provided configuration with the existing defaultConfig
|
|
20
|
+
* @param config
|
|
21
|
+
* @param defaultConfig
|
|
22
|
+
*/
|
|
23
|
+
mergeConfig(config: Partial<Config>, defaultConfig: Partial<Config>): Config;
|
|
24
|
+
init(config: Config): void;
|
|
25
|
+
private manageCrossDomainLinking;
|
|
26
|
+
private findClosestLink;
|
|
27
|
+
private initializeTransport;
|
|
28
|
+
private initializePersistence;
|
|
29
|
+
private getOrCreateAnonymousId;
|
|
30
|
+
id(userData: UserProps, doNotSendEvent?: boolean): Promise<void>;
|
|
31
|
+
track(typeName: string, payload?: EventPayload, directSend?: boolean): void;
|
|
32
|
+
private trackInternal;
|
|
33
|
+
rawTrack(payload: any): void;
|
|
34
|
+
group(props: CompanyProps, doNotSendEvent?: boolean): Promise<void>;
|
|
35
|
+
private createEventPayload;
|
|
36
|
+
private processAutocaptureAttributes;
|
|
37
|
+
getCookie(name: string): string | null;
|
|
38
|
+
private getThirdPartyIds;
|
|
39
|
+
private getUtmParams;
|
|
40
|
+
pageview(): void;
|
|
41
|
+
private setupPageLeaveTracking;
|
|
42
|
+
getConfig(): Config;
|
|
43
|
+
getLogger(): Logger;
|
|
44
|
+
reset(resetAnonId?: boolean): Promise<void>;
|
|
45
|
+
set(properties: Record<string, any>, opts?: {
|
|
46
|
+
eventType?: string;
|
|
47
|
+
persist?: boolean;
|
|
48
|
+
}): void;
|
|
49
|
+
setUserId(userId: string): void;
|
|
50
|
+
unset(propertyName: string, options?: {
|
|
51
|
+
eventType?: string;
|
|
52
|
+
persist?: boolean;
|
|
53
|
+
}): void;
|
|
54
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { LogLevel } from '../utils/logger';
|
|
2
|
+
export interface EventPayload {
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
}
|
|
5
|
+
export interface UserProps extends EventPayload {
|
|
6
|
+
id?: string;
|
|
7
|
+
email?: string;
|
|
8
|
+
company?: {
|
|
9
|
+
id?: string;
|
|
10
|
+
name?: string;
|
|
11
|
+
created_at?: string;
|
|
12
|
+
custom?: {
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
18
|
+
export interface Transport {
|
|
19
|
+
send(payload: any): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export type Policy = 'strict' | 'keep' | 'comply';
|
|
22
|
+
export interface CompanyProps {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
created_at: string;
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Environment where the event have happened.
|
|
30
|
+
*/
|
|
31
|
+
export type ClientProperties = {
|
|
32
|
+
screen_resolution: string;
|
|
33
|
+
user_agent: string;
|
|
34
|
+
referer: string;
|
|
35
|
+
url: string;
|
|
36
|
+
page_title: string;
|
|
37
|
+
doc_path: string;
|
|
38
|
+
doc_host: string;
|
|
39
|
+
doc_search: string;
|
|
40
|
+
vp_size: string;
|
|
41
|
+
user_language: string;
|
|
42
|
+
doc_encoding: string;
|
|
43
|
+
};
|
|
44
|
+
export type Property = any;
|
|
45
|
+
export type Properties = Record<string, Property>;
|
|
46
|
+
export interface AutoCaptureCustomProperty {
|
|
47
|
+
name: string;
|
|
48
|
+
css_selector: string;
|
|
49
|
+
event_selectors: string[];
|
|
50
|
+
}
|
|
51
|
+
type CamelCaseConfig = {
|
|
52
|
+
key: string;
|
|
53
|
+
trackingHost: string;
|
|
54
|
+
cookieDomain?: string;
|
|
55
|
+
cookieName?: string;
|
|
56
|
+
logLevel?: LogLevel;
|
|
57
|
+
useBeaconApi?: boolean;
|
|
58
|
+
forceUseFetch?: boolean;
|
|
59
|
+
autocapture?: boolean;
|
|
60
|
+
rageClick?: boolean;
|
|
61
|
+
formTracking?: boolean | 'all' | 'tagged' | 'none';
|
|
62
|
+
autoPageview?: boolean;
|
|
63
|
+
disableEventPersistence?: boolean;
|
|
64
|
+
gaHook?: boolean;
|
|
65
|
+
segmentHook?: boolean;
|
|
66
|
+
randomizeUrl?: boolean;
|
|
67
|
+
capture3rdPartyCookies?: string[] | false;
|
|
68
|
+
idMethod?: 'cookie' | 'localStorage';
|
|
69
|
+
privacyPolicy?: 'strict';
|
|
70
|
+
ipPolicy?: Policy;
|
|
71
|
+
cookiePolicy?: Policy;
|
|
72
|
+
customHeaders?: Record<string, string> | (() => Record<string, string>);
|
|
73
|
+
minSendTimeout?: number;
|
|
74
|
+
maxSendTimeout?: number;
|
|
75
|
+
maxSendAttempts?: number;
|
|
76
|
+
propertiesStringMaxLength?: number | null;
|
|
77
|
+
propertyBlacklist?: string[];
|
|
78
|
+
exclude?: string;
|
|
79
|
+
namespace?: string;
|
|
80
|
+
crossDomainLinking?: boolean;
|
|
81
|
+
domains?: string;
|
|
82
|
+
maskAllText?: boolean;
|
|
83
|
+
maskAllElementAttributes?: boolean;
|
|
84
|
+
};
|
|
85
|
+
type SnakeCaseConfig = {
|
|
86
|
+
key: string;
|
|
87
|
+
tracking_host: string;
|
|
88
|
+
cookie_domain?: string;
|
|
89
|
+
cookie_name?: string;
|
|
90
|
+
log_level?: LogLevel;
|
|
91
|
+
use_beacon_api?: boolean;
|
|
92
|
+
force_use_fetch?: boolean;
|
|
93
|
+
autocapture?: boolean;
|
|
94
|
+
rage_click?: boolean;
|
|
95
|
+
form_tracking?: boolean | 'all' | 'tagged' | 'none';
|
|
96
|
+
auto_pageview?: boolean;
|
|
97
|
+
disable_event_persistence?: boolean;
|
|
98
|
+
ga_hook?: boolean;
|
|
99
|
+
segment_hook?: boolean;
|
|
100
|
+
randomize_url?: boolean;
|
|
101
|
+
capture_3rd_party_cookies?: string[] | false;
|
|
102
|
+
id_method?: 'cookie' | 'localStorage';
|
|
103
|
+
privacy_policy?: 'strict';
|
|
104
|
+
ip_policy?: Policy;
|
|
105
|
+
cookie_policy?: Policy;
|
|
106
|
+
custom_headers?: Record<string, string> | (() => Record<string, string>);
|
|
107
|
+
min_send_timeout?: number;
|
|
108
|
+
max_send_timeout?: number;
|
|
109
|
+
max_send_attempts?: number;
|
|
110
|
+
properties_string_max_length?: number | null;
|
|
111
|
+
property_blacklist?: string[];
|
|
112
|
+
exclude?: string;
|
|
113
|
+
namespace?: string;
|
|
114
|
+
cross_domain_linking?: boolean;
|
|
115
|
+
domains?: string;
|
|
116
|
+
mask_all_text?: boolean;
|
|
117
|
+
mask_all_element_attributes?: boolean;
|
|
118
|
+
};
|
|
119
|
+
export type Config = Partial<CamelCaseConfig & SnakeCaseConfig> & {
|
|
120
|
+
key: string;
|
|
121
|
+
trackingHost?: string;
|
|
122
|
+
tracking_host?: string;
|
|
123
|
+
} & ({
|
|
124
|
+
trackingHost: string;
|
|
125
|
+
} | {
|
|
126
|
+
tracking_host: string;
|
|
127
|
+
});
|
|
128
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { UsermavenClient } from '../core/client';
|
|
2
|
+
export declare class RageClick {
|
|
3
|
+
private client;
|
|
4
|
+
private clicks;
|
|
5
|
+
private threshold;
|
|
6
|
+
private timeWindow;
|
|
7
|
+
private distanceThreshold;
|
|
8
|
+
constructor(client: UsermavenClient);
|
|
9
|
+
private initializeEventListener;
|
|
10
|
+
private handleClick;
|
|
11
|
+
private shouldCaptureElement;
|
|
12
|
+
click(x: number, y: number, timestamp: number): void;
|
|
13
|
+
private checkRageClick;
|
|
14
|
+
private sendRageClickEvent;
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { UsermavenClient } from '../core/client';
|
|
2
|
+
export declare class ScrollDepth {
|
|
3
|
+
private client;
|
|
4
|
+
private maxScrollDepth;
|
|
5
|
+
private milestones;
|
|
6
|
+
private lastScrollDepth;
|
|
7
|
+
private documentElement;
|
|
8
|
+
private debouncedHandleScroll;
|
|
9
|
+
constructor(client: UsermavenClient);
|
|
10
|
+
private initializeEventListener;
|
|
11
|
+
track(): void;
|
|
12
|
+
send(eventType?: string): void;
|
|
13
|
+
private handleScroll;
|
|
14
|
+
private getScrollDepth;
|
|
15
|
+
private getWindowHeight;
|
|
16
|
+
private getDocumentHeight;
|
|
17
|
+
private getScrollDistance;
|
|
18
|
+
private checkMilestones;
|
|
19
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { UsermavenClient } from './core/client';
|
|
2
|
+
import { Config, UserProps, EventPayload, ClientProperties } from './core/types';
|
|
3
|
+
import { LogLevel } from './utils/logger';
|
|
4
|
+
declare function usermavenClient(config: Partial<Config>): UsermavenClient;
|
|
5
|
+
export { usermavenClient, UsermavenClient, Config as UsermavenOptions, UserProps, EventPayload, LogLevel, ClientProperties };
|
package/dist/lib.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(f,g){typeof exports=="object"&&typeof module<"u"?g(exports):typeof define=="function"&&define.amd?define(["exports"],g):(f=typeof globalThis<"u"?globalThis:f||self,g(f.Usermaven={}))})(this,function(f){"use strict";var g=(i=>(i[i.DEBUG=0]="DEBUG",i[i.INFO=1]="INFO",i[i.WARN=2]="WARN",i[i.ERROR=3]="ERROR",i))(g||{});class X{constructor(e){this.level=e}debug(e,...t){this.level<=0&&console.debug("[Usermaven Debug]:",e,...t)}info(e,...t){this.level<=1&&console.info("[Usermaven Info]:",e,...t)}warn(e,...t){this.level<=2&&console.warn("[Usermaven Warning]:",e,...t)}error(e,...t){this.level<=3&&console.error("[Usermaven Error]:",e,...t)}}function d(i=0){return new X(i)}const L={logLevel:g.ERROR,useBeaconApi:!1,forceUseFetch:!1,trackingHost:"t.usermaven.com",autocapture:!1,rageClick:!1,formTracking:!1,autoPageview:!1,disableEventPersistence:!1,gaHook:!1,segmentHook:!1,randomizeUrl:!1,capture3rdPartyCookies:["_ga","_fbp","_ym_uid","ajs_user_id","ajs_anonymous_id"],idMethod:"cookie",ipPolicy:"keep",cookiePolicy:"keep",minSendTimeout:0,maxSendTimeout:2e3,maxSendAttempts:4,propertiesStringMaxLength:null,propertyBlacklist:[],crossDomainLinking:!0,maskAllText:!1,maskAllElementAttributes:!1};class K{constructor(e){this.domain=e,this.cookieDomain=this.getCookieDomain()}set(e,t,s=365,n=!0,r=!1){const o=new Date;o.setTime(o.getTime()+s*24*60*60*1e3);const c=`expires=${o.toUTCString()}`,l=n?"; Secure":"",a=r?"; HttpOnly":"";document.cookie=`${e}=${t};${c};path=/;domain=${this.cookieDomain}${l}${a}`}get(e){const t=e+"=",s=document.cookie.split(";");for(let n=0;n<s.length;n++){let r=s[n].trim();if(r.indexOf(t)===0)return decodeURIComponent(r.substring(t.length))}return null}delete(e,t="/"){document.cookie=`${e}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${t};domain=${this.cookieDomain}`}getCookieDomain(){return typeof window>"u"||this.domain?this.domain||"":this.extractRoot(window.location.hostname)}extractRoot(e){if(this.isIpAddress(e)||e==="localhost")return e;let t=this.extractTopLevelDomain(e);return t||(t=this.extractRootDomain(e)),"."+t}isIpAddress(e){const t=e.split(".");return t.length===4&&t.every(s=>!isNaN(Number(s)))}extractHostname(e){let t;return e.indexOf("//")>-1?t=e.split("/")[2]:t=e.split("/")[0],t=t.split(":")[0],t=t.split("?")[0],t}extractRootDomain(e){let t=this.extractHostname(e);const s=t.split("."),n=s.length;return n>2&&(s[n-1].length==2?(t=s[n-2]+"."+s[n-1],s[n-2].length==2&&(t=s[n-3]+"."+t)):t=s[n-2]+"."+s[n-1]),t}extractTopLevelDomain(e){const t=/[a-z0-9][a-z0-9-]+\.[a-z.]{2,6}$/i,s=e.match(t);return s?s[0]:""}}const G=Object.prototype.hasOwnProperty,P=Array.prototype.forEach,A={};function Y(i,e,t){if(Array.isArray(i)){if(P&&i.forEach===P)i.forEach(e,t);else if("length"in i&&i.length===+i.length){for(let s=0,n=i.length;s<n;s++)if(s in i&&e.call(t,i[s],s)===A)return}}}const x=function(i){return i.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")},Z=function(i){for(const e in i)typeof i[e]=="function"&&(i[e]=i[e].bind(i))};function m(i,e,t){if(i!=null){if(P&&Array.isArray(i)&&i.forEach===P)i.forEach(e,t);else if("length"in i&&i.length===+i.length){for(let s=0,n=i.length;s<n;s++)if(s in i&&e.call(t,i[s],s)===A)return}else for(const s in i)if(G.call(i,s)&&e.call(t,i[s],s)===A)return}}const j=function(i,...e){return Y(e,function(t){for(const s in t)t[s]!==void 0&&(i[s]=t[s])}),i};function v(i,e){return i.indexOf(e)!==-1}const ee=function(i){try{return/^\s*\bfunction\b/.test(i)}catch{return!1}},te=function(i){return i===void 0},w=function(){const i=function(s,n,r,o,c){if(!s){d().error("No valid element provided to register_event");return}if(s.addEventListener&&!o)s.addEventListener(n,r,!!c);else{const l="on"+n,a=s[l];s[l]=e(s,r,a)}};function e(s,n,r){return function(o){if(o=o||t(window.event),!o)return;let c=!0,l;ee(r)&&(l=r(o));const a=n.call(s,o);return(l===!1||a===!1)&&(c=!1),c}}function t(s){return s&&(s.preventDefault=t.preventDefault,s.stopPropagation=t.stopPropagation),s}return t.preventDefault=function(){this.returnValue=!1},t.stopPropagation=function(){this.cancelBubble=!0},i}(),ie=function(i){return function(...e){try{return i.apply(this,e)}catch(t){d().error("Implementation error. Please turn on debug and contact support@usermaven.com.",t)}}},I=function(i){for(const e in i)typeof i[e]=="function"&&(i[e]=ie(i[e]))};function D(i){for(let e in i)(i[e]===""||i[e]===null||i[e]===void 0||typeof i[e]=="object"&&Object.keys(i[e]).length===0)&&delete i[e];return i}function u(){try{return typeof window<"u"&&window.document!==void 0&&window.document.createElement!==void 0}catch{return d().warn("window is not available"),!1}}function y(i=5){const e=new Uint8Array(i);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(36).padStart(2,"0")).join("").slice(0,i)}function se(i){return i.replace(/([-_][a-z])/g,e=>e.toUpperCase().replace("-","").replace("_",""))}function H(i){return typeof i!="object"||i===null?i:Array.isArray(i)?i.map(H):Object.keys(i).reduce((e,t)=>{const s=se(t);return e[s]=H(i[t]),e},{})}function E(i){switch(typeof i.className){case"string":return i.className;case"object":return("baseVal"in i.className?i.className.baseVal:null)||i.getAttribute("class")||"";default:return""}}function U(i){let e="";return O(i)&&!M(i)&&i.childNodes&&i.childNodes.length&&m(i.childNodes,function(t){z(t)&&t.textContent&&(e+=x(t.textContent).split(/(\s+)/).filter(S).join("").replace(/[\r\n]/g," ").replace(/[ ]+/g," ").substring(0,255))}),x(e)}function F(i){return!!i&&i.nodeType===1}function p(i,e){return!!i&&!!i.tagName&&i.tagName.toLowerCase()===e.toLowerCase()}function z(i){return!!i&&i.nodeType===3}function N(i){return!!i&&i.nodeType===11}const $=["a","button","form","input","select","textarea","label"];function ne(i,e){if(!i||p(i,"html")||!F(i))return!1;let t=i;for(;t&&!p(t,"body");){if(t.classList&&t.classList.contains("um-no-capture"))return!1;t.parentNode&&N(t.parentNode)?t=t.parentNode.host:t=t.parentNode}let s=!1;for(t=i;t&&!p(t,"body");){if(t.parentNode&&N(t.parentNode)){t=t.parentNode.host,t&&$.indexOf(t.tagName.toLowerCase())>-1&&(s=!0);continue}const o=t.parentNode;if(!o)break;if($.indexOf(o.tagName.toLowerCase())>-1)s=!0;else{const c=window.getComputedStyle(o);c&&c.getPropertyValue("cursor")==="pointer"&&(s=!0)}t=o}const n=window.getComputedStyle(i);if(n&&n.getPropertyValue("cursor")==="pointer"&&e.type==="click")return!0;const r=i.tagName.toLowerCase();switch(r){case"html":return!1;case"form":return e.type==="submit";case"input":return e.type==="change"||e.type==="click";case"select":case"textarea":return e.type==="change"||e.type==="click";default:return s?e.type==="click":e.type==="click"&&($.indexOf(r)>-1||i.getAttribute("contenteditable")==="true")}}function O(i){for(let s=i;s.parentNode&&!p(s,"body");s=s.parentNode){const n=E(s).split(" ");if(v(n,"ph-sensitive")||v(n,"ph-no-capture"))return!1}if(v(E(i).split(" "),"ph-include"))return!0;const e=i.type||"";if(typeof e=="string")switch(e.toLowerCase()){case"hidden":return!1;case"password":return!1}const t=i.name||i.id||"";return!(typeof t=="string"&&/^cc|cardnum|ccnum|creditcard|csc|cvc|cvv|exp|pass|pwd|routing|seccode|securitycode|securitynum|socialsec|socsec|ssn/i.test(t.replace(/[^a-zA-Z0-9]/g,"")))}function M(i){const e=["button","checkbox","submit","reset"];return!!(p(i,"input")&&!e.includes(i.type)||p(i,"select")||p(i,"textarea")||i.getAttribute("contenteditable")==="true")}function S(i){return!(i===null||te(i)||typeof i=="string"&&(i=x(i),/^(?:(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11}))$/.test((i||"").replace(/[- ]/g,""))||/(^\d{3}-?\d{2}-?\d{4}$)/.test(i)))}function re(i){return typeof i=="string"?i.substring(0,10)==="_ngcontent"||i.substring(0,7)==="_nghost":!1}function R(){return y(10)}function oe(i){return/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(String(i).toLowerCase())}function ae(i,e){let t;return function(...s){const n=()=>{clearTimeout(t),i(...s)};clearTimeout(t),t=setTimeout(n,e)}}function ce(i){const e={},t=i.replace(/^\?/,"").split("&");for(let s=0;s<t.length;s++){const n=t[s].split("=");n[0]!==""&&(e[decodeURIComponent(n[0])]=decodeURIComponent(n[1]||""))}return e}function q(i){return typeof i=="string"||i instanceof String}function _(i){return i!==null&&typeof i=="object"&&i.constructor===Object}function le(i){if(i===null)return g.ERROR;const e=i.toUpperCase(),t=g[e];return t||t===0?t:g.ERROR}class ue{constructor(e){this.maxScrollDepth=0,this.milestones=[25,50,75,90],this.lastScrollDepth=0,this.client=e,this.documentElement=document.documentElement,this.debouncedHandleScroll=ae(this.handleScroll.bind(this),250),this.initializeEventListener()}initializeEventListener(){window.addEventListener("scroll",this.debouncedHandleScroll)}track(){const e=this.getScrollDepth();e>this.lastScrollDepth&&(this.lastScrollDepth=e,this.checkMilestones(e))}send(e="$scroll"){if(!this.lastScrollDepth)return;const t={percent:this.lastScrollDepth,window_height:this.getWindowHeight(),document_height:this.getDocumentHeight(),scroll_distance:this.getScrollDistance()};this.client.track(e,t)}handleScroll(){this.track()}getScrollDepth(){const e=this.getWindowHeight(),t=this.getDocumentHeight(),s=this.getScrollDistance(),n=t-e;return Math.min(100,Math.floor(s/n*100))}getWindowHeight(){return window.innerHeight||this.documentElement.clientHeight||document.body.clientHeight||0}getDocumentHeight(){return Math.max(document.body.scrollHeight||0,this.documentElement.scrollHeight||0,document.body.offsetHeight||0,this.documentElement.offsetHeight||0,document.body.clientHeight||0,this.documentElement.clientHeight||0)}getScrollDistance(){return window.pageYOffset||this.documentElement.scrollTop||document.body.scrollTop||0}checkMilestones(e){this.milestones.filter(s=>e>=s).forEach(s=>{this.send(),this.milestones=this.milestones.filter(n=>n!==s)})}}const T=class T{constructor(e,t,s=d()){this.logger=s,this.scrollDepth=null,this.customProperties=[],this.client=e,this.options=t,this.scrollDepth=new ue(e),Z(this),I(this)}init(){if(!(document&&document.body)){this.logger.debug("Document not ready yet, trying again in 500 milliseconds..."),setTimeout(()=>this.init(),500);return}this.addDomEventHandlers()}addDomEventHandlers(){const e=t=>{t=t||window.event,this.captureEvent(t)};w(document,"submit",e,!1,!0),w(document,"change",e,!1,!0),w(document,"click",e,!1,!0),w(document,"visibilitychange",e,!1,!0),w(document,"scroll",e,!1,!0),w(window,"popstate",e,!1,!0)}isPageRefresh(){if("PerformanceNavigationTiming"in window){const e=performance.getEntriesByType("navigation");if(e.length>0)return e[0].type==="reload"}return performance.navigation&&performance.navigation.type===1}captureEvent(e){var s,n;let t=this.getEventTarget(e);if(z(t)&&(t=t.parentNode||null),e.type==="scroll")return(s=this.scrollDepth)==null||s.track(),!0;if(e.type==="visibilitychange"&&document.visibilityState==="hidden"||e.type==="popstate")return this.isPageRefresh()||(n=this.scrollDepth)==null||n.send(),!0;if(t&&ne(t,e)){const r=[t];let o=t;for(;o.parentNode&&!p(o,"body");){if(N(o.parentNode)){r.push(o.parentNode.host),o=o.parentNode.host;continue}r.push(o.parentNode),o=o.parentNode}const c=[];let l,a=!1;if(m(r,b=>{const ke=O(b);b.tagName.toLowerCase()==="a"&&(l=b.getAttribute("href"),l=ke&&S(l)&&l);const ve=E(b).split(" ");v(ve,"ph-no-capture")&&(a=!0),c.push(this.getPropertiesFromElement(b,this.options.maskAllElementAttributes??!1,this.options.maskAllText??!1))}),this.options.maskAllText||(c[0].$el_text=U(t)),l&&(c[0].attr__href=l),a)return!1;const h=j(this.getDefaultProperties(e.type),{$elements:c},this.getCustomProperties(r));return this.client.track("$autocapture",h),!0}}getCustomProperties(e){const t={};return m(this.customProperties,s=>{m(s.event_selectors,n=>{const r=document.querySelectorAll(n);m(r,o=>{v(e,o)&&O(o)&&(t[s.name]=this.extractCustomPropertyValue(s))})})}),t}extractCustomPropertyValue(e){const t=[];return m(document.querySelectorAll(e.css_selector),function(s){let n;["input","select"].indexOf(s.tagName.toLowerCase())>-1?n=s.value:s.textContent&&(n=s.textContent),S(n)&&t.push(n)}),t.join(", ")}getEventTarget(e){var t;return typeof e.target>"u"?e.srcElement||null:(t=e.target)!=null&&t.shadowRoot?e.composedPath()[0]||null:e.target||null}getPropertiesFromElement(e,t,s){const n=e.tagName.toLowerCase(),r={tag_name:n};$.indexOf(n)>-1&&!s&&(r.$el_text=U(e));const o=E(e);o.length>0&&(r.classes=o.split(" ").filter(function(h){return h!==""})),m(e.attributes,function(h){M(e)&&["name","id","class"].indexOf(h.name)===-1||!t&&S(h.value)&&!re(h.name)&&(r["attr__"+h.name]=h.value)});let c=1,l=1,a=e;for(;a=this.previousElementSibling(a);)c++,a.tagName===e.tagName&&l++;return r.nth_child=c,r.nth_of_type=l,r}previousElementSibling(e){if(e.previousElementSibling)return e.previousElementSibling;{let t=e;do t=t.previousSibling;while(t&&!F(t));return t}}getDefaultProperties(e){return{$event_type:e,$ce_version:1}}encodeHtml(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}static enabledForProject(e,t=10,s=10){if(!e)return!1;let n=0;for(let r=0;r<e.length;r++)n+=e.charCodeAt(r);return n%t<s}};T.FORCE_CAPTURE_ATTR="data-um-force-capture",T.PREVENT_CAPTURE_ATTR="data-um-no-capture";let C=T;class he{constructor(e){this.client=e,this.lastPageUrl=window.location.href,this.trackInitialPageview(),this.initializePageviewTracking()}trackInitialPageview(){this.trackPageview()}initializePageviewTracking(){window.addEventListener("popstate",this.handlePageview.bind(this));const e=history.pushState;history.pushState=(...t)=>{e.apply(history,t),this.handlePageview()},window.addEventListener("hashchange",this.handlePageview.bind(this)),setInterval(this.checkForUrlChange.bind(this),1e3)}handlePageview(){this.trackPageview()}checkForUrlChange(){window.location.href!==this.lastPageUrl&&this.trackPageview()}trackPageview(){const e=window.location.href;e!==this.lastPageUrl&&(this.lastPageUrl=e,this.client.track("pageview",{url:e,referrer:document.referrer,title:document.title}))}}class de{constructor(e,t,s=d()){this.trackingHost=e,this.logger=s,this.config=t}async send(e){const t=this.config.key,s=this.constructUrl(t),n=new Blob([JSON.stringify(e)],{type:"application/json"});if(navigator.sendBeacon(s,n))this.logger.debug(`Successfully queued ${e.length} event(s) via Beacon API`);else throw new Error("Failed to queue events via Beacon API")}constructUrl(e){const t=this.config.cookiePolicy!=="keep"?`&cookie_policy=${this.config.cookiePolicy}`:"",s=this.config.ipPolicy!=="keep"?`&ip_policy=${this.config.ipPolicy}`:"",n=u()?"/api/v1/event":"/api/v1/s2s/event";return this.config.randomizeUrl?`${this.trackingHost}/api.${y()}?p_${y()}=${e}${t}${s}`:`${this.trackingHost}${n}?token=${e}${t}${s}`}}class B{constructor(e,t,s=d()){this.trackingHost=e,this.logger=s,this.config=t}async send(e){const t=this.config.key,s=this.constructUrl(t),n=JSON.stringify(e),r={"Content-Type":"application/json",...this.getCustomHeaders()},o=await fetch(s,{method:"POST",headers:r,body:n});if(!o.ok)throw new Error(`HTTP error! status: ${o.status}`);this.logger.debug(`Successfully sent ${e.length} event(s)`),this.postHandle(o.status,await o.text())}constructUrl(e){const t=this.config.cookiePolicy!=="keep"?`&cookie_policy=${this.config.cookiePolicy}`:"",s=this.config.ipPolicy!=="keep"?`&ip_policy=${this.config.ipPolicy}`:"",n=u()?"/api/v1/event":"/api/v1/s2s/event";return this.config.randomizeUrl?`${this.trackingHost}/api.${y()}?p_${y()}=${e}${t}${s}`:`${this.trackingHost}${n}?token=${e}${t}${s}`}getCustomHeaders(){return typeof this.config.customHeaders=="function"?this.config.customHeaders():this.config.customHeaders?this.config.customHeaders:{}}postHandle(e,t){this.logger.debug(`Response received. Status: ${e}, Body: ${t}`)}}class ge{constructor(e,t,s=d()){this.trackingHost=e,this.logger=s,this.config=t}send(e){return new Promise((t,s)=>{const n=new XMLHttpRequest,r=this.config.key,o=this.constructUrl(r);n.open("POST",o,!0),n.setRequestHeader("Content-Type","application/json");const c=this.getCustomHeaders();Object.keys(c).forEach(l=>{n.setRequestHeader(l,c[l])}),n.onload=()=>{n.status>=200&&n.status<300?(this.logger.debug(`Successfully sent ${e.length} event(s)`),t()):s(new Error(`HTTP error! status: ${n.status}`))},n.onerror=()=>{s(new Error("Network error"))},n.send(JSON.stringify(e))})}constructUrl(e){const t=this.config.cookiePolicy!=="keep"?`&cookie_policy=${this.config.cookiePolicy}`:"",s=this.config.ipPolicy!=="keep"?`&ip_policy=${this.config.ipPolicy}`:"",n=u()?"/api/v1/event":"/api/v1/s2s/event";return this.config.randomizeUrl?`${this.trackingHost}/api.${y()}?p_${y()}=${e}${t}${s}`:`${this.trackingHost}${n}?token=${e}${t}${s}`}getCustomHeaders(){return typeof this.config.customHeaders=="function"?this.config.customHeaders():this.config.customHeaders?this.config.customHeaders:{}}postHandle(e,t){this.logger.debug(`Response received. Status: ${e}, Body: ${t}`)}}class V{constructor(e,t){this.storage={},this.prefix=`usermaven_${e}_`,this.load(),this.logger=t||d()}set(e,t){this.storage[e]=t,this.save()}get(e){return this.storage[e]}remove(e){delete this.storage[e],this.save()}clear(){this.storage={},this.save()}save(){if(!u()){this.logger.warn("localStorage is not available in this environment");return}try{localStorage.setItem(this.prefix+"data",JSON.stringify(this.storage))}catch(e){this.logger.error("Error saving to localStorage:",e)}}load(){if(!u()){this.logger.warn("localStorage is not available in this environment");return}try{const e=localStorage.getItem(this.prefix+"data");e&&(this.storage=JSON.parse(e))}catch(e){this.logger.error("Error loading from localStorage:",e)}}}class fe{constructor(){this.storage={}}set(e,t){this.storage[e]=t}get(e){return this.storage[e]}remove(e){delete this.storage[e]}save(){}clear(){this.storage={}}}class J{constructor(e,t=3,s=1e3,n=10,r=1e3,o=d(),c="default"){this.transport=e,this.maxRetries=t,this.retryInterval=s,this.batchSize=n,this.batchInterval=r,this.logger=o,this.queue=[],this.processing=!1,this.batchTimeoutId=null,this.isOnline=!0,this.persistence=new V(`offline_queue_${c}`),u()&&(this.isOnline=navigator.onLine,this.loadQueueFromStorage(),this.initNetworkListeners(),this.scheduleBatch())}add(e){const t={payload:e,retries:0,timestamp:Date.now()};this.queue.push(t),u()?this.saveQueueToStorage():this.processBatch()}initNetworkListeners(){u()&&(window.addEventListener("online",()=>{this.isOnline=!0,this.processBatch()}),window.addEventListener("offline",()=>{this.isOnline=!1}))}scheduleBatch(){u()&&(this.batchTimeoutId!==null&&clearTimeout(this.batchTimeoutId),this.batchTimeoutId=window.setTimeout(()=>this.processBatch(),this.batchInterval))}async processBatch(){if((!u()||this.isOnline)&&!this.processing&&this.queue.length>0){this.processing=!0;const e=this.queue.splice(0,this.batchSize),t=e.map(s=>s.payload);try{await this.transport.send(t),this.logger.debug(`Successfully sent batch of ${e.length} payloads`),u()&&this.saveQueueToStorage()}catch(s){this.logger.error("Failed to send batch",s),await this.handleBatchFailure(e)}this.processing=!1}u()&&this.scheduleBatch()}async handleBatchFailure(e){for(const t of e)t.retries<this.maxRetries?(t.retries++,this.queue.unshift(t),this.logger.warn(`Retry attempt ${t.retries} for payload`)):this.logger.error("Max retries reached, discarding payload",t.payload);u()&&(this.saveQueueToStorage(),await new Promise(t=>setTimeout(t,this.retryInterval)))}loadQueueFromStorage(){if(u()){const e=this.persistence.get("queue");e&&(this.queue=JSON.parse(e))}}saveQueueToStorage(){u()&&this.persistence.set("queue",JSON.stringify(this.queue))}}class pe{constructor(e){this.clicks=[],this.threshold=3,this.timeWindow=2e3,this.distanceThreshold=30,this.client=e,this.initializeEventListener(),I(this)}initializeEventListener(){document.addEventListener("click",this.handleClick.bind(this))}handleClick(e){const t=e.target;this.shouldCaptureElement(t)&&this.click(e.clientX,e.clientY,Date.now())}shouldCaptureElement(e){return!e.closest(".um-no-capture")}click(e,t,s){const n={x:e,y:t,timestamp:s};this.clicks.push(n),this.clicks=this.clicks.filter(r=>s-r.timestamp<this.timeWindow),this.clicks.length>=this.threshold&&this.checkRageClick()}checkRageClick(){const e=this.clicks[0],s=(this.clicks[this.clicks.length-1].timestamp-e.timestamp)/1e3;this.clicks.every((r,o)=>{if(o===0)return!0;const c=this.clicks[o-1];return Math.sqrt(Math.pow(r.x-c.x,2)+Math.pow(r.y-c.y,2))<this.distanceThreshold})&&this.sendRageClickEvent(s)}sendRageClickEvent(e){const t=this.clicks[this.clicks.length-1];document.elementFromPoint(t.x,t.y)&&this.client.track("$rage_click",{no_of_clicks:this.clicks.length,time:e.toFixed(2)}),this.clicks=[]}}class me{constructor(e,t,s=d()){this.trackingHost=e,this.logger=s,this.config=t}async send(e){const t=this.config.key,s=new(void 0)(this.constructUrl(t)),n={hostname:s.hostname,port:443,path:`${s.pathname}${s.search}`,method:"POST",headers:{"Content-Type":"application/json",...this.getCustomHeaders()}};return new Promise((r,o)=>{const c=(void 0)(n,l=>{l.on("data",a=>{}),l.on("end",()=>{const a=l.statusCode||0;a>=200&&a<300?(this.logger.debug(`Successfully sent ${e.length} event(s)`),r()):o(new Error(`HTTP error! status: ${a}`))})});c.on("error",l=>{o(l)}),c.write(JSON.stringify(e)),c.end()})}constructUrl(e){const t=this.config.cookiePolicy!=="keep"?`&cookie_policy=${this.config.cookiePolicy}`:"",s=this.config.ipPolicy!=="keep"?`&ip_policy=${this.config.ipPolicy}`:"";return`${this.trackingHost}/api/v1/s2s/event?token=${e}${t}${s}`}getCustomHeaders(){return typeof this.config.customHeaders=="function"?this.config.customHeaders():this.config.customHeaders?this.config.customHeaders:{}}}class k{constructor(e,t="all",s={}){this.instance=e,this.trackingType=t,this.options=s,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",this.initialize.bind(this)):this.initialize()}initialize(){this.trackingType!=="none"&&this.setupFormTracking()}setupFormTracking(){var e;this.formElements=this.trackingType==="tagged"?document.querySelectorAll("form[data-um-form]"):document.querySelectorAll("form"),(e=this.formElements)==null||e.forEach(t=>{t.addEventListener("submit",this.handleFormSubmit.bind(this))})}handleFormSubmit(e){const t=e.target,s=this._getFormDetails(t);this.instance.track("$form",D(s)),this.options.trackFieldChanges&&this.trackFieldChanges(t)}trackFieldChanges(e){e.querySelectorAll("input, select, textarea").forEach(s=>{s.addEventListener("change",n=>{const r=this._getFieldProps(n.target,0);this.instance.track("$form_field_change",D(r))})})}static getInstance(e,t="all",s={}){return k.instance||(k.instance=new k(e,t,s)),k.instance}_getFormDetails(e){const t={form_id:e.id,form_name:e.name||"",form_action:e.action,form_method:e.method,form_class:e.className,form_attributes:this._getElementAttributes(e)},s=e.querySelectorAll("input, select, textarea");return Array.from(s).filter(r=>!r.classList.contains("um-no-capture")).forEach((r,o)=>{const c=this._getFieldProps(r,o);Object.assign(t,c)}),t}_getFieldProps(e,t){const s=Object.keys(e.dataset).length?JSON.stringify(e.dataset):void 0,n=this.getSafeText(e);return{[`field_${t+1}_tag`]:e.tagName.toLowerCase(),[`field_${t+1}_type`]:e instanceof HTMLInputElement?e.type:void 0,[`field_${t+1}_data_attributes`]:s,[`field_${t+1}_id`]:e.id,[`field_${t+1}_value`]:n,[`field_${t+1}_class`]:e.className,[`field_${t+1}_name`]:e.name,[`field_${t+1}_attributes`]:this._getElementAttributes(e)}}_getElementAttributes(e){return Object.keys(e.dataset).length?JSON.parse(JSON.stringify(e.dataset)):{}}getSafeText(e){let t="";return"value"in e&&e.type!=="password"?t=e.value:e.hasChildNodes()?t=Array.from(e.childNodes).filter(n=>n.nodeType===Node.TEXT_NODE).map(n=>n.textContent).join(""):t=e.textContent||"",this._scrubPotentiallySensitiveValues(t)}_scrubPotentiallySensitiveValues(e){return this._shouldCaptureValue(e)?e:"<redacted>"}_shouldCaptureValue(e){return!(this._isNullish(e)||this._isString(e)&&(e=this._trim(e),/^(?:(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11}))$/.test((e||"").replace(/[- ]/g,""))||/(^\d{3}-?\d{2}-?\d{4}$)/.test(e)))}_isNullish(e){return e==null}_isString(e){return typeof e=="string"||e instanceof String}_trim(e){if(typeof String.prototype.trim=="function")return e.trim();let t=0,s=e.length-1;const n=[" ",`
|
|
2
|
+
`,"\r"," ","\f","\v"," "," "," "," "," "," "," "," "," "," "," "," "," ","\u2028","\u2029"," "," "," "].join("");for(;t<=s&&n.indexOf(e[t])>-1;)t++;for(;s>=t&&n.indexOf(e[s])>-1;)s--;return e.slice(t,s+1)}}class Q{constructor(e){this.config=this.mergeConfig(e,L),this.logger=d(this.config.logLevel),this.namespace=e.namespace||"default",this.transport=this.initializeTransport(this.config),this.persistence=this.initializePersistence(),this.retryQueue=new J(this.transport,this.config.maxSendAttempts||3,this.config.minSendTimeout||1e3,10,200,this.logger,this.namespace),u()&&this.initializeBrowserFeatures(),this.anonymousId=this.getOrCreateAnonymousId(),this.logger.info(`Usermaven client initialized for namespace: ${this.namespace}`)}initializeBrowserFeatures(){if(this.cookieManager=new K(this.config.cookieDomain),this.config.autocapture&&C.enabledForProject(this.config.key)&&(this.autoCapture=new C(this,this.config,this.logger),this.autoCapture.init()),this.config.formTracking){const e=this.config.formTracking===!0?"all":this.config.formTracking;this.formTracking=k.getInstance(this,e||"none",{trackFieldChanges:!1})}this.config.autoPageview&&(this.pageviewTracking=new he(this)),this.config.crossDomainLinking&&this.manageCrossDomainLinking(),this.config.rageClick&&(this.rageClick=new pe(this)),this.setupPageLeaveTracking()}mergeConfig(e,t){const s=JSON.parse(JSON.stringify(e));let n={...t,...s};return Object.keys(t).forEach(r=>{_(t[r])&&(n[r]=this.mergeConfig(e[r],t[r]))}),n}init(e){this.config={...this.config,...e},this.logger=d(this.config.logLevel),this.namespace=e.namespace||this.namespace,this.transport=this.initializeTransport(e),this.persistence=this.initializePersistence(),this.retryQueue=new J(this.transport,this.config.maxSendAttempts||3,this.config.minSendTimeout||1e3,10,250,this.logger,this.namespace),u()&&this.initializeBrowserFeatures(),this.anonymousId=this.getOrCreateAnonymousId(),this.logger.info(`Usermaven client reinitialized for namespace: ${this.namespace}`)}manageCrossDomainLinking(){if(!this.config.crossDomainLinking||!this.config.domains)return;const e=this.config.domains.split(",").map(s=>s.trim()),t=this.config.cookieName||`__eventn_id_${this.config.key}`;document.addEventListener("click",s=>{var c;const n=this.findClosestLink(s.target);if(!n)return;const r=n.getAttribute("href");if(!r||!r.startsWith("http"))return;const o=new URL(r);if(o.hostname!==window.location.hostname&&e.includes(o.hostname)){const l=(c=this.cookieManager)==null?void 0:c.get(t);l&&(o.searchParams.append("_um",l),n.setAttribute("href",o.toString()))}}),this.logger.debug("Cross-domain linking initialized")}findClosestLink(e){for(;e&&e.tagName!=="A";)e=e.parentElement;return e}initializeTransport(e){const t="https://events.usermaven.com";if(!u())return new me(e.trackingHost||t,e);const s="XMLHttpRequest"in window,n=typeof fetch<"u",r=typeof navigator<"u"&&"sendBeacon"in navigator;if(e.useBeaconApi&&r)return new de(e.trackingHost||t,e,this.logger);if(e.forceUseFetch&&n)return new B(e.trackingHost||t,e,this.logger);if(s)return new ge(e.trackingHost||t,e,this.logger);if(n)return new B(e.trackingHost||t,e,this.logger);throw new Error("No suitable transport method available")}initializePersistence(){return this.config.disableEventPersistence||!u()?new fe:new V(`${this.namespace}_${this.config.key}`,this.logger)}getOrCreateAnonymousId(){var s,n;if(!u())return R();if(this.config.privacyPolicy==="strict"||this.config.cookiePolicy==="strict")return"";const e=this.config.cookieName||`__eventn_id_${this.config.key}`;let t=(s=this.cookieManager)==null?void 0:s.get(e);if(!t){if(this.config.crossDomainLinking){const c=new URLSearchParams(window.location.search).get("_um"),a=window.location.hash.substring(1).split("~"),h=a.length>1?a[1]:void 0;t=c||h||R()}t||(t=R());const r=365*10;(n=this.cookieManager)==null||n.set(e,t,r,document.location.protocol!=="http:",!1)}return t}async id(e,t=!1){if(!_(e))throw new Error("User data must be an object");if(e.email&&!oe(e.email))throw new Error("Invalid email provided");if(!e.id||!q(e.id))throw new Error("User ID must be a string");const s=e.id;if(this.persistence.set("userId",s),this.persistence.set("userProps",e),!t){const n={...e,anonymous_id:this.anonymousId};await this.track("user_identify",n)}this.logger.info("User identified:",e)}track(e,t,s=!1){this.trackInternal(e,t,s)}trackInternal(e,t,s=!1){if(!q(e))throw new Error("Event name must be a string");if(t!==void 0&&(typeof t!="object"||t===null||Array.isArray(t)))throw new Error("Event payload must be a non-null object and not an array");const n=this.createEventPayload(e,t);try{if(s){this.transport.send(n),this.logger.debug(`Event sent: ${e}`,[n]);return}this.retryQueue.add(n),this.logger.debug(`Event tracked: ${e}`,[n])}catch(r){throw this.logger.error(`Failed to track event: ${e}`,r),new Error(`Failed to track event: ${e}`)}}rawTrack(e){if(!_(e))throw new Error("Event payload must be an object");this.track("raw",e)}async group(e,t=!1){if(!_(e))throw new Error("Company properties must be an object");if(!e.id||!e.name||!e.created_at)throw new Error("Company properties must include id, name, and created_at");this.persistence.set("companyProps",e),t||await this.track("group",e),this.logger.info("Company identified:",e)}createEventPayload(e,t){const s=this.persistence.get("userProps")||{},n=this.persistence.get("companyProps")||(s==null?void 0:s.company)||{},r=this.persistence.get("userId"),o=this.persistence.get("global_props")||{},c=this.persistence.get(`props_${e}`)||{};let l=t||{};const a={event_id:"",user:{anonymous_id:this.anonymousId,id:r,...s},...n&&{company:n},ids:this.getThirdPartyIds(),utc_time:new Date().toISOString(),local_tz_offset:new Date().getTimezoneOffset(),api_key:this.config.key,src:"usermaven",event_type:e,namespace:this.namespace,...o,...c};if(e==="$autocapture"){const h=this.processAutocaptureAttributes(t||{});a.autocapture_attributes=h}else e!=="user_identify"&&e!=="group"&&(Array.isArray(this.config.propertyBlacklist)&&this.config.propertyBlacklist.forEach(h=>{delete l[h]}),a.event_attributes=l);return u()&&(a.referer=document.referrer,a.url=window.location.href,a.page_title=document.title,a.doc_path=window.location.pathname,a.doc_host=window.location.hostname,a.doc_search=window.location.search,a.screen_resolution=`${window.screen.width}x${window.screen.height}`,a.vp_size=`${window.innerWidth}x${window.innerHeight}`,a.user_agent=navigator.userAgent,a.user_language=navigator.language,a.doc_encoding=document.characterSet,a.utm=this.getUtmParams()),a}processAutocaptureAttributes(e){let t={};const s=e.$elements||[];return s.length&&(t={...s[0]}),t.el_text=t.$el_text||"",t.event_type=e.$event_type||"",["$ce_version","$event_type","$initial_referrer","$initial_referring_domain","$referrer","$referring_domain","$elements"].forEach(n=>{delete t[n]}),delete t.$el_text,delete t.nth_child,delete t.nth_of_type,t}getCookie(e){var t;return((t=this.cookieManager)==null?void 0:t.get(e))||null}getThirdPartyIds(){const e={};if(u()){const t=this.getCookie("_fbp");t&&(e.fbp=t)}return e}getUtmParams(){const e={},t=ce(window.location.search);return["utm_source","utm_medium","utm_campaign","utm_term","utm_content"].forEach(n=>{t[n]&&(e[n.replace("utm_","")]=t[n])}),e}pageview(){u()?this.track("pageview",{url:window.location.href,referrer:document.referrer,title:document.title},!0):this.logger.warn("Pageview tracking is not available in server-side environments")}setupPageLeaveTracking(){if(!u())return;let e=!1,t=!1;const s=()=>{!e&&!t&&(e=!0,this.track("$pageleave",{url:window.location.href,referrer:document.referrer,title:document.title}))};window.addEventListener("beforeunload",r=>{t=!0,setTimeout(()=>{t=!1},100)}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&!t&&s()});const n=history.pushState;history.pushState=function(){return s(),n.apply(this,arguments)},window.addEventListener("popstate",s)}getConfig(){return this.config}getLogger(){return this.logger}async reset(e=!1){if(this.persistence.clear(),e&&this.cookieManager){const t=this.config.cookieName||`__eventn_id_${this.config.key}`;this.cookieManager.delete(t),this.anonymousId=this.getOrCreateAnonymousId()}this.logger.info("core state reset",{resetAnonId:e,namespace:this.namespace})}set(e,t){if(!_(e))throw new Error("Properties must be an object");const s=t==null?void 0:t.eventType,n=(t==null?void 0:t.persist)??!0;if(s){let r=this.persistence.get(`props_${s}`)||{};r={...r,...e},this.persistence.set(`props_${s}`,r)}else{let r=this.persistence.get("global_props")||{};r={...r,...e},this.persistence.set("global_props",r)}n&&this.persistence.save(),this.logger.debug("Properties set",{properties:e,eventType:s||"global",persist:n})}setUserId(e){this.persistence.set("userId",e);let t=this.persistence.get("userProps")||{};t.id=e,this.persistence.set("userProps",t),this.persistence.save()}unset(e,t){const s=t==null?void 0:t.eventType,n=(t==null?void 0:t.persist)??!0;if(s){let r=this.persistence.get(`props_${s}`)||{};delete r[e],this.persistence.set(`props_${s}`,r)}else{let r=this.persistence.get("global_props")||{};delete r[e],this.persistence.set("global_props",r)}n&&this.persistence.save(),this.logger.debug(`Property unset: ${e}`,`Event type: ${s||"global"}`)}}function W(i){const e=JSON.parse(JSON.stringify(i)),t=H(e),s={...L,...t};if(!s.key)throw new Error("API key is required!");if(!s.trackingHost)throw new Error("Tracking host is required!");return new Q(s)}function ye(i){var n;const e={key:i.getAttribute("data-key")||void 0,trackingHost:i.getAttribute("data-tracking-host")||"https://events.usermaven.com",logLevel:le(i.getAttribute("data-log-level")),autocapture:i.getAttribute("data-autocapture")==="true",formTracking:i.getAttribute("data-form-tracking")==="false"?!1:i.getAttribute("data-form-tracking")==="true"?"all":i.getAttribute("data-form-tracking"),autoPageview:i.getAttribute("data-auto-pageview")==="true",useBeaconApi:i.getAttribute("data-use-beacon-api")==="true",forceUseFetch:i.getAttribute("data-force-use-fetch")==="true",gaHook:i.getAttribute("data-ga-hook")==="true",segmentHook:i.getAttribute("data-segment-hook")==="true",randomizeUrl:i.getAttribute("data-randomize-url")==="true",capture3rdPartyCookies:i.getAttribute("data-capture-3rd-party-cookies")==="false"?!1:void 0,idMethod:i.getAttribute("data-id-method")||void 0,privacyPolicy:i.getAttribute("data-privacy-policy")==="strict"?"strict":void 0,ipPolicy:i.getAttribute("data-ip-policy")||void 0,cookiePolicy:i.getAttribute("data-cookie-policy")||void 0,minSendTimeout:parseInt(i.getAttribute("data-min-send-timeout")||"",10)||void 0,maxSendTimeout:parseInt(i.getAttribute("data-max-send-timeout")||"",10)||void 0,maxSendAttempts:parseInt(i.getAttribute("data-max-send-attempts")||"",10)||void 0,propertiesStringMaxLength:parseInt(i.getAttribute("data-properties-string-max-length")||"",10)||null,propertyBlacklist:((n=i.getAttribute("data-property-blacklist"))==null?void 0:n.split(","))||void 0,exclude:i.getAttribute("data-exclude")||void 0,namespace:i.getAttribute("data-namespace")||void 0,crossDomainLinking:i.getAttribute("data-cross-domain-linking")!=="false",domains:i.getAttribute("data-domains")||void 0,maskAllText:i.getAttribute("data-mask-all-text")==="true",maskAllElementAttributes:i.getAttribute("data-mask-all-element-attributes")==="true"},t=W(e),s=e.namespace||"usermaven";u()&&t.pageview(),we(s,t)}function we(i,e){let t=!1;const s=[],n=[];function r(){for(;s.length>0;){const a=s.shift();a&&window[i].apply(null,a)}}function o(){n.forEach(a=>a()),n.length=0}window[i]=function(...a){const h=a[0];if(h==="onLoad"){typeof a[1]=="function"&&(t?a[1]():n.push(a[1]));return}if(!t){s.push(a);return}if(typeof e[h]=="function")return e[h].apply(e,a.slice(1));console.error(`Method ${h} not found on UsermavenClient`)};const c=`${i}Q`,l=window[c]||[];for(window[c]=l,l.push=function(...a){return window[i].apply(null,a),Array.prototype.push.apply(this,a)},setTimeout(()=>{t=!0,r(),o(),console.log(`Usermaven client for namespace ${i} is ready`)},0);l.length>0;){const a=l.shift();a&&s.push(a)}}u()&&function(i,e){const t=i.currentScript;function s(){t&&t.src.includes("lib.js")&&ye(t)}typeof e<"u"&&(i.readyState==="loading"?i.addEventListener("DOMContentLoaded",s):s())}(document,window),f.LogLevel=g,f.UsermavenClient=Q,f.usermavenClient=W,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Logger } from '../utils/logger';
|
|
2
|
+
export declare class LocalStoragePersistence {
|
|
3
|
+
private storage;
|
|
4
|
+
private prefix;
|
|
5
|
+
private logger;
|
|
6
|
+
constructor(apiKey: string, logger?: Logger);
|
|
7
|
+
set(key: string, value: any): void;
|
|
8
|
+
get(key: string): any;
|
|
9
|
+
remove(key: string): void;
|
|
10
|
+
clear(): void;
|
|
11
|
+
save(): void;
|
|
12
|
+
private load;
|
|
13
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { UsermavenClient } from '../core/client';
|
|
2
|
+
import { Config } from '../core/types';
|
|
3
|
+
declare class AutoCapture {
|
|
4
|
+
private logger;
|
|
5
|
+
private client;
|
|
6
|
+
private options;
|
|
7
|
+
private scrollDepth;
|
|
8
|
+
private customProperties;
|
|
9
|
+
static readonly FORCE_CAPTURE_ATTR = "data-um-force-capture";
|
|
10
|
+
static readonly PREVENT_CAPTURE_ATTR = "data-um-no-capture";
|
|
11
|
+
constructor(client: UsermavenClient, options: Config, logger?: import('../utils/logger').Logger);
|
|
12
|
+
init(): void;
|
|
13
|
+
private addDomEventHandlers;
|
|
14
|
+
private isPageRefresh;
|
|
15
|
+
private captureEvent;
|
|
16
|
+
private getCustomProperties;
|
|
17
|
+
private extractCustomPropertyValue;
|
|
18
|
+
private getEventTarget;
|
|
19
|
+
private getPropertiesFromElement;
|
|
20
|
+
private previousElementSibling;
|
|
21
|
+
private getDefaultProperties;
|
|
22
|
+
private encodeHtml;
|
|
23
|
+
static enabledForProject(token: string, numBuckets?: number, numEnabledBuckets?: number): boolean;
|
|
24
|
+
}
|
|
25
|
+
export default AutoCapture;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { UsermavenClient } from '../core/client';
|
|
2
|
+
export default class FormTracking {
|
|
3
|
+
private instance;
|
|
4
|
+
private formElements?;
|
|
5
|
+
private trackingType;
|
|
6
|
+
private options;
|
|
7
|
+
private static instance;
|
|
8
|
+
private constructor();
|
|
9
|
+
private initialize;
|
|
10
|
+
private setupFormTracking;
|
|
11
|
+
private handleFormSubmit;
|
|
12
|
+
private trackFieldChanges;
|
|
13
|
+
static getInstance(instance: UsermavenClient, trackingType?: 'all' | 'tagged' | 'none', options?: FormTrackingOptions): FormTracking;
|
|
14
|
+
private _getFormDetails;
|
|
15
|
+
private _getFieldProps;
|
|
16
|
+
private _getElementAttributes;
|
|
17
|
+
private getSafeText;
|
|
18
|
+
private _scrubPotentiallySensitiveValues;
|
|
19
|
+
private _shouldCaptureValue;
|
|
20
|
+
private _isNullish;
|
|
21
|
+
private _isString;
|
|
22
|
+
private _trim;
|
|
23
|
+
}
|
|
24
|
+
interface FormTrackingOptions {
|
|
25
|
+
trackFieldChanges?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { UsermavenClient } from '../core/client';
|
|
2
|
+
export declare class PageviewTracking {
|
|
3
|
+
private client;
|
|
4
|
+
private lastPageUrl;
|
|
5
|
+
constructor(client: UsermavenClient);
|
|
6
|
+
private trackInitialPageview;
|
|
7
|
+
private initializePageviewTracking;
|
|
8
|
+
private handlePageview;
|
|
9
|
+
private checkForUrlChange;
|
|
10
|
+
private trackPageview;
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Transport, Config } from '../core/types';
|
|
2
|
+
export declare class BeaconTransport implements Transport {
|
|
3
|
+
private trackingHost;
|
|
4
|
+
private logger;
|
|
5
|
+
private config;
|
|
6
|
+
constructor(trackingHost: string, config: Config, logger?: import('../utils/logger').Logger);
|
|
7
|
+
send(payloads: any[]): Promise<void>;
|
|
8
|
+
private constructUrl;
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Transport, Config } from '../core/types';
|
|
2
|
+
import { Logger } from '../utils/logger';
|
|
3
|
+
export declare class FetchTransport implements Transport {
|
|
4
|
+
private trackingHost;
|
|
5
|
+
private logger;
|
|
6
|
+
private config;
|
|
7
|
+
constructor(trackingHost: string, config: Config, logger?: Logger);
|
|
8
|
+
send(payloads: any[]): Promise<void>;
|
|
9
|
+
private constructUrl;
|
|
10
|
+
private getCustomHeaders;
|
|
11
|
+
private postHandle;
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Transport, Config } from '../core/types';
|
|
2
|
+
export declare class HttpsTransport implements Transport {
|
|
3
|
+
private trackingHost;
|
|
4
|
+
private logger;
|
|
5
|
+
private config;
|
|
6
|
+
constructor(trackingHost: string, config: Config, logger?: import('../utils/logger').Logger);
|
|
7
|
+
send(payloads: any[]): Promise<void>;
|
|
8
|
+
private constructUrl;
|
|
9
|
+
private getCustomHeaders;
|
|
10
|
+
}
|