@v-tilt/browser 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/array.full.js +1 -1
- package/dist/array.full.js.map +1 -1
- package/dist/array.js +1 -1
- package/dist/array.js.map +1 -1
- package/dist/array.no-external.js +1 -1
- package/dist/array.no-external.js.map +1 -1
- package/dist/chat.js +1 -1
- package/dist/chat.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/entrypoints/server.es.d.ts +12 -0
- package/dist/external-scripts-loader.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +6 -3
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.d.ts +6 -3
- package/dist/module.no-external.js +1 -1
- package/dist/module.no-external.js.map +1 -1
- package/dist/server.d.ts +105 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +3 -1
- package/dist/vtilt.d.ts +3 -2
- package/package.json +1 -2
- package/lib/config.d.ts +0 -17
- package/lib/config.js +0 -76
- package/lib/constants.d.ts +0 -178
- package/lib/constants.js +0 -656
- package/lib/entrypoints/all-external-dependencies.d.ts +0 -8
- package/lib/entrypoints/all-external-dependencies.js +0 -10
- package/lib/entrypoints/array.d.ts +0 -2
- package/lib/entrypoints/array.full.d.ts +0 -17
- package/lib/entrypoints/array.full.js +0 -19
- package/lib/entrypoints/array.js +0 -4
- package/lib/entrypoints/array.no-external.d.ts +0 -1
- package/lib/entrypoints/array.no-external.js +0 -4
- package/lib/entrypoints/chat.d.ts +0 -22
- package/lib/entrypoints/chat.js +0 -32
- package/lib/entrypoints/external-scripts-loader.d.ts +0 -24
- package/lib/entrypoints/external-scripts-loader.js +0 -104
- package/lib/entrypoints/main.cjs.d.ts +0 -4
- package/lib/entrypoints/main.cjs.js +0 -29
- package/lib/entrypoints/module.es.d.ts +0 -4
- package/lib/entrypoints/module.es.js +0 -23
- package/lib/entrypoints/module.no-external.es.d.ts +0 -4
- package/lib/entrypoints/module.no-external.es.js +0 -23
- package/lib/entrypoints/recorder.d.ts +0 -23
- package/lib/entrypoints/recorder.js +0 -42
- package/lib/entrypoints/web-vitals.d.ts +0 -14
- package/lib/entrypoints/web-vitals.js +0 -29
- package/lib/extensions/chat/chat-wrapper.d.ts +0 -196
- package/lib/extensions/chat/chat-wrapper.js +0 -545
- package/lib/extensions/chat/chat.d.ts +0 -99
- package/lib/extensions/chat/chat.js +0 -1891
- package/lib/extensions/chat/index.d.ts +0 -10
- package/lib/extensions/chat/index.js +0 -27
- package/lib/extensions/chat/types.d.ts +0 -159
- package/lib/extensions/chat/types.js +0 -22
- package/lib/extensions/history-autocapture.d.ts +0 -17
- package/lib/extensions/history-autocapture.js +0 -105
- package/lib/extensions/replay/index.d.ts +0 -13
- package/lib/extensions/replay/index.js +0 -31
- package/lib/extensions/replay/session-recording-utils.d.ts +0 -92
- package/lib/extensions/replay/session-recording-utils.js +0 -212
- package/lib/extensions/replay/session-recording-wrapper.d.ts +0 -61
- package/lib/extensions/replay/session-recording-wrapper.js +0 -149
- package/lib/extensions/replay/session-recording.d.ts +0 -95
- package/lib/extensions/replay/session-recording.js +0 -700
- package/lib/extensions/replay/types.d.ts +0 -211
- package/lib/extensions/replay/types.js +0 -8
- package/lib/geolocation.d.ts +0 -5
- package/lib/geolocation.js +0 -31
- package/lib/rate-limiter.d.ts +0 -52
- package/lib/rate-limiter.js +0 -80
- package/lib/request-queue.d.ts +0 -78
- package/lib/request-queue.js +0 -156
- package/lib/request.d.ts +0 -54
- package/lib/request.js +0 -265
- package/lib/retry-queue.d.ts +0 -64
- package/lib/retry-queue.js +0 -182
- package/lib/session.d.ts +0 -66
- package/lib/session.js +0 -191
- package/lib/storage.d.ts +0 -117
- package/lib/storage.js +0 -438
- package/lib/types.d.ts +0 -350
- package/lib/types.js +0 -24
- package/lib/user-manager.d.ts +0 -154
- package/lib/user-manager.js +0 -589
- package/lib/utils/event-utils.d.ts +0 -52
- package/lib/utils/event-utils.js +0 -305
- package/lib/utils/globals.d.ts +0 -235
- package/lib/utils/globals.js +0 -30
- package/lib/utils/index.d.ts +0 -46
- package/lib/utils/index.js +0 -134
- package/lib/utils/patch.d.ts +0 -6
- package/lib/utils/patch.js +0 -39
- package/lib/utils/request-utils.d.ts +0 -17
- package/lib/utils/request-utils.js +0 -80
- package/lib/utils/type-utils.d.ts +0 -4
- package/lib/utils/type-utils.js +0 -9
- package/lib/utils/user-agent-utils.d.ts +0 -18
- package/lib/utils/user-agent-utils.js +0 -411
- package/lib/vtilt.d.ts +0 -359
- package/lib/vtilt.js +0 -1188
- package/lib/web-vitals.d.ts +0 -95
- package/lib/web-vitals.js +0 -380
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Recording Types
|
|
3
|
-
*
|
|
4
|
-
* Type definitions for rrweb session recording.
|
|
5
|
-
* Based on PostHog's implementation.
|
|
6
|
-
*/
|
|
7
|
-
import type { blockClass, eventWithTime, hooksParam, KeepIframeSrcFn, maskTextClass, PackFn, RecordPlugin, SamplingStrategy } from "@rrweb/types";
|
|
8
|
-
/** Mask options for input elements */
|
|
9
|
-
export type MaskInputOptions = Partial<{
|
|
10
|
-
color: boolean;
|
|
11
|
-
date: boolean;
|
|
12
|
-
"datetime-local": boolean;
|
|
13
|
-
email: boolean;
|
|
14
|
-
month: boolean;
|
|
15
|
-
number: boolean;
|
|
16
|
-
range: boolean;
|
|
17
|
-
search: boolean;
|
|
18
|
-
tel: boolean;
|
|
19
|
-
text: boolean;
|
|
20
|
-
time: boolean;
|
|
21
|
-
url: boolean;
|
|
22
|
-
week: boolean;
|
|
23
|
-
textarea: boolean;
|
|
24
|
-
select: boolean;
|
|
25
|
-
password: boolean;
|
|
26
|
-
}>;
|
|
27
|
-
/** Function to mask input values */
|
|
28
|
-
export type MaskInputFn = (text: string, element: HTMLElement) => string;
|
|
29
|
-
/** Function to mask text content */
|
|
30
|
-
export type MaskTextFn = (text: string, element: HTMLElement | null) => string;
|
|
31
|
-
/** Options for slim DOM mode */
|
|
32
|
-
export type SlimDOMOptions = Partial<{
|
|
33
|
-
script: boolean;
|
|
34
|
-
comment: boolean;
|
|
35
|
-
headFavicon: boolean;
|
|
36
|
-
headWhitespace: boolean;
|
|
37
|
-
headMetaDescKeywords: boolean;
|
|
38
|
-
headMetaSocial: boolean;
|
|
39
|
-
headMetaRobots: boolean;
|
|
40
|
-
headMetaHttpEquiv: boolean;
|
|
41
|
-
headMetaAuthorship: boolean;
|
|
42
|
-
headMetaVerification: boolean;
|
|
43
|
-
headTitleMutations: boolean;
|
|
44
|
-
}>;
|
|
45
|
-
/** Options for data URL generation */
|
|
46
|
-
export type DataURLOptions = Partial<{
|
|
47
|
-
type: string;
|
|
48
|
-
quality: number;
|
|
49
|
-
}>;
|
|
50
|
-
/** Error handler type */
|
|
51
|
-
export type ErrorHandler = (error: unknown) => void | boolean;
|
|
52
|
-
/** rrweb record options */
|
|
53
|
-
export interface RecordOptions {
|
|
54
|
-
emit?: (e: eventWithTime, isCheckout?: boolean) => void;
|
|
55
|
-
checkoutEveryNth?: number;
|
|
56
|
-
checkoutEveryNms?: number;
|
|
57
|
-
blockClass?: blockClass;
|
|
58
|
-
blockSelector?: string;
|
|
59
|
-
ignoreClass?: string;
|
|
60
|
-
ignoreSelector?: string;
|
|
61
|
-
maskTextClass?: maskTextClass;
|
|
62
|
-
maskTextSelector?: string;
|
|
63
|
-
maskAllInputs?: boolean;
|
|
64
|
-
maskInputOptions?: MaskInputOptions;
|
|
65
|
-
maskInputFn?: MaskInputFn;
|
|
66
|
-
maskTextFn?: MaskTextFn;
|
|
67
|
-
slimDOMOptions?: SlimDOMOptions | "all" | true;
|
|
68
|
-
ignoreCSSAttributes?: Set<string>;
|
|
69
|
-
inlineStylesheet?: boolean;
|
|
70
|
-
hooks?: hooksParam;
|
|
71
|
-
packFn?: PackFn;
|
|
72
|
-
sampling?: SamplingStrategy;
|
|
73
|
-
dataURLOptions?: DataURLOptions;
|
|
74
|
-
recordDOM?: boolean;
|
|
75
|
-
recordCanvas?: boolean;
|
|
76
|
-
recordCrossOriginIframes?: boolean;
|
|
77
|
-
recordAfter?: "DOMContentLoaded" | "load";
|
|
78
|
-
userTriggeredOnInput?: boolean;
|
|
79
|
-
collectFonts?: boolean;
|
|
80
|
-
inlineImages?: boolean;
|
|
81
|
-
plugins?: RecordPlugin[];
|
|
82
|
-
mousemoveWait?: number;
|
|
83
|
-
keepIframeSrcFn?: KeepIframeSrcFn;
|
|
84
|
-
errorHandler?: ErrorHandler;
|
|
85
|
-
}
|
|
86
|
-
/** rrweb record function type */
|
|
87
|
-
export interface RRWebRecord {
|
|
88
|
-
(options: RecordOptions): () => void;
|
|
89
|
-
addCustomEvent: (tag: string, payload: unknown) => void;
|
|
90
|
-
takeFullSnapshot: () => void;
|
|
91
|
-
mirror: {
|
|
92
|
-
getId(n: Node | undefined | null): number;
|
|
93
|
-
getNode(id: number): Node | null;
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
/** Canvas recording configuration */
|
|
97
|
-
export interface CanvasRecordingConfig {
|
|
98
|
-
enabled: boolean;
|
|
99
|
-
fps: number;
|
|
100
|
-
quality: number;
|
|
101
|
-
}
|
|
102
|
-
/** Network payload capture configuration */
|
|
103
|
-
export interface NetworkPayloadCaptureConfig {
|
|
104
|
-
recordHeaders?: boolean;
|
|
105
|
-
recordBody?: boolean;
|
|
106
|
-
recordPerformance?: boolean;
|
|
107
|
-
}
|
|
108
|
-
/** Masking configuration */
|
|
109
|
-
export interface MaskingConfig {
|
|
110
|
-
maskAllInputs?: boolean;
|
|
111
|
-
maskTextSelector?: string;
|
|
112
|
-
blockSelector?: string;
|
|
113
|
-
}
|
|
114
|
-
/** Session recording configuration */
|
|
115
|
-
export interface SessionRecordingConfig {
|
|
116
|
-
/** Enable session recording */
|
|
117
|
-
enabled?: boolean;
|
|
118
|
-
/** Sample rate (0-1, where 1 = 100%) */
|
|
119
|
-
sampleRate?: number;
|
|
120
|
-
/** Minimum session duration in ms before sending */
|
|
121
|
-
minimumDurationMs?: number;
|
|
122
|
-
/** Session idle threshold in ms */
|
|
123
|
-
sessionIdleThresholdMs?: number;
|
|
124
|
-
/** Full snapshot interval in ms */
|
|
125
|
-
fullSnapshotIntervalMs?: number;
|
|
126
|
-
/** Enable console log capture */
|
|
127
|
-
captureConsole?: boolean;
|
|
128
|
-
/** Enable network request capture */
|
|
129
|
-
captureNetwork?: boolean;
|
|
130
|
-
/** Canvas recording settings */
|
|
131
|
-
captureCanvas?: {
|
|
132
|
-
recordCanvas?: boolean;
|
|
133
|
-
canvasFps?: number;
|
|
134
|
-
canvasQuality?: number;
|
|
135
|
-
};
|
|
136
|
-
/** Masking settings */
|
|
137
|
-
masking?: MaskingConfig;
|
|
138
|
-
/** Block class for elements to hide */
|
|
139
|
-
blockClass?: string;
|
|
140
|
-
/** Block selector for elements to hide */
|
|
141
|
-
blockSelector?: string;
|
|
142
|
-
/** Ignore class for input masking */
|
|
143
|
-
ignoreClass?: string;
|
|
144
|
-
/** Mask text class */
|
|
145
|
-
maskTextClass?: string;
|
|
146
|
-
/** Mask text selector */
|
|
147
|
-
maskTextSelector?: string;
|
|
148
|
-
/** Mask all inputs */
|
|
149
|
-
maskAllInputs?: boolean;
|
|
150
|
-
/** Mask input options */
|
|
151
|
-
maskInputOptions?: MaskInputOptions;
|
|
152
|
-
/** Record headers in network requests */
|
|
153
|
-
recordHeaders?: boolean;
|
|
154
|
-
/** Record body in network requests */
|
|
155
|
-
recordBody?: boolean;
|
|
156
|
-
/** Compress events before sending */
|
|
157
|
-
compressEvents?: boolean;
|
|
158
|
-
/** Internal: Mutation throttler refill rate */
|
|
159
|
-
__mutationThrottlerRefillRate?: number;
|
|
160
|
-
/** Internal: Mutation throttler bucket size */
|
|
161
|
-
__mutationThrottlerBucketSize?: number;
|
|
162
|
-
}
|
|
163
|
-
/** Recording status values */
|
|
164
|
-
export type SessionRecordingStatus = "disabled" | "buffering" | "active" | "paused" | "sampled" | "trigger_pending";
|
|
165
|
-
/** Recording start reason */
|
|
166
|
-
export type SessionStartReason = "recording_initialized" | "session_id_changed" | "linked_flag_matched" | "linked_flag_overridden" | "sampling_overridden" | "url_trigger_matched" | "event_trigger_matched" | "sampled";
|
|
167
|
-
/** Trigger type for starting recording */
|
|
168
|
-
export type TriggerType = "url" | "event";
|
|
169
|
-
/** Buffer for snapshot events */
|
|
170
|
-
export interface SnapshotBuffer {
|
|
171
|
-
size: number;
|
|
172
|
-
data: eventWithTime[];
|
|
173
|
-
sessionId: string;
|
|
174
|
-
windowId: string;
|
|
175
|
-
}
|
|
176
|
-
/** Remote configuration for session recording */
|
|
177
|
-
export interface SessionRecordingRemoteConfig {
|
|
178
|
-
enabled?: boolean;
|
|
179
|
-
endpoint?: string;
|
|
180
|
-
sampleRate?: string;
|
|
181
|
-
minimumDurationMilliseconds?: number;
|
|
182
|
-
consoleLogRecordingEnabled?: boolean;
|
|
183
|
-
networkPayloadCapture?: {
|
|
184
|
-
recordHeaders?: boolean;
|
|
185
|
-
recordBody?: boolean;
|
|
186
|
-
capturePerformance?: boolean;
|
|
187
|
-
};
|
|
188
|
-
masking?: MaskingConfig;
|
|
189
|
-
recordCanvas?: boolean;
|
|
190
|
-
canvasFps?: number;
|
|
191
|
-
canvasQuality?: number;
|
|
192
|
-
scriptConfig?: {
|
|
193
|
-
script?: string;
|
|
194
|
-
};
|
|
195
|
-
triggerMatchType?: "any" | "all";
|
|
196
|
-
urlTriggers?: Array<{
|
|
197
|
-
url: string;
|
|
198
|
-
matching: "regex" | "exact" | "contains";
|
|
199
|
-
}>;
|
|
200
|
-
urlBlocklist?: Array<{
|
|
201
|
-
url: string;
|
|
202
|
-
matching: "regex" | "exact" | "contains";
|
|
203
|
-
}>;
|
|
204
|
-
eventTriggers?: string[];
|
|
205
|
-
}
|
|
206
|
-
/** Queued rrweb method call */
|
|
207
|
-
export interface QueuedRRWebEvent {
|
|
208
|
-
rrwebMethod: () => void;
|
|
209
|
-
attempt: number;
|
|
210
|
-
enqueuedAt: number;
|
|
211
|
-
}
|
package/lib/geolocation.d.ts
DELETED
package/lib/geolocation.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getCountryAndLocale = getCountryAndLocale;
|
|
4
|
-
const constants_1 = require("./constants");
|
|
5
|
-
const globals_1 = require("./utils/globals");
|
|
6
|
-
/**
|
|
7
|
-
* Get country and locale from timezone and navigator
|
|
8
|
-
*/
|
|
9
|
-
function getCountryAndLocale() {
|
|
10
|
-
let country;
|
|
11
|
-
let locale;
|
|
12
|
-
// Only get geolocation data in browser environment (not SSR)
|
|
13
|
-
if (!globals_1.navigator) {
|
|
14
|
-
return { country, locale };
|
|
15
|
-
}
|
|
16
|
-
try {
|
|
17
|
-
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
18
|
-
country = constants_1.TIMEZONES[timezone];
|
|
19
|
-
locale =
|
|
20
|
-
globals_1.navigator.languages && globals_1.navigator.languages.length
|
|
21
|
-
? globals_1.navigator.languages[0]
|
|
22
|
-
: globals_1.navigator.userLanguage ||
|
|
23
|
-
globals_1.navigator.language ||
|
|
24
|
-
globals_1.navigator.browserLanguage ||
|
|
25
|
-
"en";
|
|
26
|
-
}
|
|
27
|
-
catch (_error) {
|
|
28
|
-
// ignore error
|
|
29
|
-
}
|
|
30
|
-
return { country, locale };
|
|
31
|
-
}
|
package/lib/rate-limiter.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rate Limiter - Token Bucket Algorithm (PostHog-style)
|
|
3
|
-
*
|
|
4
|
-
* Prevents runaway loops from flooding the server with events.
|
|
5
|
-
* Uses a token bucket algorithm with configurable rate and burst limits.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Configurable events per second (default: 10)
|
|
9
|
-
* - Configurable burst limit (default: 100)
|
|
10
|
-
* - Token replenishment over time
|
|
11
|
-
* - Warning event when rate limited
|
|
12
|
-
*/
|
|
13
|
-
export declare const RATE_LIMIT_WARNING_EVENT = "$$client_ingestion_warning";
|
|
14
|
-
export interface RateLimitBucket {
|
|
15
|
-
tokens: number;
|
|
16
|
-
last: number;
|
|
17
|
-
}
|
|
18
|
-
export interface RateLimiterConfig {
|
|
19
|
-
eventsPerSecond?: number;
|
|
20
|
-
eventsBurstLimit?: number;
|
|
21
|
-
persistence?: {
|
|
22
|
-
get: (key: string) => RateLimitBucket | null;
|
|
23
|
-
set: (key: string, value: RateLimitBucket) => void;
|
|
24
|
-
};
|
|
25
|
-
captureWarning?: (message: string) => void;
|
|
26
|
-
}
|
|
27
|
-
export declare class RateLimiter {
|
|
28
|
-
private eventsPerSecond;
|
|
29
|
-
private eventsBurstLimit;
|
|
30
|
-
private lastEventRateLimited;
|
|
31
|
-
private persistence?;
|
|
32
|
-
private captureWarning?;
|
|
33
|
-
constructor(config?: RateLimiterConfig);
|
|
34
|
-
/**
|
|
35
|
-
* Check if the client should be rate limited
|
|
36
|
-
*
|
|
37
|
-
* @param checkOnly - If true, don't consume a token (just check)
|
|
38
|
-
* @returns Object with isRateLimited flag and remaining tokens
|
|
39
|
-
*/
|
|
40
|
-
checkRateLimit(checkOnly?: boolean): {
|
|
41
|
-
isRateLimited: boolean;
|
|
42
|
-
remainingTokens: number;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Check if an event should be allowed (consumes a token if allowed)
|
|
46
|
-
*/
|
|
47
|
-
shouldAllowEvent(): boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Get remaining tokens without consuming
|
|
50
|
-
*/
|
|
51
|
-
getRemainingTokens(): number;
|
|
52
|
-
}
|
package/lib/rate-limiter.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Rate Limiter - Token Bucket Algorithm (PostHog-style)
|
|
4
|
-
*
|
|
5
|
-
* Prevents runaway loops from flooding the server with events.
|
|
6
|
-
* Uses a token bucket algorithm with configurable rate and burst limits.
|
|
7
|
-
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - Configurable events per second (default: 10)
|
|
10
|
-
* - Configurable burst limit (default: 100)
|
|
11
|
-
* - Token replenishment over time
|
|
12
|
-
* - Warning event when rate limited
|
|
13
|
-
*/
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.RateLimiter = exports.RATE_LIMIT_WARNING_EVENT = void 0;
|
|
16
|
-
const RATE_LIMIT_STORAGE_KEY = "vt_rate_limit";
|
|
17
|
-
exports.RATE_LIMIT_WARNING_EVENT = "$$client_ingestion_warning";
|
|
18
|
-
class RateLimiter {
|
|
19
|
-
constructor(config = {}) {
|
|
20
|
-
var _a, _b;
|
|
21
|
-
this.lastEventRateLimited = false;
|
|
22
|
-
this.eventsPerSecond = (_a = config.eventsPerSecond) !== null && _a !== void 0 ? _a : 10;
|
|
23
|
-
this.eventsBurstLimit = Math.max((_b = config.eventsBurstLimit) !== null && _b !== void 0 ? _b : this.eventsPerSecond * 10, this.eventsPerSecond);
|
|
24
|
-
this.persistence = config.persistence;
|
|
25
|
-
this.captureWarning = config.captureWarning;
|
|
26
|
-
// Initialize lastEventRateLimited from current state
|
|
27
|
-
this.lastEventRateLimited = this.checkRateLimit(true).isRateLimited;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Check if the client should be rate limited
|
|
31
|
-
*
|
|
32
|
-
* @param checkOnly - If true, don't consume a token (just check)
|
|
33
|
-
* @returns Object with isRateLimited flag and remaining tokens
|
|
34
|
-
*/
|
|
35
|
-
checkRateLimit(checkOnly = false) {
|
|
36
|
-
var _a, _b, _c, _d;
|
|
37
|
-
const now = Date.now();
|
|
38
|
-
// Get current bucket state from persistence or create new
|
|
39
|
-
const bucket = (_b = (_a = this.persistence) === null || _a === void 0 ? void 0 : _a.get(RATE_LIMIT_STORAGE_KEY)) !== null && _b !== void 0 ? _b : {
|
|
40
|
-
tokens: this.eventsBurstLimit,
|
|
41
|
-
last: now,
|
|
42
|
-
};
|
|
43
|
-
// Replenish tokens based on time elapsed
|
|
44
|
-
const secondsElapsed = (now - bucket.last) / 1000;
|
|
45
|
-
bucket.tokens += secondsElapsed * this.eventsPerSecond;
|
|
46
|
-
bucket.last = now;
|
|
47
|
-
// Cap tokens at burst limit
|
|
48
|
-
if (bucket.tokens > this.eventsBurstLimit) {
|
|
49
|
-
bucket.tokens = this.eventsBurstLimit;
|
|
50
|
-
}
|
|
51
|
-
const isRateLimited = bucket.tokens < 1;
|
|
52
|
-
// Consume a token if not just checking
|
|
53
|
-
if (!isRateLimited && !checkOnly) {
|
|
54
|
-
bucket.tokens = Math.max(0, bucket.tokens - 1);
|
|
55
|
-
}
|
|
56
|
-
// Capture warning event when first rate limited
|
|
57
|
-
if (isRateLimited && !this.lastEventRateLimited && !checkOnly) {
|
|
58
|
-
(_c = this.captureWarning) === null || _c === void 0 ? void 0 : _c.call(this, `vTilt client rate limited. Config: ${this.eventsPerSecond} events/second, ${this.eventsBurstLimit} burst limit.`);
|
|
59
|
-
}
|
|
60
|
-
this.lastEventRateLimited = isRateLimited;
|
|
61
|
-
(_d = this.persistence) === null || _d === void 0 ? void 0 : _d.set(RATE_LIMIT_STORAGE_KEY, bucket);
|
|
62
|
-
return {
|
|
63
|
-
isRateLimited,
|
|
64
|
-
remainingTokens: bucket.tokens,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Check if an event should be allowed (consumes a token if allowed)
|
|
69
|
-
*/
|
|
70
|
-
shouldAllowEvent() {
|
|
71
|
-
return !this.checkRateLimit(false).isRateLimited;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Get remaining tokens without consuming
|
|
75
|
-
*/
|
|
76
|
-
getRemainingTokens() {
|
|
77
|
-
return this.checkRateLimit(true).remainingTokens;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
exports.RateLimiter = RateLimiter;
|
package/lib/request-queue.d.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request Queue - Event Batching (PostHog-style)
|
|
3
|
-
*
|
|
4
|
-
* Batches multiple events together and sends them at configurable intervals.
|
|
5
|
-
* This reduces the number of HTTP requests significantly for active users.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Configurable flush interval (default 3 seconds)
|
|
9
|
-
* - Batches events by URL/batchKey
|
|
10
|
-
* - Uses sendBeacon on page unload for reliable delivery
|
|
11
|
-
* - Converts absolute timestamps to relative offsets before sending
|
|
12
|
-
*/
|
|
13
|
-
import type { TrackingEvent } from "./types";
|
|
14
|
-
export declare const DEFAULT_FLUSH_INTERVAL_MS = 3000;
|
|
15
|
-
export interface QueuedRequest {
|
|
16
|
-
url: string;
|
|
17
|
-
event: TrackingEvent;
|
|
18
|
-
batchKey?: string;
|
|
19
|
-
transport?: "xhr" | "sendBeacon";
|
|
20
|
-
}
|
|
21
|
-
export interface BatchedRequest {
|
|
22
|
-
url: string;
|
|
23
|
-
events: TrackingEvent[];
|
|
24
|
-
batchKey?: string;
|
|
25
|
-
transport?: "xhr" | "sendBeacon";
|
|
26
|
-
}
|
|
27
|
-
export interface RequestQueueConfig {
|
|
28
|
-
flush_interval_ms?: number;
|
|
29
|
-
}
|
|
30
|
-
export declare class RequestQueue {
|
|
31
|
-
private _isPaused;
|
|
32
|
-
private _queue;
|
|
33
|
-
private _flushTimeout?;
|
|
34
|
-
private _flushTimeoutMs;
|
|
35
|
-
private _sendRequest;
|
|
36
|
-
constructor(sendRequest: (req: BatchedRequest) => void, config?: RequestQueueConfig);
|
|
37
|
-
/**
|
|
38
|
-
* Get the current queue length
|
|
39
|
-
*/
|
|
40
|
-
get length(): number;
|
|
41
|
-
/**
|
|
42
|
-
* Enqueue an event for batched sending
|
|
43
|
-
*/
|
|
44
|
-
enqueue(req: QueuedRequest): void;
|
|
45
|
-
/**
|
|
46
|
-
* Flush all queued events immediately using sendBeacon
|
|
47
|
-
* Called on page unload to ensure events are delivered
|
|
48
|
-
*/
|
|
49
|
-
unload(): void;
|
|
50
|
-
/**
|
|
51
|
-
* Enable the queue and start flushing
|
|
52
|
-
*/
|
|
53
|
-
enable(): void;
|
|
54
|
-
/**
|
|
55
|
-
* Pause the queue (stops flushing but keeps events)
|
|
56
|
-
*/
|
|
57
|
-
pause(): void;
|
|
58
|
-
/**
|
|
59
|
-
* Force an immediate flush
|
|
60
|
-
*/
|
|
61
|
-
flush(): void;
|
|
62
|
-
/**
|
|
63
|
-
* Set up the flush timeout
|
|
64
|
-
*/
|
|
65
|
-
private _setFlushTimeout;
|
|
66
|
-
/**
|
|
67
|
-
* Clear the flush timeout
|
|
68
|
-
*/
|
|
69
|
-
private _clearFlushTimeout;
|
|
70
|
-
/**
|
|
71
|
-
* Flush all queued events now
|
|
72
|
-
*/
|
|
73
|
-
private _flushNow;
|
|
74
|
-
/**
|
|
75
|
-
* Format the queue into batched requests by URL/batchKey
|
|
76
|
-
*/
|
|
77
|
-
private _formatQueue;
|
|
78
|
-
}
|
package/lib/request-queue.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Request Queue - Event Batching (PostHog-style)
|
|
4
|
-
*
|
|
5
|
-
* Batches multiple events together and sends them at configurable intervals.
|
|
6
|
-
* This reduces the number of HTTP requests significantly for active users.
|
|
7
|
-
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - Configurable flush interval (default 3 seconds)
|
|
10
|
-
* - Batches events by URL/batchKey
|
|
11
|
-
* - Uses sendBeacon on page unload for reliable delivery
|
|
12
|
-
* - Converts absolute timestamps to relative offsets before sending
|
|
13
|
-
*/
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.RequestQueue = exports.DEFAULT_FLUSH_INTERVAL_MS = void 0;
|
|
16
|
-
exports.DEFAULT_FLUSH_INTERVAL_MS = 3000;
|
|
17
|
-
/**
|
|
18
|
-
* Clamp a value to a range
|
|
19
|
-
*/
|
|
20
|
-
function clampToRange(value, min, max, defaultValue) {
|
|
21
|
-
if (typeof value !== "number" || isNaN(value)) {
|
|
22
|
-
return defaultValue;
|
|
23
|
-
}
|
|
24
|
-
return Math.min(Math.max(value, min), max);
|
|
25
|
-
}
|
|
26
|
-
class RequestQueue {
|
|
27
|
-
constructor(sendRequest, config) {
|
|
28
|
-
// We start in a paused state and only start flushing when enabled
|
|
29
|
-
this._isPaused = true;
|
|
30
|
-
this._queue = [];
|
|
31
|
-
this._flushTimeoutMs = clampToRange((config === null || config === void 0 ? void 0 : config.flush_interval_ms) || exports.DEFAULT_FLUSH_INTERVAL_MS, 250, // Min 250ms
|
|
32
|
-
5000, // Max 5 seconds
|
|
33
|
-
exports.DEFAULT_FLUSH_INTERVAL_MS);
|
|
34
|
-
this._sendRequest = sendRequest;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Get the current queue length
|
|
38
|
-
*/
|
|
39
|
-
get length() {
|
|
40
|
-
return this._queue.length;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Enqueue an event for batched sending
|
|
44
|
-
*/
|
|
45
|
-
enqueue(req) {
|
|
46
|
-
this._queue.push(req);
|
|
47
|
-
// Start flush timer if not already running
|
|
48
|
-
if (!this._flushTimeout) {
|
|
49
|
-
this._setFlushTimeout();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Flush all queued events immediately using sendBeacon
|
|
54
|
-
* Called on page unload to ensure events are delivered
|
|
55
|
-
*/
|
|
56
|
-
unload() {
|
|
57
|
-
this._clearFlushTimeout();
|
|
58
|
-
if (this._queue.length === 0) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const requests = this._formatQueue();
|
|
62
|
-
// Send each batched request using sendBeacon for reliable delivery
|
|
63
|
-
for (const key in requests) {
|
|
64
|
-
const req = requests[key];
|
|
65
|
-
this._sendRequest({ ...req, transport: "sendBeacon" });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Enable the queue and start flushing
|
|
70
|
-
*/
|
|
71
|
-
enable() {
|
|
72
|
-
this._isPaused = false;
|
|
73
|
-
this._setFlushTimeout();
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Pause the queue (stops flushing but keeps events)
|
|
77
|
-
*/
|
|
78
|
-
pause() {
|
|
79
|
-
this._isPaused = true;
|
|
80
|
-
this._clearFlushTimeout();
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Force an immediate flush
|
|
84
|
-
*/
|
|
85
|
-
flush() {
|
|
86
|
-
this._clearFlushTimeout();
|
|
87
|
-
this._flushNow();
|
|
88
|
-
this._setFlushTimeout();
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Set up the flush timeout
|
|
92
|
-
*/
|
|
93
|
-
_setFlushTimeout() {
|
|
94
|
-
if (this._isPaused) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
this._flushTimeout = setTimeout(() => {
|
|
98
|
-
this._clearFlushTimeout();
|
|
99
|
-
this._flushNow();
|
|
100
|
-
// Restart the timeout for continuous flushing
|
|
101
|
-
if (this._queue.length > 0) {
|
|
102
|
-
this._setFlushTimeout();
|
|
103
|
-
}
|
|
104
|
-
}, this._flushTimeoutMs);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Clear the flush timeout
|
|
108
|
-
*/
|
|
109
|
-
_clearFlushTimeout() {
|
|
110
|
-
if (this._flushTimeout) {
|
|
111
|
-
clearTimeout(this._flushTimeout);
|
|
112
|
-
this._flushTimeout = undefined;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Flush all queued events now
|
|
117
|
-
*/
|
|
118
|
-
_flushNow() {
|
|
119
|
-
if (this._queue.length === 0) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const requests = this._formatQueue();
|
|
123
|
-
const now = Date.now();
|
|
124
|
-
for (const key in requests) {
|
|
125
|
-
const req = requests[key];
|
|
126
|
-
// Convert absolute timestamps to relative offsets
|
|
127
|
-
// This helps with clock skew between client and server
|
|
128
|
-
req.events.forEach((event) => {
|
|
129
|
-
const eventTime = new Date(event.timestamp).getTime();
|
|
130
|
-
event.$offset = Math.abs(eventTime - now);
|
|
131
|
-
});
|
|
132
|
-
this._sendRequest(req);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Format the queue into batched requests by URL/batchKey
|
|
137
|
-
*/
|
|
138
|
-
_formatQueue() {
|
|
139
|
-
const requests = {};
|
|
140
|
-
this._queue.forEach((request) => {
|
|
141
|
-
const key = request.batchKey || request.url;
|
|
142
|
-
if (!requests[key]) {
|
|
143
|
-
requests[key] = {
|
|
144
|
-
url: request.url,
|
|
145
|
-
events: [],
|
|
146
|
-
batchKey: request.batchKey,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
requests[key].events.push(request.event);
|
|
150
|
-
});
|
|
151
|
-
// Clear the queue
|
|
152
|
-
this._queue = [];
|
|
153
|
-
return requests;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
exports.RequestQueue = RequestQueue;
|
package/lib/request.d.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request utilities for vTilt tracking
|
|
3
|
-
*
|
|
4
|
-
* Handles HTTP requests with:
|
|
5
|
-
* - GZip compression (via fflate)
|
|
6
|
-
* - Multiple transport methods (fetch, XHR, sendBeacon)
|
|
7
|
-
* - Automatic fallback between transports
|
|
8
|
-
*
|
|
9
|
-
* Based on PostHog's request.ts pattern
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Compression methods supported by the SDK
|
|
13
|
-
*/
|
|
14
|
-
export declare enum Compression {
|
|
15
|
-
GZipJS = "gzip-js",
|
|
16
|
-
None = "none"
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Response from a request
|
|
20
|
-
*/
|
|
21
|
-
export interface RequestResponse {
|
|
22
|
-
statusCode: number;
|
|
23
|
-
text?: string;
|
|
24
|
-
json?: any;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Options for making a request
|
|
28
|
-
*/
|
|
29
|
-
export interface RequestOptions {
|
|
30
|
-
url: string;
|
|
31
|
-
data?: any;
|
|
32
|
-
method?: "POST" | "GET";
|
|
33
|
-
headers?: Record<string, string>;
|
|
34
|
-
transport?: "XHR" | "fetch" | "sendBeacon";
|
|
35
|
-
compression?: Compression;
|
|
36
|
-
timeout?: number;
|
|
37
|
-
callback?: (response: RequestResponse) => void;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* JSON stringify with BigInt support
|
|
41
|
-
*/
|
|
42
|
-
export declare const jsonStringify: (data: any) => string;
|
|
43
|
-
/**
|
|
44
|
-
* Main request function - handles transport selection and dispatching
|
|
45
|
-
*/
|
|
46
|
-
export declare const request: (options: RequestOptions) => void;
|
|
47
|
-
/**
|
|
48
|
-
* Promise-based request wrapper
|
|
49
|
-
*/
|
|
50
|
-
export declare const requestAsync: (options: Omit<RequestOptions, "callback">) => Promise<RequestResponse>;
|
|
51
|
-
/**
|
|
52
|
-
* Check if compression is supported and beneficial
|
|
53
|
-
*/
|
|
54
|
-
export declare const shouldCompress: (data: any) => boolean;
|