@bentolabs/sdk 1.2.2 → 2.0.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/index.d.ts +188 -27
- package/dist/index.js +1516 -169
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -51,7 +51,9 @@ var index_exports = {};
|
|
|
51
51
|
__export(index_exports, {
|
|
52
52
|
BentoLabsSDK: () => BentoLabsSDK,
|
|
53
53
|
default: () => index_default,
|
|
54
|
-
generateSelector: () => generateSelector
|
|
54
|
+
generateSelector: () => generateSelector,
|
|
55
|
+
generateSelectorFromElement: () => generateSelectorFromElement,
|
|
56
|
+
generateSelectorFromHTML: () => generateSelectorFromHTML
|
|
55
57
|
});
|
|
56
58
|
module.exports = __toCommonJS(index_exports);
|
|
57
59
|
|
|
@@ -9149,10 +9151,145 @@ function quickHash(str) {
|
|
|
9149
9151
|
}
|
|
9150
9152
|
return (hash >>> 0).toString(16);
|
|
9151
9153
|
}
|
|
9152
|
-
function
|
|
9154
|
+
function getParentAcrossShadow(element) {
|
|
9155
|
+
if (element.parentElement) {
|
|
9156
|
+
return element.parentElement;
|
|
9157
|
+
}
|
|
9158
|
+
const root2 = element.getRootNode();
|
|
9159
|
+
if (root2 instanceof ShadowRoot) {
|
|
9160
|
+
return root2.host;
|
|
9161
|
+
}
|
|
9162
|
+
return null;
|
|
9163
|
+
}
|
|
9164
|
+
function isPortalContainer(element) {
|
|
9165
|
+
return element.hasAttribute("data-radix-portal") || element.hasAttribute("data-headlessui-portal") || element.hasAttribute("data-floating-ui-portal") || element.hasAttribute("data-portal") || element.id !== "" && element.id.toLowerCase().includes("portal") || element.classList.contains("portal") || element.getAttribute("role") === "dialog";
|
|
9166
|
+
}
|
|
9167
|
+
function findUniqueAncestor(element, maxDepth = 5) {
|
|
9168
|
+
let current = getParentAcrossShadow(element);
|
|
9169
|
+
let depth = 0;
|
|
9170
|
+
while (current && depth < maxDepth) {
|
|
9171
|
+
if (isPortalContainer(current)) {
|
|
9172
|
+
current = getParentAcrossShadow(current);
|
|
9173
|
+
continue;
|
|
9174
|
+
}
|
|
9175
|
+
const tag = current.tagName.toLowerCase();
|
|
9176
|
+
if (current.id && isStableId(current.id)) {
|
|
9177
|
+
return `${tag}#${current.id}`;
|
|
9178
|
+
}
|
|
9179
|
+
const testId = current.getAttribute("data-testid");
|
|
9180
|
+
if (testId) {
|
|
9181
|
+
return `${tag}[data-testid=${testId}]`;
|
|
9182
|
+
}
|
|
9183
|
+
const dataId = current.getAttribute("data-id");
|
|
9184
|
+
if (dataId) {
|
|
9185
|
+
return `${tag}[data-id=${dataId}]`;
|
|
9186
|
+
}
|
|
9187
|
+
const name = current.getAttribute("name");
|
|
9188
|
+
if (name) {
|
|
9189
|
+
return `${tag}[name=${name}]`;
|
|
9190
|
+
}
|
|
9191
|
+
current = getParentAcrossShadow(current);
|
|
9192
|
+
depth++;
|
|
9193
|
+
}
|
|
9194
|
+
return null;
|
|
9195
|
+
}
|
|
9196
|
+
function findSection(element, maxDepth = 15) {
|
|
9197
|
+
const sectionTags = [
|
|
9198
|
+
"header",
|
|
9199
|
+
"nav",
|
|
9200
|
+
"main",
|
|
9201
|
+
"aside",
|
|
9202
|
+
"footer",
|
|
9203
|
+
"section",
|
|
9204
|
+
"article"
|
|
9205
|
+
];
|
|
9206
|
+
let current = getParentAcrossShadow(element);
|
|
9207
|
+
let depth = 0;
|
|
9208
|
+
while (current && depth < maxDepth) {
|
|
9209
|
+
if (isPortalContainer(current)) {
|
|
9210
|
+
current = getParentAcrossShadow(current);
|
|
9211
|
+
continue;
|
|
9212
|
+
}
|
|
9213
|
+
const tag = current.tagName.toLowerCase();
|
|
9214
|
+
if (sectionTags.includes(tag)) {
|
|
9215
|
+
const label = current.getAttribute("aria-label");
|
|
9216
|
+
return label ? `${tag}[${label}]` : tag;
|
|
9217
|
+
}
|
|
9218
|
+
current = getParentAcrossShadow(current);
|
|
9219
|
+
depth++;
|
|
9220
|
+
}
|
|
9221
|
+
return null;
|
|
9222
|
+
}
|
|
9223
|
+
function findForm(element) {
|
|
9224
|
+
const form = element.closest("form");
|
|
9225
|
+
if (!form) return null;
|
|
9226
|
+
if (form.id && isStableId(form.id)) return form.id;
|
|
9227
|
+
if (form.name) return form.name;
|
|
9228
|
+
return null;
|
|
9229
|
+
}
|
|
9230
|
+
function findRegion(element, maxDepth = 15) {
|
|
9231
|
+
let current = getParentAcrossShadow(element);
|
|
9232
|
+
let depth = 0;
|
|
9233
|
+
while (current && depth < maxDepth) {
|
|
9234
|
+
if (isPortalContainer(current)) {
|
|
9235
|
+
current = getParentAcrossShadow(current);
|
|
9236
|
+
continue;
|
|
9237
|
+
}
|
|
9238
|
+
const role = current.getAttribute("role");
|
|
9239
|
+
if (role === "region" || role === "navigation" || role === "banner" || role === "main" || role === "contentinfo" || role === "complementary") {
|
|
9240
|
+
const label = current.getAttribute("aria-label");
|
|
9241
|
+
return label ? `${role}[${label}]` : role;
|
|
9242
|
+
}
|
|
9243
|
+
current = getParentAcrossShadow(current);
|
|
9244
|
+
depth++;
|
|
9245
|
+
}
|
|
9246
|
+
return null;
|
|
9247
|
+
}
|
|
9248
|
+
function getNthPosition(element) {
|
|
9249
|
+
const parent = element.parentElement;
|
|
9250
|
+
if (!parent) return 1;
|
|
9251
|
+
const tag = element.tagName;
|
|
9252
|
+
const text = getFullText$1(element);
|
|
9253
|
+
let position = 0;
|
|
9254
|
+
for (const sibling of Array.from(parent.children)) {
|
|
9255
|
+
if (sibling.tagName === tag && getFullText$1(sibling) === text) {
|
|
9256
|
+
position++;
|
|
9257
|
+
if (sibling === element) return position;
|
|
9258
|
+
}
|
|
9259
|
+
}
|
|
9260
|
+
return 1;
|
|
9261
|
+
}
|
|
9262
|
+
function buildBentoSelector(element, pathname) {
|
|
9153
9263
|
const parts = [];
|
|
9154
9264
|
const tag = element.tagName.toLowerCase();
|
|
9155
9265
|
parts.push(tag);
|
|
9266
|
+
if (pathname) {
|
|
9267
|
+
parts.push(`page=${escapeValue(pathname)}`);
|
|
9268
|
+
}
|
|
9269
|
+
let hasContext = false;
|
|
9270
|
+
const ancestor = findUniqueAncestor(element, 5);
|
|
9271
|
+
if (ancestor) {
|
|
9272
|
+
parts.push(`ancestor=${escapeValue(ancestor)}`);
|
|
9273
|
+
hasContext = true;
|
|
9274
|
+
} else {
|
|
9275
|
+
const section = findSection(element, 15);
|
|
9276
|
+
if (section) {
|
|
9277
|
+
parts.push(`section=${escapeValue(section)}`);
|
|
9278
|
+
hasContext = true;
|
|
9279
|
+
} else {
|
|
9280
|
+
const form = findForm(element);
|
|
9281
|
+
if (form) {
|
|
9282
|
+
parts.push(`form=${escapeValue(form)}`);
|
|
9283
|
+
hasContext = true;
|
|
9284
|
+
} else {
|
|
9285
|
+
const region = findRegion(element, 15);
|
|
9286
|
+
if (region) {
|
|
9287
|
+
parts.push(`region=${escapeValue(region)}`);
|
|
9288
|
+
hasContext = true;
|
|
9289
|
+
}
|
|
9290
|
+
}
|
|
9291
|
+
}
|
|
9292
|
+
}
|
|
9156
9293
|
const testId = element.getAttribute("data-testid");
|
|
9157
9294
|
if (testId) {
|
|
9158
9295
|
parts.push(`testid=${escapeValue(truncate(testId, 50))}`);
|
|
@@ -9227,7 +9364,13 @@ function buildBentoSelector(element) {
|
|
|
9227
9364
|
parts.push(`text=${escapeValue(truncate(text, 50))}`);
|
|
9228
9365
|
}
|
|
9229
9366
|
}
|
|
9230
|
-
if (
|
|
9367
|
+
if (!hasContext) {
|
|
9368
|
+
const nth = getNthPosition(element);
|
|
9369
|
+
if (nth > 1) {
|
|
9370
|
+
parts.push(`nth=${nth}`);
|
|
9371
|
+
}
|
|
9372
|
+
}
|
|
9373
|
+
if (parts.length === 1 || parts.length === 2 && pathname) {
|
|
9231
9374
|
const childSig = getChildSignature(element);
|
|
9232
9375
|
if (childSig) {
|
|
9233
9376
|
parts.push(`children=${childSig}`);
|
|
@@ -9238,7 +9381,11 @@ function buildBentoSelector(element) {
|
|
|
9238
9381
|
}
|
|
9239
9382
|
return parts.join("|");
|
|
9240
9383
|
}
|
|
9241
|
-
function
|
|
9384
|
+
function generateSelectorFromElement(element, pathname) {
|
|
9385
|
+
const path = pathname != null ? pathname : typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
9386
|
+
return buildBentoSelector(element, path);
|
|
9387
|
+
}
|
|
9388
|
+
function generateSelectorFromHTML(outerHTML) {
|
|
9242
9389
|
const parser2 = new DOMParser();
|
|
9243
9390
|
const doc = parser2.parseFromString(outerHTML, "text/html");
|
|
9244
9391
|
const element = doc.body.firstElementChild;
|
|
@@ -9247,6 +9394,9 @@ function generateSelector(outerHTML) {
|
|
|
9247
9394
|
}
|
|
9248
9395
|
return buildBentoSelector(element);
|
|
9249
9396
|
}
|
|
9397
|
+
function generateSelector(outerHTML) {
|
|
9398
|
+
return generateSelectorFromHTML(outerHTML);
|
|
9399
|
+
}
|
|
9250
9400
|
var DEFAULT_OPTIONS = {
|
|
9251
9401
|
maxTextLength: 500,
|
|
9252
9402
|
includeOuterHTML: true,
|
|
@@ -9276,6 +9426,7 @@ function isInputElement(element) {
|
|
|
9276
9426
|
return tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT";
|
|
9277
9427
|
}
|
|
9278
9428
|
function extractElementContext(element, options = {}) {
|
|
9429
|
+
var _a2;
|
|
9279
9430
|
const opts = __spreadValues(__spreadValues({}, DEFAULT_OPTIONS), options.elementContextOptions);
|
|
9280
9431
|
const {
|
|
9281
9432
|
isClickEvent = false,
|
|
@@ -9339,7 +9490,8 @@ function extractElementContext(element, options = {}) {
|
|
|
9339
9490
|
}
|
|
9340
9491
|
if (isClickEvent) {
|
|
9341
9492
|
try {
|
|
9342
|
-
|
|
9493
|
+
const path = (_a2 = options.pathname) != null ? _a2 : typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
9494
|
+
context.bentoSelector = buildBentoSelector(element, path);
|
|
9343
9495
|
} catch (e) {
|
|
9344
9496
|
}
|
|
9345
9497
|
}
|
|
@@ -10175,6 +10327,7 @@ function initMouseInteractionObserver({
|
|
|
10175
10327
|
let currentPointerType = null;
|
|
10176
10328
|
const getHandler = (eventKey) => {
|
|
10177
10329
|
return (event) => {
|
|
10330
|
+
const pathname = typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
10178
10331
|
const target = getEventTarget(event);
|
|
10179
10332
|
if (isBlocked(target, blockClass, blockSelector, true)) {
|
|
10180
10333
|
return;
|
|
@@ -10225,7 +10378,9 @@ function initMouseInteractionObserver({
|
|
|
10225
10378
|
elementContextOptions,
|
|
10226
10379
|
isClickEvent,
|
|
10227
10380
|
maskInputOptions,
|
|
10228
|
-
maskInputFn
|
|
10381
|
+
maskInputFn,
|
|
10382
|
+
pathname
|
|
10383
|
+
// Pass pathname captured at event time
|
|
10229
10384
|
});
|
|
10230
10385
|
}
|
|
10231
10386
|
callbackWrapper(mouseInteractionCb)(__spreadValues(__spreadValues({
|
|
@@ -12620,6 +12775,641 @@ var { freezePage } = record;
|
|
|
12620
12775
|
var { takeFullSnapshot } = record;
|
|
12621
12776
|
|
|
12622
12777
|
// src/index.ts
|
|
12778
|
+
var PERSISTENCE_KEYS = {
|
|
12779
|
+
DISTINCT_ID: "bentolabs_distinct_id",
|
|
12780
|
+
SUPER_PROPERTIES: "bentolabs_super_properties",
|
|
12781
|
+
OPTED_OUT: "bentolabs_opted_out",
|
|
12782
|
+
USER_PROPERTIES: "bentolabs_user_properties",
|
|
12783
|
+
IS_IDENTIFIED: "bentolabs_is_identified"
|
|
12784
|
+
};
|
|
12785
|
+
var Persistence = class {
|
|
12786
|
+
constructor(mode) {
|
|
12787
|
+
this.mode = mode;
|
|
12788
|
+
this.memoryStorage = /* @__PURE__ */ new Map();
|
|
12789
|
+
}
|
|
12790
|
+
get(key) {
|
|
12791
|
+
if (this.mode === "none") return null;
|
|
12792
|
+
if (this.mode === "memory") {
|
|
12793
|
+
return this.memoryStorage.get(key) || null;
|
|
12794
|
+
}
|
|
12795
|
+
if (this.mode === "localStorage" || this.mode === "localStorage+cookie") {
|
|
12796
|
+
try {
|
|
12797
|
+
const value = localStorage.getItem(key);
|
|
12798
|
+
if (value !== null) return value;
|
|
12799
|
+
} catch (e) {
|
|
12800
|
+
}
|
|
12801
|
+
}
|
|
12802
|
+
if (this.mode === "cookie" || this.mode === "localStorage+cookie") {
|
|
12803
|
+
try {
|
|
12804
|
+
const cookies = document.cookie.split(";");
|
|
12805
|
+
for (const cookie of cookies) {
|
|
12806
|
+
const [cookieKey, cookieValue] = cookie.trim().split("=");
|
|
12807
|
+
if (cookieKey === key) {
|
|
12808
|
+
return decodeURIComponent(cookieValue);
|
|
12809
|
+
}
|
|
12810
|
+
}
|
|
12811
|
+
} catch (e) {
|
|
12812
|
+
}
|
|
12813
|
+
}
|
|
12814
|
+
return null;
|
|
12815
|
+
}
|
|
12816
|
+
set(key, value) {
|
|
12817
|
+
if (this.mode === "none") return;
|
|
12818
|
+
if (this.mode === "memory") {
|
|
12819
|
+
this.memoryStorage.set(key, value);
|
|
12820
|
+
return;
|
|
12821
|
+
}
|
|
12822
|
+
if (this.mode === "localStorage" || this.mode === "localStorage+cookie") {
|
|
12823
|
+
try {
|
|
12824
|
+
localStorage.setItem(key, value);
|
|
12825
|
+
} catch (e) {
|
|
12826
|
+
}
|
|
12827
|
+
}
|
|
12828
|
+
if (this.mode === "cookie" || this.mode === "localStorage+cookie") {
|
|
12829
|
+
try {
|
|
12830
|
+
const expires = /* @__PURE__ */ new Date();
|
|
12831
|
+
expires.setFullYear(expires.getFullYear() + 1);
|
|
12832
|
+
document.cookie = `${key}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
|
|
12833
|
+
} catch (e) {
|
|
12834
|
+
}
|
|
12835
|
+
}
|
|
12836
|
+
}
|
|
12837
|
+
remove(key) {
|
|
12838
|
+
if (this.mode === "none") return;
|
|
12839
|
+
if (this.mode === "memory") {
|
|
12840
|
+
this.memoryStorage.delete(key);
|
|
12841
|
+
return;
|
|
12842
|
+
}
|
|
12843
|
+
if (this.mode === "localStorage" || this.mode === "localStorage+cookie") {
|
|
12844
|
+
try {
|
|
12845
|
+
localStorage.removeItem(key);
|
|
12846
|
+
} catch (e) {
|
|
12847
|
+
}
|
|
12848
|
+
}
|
|
12849
|
+
if (this.mode === "cookie" || this.mode === "localStorage+cookie") {
|
|
12850
|
+
try {
|
|
12851
|
+
document.cookie = `${key}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
|
|
12852
|
+
} catch (e) {
|
|
12853
|
+
}
|
|
12854
|
+
}
|
|
12855
|
+
}
|
|
12856
|
+
clear() {
|
|
12857
|
+
if (this.mode === "memory") {
|
|
12858
|
+
this.memoryStorage.clear();
|
|
12859
|
+
return;
|
|
12860
|
+
}
|
|
12861
|
+
Object.values(PERSISTENCE_KEYS).forEach((key) => this.remove(key));
|
|
12862
|
+
}
|
|
12863
|
+
};
|
|
12864
|
+
var NetworkMonitor = class {
|
|
12865
|
+
constructor(options, onCapture) {
|
|
12866
|
+
this.logs = [];
|
|
12867
|
+
this.originalFetch = null;
|
|
12868
|
+
this.originalXHROpen = null;
|
|
12869
|
+
this.originalXHRSend = null;
|
|
12870
|
+
this.isMonitoring = false;
|
|
12871
|
+
var _a2, _b, _c, _d;
|
|
12872
|
+
this.options = {
|
|
12873
|
+
skipUrls: options.skipUrls || ["api.bentolabs.ai"],
|
|
12874
|
+
captureHeaders: (_a2 = options.captureHeaders) != null ? _a2 : false,
|
|
12875
|
+
captureBody: (_b = options.captureBody) != null ? _b : false,
|
|
12876
|
+
maxBodySize: (_c = options.maxBodySize) != null ? _c : 5e3,
|
|
12877
|
+
sampleRate: (_d = options.sampleRate) != null ? _d : 1
|
|
12878
|
+
};
|
|
12879
|
+
this.onCapture = onCapture;
|
|
12880
|
+
}
|
|
12881
|
+
start() {
|
|
12882
|
+
if (this.isMonitoring || typeof window === "undefined") return;
|
|
12883
|
+
this.isMonitoring = true;
|
|
12884
|
+
this.interceptFetch();
|
|
12885
|
+
this.interceptXHR();
|
|
12886
|
+
}
|
|
12887
|
+
stop() {
|
|
12888
|
+
if (!this.isMonitoring) return;
|
|
12889
|
+
this.isMonitoring = false;
|
|
12890
|
+
this.restoreFetch();
|
|
12891
|
+
this.restoreXHR();
|
|
12892
|
+
}
|
|
12893
|
+
getLogs() {
|
|
12894
|
+
return [...this.logs];
|
|
12895
|
+
}
|
|
12896
|
+
clearLogs() {
|
|
12897
|
+
this.logs = [];
|
|
12898
|
+
}
|
|
12899
|
+
shouldSkip(url) {
|
|
12900
|
+
return this.options.skipUrls.some((skipUrl) => url.includes(skipUrl));
|
|
12901
|
+
}
|
|
12902
|
+
shouldSample() {
|
|
12903
|
+
return Math.random() < this.options.sampleRate;
|
|
12904
|
+
}
|
|
12905
|
+
sanitizeUrl(url) {
|
|
12906
|
+
try {
|
|
12907
|
+
const urlObj = new URL(url, window.location.origin);
|
|
12908
|
+
const sensitiveParams = ["token", "key", "secret", "password", "auth", "apikey", "api_key"];
|
|
12909
|
+
sensitiveParams.forEach((param) => {
|
|
12910
|
+
if (urlObj.searchParams.has(param)) {
|
|
12911
|
+
urlObj.searchParams.set(param, "[REDACTED]");
|
|
12912
|
+
}
|
|
12913
|
+
});
|
|
12914
|
+
return urlObj.toString();
|
|
12915
|
+
} catch (e) {
|
|
12916
|
+
return url;
|
|
12917
|
+
}
|
|
12918
|
+
}
|
|
12919
|
+
interceptFetch() {
|
|
12920
|
+
if (typeof fetch === "undefined") return;
|
|
12921
|
+
this.originalFetch = fetch.bind(window);
|
|
12922
|
+
const self = this;
|
|
12923
|
+
window.fetch = async function(input2, init) {
|
|
12924
|
+
const url = typeof input2 === "string" ? input2 : input2 instanceof URL ? input2.toString() : input2.url;
|
|
12925
|
+
if (self.shouldSkip(url) || !self.shouldSample()) {
|
|
12926
|
+
return self.originalFetch(input2, init);
|
|
12927
|
+
}
|
|
12928
|
+
const startTime = Date.now();
|
|
12929
|
+
const method = (init == null ? void 0 : init.method) || "GET";
|
|
12930
|
+
try {
|
|
12931
|
+
const response = await self.originalFetch(input2, init);
|
|
12932
|
+
const duration = Date.now() - startTime;
|
|
12933
|
+
const log = {
|
|
12934
|
+
url: self.sanitizeUrl(url),
|
|
12935
|
+
method: method.toUpperCase(),
|
|
12936
|
+
status: response.status,
|
|
12937
|
+
duration,
|
|
12938
|
+
responseSize: parseInt(response.headers.get("content-length") || "0", 10),
|
|
12939
|
+
initiator: "fetch",
|
|
12940
|
+
timestamp: Date.now()
|
|
12941
|
+
};
|
|
12942
|
+
self.logs.push(log);
|
|
12943
|
+
if (self.logs.length > 500) self.logs.shift();
|
|
12944
|
+
self.onCapture(log);
|
|
12945
|
+
return response;
|
|
12946
|
+
} catch (error) {
|
|
12947
|
+
const duration = Date.now() - startTime;
|
|
12948
|
+
const log = {
|
|
12949
|
+
url: self.sanitizeUrl(url),
|
|
12950
|
+
method: method.toUpperCase(),
|
|
12951
|
+
status: 0,
|
|
12952
|
+
duration,
|
|
12953
|
+
responseSize: 0,
|
|
12954
|
+
initiator: "fetch",
|
|
12955
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
12956
|
+
timestamp: Date.now()
|
|
12957
|
+
};
|
|
12958
|
+
self.logs.push(log);
|
|
12959
|
+
if (self.logs.length > 500) self.logs.shift();
|
|
12960
|
+
self.onCapture(log);
|
|
12961
|
+
throw error;
|
|
12962
|
+
}
|
|
12963
|
+
};
|
|
12964
|
+
}
|
|
12965
|
+
restoreFetch() {
|
|
12966
|
+
if (this.originalFetch && typeof window !== "undefined") {
|
|
12967
|
+
window.fetch = this.originalFetch;
|
|
12968
|
+
this.originalFetch = null;
|
|
12969
|
+
}
|
|
12970
|
+
}
|
|
12971
|
+
interceptXHR() {
|
|
12972
|
+
if (typeof XMLHttpRequest === "undefined") return;
|
|
12973
|
+
this.originalXHROpen = XMLHttpRequest.prototype.open;
|
|
12974
|
+
this.originalXHRSend = XMLHttpRequest.prototype.send;
|
|
12975
|
+
const self = this;
|
|
12976
|
+
XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
|
|
12977
|
+
this._bentoUrl = url.toString();
|
|
12978
|
+
this._bentoMethod = method;
|
|
12979
|
+
this._bentoStartTime = 0;
|
|
12980
|
+
return self.originalXHROpen.call(this, method, url, async != null ? async : true, username, password);
|
|
12981
|
+
};
|
|
12982
|
+
XMLHttpRequest.prototype.send = function(body) {
|
|
12983
|
+
const xhr = this;
|
|
12984
|
+
const url = xhr._bentoUrl;
|
|
12985
|
+
if (self.shouldSkip(url) || !self.shouldSample()) {
|
|
12986
|
+
return self.originalXHRSend.call(this, body);
|
|
12987
|
+
}
|
|
12988
|
+
xhr._bentoStartTime = Date.now();
|
|
12989
|
+
const handleLoadEnd = () => {
|
|
12990
|
+
const duration = Date.now() - xhr._bentoStartTime;
|
|
12991
|
+
const log = {
|
|
12992
|
+
url: self.sanitizeUrl(url),
|
|
12993
|
+
method: xhr._bentoMethod.toUpperCase(),
|
|
12994
|
+
status: xhr.status,
|
|
12995
|
+
duration,
|
|
12996
|
+
responseSize: parseInt(xhr.getResponseHeader("content-length") || "0", 10),
|
|
12997
|
+
initiator: "xhr",
|
|
12998
|
+
timestamp: Date.now()
|
|
12999
|
+
};
|
|
13000
|
+
if (xhr.status === 0) {
|
|
13001
|
+
log.error = "Request failed or was aborted";
|
|
13002
|
+
}
|
|
13003
|
+
self.logs.push(log);
|
|
13004
|
+
if (self.logs.length > 500) self.logs.shift();
|
|
13005
|
+
self.onCapture(log);
|
|
13006
|
+
};
|
|
13007
|
+
xhr.addEventListener("loadend", handleLoadEnd);
|
|
13008
|
+
return self.originalXHRSend.call(this, body);
|
|
13009
|
+
};
|
|
13010
|
+
}
|
|
13011
|
+
restoreXHR() {
|
|
13012
|
+
if (this.originalXHROpen) {
|
|
13013
|
+
XMLHttpRequest.prototype.open = this.originalXHROpen;
|
|
13014
|
+
this.originalXHROpen = null;
|
|
13015
|
+
}
|
|
13016
|
+
if (this.originalXHRSend) {
|
|
13017
|
+
XMLHttpRequest.prototype.send = this.originalXHRSend;
|
|
13018
|
+
this.originalXHRSend = null;
|
|
13019
|
+
}
|
|
13020
|
+
}
|
|
13021
|
+
};
|
|
13022
|
+
var StorageMonitor = class {
|
|
13023
|
+
constructor(options, onCapture) {
|
|
13024
|
+
this.logs = [];
|
|
13025
|
+
this.isMonitoring = false;
|
|
13026
|
+
this.originalLocalStorage = null;
|
|
13027
|
+
this.originalSessionStorage = null;
|
|
13028
|
+
this.originalCookieDescriptor = null;
|
|
13029
|
+
var _a2, _b, _c;
|
|
13030
|
+
this.options = {
|
|
13031
|
+
localStorage: (_a2 = options.localStorage) != null ? _a2 : true,
|
|
13032
|
+
sessionStorage: (_b = options.sessionStorage) != null ? _b : true,
|
|
13033
|
+
cookies: (_c = options.cookies) != null ? _c : true,
|
|
13034
|
+
sensitiveKeys: options.sensitiveKeys || ["password", "token", "secret", "api_key", "apikey", "auth", "credential"]
|
|
13035
|
+
};
|
|
13036
|
+
this.onCapture = onCapture;
|
|
13037
|
+
}
|
|
13038
|
+
start() {
|
|
13039
|
+
if (this.isMonitoring || typeof window === "undefined") return;
|
|
13040
|
+
this.isMonitoring = true;
|
|
13041
|
+
if (this.options.localStorage) this.interceptLocalStorage();
|
|
13042
|
+
if (this.options.sessionStorage) this.interceptSessionStorage();
|
|
13043
|
+
if (this.options.cookies) this.interceptCookies();
|
|
13044
|
+
}
|
|
13045
|
+
stop() {
|
|
13046
|
+
if (!this.isMonitoring) return;
|
|
13047
|
+
this.isMonitoring = false;
|
|
13048
|
+
this.restoreLocalStorage();
|
|
13049
|
+
this.restoreSessionStorage();
|
|
13050
|
+
this.restoreCookies();
|
|
13051
|
+
}
|
|
13052
|
+
getLogs() {
|
|
13053
|
+
return [...this.logs];
|
|
13054
|
+
}
|
|
13055
|
+
clearLogs() {
|
|
13056
|
+
this.logs = [];
|
|
13057
|
+
}
|
|
13058
|
+
isSensitiveKey(key) {
|
|
13059
|
+
const lowerKey = key.toLowerCase();
|
|
13060
|
+
return this.options.sensitiveKeys.some((sensitive) => lowerKey.includes(sensitive.toLowerCase()));
|
|
13061
|
+
}
|
|
13062
|
+
addLog(log) {
|
|
13063
|
+
if (this.isSensitiveKey(log.key) || log.key.startsWith("bentolabs_")) return;
|
|
13064
|
+
this.logs.push(log);
|
|
13065
|
+
if (this.logs.length > 500) this.logs.shift();
|
|
13066
|
+
this.onCapture(log);
|
|
13067
|
+
}
|
|
13068
|
+
interceptLocalStorage() {
|
|
13069
|
+
if (typeof localStorage === "undefined") return;
|
|
13070
|
+
const self = this;
|
|
13071
|
+
this.originalLocalStorage = {
|
|
13072
|
+
setItem: localStorage.setItem.bind(localStorage),
|
|
13073
|
+
getItem: localStorage.getItem.bind(localStorage),
|
|
13074
|
+
removeItem: localStorage.removeItem.bind(localStorage),
|
|
13075
|
+
clear: localStorage.clear.bind(localStorage)
|
|
13076
|
+
};
|
|
13077
|
+
localStorage.setItem = function(key, value) {
|
|
13078
|
+
self.addLog({
|
|
13079
|
+
storageType: "localStorage",
|
|
13080
|
+
operation: "set",
|
|
13081
|
+
key,
|
|
13082
|
+
valueType: typeof value,
|
|
13083
|
+
timestamp: Date.now()
|
|
13084
|
+
});
|
|
13085
|
+
return self.originalLocalStorage.setItem(key, value);
|
|
13086
|
+
};
|
|
13087
|
+
localStorage.getItem = function(key) {
|
|
13088
|
+
self.addLog({
|
|
13089
|
+
storageType: "localStorage",
|
|
13090
|
+
operation: "get",
|
|
13091
|
+
key,
|
|
13092
|
+
timestamp: Date.now()
|
|
13093
|
+
});
|
|
13094
|
+
return self.originalLocalStorage.getItem(key);
|
|
13095
|
+
};
|
|
13096
|
+
localStorage.removeItem = function(key) {
|
|
13097
|
+
self.addLog({
|
|
13098
|
+
storageType: "localStorage",
|
|
13099
|
+
operation: "remove",
|
|
13100
|
+
key,
|
|
13101
|
+
timestamp: Date.now()
|
|
13102
|
+
});
|
|
13103
|
+
return self.originalLocalStorage.removeItem(key);
|
|
13104
|
+
};
|
|
13105
|
+
localStorage.clear = function() {
|
|
13106
|
+
self.addLog({
|
|
13107
|
+
storageType: "localStorage",
|
|
13108
|
+
operation: "clear",
|
|
13109
|
+
key: "*",
|
|
13110
|
+
timestamp: Date.now()
|
|
13111
|
+
});
|
|
13112
|
+
return self.originalLocalStorage.clear();
|
|
13113
|
+
};
|
|
13114
|
+
}
|
|
13115
|
+
restoreLocalStorage() {
|
|
13116
|
+
if (this.originalLocalStorage && typeof localStorage !== "undefined") {
|
|
13117
|
+
localStorage.setItem = this.originalLocalStorage.setItem;
|
|
13118
|
+
localStorage.getItem = this.originalLocalStorage.getItem;
|
|
13119
|
+
localStorage.removeItem = this.originalLocalStorage.removeItem;
|
|
13120
|
+
localStorage.clear = this.originalLocalStorage.clear;
|
|
13121
|
+
this.originalLocalStorage = null;
|
|
13122
|
+
}
|
|
13123
|
+
}
|
|
13124
|
+
interceptSessionStorage() {
|
|
13125
|
+
if (typeof sessionStorage === "undefined") return;
|
|
13126
|
+
const self = this;
|
|
13127
|
+
this.originalSessionStorage = {
|
|
13128
|
+
setItem: sessionStorage.setItem.bind(sessionStorage),
|
|
13129
|
+
getItem: sessionStorage.getItem.bind(sessionStorage),
|
|
13130
|
+
removeItem: sessionStorage.removeItem.bind(sessionStorage),
|
|
13131
|
+
clear: sessionStorage.clear.bind(sessionStorage)
|
|
13132
|
+
};
|
|
13133
|
+
sessionStorage.setItem = function(key, value) {
|
|
13134
|
+
self.addLog({
|
|
13135
|
+
storageType: "sessionStorage",
|
|
13136
|
+
operation: "set",
|
|
13137
|
+
key,
|
|
13138
|
+
valueType: typeof value,
|
|
13139
|
+
timestamp: Date.now()
|
|
13140
|
+
});
|
|
13141
|
+
return self.originalSessionStorage.setItem(key, value);
|
|
13142
|
+
};
|
|
13143
|
+
sessionStorage.getItem = function(key) {
|
|
13144
|
+
self.addLog({
|
|
13145
|
+
storageType: "sessionStorage",
|
|
13146
|
+
operation: "get",
|
|
13147
|
+
key,
|
|
13148
|
+
timestamp: Date.now()
|
|
13149
|
+
});
|
|
13150
|
+
return self.originalSessionStorage.getItem(key);
|
|
13151
|
+
};
|
|
13152
|
+
sessionStorage.removeItem = function(key) {
|
|
13153
|
+
self.addLog({
|
|
13154
|
+
storageType: "sessionStorage",
|
|
13155
|
+
operation: "remove",
|
|
13156
|
+
key,
|
|
13157
|
+
timestamp: Date.now()
|
|
13158
|
+
});
|
|
13159
|
+
return self.originalSessionStorage.removeItem(key);
|
|
13160
|
+
};
|
|
13161
|
+
sessionStorage.clear = function() {
|
|
13162
|
+
self.addLog({
|
|
13163
|
+
storageType: "sessionStorage",
|
|
13164
|
+
operation: "clear",
|
|
13165
|
+
key: "*",
|
|
13166
|
+
timestamp: Date.now()
|
|
13167
|
+
});
|
|
13168
|
+
return self.originalSessionStorage.clear();
|
|
13169
|
+
};
|
|
13170
|
+
}
|
|
13171
|
+
restoreSessionStorage() {
|
|
13172
|
+
if (this.originalSessionStorage && typeof sessionStorage !== "undefined") {
|
|
13173
|
+
sessionStorage.setItem = this.originalSessionStorage.setItem;
|
|
13174
|
+
sessionStorage.getItem = this.originalSessionStorage.getItem;
|
|
13175
|
+
sessionStorage.removeItem = this.originalSessionStorage.removeItem;
|
|
13176
|
+
sessionStorage.clear = this.originalSessionStorage.clear;
|
|
13177
|
+
this.originalSessionStorage = null;
|
|
13178
|
+
}
|
|
13179
|
+
}
|
|
13180
|
+
interceptCookies() {
|
|
13181
|
+
if (typeof document === "undefined") return;
|
|
13182
|
+
const self = this;
|
|
13183
|
+
const descriptor = Object.getOwnPropertyDescriptor(Document.prototype, "cookie");
|
|
13184
|
+
if (!descriptor) return;
|
|
13185
|
+
this.originalCookieDescriptor = descriptor;
|
|
13186
|
+
Object.defineProperty(document, "cookie", {
|
|
13187
|
+
get: function() {
|
|
13188
|
+
return self.originalCookieDescriptor.get.call(this);
|
|
13189
|
+
},
|
|
13190
|
+
set: function(value) {
|
|
13191
|
+
const name = value.split("=")[0].trim();
|
|
13192
|
+
self.addLog({
|
|
13193
|
+
storageType: "cookie",
|
|
13194
|
+
operation: "set",
|
|
13195
|
+
key: name,
|
|
13196
|
+
timestamp: Date.now()
|
|
13197
|
+
});
|
|
13198
|
+
return self.originalCookieDescriptor.set.call(this, value);
|
|
13199
|
+
},
|
|
13200
|
+
configurable: true
|
|
13201
|
+
});
|
|
13202
|
+
}
|
|
13203
|
+
restoreCookies() {
|
|
13204
|
+
if (this.originalCookieDescriptor && typeof document !== "undefined") {
|
|
13205
|
+
Object.defineProperty(document, "cookie", this.originalCookieDescriptor);
|
|
13206
|
+
this.originalCookieDescriptor = null;
|
|
13207
|
+
}
|
|
13208
|
+
}
|
|
13209
|
+
};
|
|
13210
|
+
var ConsoleMonitor = class {
|
|
13211
|
+
constructor(options, onCapture) {
|
|
13212
|
+
this.logs = [];
|
|
13213
|
+
this.isMonitoring = false;
|
|
13214
|
+
this.inStack = false;
|
|
13215
|
+
this.originalConsole = null;
|
|
13216
|
+
this.originalOnError = null;
|
|
13217
|
+
this.originalOnUnhandledRejection = null;
|
|
13218
|
+
var _a2, _b, _c;
|
|
13219
|
+
this.options = {
|
|
13220
|
+
levels: options.levels || ["log", "warn", "error", "info"],
|
|
13221
|
+
maxLogs: (_a2 = options.maxLogs) != null ? _a2 : 500,
|
|
13222
|
+
maxPayloadSize: (_b = options.maxPayloadSize) != null ? _b : 5e3,
|
|
13223
|
+
captureStackTrace: (_c = options.captureStackTrace) != null ? _c : true
|
|
13224
|
+
};
|
|
13225
|
+
this.onCapture = onCapture;
|
|
13226
|
+
}
|
|
13227
|
+
start() {
|
|
13228
|
+
if (this.isMonitoring || typeof console === "undefined") return;
|
|
13229
|
+
this.isMonitoring = true;
|
|
13230
|
+
this.interceptConsole();
|
|
13231
|
+
this.interceptGlobalErrors();
|
|
13232
|
+
}
|
|
13233
|
+
stop() {
|
|
13234
|
+
if (!this.isMonitoring) return;
|
|
13235
|
+
this.isMonitoring = false;
|
|
13236
|
+
this.restoreConsole();
|
|
13237
|
+
this.restoreGlobalErrors();
|
|
13238
|
+
}
|
|
13239
|
+
getLogs() {
|
|
13240
|
+
return [...this.logs];
|
|
13241
|
+
}
|
|
13242
|
+
clearLogs() {
|
|
13243
|
+
this.logs = [];
|
|
13244
|
+
}
|
|
13245
|
+
stringifyArg(arg, seen = /* @__PURE__ */ new WeakSet()) {
|
|
13246
|
+
if (arg === null) return "null";
|
|
13247
|
+
if (arg === void 0) return "undefined";
|
|
13248
|
+
const type = typeof arg;
|
|
13249
|
+
if (type === "string") return arg;
|
|
13250
|
+
if (type === "number" || type === "boolean") return String(arg);
|
|
13251
|
+
if (type === "function") return `[Function: ${arg.name || "anonymous"}]`;
|
|
13252
|
+
if (type === "symbol") return arg.toString();
|
|
13253
|
+
if (type === "object") {
|
|
13254
|
+
if (seen.has(arg)) return "[Circular]";
|
|
13255
|
+
seen.add(arg);
|
|
13256
|
+
if (arg instanceof Error) {
|
|
13257
|
+
return `${arg.name}: ${arg.message}`;
|
|
13258
|
+
}
|
|
13259
|
+
try {
|
|
13260
|
+
const str = JSON.stringify(arg, (key, value) => {
|
|
13261
|
+
if (typeof value === "object" && value !== null) {
|
|
13262
|
+
if (seen.has(value)) return "[Circular]";
|
|
13263
|
+
seen.add(value);
|
|
13264
|
+
}
|
|
13265
|
+
if (typeof value === "function") return `[Function: ${value.name || "anonymous"}]`;
|
|
13266
|
+
if (typeof value === "symbol") return value.toString();
|
|
13267
|
+
return value;
|
|
13268
|
+
});
|
|
13269
|
+
return str.length > this.options.maxPayloadSize ? str.slice(0, this.options.maxPayloadSize) + "..." : str;
|
|
13270
|
+
} catch (e) {
|
|
13271
|
+
return "[Object]";
|
|
13272
|
+
}
|
|
13273
|
+
}
|
|
13274
|
+
return String(arg);
|
|
13275
|
+
}
|
|
13276
|
+
getStackTrace() {
|
|
13277
|
+
if (!this.options.captureStackTrace) return [];
|
|
13278
|
+
try {
|
|
13279
|
+
const stack = new Error().stack || "";
|
|
13280
|
+
const lines = stack.split("\n").slice(3);
|
|
13281
|
+
return lines.slice(0, 5).map((line) => line.trim());
|
|
13282
|
+
} catch (e) {
|
|
13283
|
+
return [];
|
|
13284
|
+
}
|
|
13285
|
+
}
|
|
13286
|
+
addLog(level, args) {
|
|
13287
|
+
if (this.inStack) return;
|
|
13288
|
+
this.inStack = true;
|
|
13289
|
+
try {
|
|
13290
|
+
const payload = args.map((arg) => this.stringifyArg(arg));
|
|
13291
|
+
const log = {
|
|
13292
|
+
level,
|
|
13293
|
+
payload,
|
|
13294
|
+
trace: this.getStackTrace(),
|
|
13295
|
+
timestamp: Date.now()
|
|
13296
|
+
};
|
|
13297
|
+
this.logs.push(log);
|
|
13298
|
+
if (this.logs.length > this.options.maxLogs) this.logs.shift();
|
|
13299
|
+
this.onCapture(log);
|
|
13300
|
+
} finally {
|
|
13301
|
+
this.inStack = false;
|
|
13302
|
+
}
|
|
13303
|
+
}
|
|
13304
|
+
interceptConsole() {
|
|
13305
|
+
const self = this;
|
|
13306
|
+
this.originalConsole = {
|
|
13307
|
+
log: console.log.bind(console),
|
|
13308
|
+
warn: console.warn.bind(console),
|
|
13309
|
+
error: console.error.bind(console),
|
|
13310
|
+
info: console.info.bind(console),
|
|
13311
|
+
debug: console.debug.bind(console)
|
|
13312
|
+
};
|
|
13313
|
+
const levels = this.options.levels;
|
|
13314
|
+
if (levels.includes("log")) {
|
|
13315
|
+
console.log = function(...args) {
|
|
13316
|
+
self.addLog("log", args);
|
|
13317
|
+
return self.originalConsole.log(...args);
|
|
13318
|
+
};
|
|
13319
|
+
}
|
|
13320
|
+
if (levels.includes("warn")) {
|
|
13321
|
+
console.warn = function(...args) {
|
|
13322
|
+
self.addLog("warn", args);
|
|
13323
|
+
return self.originalConsole.warn(...args);
|
|
13324
|
+
};
|
|
13325
|
+
}
|
|
13326
|
+
if (levels.includes("error")) {
|
|
13327
|
+
console.error = function(...args) {
|
|
13328
|
+
self.addLog("error", args);
|
|
13329
|
+
return self.originalConsole.error(...args);
|
|
13330
|
+
};
|
|
13331
|
+
}
|
|
13332
|
+
if (levels.includes("info")) {
|
|
13333
|
+
console.info = function(...args) {
|
|
13334
|
+
self.addLog("info", args);
|
|
13335
|
+
return self.originalConsole.info(...args);
|
|
13336
|
+
};
|
|
13337
|
+
}
|
|
13338
|
+
if (levels.includes("debug")) {
|
|
13339
|
+
console.debug = function(...args) {
|
|
13340
|
+
self.addLog("debug", args);
|
|
13341
|
+
return self.originalConsole.debug(...args);
|
|
13342
|
+
};
|
|
13343
|
+
}
|
|
13344
|
+
}
|
|
13345
|
+
restoreConsole() {
|
|
13346
|
+
if (this.originalConsole) {
|
|
13347
|
+
console.log = this.originalConsole.log;
|
|
13348
|
+
console.warn = this.originalConsole.warn;
|
|
13349
|
+
console.error = this.originalConsole.error;
|
|
13350
|
+
console.info = this.originalConsole.info;
|
|
13351
|
+
console.debug = this.originalConsole.debug;
|
|
13352
|
+
this.originalConsole = null;
|
|
13353
|
+
}
|
|
13354
|
+
}
|
|
13355
|
+
interceptGlobalErrors() {
|
|
13356
|
+
if (typeof window === "undefined") return;
|
|
13357
|
+
const self = this;
|
|
13358
|
+
this.originalOnError = window.onerror;
|
|
13359
|
+
window.onerror = function(message, source, lineno, colno, error) {
|
|
13360
|
+
self.addLog("error", [
|
|
13361
|
+
`Uncaught error: ${message}`,
|
|
13362
|
+
`at ${source}:${lineno}:${colno}`,
|
|
13363
|
+
(error == null ? void 0 : error.stack) || ""
|
|
13364
|
+
]);
|
|
13365
|
+
if (self.originalOnError && typeof self.originalOnError === "function") {
|
|
13366
|
+
return self.originalOnError(message, source, lineno, colno, error);
|
|
13367
|
+
}
|
|
13368
|
+
return false;
|
|
13369
|
+
};
|
|
13370
|
+
this.originalOnUnhandledRejection = window.onunhandledrejection;
|
|
13371
|
+
window.onunhandledrejection = function(event) {
|
|
13372
|
+
self.addLog("error", [`Unhandled promise rejection: ${self.stringifyArg(event.reason)}`]);
|
|
13373
|
+
if (self.originalOnUnhandledRejection) {
|
|
13374
|
+
self.originalOnUnhandledRejection(event);
|
|
13375
|
+
}
|
|
13376
|
+
};
|
|
13377
|
+
}
|
|
13378
|
+
restoreGlobalErrors() {
|
|
13379
|
+
if (typeof window === "undefined") return;
|
|
13380
|
+
if (this.originalOnError !== null) {
|
|
13381
|
+
window.onerror = this.originalOnError;
|
|
13382
|
+
this.originalOnError = null;
|
|
13383
|
+
}
|
|
13384
|
+
if (this.originalOnUnhandledRejection !== null) {
|
|
13385
|
+
window.onunhandledrejection = this.originalOnUnhandledRejection;
|
|
13386
|
+
this.originalOnUnhandledRejection = null;
|
|
13387
|
+
}
|
|
13388
|
+
}
|
|
13389
|
+
};
|
|
13390
|
+
var PeopleAPI = class {
|
|
13391
|
+
constructor(sdk2) {
|
|
13392
|
+
this.sdk = sdk2;
|
|
13393
|
+
}
|
|
13394
|
+
/**
|
|
13395
|
+
* Set properties on the current user
|
|
13396
|
+
*/
|
|
13397
|
+
set(properties) {
|
|
13398
|
+
this.sdk.capture("$set", { $set: properties });
|
|
13399
|
+
}
|
|
13400
|
+
/**
|
|
13401
|
+
* Set properties on the current user only if they haven't been set already
|
|
13402
|
+
*/
|
|
13403
|
+
setOnce(properties) {
|
|
13404
|
+
this.sdk.capture("$set", { $set_once: properties });
|
|
13405
|
+
}
|
|
13406
|
+
/**
|
|
13407
|
+
* Remove properties from the current user
|
|
13408
|
+
*/
|
|
13409
|
+
unset(propertyNames) {
|
|
13410
|
+
this.sdk.capture("$set", { $unset: propertyNames });
|
|
13411
|
+
}
|
|
13412
|
+
};
|
|
12623
13413
|
var BentoLabsSDK = class {
|
|
12624
13414
|
constructor() {
|
|
12625
13415
|
this.config = {
|
|
@@ -12628,43 +13418,114 @@ var BentoLabsSDK = class {
|
|
|
12628
13418
|
debug: false,
|
|
12629
13419
|
batchSize: 50,
|
|
12630
13420
|
batchInterval: 1e4,
|
|
12631
|
-
// 10 seconds
|
|
12632
13421
|
enableRecording: true,
|
|
12633
13422
|
maxRetries: 3,
|
|
12634
|
-
baseRetryDelay: 1e3
|
|
13423
|
+
baseRetryDelay: 1e3,
|
|
13424
|
+
enableCompression: true,
|
|
13425
|
+
// PostHog-like defaults
|
|
13426
|
+
persistence: "localStorage+cookie",
|
|
13427
|
+
respect_dnt: false,
|
|
13428
|
+
autocapture: true,
|
|
13429
|
+
capture_pageview: true,
|
|
13430
|
+
capture_pageleave: true,
|
|
13431
|
+
// Monitoring defaults
|
|
13432
|
+
capture_network: true,
|
|
13433
|
+
networkOptions: {
|
|
13434
|
+
skipUrls: ["api.bentolabs.ai"],
|
|
13435
|
+
captureHeaders: false,
|
|
13436
|
+
captureBody: false,
|
|
13437
|
+
maxBodySize: 5e3,
|
|
13438
|
+
sampleRate: 1
|
|
13439
|
+
},
|
|
13440
|
+
capture_storage: true,
|
|
13441
|
+
storageOptions: {
|
|
13442
|
+
localStorage: true,
|
|
13443
|
+
sessionStorage: true,
|
|
13444
|
+
cookies: true,
|
|
13445
|
+
sensitiveKeys: ["password", "token", "secret", "api_key", "apikey", "auth", "credential"]
|
|
13446
|
+
},
|
|
13447
|
+
capture_console: true,
|
|
13448
|
+
consoleOptions: {
|
|
13449
|
+
levels: ["log", "warn", "error", "info"],
|
|
13450
|
+
maxLogs: 500,
|
|
13451
|
+
maxPayloadSize: 5e3,
|
|
13452
|
+
captureStackTrace: true
|
|
13453
|
+
}
|
|
12635
13454
|
};
|
|
12636
13455
|
this.sessionId = "";
|
|
12637
13456
|
this.events = [];
|
|
12638
13457
|
this.isRecording = false;
|
|
12639
13458
|
this.batchTimer = null;
|
|
12640
13459
|
this.retryTimer = null;
|
|
12641
|
-
this.
|
|
13460
|
+
this.stopRecordingFn = null;
|
|
13461
|
+
this.distinctId = "";
|
|
13462
|
+
this.identity = {
|
|
13463
|
+
distinctId: null,
|
|
13464
|
+
properties: {},
|
|
13465
|
+
isIdentified: false
|
|
13466
|
+
};
|
|
13467
|
+
this.superProperties = {};
|
|
13468
|
+
this.persistence = null;
|
|
13469
|
+
this.initialized = false;
|
|
13470
|
+
this.optedOut = false;
|
|
13471
|
+
this.networkMonitor = null;
|
|
13472
|
+
this.storageMonitor = null;
|
|
13473
|
+
this.consoleMonitor = null;
|
|
13474
|
+
this.people = new PeopleAPI(this);
|
|
13475
|
+
this.autocaptureCleanup = null;
|
|
12642
13476
|
}
|
|
12643
13477
|
/**
|
|
12644
13478
|
* Initialize the BentoLabs SDK
|
|
12645
|
-
* @param apiKey - Your API key for authentication
|
|
12646
|
-
* @param options - Optional configuration options
|
|
12647
13479
|
*/
|
|
12648
13480
|
init(apiKey, options) {
|
|
12649
|
-
var _a2;
|
|
12650
|
-
if (this.isRecording || this.
|
|
13481
|
+
var _a2, _b, _c;
|
|
13482
|
+
if (this.isRecording || this.stopRecordingFn) {
|
|
12651
13483
|
this.stopRecordingInternal();
|
|
12652
13484
|
}
|
|
12653
13485
|
const defaultOptions = {
|
|
12654
13486
|
endpoint: "https://api.bentolabs.ai",
|
|
12655
13487
|
debug: false,
|
|
12656
13488
|
batchSize: 100,
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
// 30 seconds (increased from 10s)
|
|
13489
|
+
batchInterval: 5e3,
|
|
13490
|
+
// 5 seconds (PostHog-style)
|
|
12660
13491
|
enableRecording: true,
|
|
12661
13492
|
maxRetries: 3,
|
|
12662
|
-
baseRetryDelay: 1e3
|
|
12663
|
-
|
|
13493
|
+
baseRetryDelay: 1e3,
|
|
13494
|
+
enableCompression: true,
|
|
13495
|
+
// PostHog-like defaults
|
|
13496
|
+
persistence: "localStorage+cookie",
|
|
13497
|
+
respect_dnt: false,
|
|
13498
|
+
autocapture: true,
|
|
13499
|
+
capture_pageview: true,
|
|
13500
|
+
capture_pageleave: true,
|
|
13501
|
+
// Monitoring defaults
|
|
13502
|
+
capture_network: true,
|
|
13503
|
+
networkOptions: {
|
|
13504
|
+
skipUrls: ["api.bentolabs.ai"],
|
|
13505
|
+
captureHeaders: false,
|
|
13506
|
+
captureBody: false,
|
|
13507
|
+
maxBodySize: 5e3,
|
|
13508
|
+
sampleRate: 1
|
|
13509
|
+
},
|
|
13510
|
+
capture_storage: true,
|
|
13511
|
+
storageOptions: {
|
|
13512
|
+
localStorage: true,
|
|
13513
|
+
sessionStorage: true,
|
|
13514
|
+
cookies: true,
|
|
13515
|
+
sensitiveKeys: ["password", "token", "secret", "api_key", "apikey", "auth", "credential"]
|
|
13516
|
+
},
|
|
13517
|
+
capture_console: true,
|
|
13518
|
+
consoleOptions: {
|
|
13519
|
+
levels: ["log", "warn", "error", "info"],
|
|
13520
|
+
maxLogs: 500,
|
|
13521
|
+
maxPayloadSize: 5e3,
|
|
13522
|
+
captureStackTrace: true
|
|
13523
|
+
}
|
|
12664
13524
|
};
|
|
12665
13525
|
const mergedOptions = __spreadProps(__spreadValues(__spreadValues({}, defaultOptions), options), {
|
|
12666
|
-
|
|
12667
|
-
|
|
13526
|
+
networkOptions: __spreadValues(__spreadValues({}, defaultOptions.networkOptions), options == null ? void 0 : options.networkOptions),
|
|
13527
|
+
storageOptions: __spreadValues(__spreadValues({}, defaultOptions.storageOptions), options == null ? void 0 : options.storageOptions),
|
|
13528
|
+
consoleOptions: __spreadValues(__spreadValues({}, defaultOptions.consoleOptions), options == null ? void 0 : options.consoleOptions)
|
|
12668
13529
|
});
|
|
12669
13530
|
this.config = {
|
|
12670
13531
|
apiKey,
|
|
@@ -12674,57 +13535,523 @@ var BentoLabsSDK = class {
|
|
|
12674
13535
|
batchInterval: mergedOptions.batchInterval,
|
|
12675
13536
|
enableRecording: mergedOptions.enableRecording,
|
|
12676
13537
|
maxRetries: mergedOptions.maxRetries,
|
|
12677
|
-
baseRetryDelay: mergedOptions.baseRetryDelay
|
|
13538
|
+
baseRetryDelay: mergedOptions.baseRetryDelay,
|
|
13539
|
+
enableCompression: (_a2 = mergedOptions.enableCompression) != null ? _a2 : true,
|
|
13540
|
+
persistence: mergedOptions.persistence,
|
|
13541
|
+
respect_dnt: mergedOptions.respect_dnt,
|
|
13542
|
+
autocapture: mergedOptions.autocapture,
|
|
13543
|
+
capture_pageview: mergedOptions.capture_pageview,
|
|
13544
|
+
capture_pageleave: mergedOptions.capture_pageleave,
|
|
13545
|
+
capture_network: mergedOptions.capture_network,
|
|
13546
|
+
networkOptions: mergedOptions.networkOptions,
|
|
13547
|
+
capture_storage: mergedOptions.capture_storage,
|
|
13548
|
+
storageOptions: mergedOptions.storageOptions,
|
|
13549
|
+
capture_console: mergedOptions.capture_console,
|
|
13550
|
+
consoleOptions: mergedOptions.consoleOptions,
|
|
13551
|
+
bootstrap: mergedOptions.bootstrap
|
|
12678
13552
|
};
|
|
13553
|
+
if (this.config.respect_dnt && this.isDNTEnabled()) {
|
|
13554
|
+
if (this.config.debug) {
|
|
13555
|
+
console.log("[BentoLabsSDK] Do Not Track is enabled, opting out");
|
|
13556
|
+
}
|
|
13557
|
+
this.optedOut = true;
|
|
13558
|
+
}
|
|
13559
|
+
this.persistence = new Persistence(this.config.persistence);
|
|
13560
|
+
this.loadPersistedState();
|
|
13561
|
+
if ((_b = this.config.bootstrap) == null ? void 0 : _b.distinctID) {
|
|
13562
|
+
this.distinctId = this.config.bootstrap.distinctID;
|
|
13563
|
+
this.identity.distinctId = this.config.bootstrap.distinctID;
|
|
13564
|
+
this.identity.isIdentified = (_c = this.config.bootstrap.isIdentifiedID) != null ? _c : false;
|
|
13565
|
+
this.persistence.set(PERSISTENCE_KEYS.DISTINCT_ID, this.distinctId);
|
|
13566
|
+
if (this.identity.isIdentified) {
|
|
13567
|
+
this.persistence.set(PERSISTENCE_KEYS.IS_IDENTIFIED, "true");
|
|
13568
|
+
}
|
|
13569
|
+
}
|
|
13570
|
+
if (!this.distinctId) {
|
|
13571
|
+
this.distinctId = this.generateAnonymousId();
|
|
13572
|
+
this.persistence.set(PERSISTENCE_KEYS.DISTINCT_ID, this.distinctId);
|
|
13573
|
+
}
|
|
12679
13574
|
this.sessionId = this.generateSessionId();
|
|
13575
|
+
this.initialized = true;
|
|
12680
13576
|
if (this.config.debug) {
|
|
12681
13577
|
console.log("[BentoLabsSDK] Initialized with config:", {
|
|
12682
13578
|
apiKey: apiKey.substring(0, 8) + "...",
|
|
12683
13579
|
endpoint: this.config.endpoint,
|
|
12684
13580
|
debug: this.config.debug,
|
|
12685
|
-
sessionId: this.sessionId
|
|
13581
|
+
sessionId: this.sessionId,
|
|
13582
|
+
distinctId: this.distinctId
|
|
12686
13583
|
});
|
|
12687
13584
|
}
|
|
12688
13585
|
this.startRecording();
|
|
12689
13586
|
this.startBatching();
|
|
13587
|
+
if (this.config.autocapture) {
|
|
13588
|
+
this.setupAutocapture();
|
|
13589
|
+
}
|
|
13590
|
+
if (this.config.capture_pageview) {
|
|
13591
|
+
this.capture("$pageview", {
|
|
13592
|
+
$current_url: typeof window !== "undefined" ? window.location.href : "",
|
|
13593
|
+
$pathname: typeof window !== "undefined" ? window.location.pathname : "",
|
|
13594
|
+
$referrer: typeof document !== "undefined" ? document.referrer : ""
|
|
13595
|
+
});
|
|
13596
|
+
}
|
|
13597
|
+
if (this.config.capture_pageleave && typeof window !== "undefined") {
|
|
13598
|
+
window.addEventListener("beforeunload", this.handlePageLeave.bind(this));
|
|
13599
|
+
}
|
|
13600
|
+
if (this.config.capture_network) {
|
|
13601
|
+
this.startNetworkCapture();
|
|
13602
|
+
}
|
|
13603
|
+
if (this.config.capture_storage) {
|
|
13604
|
+
this.startStorageCapture();
|
|
13605
|
+
}
|
|
13606
|
+
if (this.config.capture_console) {
|
|
13607
|
+
this.startConsoleCapture();
|
|
13608
|
+
}
|
|
12690
13609
|
}
|
|
13610
|
+
// ============================================================================
|
|
13611
|
+
// Identity Methods
|
|
13612
|
+
// ============================================================================
|
|
12691
13613
|
/**
|
|
12692
|
-
*
|
|
13614
|
+
* Identify a user with a distinct ID and optional properties
|
|
12693
13615
|
*/
|
|
12694
|
-
|
|
12695
|
-
|
|
12696
|
-
|
|
13616
|
+
identify(distinctId, properties) {
|
|
13617
|
+
var _a2, _b, _c;
|
|
13618
|
+
if (!this.initialized) {
|
|
13619
|
+
console.warn("[BentoLabsSDK] Cannot identify: SDK not initialized");
|
|
13620
|
+
return;
|
|
13621
|
+
}
|
|
13622
|
+
const previousId = this.distinctId;
|
|
13623
|
+
this.distinctId = distinctId;
|
|
13624
|
+
this.identity.distinctId = distinctId;
|
|
13625
|
+
this.identity.isIdentified = true;
|
|
13626
|
+
if (properties) {
|
|
13627
|
+
this.identity.properties = __spreadValues(__spreadValues({}, this.identity.properties), properties);
|
|
13628
|
+
}
|
|
13629
|
+
(_a2 = this.persistence) == null ? void 0 : _a2.set(PERSISTENCE_KEYS.DISTINCT_ID, distinctId);
|
|
13630
|
+
(_b = this.persistence) == null ? void 0 : _b.set(PERSISTENCE_KEYS.IS_IDENTIFIED, "true");
|
|
13631
|
+
if (properties) {
|
|
13632
|
+
(_c = this.persistence) == null ? void 0 : _c.set(PERSISTENCE_KEYS.USER_PROPERTIES, JSON.stringify(this.identity.properties));
|
|
13633
|
+
}
|
|
13634
|
+
this.capture("$identify", __spreadValues({
|
|
13635
|
+
$anon_distinct_id: previousId
|
|
13636
|
+
}, properties));
|
|
13637
|
+
if (this.config.debug) {
|
|
13638
|
+
console.log("[BentoLabsSDK] Identified user:", distinctId);
|
|
13639
|
+
}
|
|
12697
13640
|
}
|
|
12698
13641
|
/**
|
|
12699
|
-
*
|
|
13642
|
+
* Reset the user to an anonymous state
|
|
12700
13643
|
*/
|
|
12701
|
-
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
12707
|
-
|
|
13644
|
+
reset() {
|
|
13645
|
+
var _a2, _b;
|
|
13646
|
+
if (!this.initialized) return;
|
|
13647
|
+
this.distinctId = this.generateAnonymousId();
|
|
13648
|
+
this.identity = {
|
|
13649
|
+
distinctId: null,
|
|
13650
|
+
properties: {},
|
|
13651
|
+
isIdentified: false
|
|
13652
|
+
};
|
|
13653
|
+
this.superProperties = {};
|
|
13654
|
+
(_a2 = this.persistence) == null ? void 0 : _a2.clear();
|
|
13655
|
+
(_b = this.persistence) == null ? void 0 : _b.set(PERSISTENCE_KEYS.DISTINCT_ID, this.distinctId);
|
|
13656
|
+
if (this.config.debug) {
|
|
13657
|
+
console.log("[BentoLabsSDK] Reset to anonymous:", this.distinctId);
|
|
13658
|
+
}
|
|
13659
|
+
}
|
|
13660
|
+
/**
|
|
13661
|
+
* Get the current distinct ID
|
|
13662
|
+
*/
|
|
13663
|
+
getDistinctId() {
|
|
13664
|
+
return this.distinctId;
|
|
13665
|
+
}
|
|
13666
|
+
// ============================================================================
|
|
13667
|
+
// Super Properties Methods
|
|
13668
|
+
// ============================================================================
|
|
13669
|
+
/**
|
|
13670
|
+
* Register super properties to be sent with every event
|
|
13671
|
+
*/
|
|
13672
|
+
register(properties) {
|
|
13673
|
+
var _a2;
|
|
13674
|
+
this.superProperties = __spreadValues(__spreadValues({}, this.superProperties), properties);
|
|
13675
|
+
(_a2 = this.persistence) == null ? void 0 : _a2.set(PERSISTENCE_KEYS.SUPER_PROPERTIES, JSON.stringify(this.superProperties));
|
|
13676
|
+
if (this.config.debug) {
|
|
13677
|
+
console.log("[BentoLabsSDK] Registered super properties:", properties);
|
|
13678
|
+
}
|
|
13679
|
+
}
|
|
13680
|
+
/**
|
|
13681
|
+
* Register super properties only if they haven't been set
|
|
13682
|
+
*/
|
|
13683
|
+
registerOnce(properties) {
|
|
13684
|
+
const newProps = {};
|
|
13685
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
13686
|
+
if (!(key in this.superProperties)) {
|
|
13687
|
+
newProps[key] = value;
|
|
12708
13688
|
}
|
|
12709
|
-
|
|
13689
|
+
}
|
|
13690
|
+
if (Object.keys(newProps).length > 0) {
|
|
13691
|
+
this.register(newProps);
|
|
13692
|
+
}
|
|
12710
13693
|
}
|
|
12711
13694
|
/**
|
|
12712
|
-
*
|
|
13695
|
+
* Remove a super property
|
|
12713
13696
|
*/
|
|
12714
|
-
|
|
12715
|
-
|
|
13697
|
+
unregister(propertyName) {
|
|
13698
|
+
var _a2;
|
|
13699
|
+
delete this.superProperties[propertyName];
|
|
13700
|
+
(_a2 = this.persistence) == null ? void 0 : _a2.set(PERSISTENCE_KEYS.SUPER_PROPERTIES, JSON.stringify(this.superProperties));
|
|
13701
|
+
if (this.config.debug) {
|
|
13702
|
+
console.log("[BentoLabsSDK] Unregistered super property:", propertyName);
|
|
13703
|
+
}
|
|
13704
|
+
}
|
|
13705
|
+
// ============================================================================
|
|
13706
|
+
// Event Capture
|
|
13707
|
+
// ============================================================================
|
|
13708
|
+
/**
|
|
13709
|
+
* Capture an event
|
|
13710
|
+
*/
|
|
13711
|
+
capture(eventName, properties) {
|
|
13712
|
+
if (!this.initialized) {
|
|
13713
|
+
console.warn("[BentoLabsSDK] Cannot capture event: SDK not initialized");
|
|
13714
|
+
return;
|
|
13715
|
+
}
|
|
13716
|
+
if (this.optedOut) {
|
|
12716
13717
|
if (this.config.debug) {
|
|
12717
|
-
console.log("[BentoLabsSDK]
|
|
13718
|
+
console.log("[BentoLabsSDK] Event not captured (opted out):", eventName);
|
|
12718
13719
|
}
|
|
12719
13720
|
return;
|
|
12720
13721
|
}
|
|
13722
|
+
const event = {
|
|
13723
|
+
event: eventName,
|
|
13724
|
+
properties: __spreadProps(__spreadValues(__spreadValues({}, this.superProperties), properties), {
|
|
13725
|
+
$current_url: typeof window !== "undefined" ? window.location.href : "",
|
|
13726
|
+
$pathname: typeof window !== "undefined" ? window.location.pathname : ""
|
|
13727
|
+
}),
|
|
13728
|
+
$timestamp: Date.now(),
|
|
13729
|
+
$session_id: this.sessionId,
|
|
13730
|
+
$distinct_id: this.distinctId
|
|
13731
|
+
};
|
|
13732
|
+
this.addEvent({
|
|
13733
|
+
timestamp: event.$timestamp,
|
|
13734
|
+
type: `capture:${eventName}`,
|
|
13735
|
+
data: event,
|
|
13736
|
+
sessionId: this.sessionId
|
|
13737
|
+
});
|
|
12721
13738
|
if (this.config.debug) {
|
|
12722
|
-
console.log(
|
|
12723
|
-
"[BentoLabsSDK] Starting recording for session:",
|
|
12724
|
-
this.sessionId
|
|
12725
|
-
);
|
|
13739
|
+
console.log("[BentoLabsSDK] Captured event:", eventName, properties);
|
|
12726
13740
|
}
|
|
12727
|
-
|
|
13741
|
+
}
|
|
13742
|
+
/**
|
|
13743
|
+
* Track a custom event (legacy method, delegates to capture)
|
|
13744
|
+
*/
|
|
13745
|
+
trackCustomEvent(eventName, data) {
|
|
13746
|
+
if (!this.sessionId) {
|
|
13747
|
+
console.warn("[BentoLabsSDK] Cannot track event: SDK not initialized");
|
|
13748
|
+
return;
|
|
13749
|
+
}
|
|
13750
|
+
this.capture(`custom:${eventName}`, data);
|
|
13751
|
+
}
|
|
13752
|
+
// ============================================================================
|
|
13753
|
+
// Opt-in/Opt-out
|
|
13754
|
+
// ============================================================================
|
|
13755
|
+
/**
|
|
13756
|
+
* Opt out of tracking
|
|
13757
|
+
*/
|
|
13758
|
+
opt_out_capturing() {
|
|
13759
|
+
var _a2;
|
|
13760
|
+
this.optedOut = true;
|
|
13761
|
+
(_a2 = this.persistence) == null ? void 0 : _a2.set(PERSISTENCE_KEYS.OPTED_OUT, "true");
|
|
13762
|
+
if (this.isRecording) {
|
|
13763
|
+
this.stopRecordingInternal();
|
|
13764
|
+
}
|
|
13765
|
+
this.stopNetworkCapture();
|
|
13766
|
+
this.stopStorageCapture();
|
|
13767
|
+
this.stopConsoleCapture();
|
|
13768
|
+
if (this.config.debug) {
|
|
13769
|
+
console.log("[BentoLabsSDK] Opted out of capturing");
|
|
13770
|
+
}
|
|
13771
|
+
}
|
|
13772
|
+
/**
|
|
13773
|
+
* Opt back into tracking
|
|
13774
|
+
*/
|
|
13775
|
+
opt_in_capturing() {
|
|
13776
|
+
var _a2;
|
|
13777
|
+
this.optedOut = false;
|
|
13778
|
+
(_a2 = this.persistence) == null ? void 0 : _a2.remove(PERSISTENCE_KEYS.OPTED_OUT);
|
|
13779
|
+
if (this.initialized && this.config.enableRecording) {
|
|
13780
|
+
this.startRecording();
|
|
13781
|
+
}
|
|
13782
|
+
if (this.config.capture_network) {
|
|
13783
|
+
this.startNetworkCapture();
|
|
13784
|
+
}
|
|
13785
|
+
if (this.config.capture_storage) {
|
|
13786
|
+
this.startStorageCapture();
|
|
13787
|
+
}
|
|
13788
|
+
if (this.config.capture_console) {
|
|
13789
|
+
this.startConsoleCapture();
|
|
13790
|
+
}
|
|
13791
|
+
if (this.config.debug) {
|
|
13792
|
+
console.log("[BentoLabsSDK] Opted back into capturing");
|
|
13793
|
+
}
|
|
13794
|
+
}
|
|
13795
|
+
/**
|
|
13796
|
+
* Check if user has opted out
|
|
13797
|
+
*/
|
|
13798
|
+
has_opted_out_capturing() {
|
|
13799
|
+
return this.optedOut;
|
|
13800
|
+
}
|
|
13801
|
+
/**
|
|
13802
|
+
* Check if user has opted in (not opted out)
|
|
13803
|
+
*/
|
|
13804
|
+
has_opted_in_capturing() {
|
|
13805
|
+
return !this.optedOut;
|
|
13806
|
+
}
|
|
13807
|
+
// ============================================================================
|
|
13808
|
+
// Monitoring Control
|
|
13809
|
+
// ============================================================================
|
|
13810
|
+
/**
|
|
13811
|
+
* Start network request monitoring
|
|
13812
|
+
*/
|
|
13813
|
+
startNetworkCapture() {
|
|
13814
|
+
if (this.networkMonitor) return;
|
|
13815
|
+
this.networkMonitor = new NetworkMonitor(this.config.networkOptions, (log) => {
|
|
13816
|
+
if (!this.optedOut) {
|
|
13817
|
+
this.capture("$network_request", log);
|
|
13818
|
+
}
|
|
13819
|
+
});
|
|
13820
|
+
this.networkMonitor.start();
|
|
13821
|
+
if (this.config.debug) {
|
|
13822
|
+
console.log("[BentoLabsSDK] Network capture started");
|
|
13823
|
+
}
|
|
13824
|
+
}
|
|
13825
|
+
/**
|
|
13826
|
+
* Stop network request monitoring
|
|
13827
|
+
*/
|
|
13828
|
+
stopNetworkCapture() {
|
|
13829
|
+
if (this.networkMonitor) {
|
|
13830
|
+
this.networkMonitor.stop();
|
|
13831
|
+
this.networkMonitor = null;
|
|
13832
|
+
if (this.config.debug) {
|
|
13833
|
+
console.log("[BentoLabsSDK] Network capture stopped");
|
|
13834
|
+
}
|
|
13835
|
+
}
|
|
13836
|
+
}
|
|
13837
|
+
/**
|
|
13838
|
+
* Start storage monitoring
|
|
13839
|
+
*/
|
|
13840
|
+
startStorageCapture() {
|
|
13841
|
+
if (this.storageMonitor) return;
|
|
13842
|
+
this.storageMonitor = new StorageMonitor(this.config.storageOptions, (log) => {
|
|
13843
|
+
if (!this.optedOut) {
|
|
13844
|
+
this.capture("$storage_event", log);
|
|
13845
|
+
}
|
|
13846
|
+
});
|
|
13847
|
+
this.storageMonitor.start();
|
|
13848
|
+
if (this.config.debug) {
|
|
13849
|
+
console.log("[BentoLabsSDK] Storage capture started");
|
|
13850
|
+
}
|
|
13851
|
+
}
|
|
13852
|
+
/**
|
|
13853
|
+
* Stop storage monitoring
|
|
13854
|
+
*/
|
|
13855
|
+
stopStorageCapture() {
|
|
13856
|
+
if (this.storageMonitor) {
|
|
13857
|
+
this.storageMonitor.stop();
|
|
13858
|
+
this.storageMonitor = null;
|
|
13859
|
+
if (this.config.debug) {
|
|
13860
|
+
console.log("[BentoLabsSDK] Storage capture stopped");
|
|
13861
|
+
}
|
|
13862
|
+
}
|
|
13863
|
+
}
|
|
13864
|
+
/**
|
|
13865
|
+
* Start console monitoring
|
|
13866
|
+
*/
|
|
13867
|
+
startConsoleCapture() {
|
|
13868
|
+
if (this.consoleMonitor) return;
|
|
13869
|
+
this.consoleMonitor = new ConsoleMonitor(this.config.consoleOptions, (log) => {
|
|
13870
|
+
if (!this.optedOut) {
|
|
13871
|
+
this.capture("$console_log", log);
|
|
13872
|
+
}
|
|
13873
|
+
});
|
|
13874
|
+
this.consoleMonitor.start();
|
|
13875
|
+
if (this.config.debug) {
|
|
13876
|
+
console.log("[BentoLabsSDK] Console capture started");
|
|
13877
|
+
}
|
|
13878
|
+
}
|
|
13879
|
+
/**
|
|
13880
|
+
* Stop console monitoring
|
|
13881
|
+
*/
|
|
13882
|
+
stopConsoleCapture() {
|
|
13883
|
+
if (this.consoleMonitor) {
|
|
13884
|
+
this.consoleMonitor.stop();
|
|
13885
|
+
this.consoleMonitor = null;
|
|
13886
|
+
if (this.config.debug) {
|
|
13887
|
+
console.log("[BentoLabsSDK] Console capture stopped");
|
|
13888
|
+
}
|
|
13889
|
+
}
|
|
13890
|
+
}
|
|
13891
|
+
/**
|
|
13892
|
+
* Get network logs
|
|
13893
|
+
*/
|
|
13894
|
+
getNetworkLogs() {
|
|
13895
|
+
var _a2;
|
|
13896
|
+
return ((_a2 = this.networkMonitor) == null ? void 0 : _a2.getLogs()) || [];
|
|
13897
|
+
}
|
|
13898
|
+
/**
|
|
13899
|
+
* Get storage logs
|
|
13900
|
+
*/
|
|
13901
|
+
getStorageLogs() {
|
|
13902
|
+
var _a2;
|
|
13903
|
+
return ((_a2 = this.storageMonitor) == null ? void 0 : _a2.getLogs()) || [];
|
|
13904
|
+
}
|
|
13905
|
+
/**
|
|
13906
|
+
* Get console logs
|
|
13907
|
+
*/
|
|
13908
|
+
getConsoleLogs() {
|
|
13909
|
+
var _a2;
|
|
13910
|
+
return ((_a2 = this.consoleMonitor) == null ? void 0 : _a2.getLogs()) || [];
|
|
13911
|
+
}
|
|
13912
|
+
// ============================================================================
|
|
13913
|
+
// Existing Public Methods (Preserved)
|
|
13914
|
+
// ============================================================================
|
|
13915
|
+
/**
|
|
13916
|
+
* Stop recording and clean up resources
|
|
13917
|
+
*/
|
|
13918
|
+
stop() {
|
|
13919
|
+
if (this.config.debug) {
|
|
13920
|
+
console.log("[BentoLabsSDK] Stopping recording and batching");
|
|
13921
|
+
}
|
|
13922
|
+
this.stopRecordingInternal();
|
|
13923
|
+
this.stopNetworkCapture();
|
|
13924
|
+
this.stopStorageCapture();
|
|
13925
|
+
this.stopConsoleCapture();
|
|
13926
|
+
if (this.events.length > 0) {
|
|
13927
|
+
this.sendBatch();
|
|
13928
|
+
}
|
|
13929
|
+
if (this.config.debug) {
|
|
13930
|
+
console.log("[BentoLabsSDK] Stopped successfully");
|
|
13931
|
+
}
|
|
13932
|
+
}
|
|
13933
|
+
/**
|
|
13934
|
+
* Get current session ID
|
|
13935
|
+
*/
|
|
13936
|
+
getSessionId() {
|
|
13937
|
+
return this.sessionId;
|
|
13938
|
+
}
|
|
13939
|
+
/**
|
|
13940
|
+
* Check if recording is active
|
|
13941
|
+
*/
|
|
13942
|
+
isRecordingActive() {
|
|
13943
|
+
return this.isRecording;
|
|
13944
|
+
}
|
|
13945
|
+
/**
|
|
13946
|
+
* Get current configuration (without exposing sensitive data)
|
|
13947
|
+
*/
|
|
13948
|
+
getConfig() {
|
|
13949
|
+
return {
|
|
13950
|
+
apiKey: this.config.apiKey ? this.config.apiKey.substring(0, 8) + "..." : "",
|
|
13951
|
+
endpoint: this.config.endpoint,
|
|
13952
|
+
debug: this.config.debug,
|
|
13953
|
+
batchSize: this.config.batchSize,
|
|
13954
|
+
batchInterval: this.config.batchInterval,
|
|
13955
|
+
enableRecording: this.config.enableRecording,
|
|
13956
|
+
maxRetries: this.config.maxRetries,
|
|
13957
|
+
baseRetryDelay: this.config.baseRetryDelay,
|
|
13958
|
+
enableCompression: this.config.enableCompression,
|
|
13959
|
+
persistence: this.config.persistence,
|
|
13960
|
+
respect_dnt: this.config.respect_dnt,
|
|
13961
|
+
autocapture: this.config.autocapture,
|
|
13962
|
+
capture_pageview: this.config.capture_pageview,
|
|
13963
|
+
capture_pageleave: this.config.capture_pageleave,
|
|
13964
|
+
capture_network: this.config.capture_network,
|
|
13965
|
+
networkOptions: this.config.networkOptions,
|
|
13966
|
+
capture_storage: this.config.capture_storage,
|
|
13967
|
+
storageOptions: this.config.storageOptions,
|
|
13968
|
+
capture_console: this.config.capture_console,
|
|
13969
|
+
consoleOptions: this.config.consoleOptions
|
|
13970
|
+
};
|
|
13971
|
+
}
|
|
13972
|
+
/**
|
|
13973
|
+
* Get current event queue length
|
|
13974
|
+
*/
|
|
13975
|
+
getEventQueueLength() {
|
|
13976
|
+
return this.events.length;
|
|
13977
|
+
}
|
|
13978
|
+
/**
|
|
13979
|
+
* Manually trigger a batch send
|
|
13980
|
+
*/
|
|
13981
|
+
async flushEvents() {
|
|
13982
|
+
await this.sendBatch();
|
|
13983
|
+
}
|
|
13984
|
+
// ============================================================================
|
|
13985
|
+
// Private Methods
|
|
13986
|
+
// ============================================================================
|
|
13987
|
+
generateSessionId() {
|
|
13988
|
+
const uuid = this.generateUUID();
|
|
13989
|
+
return `sess_${uuid}`;
|
|
13990
|
+
}
|
|
13991
|
+
generateAnonymousId() {
|
|
13992
|
+
const uuid = this.generateUUID();
|
|
13993
|
+
return `anon_${uuid}`;
|
|
13994
|
+
}
|
|
13995
|
+
generateUUID() {
|
|
13996
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
|
13997
|
+
const r = Math.random() * 16 | 0;
|
|
13998
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
13999
|
+
return v.toString(16);
|
|
14000
|
+
});
|
|
14001
|
+
}
|
|
14002
|
+
isDNTEnabled() {
|
|
14003
|
+
if (typeof navigator === "undefined") return false;
|
|
14004
|
+
return navigator.doNotTrack === "1" || navigator.doNotTrack === "yes";
|
|
14005
|
+
}
|
|
14006
|
+
loadPersistedState() {
|
|
14007
|
+
if (!this.persistence) return;
|
|
14008
|
+
const storedDistinctId = this.persistence.get(PERSISTENCE_KEYS.DISTINCT_ID);
|
|
14009
|
+
if (storedDistinctId) {
|
|
14010
|
+
this.distinctId = storedDistinctId;
|
|
14011
|
+
this.identity.distinctId = storedDistinctId;
|
|
14012
|
+
}
|
|
14013
|
+
const isIdentified = this.persistence.get(PERSISTENCE_KEYS.IS_IDENTIFIED);
|
|
14014
|
+
if (isIdentified === "true") {
|
|
14015
|
+
this.identity.isIdentified = true;
|
|
14016
|
+
}
|
|
14017
|
+
const storedSuperProps = this.persistence.get(PERSISTENCE_KEYS.SUPER_PROPERTIES);
|
|
14018
|
+
if (storedSuperProps) {
|
|
14019
|
+
try {
|
|
14020
|
+
this.superProperties = JSON.parse(storedSuperProps);
|
|
14021
|
+
} catch (e) {
|
|
14022
|
+
this.superProperties = {};
|
|
14023
|
+
}
|
|
14024
|
+
}
|
|
14025
|
+
const storedUserProps = this.persistence.get(PERSISTENCE_KEYS.USER_PROPERTIES);
|
|
14026
|
+
if (storedUserProps) {
|
|
14027
|
+
try {
|
|
14028
|
+
this.identity.properties = JSON.parse(storedUserProps);
|
|
14029
|
+
} catch (e) {
|
|
14030
|
+
this.identity.properties = {};
|
|
14031
|
+
}
|
|
14032
|
+
}
|
|
14033
|
+
const optedOut = this.persistence.get(PERSISTENCE_KEYS.OPTED_OUT);
|
|
14034
|
+
if (optedOut === "true") {
|
|
14035
|
+
this.optedOut = true;
|
|
14036
|
+
}
|
|
14037
|
+
}
|
|
14038
|
+
startRecording() {
|
|
14039
|
+
if (!this.config.enableRecording) {
|
|
14040
|
+
if (this.config.debug) {
|
|
14041
|
+
console.log("[BentoLabsSDK] Recording disabled in configuration");
|
|
14042
|
+
}
|
|
14043
|
+
return;
|
|
14044
|
+
}
|
|
14045
|
+
if (this.optedOut) {
|
|
14046
|
+
if (this.config.debug) {
|
|
14047
|
+
console.log("[BentoLabsSDK] Recording disabled (opted out)");
|
|
14048
|
+
}
|
|
14049
|
+
return;
|
|
14050
|
+
}
|
|
14051
|
+
if (this.config.debug) {
|
|
14052
|
+
console.log("[BentoLabsSDK] Starting recording for session:", this.sessionId);
|
|
14053
|
+
}
|
|
14054
|
+
try {
|
|
12728
14055
|
if (this.config.debug) {
|
|
12729
14056
|
console.log("[BentoLabsSDK] Calling rrweb record()...");
|
|
12730
14057
|
}
|
|
@@ -12743,7 +14070,6 @@ var BentoLabsSDK = class {
|
|
|
12743
14070
|
recordCanvas: true,
|
|
12744
14071
|
collectFonts: true,
|
|
12745
14072
|
plugins: [],
|
|
12746
|
-
// Enable element context capture for rich metadata on interactions
|
|
12747
14073
|
captureElementContext: true,
|
|
12748
14074
|
elementContextOptions: {
|
|
12749
14075
|
maxTextLength: 500,
|
|
@@ -12751,33 +14077,28 @@ var BentoLabsSDK = class {
|
|
|
12751
14077
|
outerHTMLDepth: 2,
|
|
12752
14078
|
includeInputValues: true
|
|
12753
14079
|
},
|
|
12754
|
-
// Mask password inputs for security
|
|
12755
14080
|
maskInputOptions: {
|
|
12756
14081
|
password: true
|
|
12757
14082
|
},
|
|
12758
|
-
// Sampling and throttling to reduce event volume
|
|
12759
14083
|
sampling: {
|
|
12760
14084
|
mousemove: true,
|
|
12761
|
-
// Sample mouse movements
|
|
12762
14085
|
mouseInteraction: { click: false, dblclick: false },
|
|
12763
|
-
// Capture all clicks
|
|
12764
14086
|
scroll: 150,
|
|
12765
|
-
// Throttle scroll events to 150ms
|
|
12766
14087
|
input: "last"
|
|
12767
|
-
// Only record final input value
|
|
12768
14088
|
},
|
|
12769
14089
|
checkoutEveryNms: 5 * 60 * 1e3
|
|
12770
|
-
// Take full snapshot every 5 minutes
|
|
12771
14090
|
});
|
|
12772
14091
|
if (typeof stopFn === "function") {
|
|
12773
|
-
this.
|
|
14092
|
+
this.stopRecordingFn = stopFn;
|
|
12774
14093
|
this.isRecording = true;
|
|
12775
14094
|
if (this.config.debug) {
|
|
12776
14095
|
console.log("[BentoLabsSDK] Recording started successfully");
|
|
12777
14096
|
}
|
|
12778
14097
|
} else {
|
|
12779
|
-
console.error(
|
|
12780
|
-
|
|
14098
|
+
console.error(
|
|
14099
|
+
"[BentoLabsSDK] rrweb record() did not return a stop function. Recording may not have started properly."
|
|
14100
|
+
);
|
|
14101
|
+
this.stopRecordingFn = null;
|
|
12781
14102
|
this.isRecording = false;
|
|
12782
14103
|
}
|
|
12783
14104
|
} catch (error) {
|
|
@@ -12785,9 +14106,6 @@ var BentoLabsSDK = class {
|
|
|
12785
14106
|
this.isRecording = false;
|
|
12786
14107
|
}
|
|
12787
14108
|
}
|
|
12788
|
-
/**
|
|
12789
|
-
* Start batching events for transmission
|
|
12790
|
-
*/
|
|
12791
14109
|
startBatching() {
|
|
12792
14110
|
if (this.config.debug) {
|
|
12793
14111
|
console.log("[BentoLabsSDK] Starting event batching");
|
|
@@ -12799,31 +14117,22 @@ var BentoLabsSDK = class {
|
|
|
12799
14117
|
this.sendBatch();
|
|
12800
14118
|
}, this.config.batchInterval);
|
|
12801
14119
|
if (this.config.debug) {
|
|
12802
|
-
console.log(
|
|
12803
|
-
`[BentoLabsSDK] Batch timer set for ${this.config.batchInterval}ms intervals`
|
|
12804
|
-
);
|
|
14120
|
+
console.log(`[BentoLabsSDK] Batch timer set for ${this.config.batchInterval}ms intervals`);
|
|
12805
14121
|
}
|
|
12806
14122
|
}
|
|
12807
|
-
/**
|
|
12808
|
-
* Add an event to the events array
|
|
12809
|
-
*/
|
|
12810
14123
|
addEvent(event) {
|
|
14124
|
+
if (this.optedOut) return;
|
|
12811
14125
|
this.events.push(event);
|
|
12812
14126
|
if (this.config.debug) {
|
|
12813
14127
|
console.log("[BentoLabsSDK] Event added:", event.type);
|
|
12814
14128
|
}
|
|
12815
14129
|
if (this.events.length >= this.config.batchSize) {
|
|
12816
14130
|
if (this.config.debug) {
|
|
12817
|
-
console.log(
|
|
12818
|
-
`[BentoLabsSDK] Batch size limit reached (${this.config.batchSize}), sending batch`
|
|
12819
|
-
);
|
|
14131
|
+
console.log(`[BentoLabsSDK] Batch size limit reached (${this.config.batchSize}), sending batch`);
|
|
12820
14132
|
}
|
|
12821
14133
|
this.sendBatch();
|
|
12822
14134
|
}
|
|
12823
14135
|
}
|
|
12824
|
-
/**
|
|
12825
|
-
* Send batched events to the API with exponential backoff retry
|
|
12826
|
-
*/
|
|
12827
14136
|
async sendBatch() {
|
|
12828
14137
|
const now = Date.now();
|
|
12829
14138
|
const readyEvents = this.events.filter((event) => {
|
|
@@ -12841,12 +14150,11 @@ var BentoLabsSDK = class {
|
|
|
12841
14150
|
events: readyEvents,
|
|
12842
14151
|
timestamp: now,
|
|
12843
14152
|
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "Unknown",
|
|
12844
|
-
url: typeof window !== "undefined" ? window.location.href : "Unknown"
|
|
14153
|
+
url: typeof window !== "undefined" ? window.location.href : "Unknown",
|
|
14154
|
+
distinctId: this.distinctId
|
|
12845
14155
|
};
|
|
12846
14156
|
if (this.config.debug) {
|
|
12847
|
-
console.log(
|
|
12848
|
-
`[BentoLabsSDK] Sending batch with ${readyEvents.length} events`
|
|
12849
|
-
);
|
|
14157
|
+
console.log(`[BentoLabsSDK] Sending batch with ${readyEvents.length} events`);
|
|
12850
14158
|
}
|
|
12851
14159
|
try {
|
|
12852
14160
|
const response = await fetch(`${this.config.endpoint}/events/`, {
|
|
@@ -12874,43 +14182,30 @@ var BentoLabsSDK = class {
|
|
|
12874
14182
|
nextRetryTime: now + delay
|
|
12875
14183
|
});
|
|
12876
14184
|
});
|
|
12877
|
-
const eventsToRetry = retryableEvents.filter(
|
|
12878
|
-
(event) => event.retryCount <= this.config.maxRetries
|
|
12879
|
-
);
|
|
14185
|
+
const eventsToRetry = retryableEvents.filter((event) => event.retryCount <= this.config.maxRetries);
|
|
12880
14186
|
const droppedEvents = retryableEvents.length - eventsToRetry.length;
|
|
12881
14187
|
if (droppedEvents > 0 && this.config.debug) {
|
|
12882
|
-
console.log(
|
|
12883
|
-
`[BentoLabsSDK] Dropped ${droppedEvents} events after max retries`
|
|
12884
|
-
);
|
|
14188
|
+
console.log(`[BentoLabsSDK] Dropped ${droppedEvents} events after max retries`);
|
|
12885
14189
|
}
|
|
12886
14190
|
this.events.unshift(...eventsToRetry);
|
|
12887
14191
|
if (this.config.debug && eventsToRetry.length > 0) {
|
|
12888
14192
|
const nextRetryIn = Math.min(...eventsToRetry.map((e) => e.nextRetryTime)) - now;
|
|
12889
|
-
console.log(
|
|
12890
|
-
`[BentoLabsSDK] ${eventsToRetry.length} events re-queued for retry in ${nextRetryIn}ms`
|
|
12891
|
-
);
|
|
14193
|
+
console.log(`[BentoLabsSDK] ${eventsToRetry.length} events re-queued for retry in ${nextRetryIn}ms`);
|
|
12892
14194
|
}
|
|
12893
14195
|
this.scheduleRetry();
|
|
12894
14196
|
}
|
|
12895
14197
|
}
|
|
12896
|
-
/**
|
|
12897
|
-
* Schedule retry attempts for failed events
|
|
12898
|
-
*/
|
|
12899
14198
|
scheduleRetry() {
|
|
12900
14199
|
if (this.retryTimer) {
|
|
12901
14200
|
clearTimeout(this.retryTimer);
|
|
12902
14201
|
this.retryTimer = null;
|
|
12903
14202
|
}
|
|
12904
14203
|
const now = Date.now();
|
|
12905
|
-
const retryableEvents = this.events.filter(
|
|
12906
|
-
(event) => "nextRetryTime" in event
|
|
12907
|
-
);
|
|
14204
|
+
const retryableEvents = this.events.filter((event) => "nextRetryTime" in event);
|
|
12908
14205
|
if (retryableEvents.length === 0) {
|
|
12909
14206
|
return;
|
|
12910
14207
|
}
|
|
12911
|
-
const nextRetryTime = Math.min(
|
|
12912
|
-
...retryableEvents.map((e) => e.nextRetryTime)
|
|
12913
|
-
);
|
|
14208
|
+
const nextRetryTime = Math.min(...retryableEvents.map((e) => e.nextRetryTime));
|
|
12914
14209
|
const delay = Math.max(0, nextRetryTime - now);
|
|
12915
14210
|
if (this.config.debug) {
|
|
12916
14211
|
console.log(`[BentoLabsSDK] Scheduling retry in ${delay}ms`);
|
|
@@ -12919,13 +14214,10 @@ var BentoLabsSDK = class {
|
|
|
12919
14214
|
this.sendBatch();
|
|
12920
14215
|
}, delay);
|
|
12921
14216
|
}
|
|
12922
|
-
/**
|
|
12923
|
-
* Internal method to stop recording without logging (used during re-init)
|
|
12924
|
-
*/
|
|
12925
14217
|
stopRecordingInternal() {
|
|
12926
|
-
if (this.
|
|
12927
|
-
this.
|
|
12928
|
-
this.
|
|
14218
|
+
if (this.stopRecordingFn) {
|
|
14219
|
+
this.stopRecordingFn();
|
|
14220
|
+
this.stopRecordingFn = null;
|
|
12929
14221
|
}
|
|
12930
14222
|
if (this.batchTimer) {
|
|
12931
14223
|
clearInterval(this.batchTimer);
|
|
@@ -12935,86 +14227,115 @@ var BentoLabsSDK = class {
|
|
|
12935
14227
|
clearTimeout(this.retryTimer);
|
|
12936
14228
|
this.retryTimer = null;
|
|
12937
14229
|
}
|
|
14230
|
+
if (this.autocaptureCleanup) {
|
|
14231
|
+
this.autocaptureCleanup();
|
|
14232
|
+
this.autocaptureCleanup = null;
|
|
14233
|
+
}
|
|
12938
14234
|
this.isRecording = false;
|
|
12939
14235
|
}
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
|
|
12949
|
-
|
|
12950
|
-
|
|
14236
|
+
setupAutocapture() {
|
|
14237
|
+
if (typeof document === "undefined") return;
|
|
14238
|
+
const handleClick = (e) => {
|
|
14239
|
+
var _a2;
|
|
14240
|
+
const target = e.target;
|
|
14241
|
+
if (!target) return;
|
|
14242
|
+
const tagName = target.tagName.toLowerCase();
|
|
14243
|
+
const allowedTags = ["a", "button", "input", "select", "textarea"];
|
|
14244
|
+
const isAllowed = allowedTags.includes(tagName) || target.getAttribute("role") === "button" || target.hasAttribute("data-bento-capture");
|
|
14245
|
+
if (!isAllowed) return;
|
|
14246
|
+
let selector = "";
|
|
14247
|
+
try {
|
|
14248
|
+
selector = generateSelectorFromElement(target);
|
|
14249
|
+
} catch (e2) {
|
|
14250
|
+
selector = "";
|
|
14251
|
+
}
|
|
14252
|
+
this.capture("$autocapture", {
|
|
14253
|
+
$event_type: "click",
|
|
14254
|
+
$element_tag: tagName,
|
|
14255
|
+
$element_text: ((_a2 = target.textContent) == null ? void 0 : _a2.slice(0, 100)) || "",
|
|
14256
|
+
$element_classes: target.className || "",
|
|
14257
|
+
$element_id: target.id || "",
|
|
14258
|
+
$bento_selector: selector
|
|
14259
|
+
});
|
|
14260
|
+
};
|
|
14261
|
+
const handleChange = (e) => {
|
|
14262
|
+
const target = e.target;
|
|
14263
|
+
if (!target) return;
|
|
14264
|
+
const tagName = target.tagName.toLowerCase();
|
|
14265
|
+
if (!["input", "select", "textarea"].includes(tagName)) return;
|
|
14266
|
+
if (target.type === "password") return;
|
|
14267
|
+
let selector = "";
|
|
14268
|
+
try {
|
|
14269
|
+
selector = generateSelectorFromElement(target);
|
|
14270
|
+
} catch (e2) {
|
|
14271
|
+
selector = "";
|
|
14272
|
+
}
|
|
14273
|
+
this.capture("$autocapture", {
|
|
14274
|
+
$event_type: "change",
|
|
14275
|
+
$element_tag: tagName,
|
|
14276
|
+
$element_type: target.type || "",
|
|
14277
|
+
$element_name: target.name || "",
|
|
14278
|
+
$element_id: target.id || "",
|
|
14279
|
+
$bento_selector: selector
|
|
14280
|
+
// Don't capture actual value for privacy
|
|
14281
|
+
});
|
|
14282
|
+
};
|
|
14283
|
+
const handleSubmit = (e) => {
|
|
14284
|
+
const target = e.target;
|
|
14285
|
+
if (!target || target.tagName.toLowerCase() !== "form") return;
|
|
14286
|
+
let selector = "";
|
|
14287
|
+
try {
|
|
14288
|
+
selector = generateSelectorFromElement(target);
|
|
14289
|
+
} catch (e2) {
|
|
14290
|
+
selector = "";
|
|
14291
|
+
}
|
|
14292
|
+
this.capture("$autocapture", {
|
|
14293
|
+
$event_type: "submit",
|
|
14294
|
+
$element_tag: "form",
|
|
14295
|
+
$form_name: target.name || "",
|
|
14296
|
+
$form_id: target.id || "",
|
|
14297
|
+
$form_action: target.action || "",
|
|
14298
|
+
$bento_selector: selector
|
|
14299
|
+
});
|
|
14300
|
+
};
|
|
14301
|
+
document.addEventListener("click", handleClick, true);
|
|
14302
|
+
document.addEventListener("change", handleChange, true);
|
|
14303
|
+
document.addEventListener("submit", handleSubmit, true);
|
|
14304
|
+
this.autocaptureCleanup = () => {
|
|
14305
|
+
document.removeEventListener("click", handleClick, true);
|
|
14306
|
+
document.removeEventListener("change", handleChange, true);
|
|
14307
|
+
document.removeEventListener("submit", handleSubmit, true);
|
|
14308
|
+
};
|
|
12951
14309
|
if (this.config.debug) {
|
|
12952
|
-
console.log("[BentoLabsSDK]
|
|
14310
|
+
console.log("[BentoLabsSDK] Autocapture setup complete");
|
|
12953
14311
|
}
|
|
12954
14312
|
}
|
|
12955
|
-
|
|
12956
|
-
|
|
12957
|
-
|
|
12958
|
-
|
|
12959
|
-
return this.sessionId;
|
|
12960
|
-
}
|
|
12961
|
-
/**
|
|
12962
|
-
* Check if recording is active
|
|
12963
|
-
*/
|
|
12964
|
-
isRecordingActive() {
|
|
12965
|
-
return this.isRecording;
|
|
12966
|
-
}
|
|
12967
|
-
/**
|
|
12968
|
-
* Get current configuration (without exposing sensitive data)
|
|
12969
|
-
*/
|
|
12970
|
-
getConfig() {
|
|
12971
|
-
return {
|
|
12972
|
-
apiKey: this.config.apiKey ? this.config.apiKey.substring(0, 8) + "..." : "",
|
|
12973
|
-
endpoint: this.config.endpoint,
|
|
12974
|
-
debug: this.config.debug,
|
|
12975
|
-
batchSize: this.config.batchSize,
|
|
12976
|
-
batchInterval: this.config.batchInterval,
|
|
12977
|
-
enableRecording: this.config.enableRecording,
|
|
12978
|
-
maxRetries: this.config.maxRetries,
|
|
12979
|
-
baseRetryDelay: this.config.baseRetryDelay
|
|
12980
|
-
};
|
|
12981
|
-
}
|
|
12982
|
-
/**
|
|
12983
|
-
* Get current event queue length
|
|
12984
|
-
*/
|
|
12985
|
-
getEventQueueLength() {
|
|
12986
|
-
return this.events.length;
|
|
12987
|
-
}
|
|
12988
|
-
/**
|
|
12989
|
-
* Manually trigger a batch send
|
|
12990
|
-
*/
|
|
12991
|
-
async flushEvents() {
|
|
12992
|
-
await this.sendBatch();
|
|
12993
|
-
}
|
|
12994
|
-
/**
|
|
12995
|
-
* Track a custom event with custom data
|
|
12996
|
-
* @param eventName - Name of the custom event
|
|
12997
|
-
* @param data - Custom event data (will be JSON stringified)
|
|
12998
|
-
*/
|
|
12999
|
-
trackCustomEvent(eventName, data) {
|
|
13000
|
-
if (!this.sessionId) {
|
|
13001
|
-
console.warn("[BentoLabsSDK] Cannot track event: SDK not initialized");
|
|
13002
|
-
return;
|
|
13003
|
-
}
|
|
13004
|
-
this.addEvent({
|
|
13005
|
-
timestamp: Date.now(),
|
|
13006
|
-
type: `custom:${eventName}`,
|
|
13007
|
-
data: data || {},
|
|
13008
|
-
sessionId: this.sessionId
|
|
14313
|
+
handlePageLeave() {
|
|
14314
|
+
this.capture("$pageleave", {
|
|
14315
|
+
$current_url: typeof window !== "undefined" ? window.location.href : "",
|
|
14316
|
+
$pathname: typeof window !== "undefined" ? window.location.pathname : ""
|
|
13009
14317
|
});
|
|
13010
|
-
if (this.
|
|
13011
|
-
|
|
14318
|
+
if (this.events.length > 0 && typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
14319
|
+
const payload = {
|
|
14320
|
+
sessionId: this.sessionId,
|
|
14321
|
+
events: this.events,
|
|
14322
|
+
timestamp: Date.now(),
|
|
14323
|
+
userAgent: navigator.userAgent,
|
|
14324
|
+
url: window.location.href,
|
|
14325
|
+
distinctId: this.distinctId
|
|
14326
|
+
};
|
|
14327
|
+
navigator.sendBeacon(
|
|
14328
|
+
`${this.config.endpoint}/events/`,
|
|
14329
|
+
new Blob([JSON.stringify(payload)], { type: "application/json" })
|
|
14330
|
+
);
|
|
14331
|
+
this.events = [];
|
|
13012
14332
|
}
|
|
13013
14333
|
}
|
|
13014
14334
|
};
|
|
13015
14335
|
var sdk = new BentoLabsSDK();
|
|
13016
14336
|
if (typeof window !== "undefined") {
|
|
13017
|
-
window.BentoLabsSDK =
|
|
14337
|
+
window.BentoLabsSDK = {
|
|
14338
|
+
// Core methods
|
|
13018
14339
|
init: sdk.init.bind(sdk),
|
|
13019
14340
|
stop: sdk.stop.bind(sdk),
|
|
13020
14341
|
getSessionId: sdk.getSessionId.bind(sdk),
|
|
@@ -13023,8 +14344,34 @@ if (typeof window !== "undefined") {
|
|
|
13023
14344
|
getEventQueueLength: sdk.getEventQueueLength.bind(sdk),
|
|
13024
14345
|
flushEvents: sdk.flushEvents.bind(sdk),
|
|
13025
14346
|
trackCustomEvent: sdk.trackCustomEvent.bind(sdk),
|
|
13026
|
-
|
|
13027
|
-
|
|
14347
|
+
// Selector generation
|
|
14348
|
+
generateSelector,
|
|
14349
|
+
generateSelectorFromElement,
|
|
14350
|
+
generateSelectorFromHTML,
|
|
14351
|
+
// PostHog-like methods
|
|
14352
|
+
capture: sdk.capture.bind(sdk),
|
|
14353
|
+
identify: sdk.identify.bind(sdk),
|
|
14354
|
+
reset: sdk.reset.bind(sdk),
|
|
14355
|
+
getDistinctId: sdk.getDistinctId.bind(sdk),
|
|
14356
|
+
register: sdk.register.bind(sdk),
|
|
14357
|
+
registerOnce: sdk.registerOnce.bind(sdk),
|
|
14358
|
+
unregister: sdk.unregister.bind(sdk),
|
|
14359
|
+
opt_out_capturing: sdk.opt_out_capturing.bind(sdk),
|
|
14360
|
+
opt_in_capturing: sdk.opt_in_capturing.bind(sdk),
|
|
14361
|
+
has_opted_out_capturing: sdk.has_opted_out_capturing.bind(sdk),
|
|
14362
|
+
has_opted_in_capturing: sdk.has_opted_in_capturing.bind(sdk),
|
|
14363
|
+
people: sdk.people,
|
|
14364
|
+
// Monitoring control
|
|
14365
|
+
startNetworkCapture: sdk.startNetworkCapture.bind(sdk),
|
|
14366
|
+
stopNetworkCapture: sdk.stopNetworkCapture.bind(sdk),
|
|
14367
|
+
startStorageCapture: sdk.startStorageCapture.bind(sdk),
|
|
14368
|
+
stopStorageCapture: sdk.stopStorageCapture.bind(sdk),
|
|
14369
|
+
startConsoleCapture: sdk.startConsoleCapture.bind(sdk),
|
|
14370
|
+
stopConsoleCapture: sdk.stopConsoleCapture.bind(sdk),
|
|
14371
|
+
getNetworkLogs: sdk.getNetworkLogs.bind(sdk),
|
|
14372
|
+
getStorageLogs: sdk.getStorageLogs.bind(sdk),
|
|
14373
|
+
getConsoleLogs: sdk.getConsoleLogs.bind(sdk)
|
|
14374
|
+
};
|
|
13028
14375
|
}
|
|
13029
14376
|
var index_default = sdk;
|
|
13030
14377
|
/*! Bundled license information:
|