@bentolabs/sdk 1.2.1 → 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 +1564 -173
- 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
|
|
|
@@ -9133,10 +9135,161 @@ function getDirectText$1(element) {
|
|
|
9133
9135
|
}
|
|
9134
9136
|
return text.replace(/\s+/g, " ").trim();
|
|
9135
9137
|
}
|
|
9136
|
-
function
|
|
9138
|
+
function getFullText$1(element) {
|
|
9139
|
+
return (element.textContent || "").replace(/\s+/g, " ").trim();
|
|
9140
|
+
}
|
|
9141
|
+
function getChildSignature(element) {
|
|
9142
|
+
const tags = Array.from(element.children).map(
|
|
9143
|
+
(c2) => c2.tagName.toLowerCase()
|
|
9144
|
+
);
|
|
9145
|
+
return tags.join(",");
|
|
9146
|
+
}
|
|
9147
|
+
function quickHash(str) {
|
|
9148
|
+
let hash = 5381;
|
|
9149
|
+
for (let i2 = 0; i2 < str.length; i2++) {
|
|
9150
|
+
hash = (hash << 5) + hash ^ str.charCodeAt(i2);
|
|
9151
|
+
}
|
|
9152
|
+
return (hash >>> 0).toString(16);
|
|
9153
|
+
}
|
|
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) {
|
|
9137
9263
|
const parts = [];
|
|
9138
9264
|
const tag = element.tagName.toLowerCase();
|
|
9139
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
|
+
}
|
|
9140
9293
|
const testId = element.getAttribute("data-testid");
|
|
9141
9294
|
if (testId) {
|
|
9142
9295
|
parts.push(`testid=${escapeValue(truncate(testId, 50))}`);
|
|
@@ -9185,16 +9338,54 @@ function buildBentoSelector(element) {
|
|
|
9185
9338
|
if (title) {
|
|
9186
9339
|
parts.push(`title=${escapeValue(truncate(title, 50))}`);
|
|
9187
9340
|
}
|
|
9188
|
-
const interactiveTags = [
|
|
9341
|
+
const interactiveTags = [
|
|
9342
|
+
"button",
|
|
9343
|
+
"a",
|
|
9344
|
+
"label",
|
|
9345
|
+
"span",
|
|
9346
|
+
"div",
|
|
9347
|
+
"li",
|
|
9348
|
+
"td",
|
|
9349
|
+
"th",
|
|
9350
|
+
"h1",
|
|
9351
|
+
"h2",
|
|
9352
|
+
"h3",
|
|
9353
|
+
"h4",
|
|
9354
|
+
"h5",
|
|
9355
|
+
"h6",
|
|
9356
|
+
"p"
|
|
9357
|
+
];
|
|
9189
9358
|
if (interactiveTags.includes(tag)) {
|
|
9190
|
-
|
|
9359
|
+
let text = getDirectText$1(element);
|
|
9360
|
+
if (!text) {
|
|
9361
|
+
text = getFullText$1(element);
|
|
9362
|
+
}
|
|
9191
9363
|
if (text) {
|
|
9192
9364
|
parts.push(`text=${escapeValue(truncate(text, 50))}`);
|
|
9193
9365
|
}
|
|
9194
9366
|
}
|
|
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) {
|
|
9374
|
+
const childSig = getChildSignature(element);
|
|
9375
|
+
if (childSig) {
|
|
9376
|
+
parts.push(`children=${childSig}`);
|
|
9377
|
+
} else {
|
|
9378
|
+
const attrs = Array.from(element.attributes).map((a2) => `${a2.name}=${a2.value}`).sort().join(";");
|
|
9379
|
+
parts.push(`hash=${quickHash(tag + attrs)}`);
|
|
9380
|
+
}
|
|
9381
|
+
}
|
|
9195
9382
|
return parts.join("|");
|
|
9196
9383
|
}
|
|
9197
|
-
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) {
|
|
9198
9389
|
const parser2 = new DOMParser();
|
|
9199
9390
|
const doc = parser2.parseFromString(outerHTML, "text/html");
|
|
9200
9391
|
const element = doc.body.firstElementChild;
|
|
@@ -9203,6 +9394,9 @@ function generateSelector(outerHTML) {
|
|
|
9203
9394
|
}
|
|
9204
9395
|
return buildBentoSelector(element);
|
|
9205
9396
|
}
|
|
9397
|
+
function generateSelector(outerHTML) {
|
|
9398
|
+
return generateSelectorFromHTML(outerHTML);
|
|
9399
|
+
}
|
|
9206
9400
|
var DEFAULT_OPTIONS = {
|
|
9207
9401
|
maxTextLength: 500,
|
|
9208
9402
|
includeOuterHTML: true,
|
|
@@ -9232,6 +9426,7 @@ function isInputElement(element) {
|
|
|
9232
9426
|
return tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT";
|
|
9233
9427
|
}
|
|
9234
9428
|
function extractElementContext(element, options = {}) {
|
|
9429
|
+
var _a2;
|
|
9235
9430
|
const opts = __spreadValues(__spreadValues({}, DEFAULT_OPTIONS), options.elementContextOptions);
|
|
9236
9431
|
const {
|
|
9237
9432
|
isClickEvent = false,
|
|
@@ -9295,7 +9490,8 @@ function extractElementContext(element, options = {}) {
|
|
|
9295
9490
|
}
|
|
9296
9491
|
if (isClickEvent) {
|
|
9297
9492
|
try {
|
|
9298
|
-
|
|
9493
|
+
const path = (_a2 = options.pathname) != null ? _a2 : typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
9494
|
+
context.bentoSelector = buildBentoSelector(element, path);
|
|
9299
9495
|
} catch (e) {
|
|
9300
9496
|
}
|
|
9301
9497
|
}
|
|
@@ -10131,6 +10327,7 @@ function initMouseInteractionObserver({
|
|
|
10131
10327
|
let currentPointerType = null;
|
|
10132
10328
|
const getHandler = (eventKey) => {
|
|
10133
10329
|
return (event) => {
|
|
10330
|
+
const pathname = typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
10134
10331
|
const target = getEventTarget(event);
|
|
10135
10332
|
if (isBlocked(target, blockClass, blockSelector, true)) {
|
|
10136
10333
|
return;
|
|
@@ -10181,7 +10378,9 @@ function initMouseInteractionObserver({
|
|
|
10181
10378
|
elementContextOptions,
|
|
10182
10379
|
isClickEvent,
|
|
10183
10380
|
maskInputOptions,
|
|
10184
|
-
maskInputFn
|
|
10381
|
+
maskInputFn,
|
|
10382
|
+
pathname
|
|
10383
|
+
// Pass pathname captured at event time
|
|
10185
10384
|
});
|
|
10186
10385
|
}
|
|
10187
10386
|
callbackWrapper(mouseInteractionCb)(__spreadValues(__spreadValues({
|
|
@@ -12576,6 +12775,641 @@ var { freezePage } = record;
|
|
|
12576
12775
|
var { takeFullSnapshot } = record;
|
|
12577
12776
|
|
|
12578
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
|
+
};
|
|
12579
13413
|
var BentoLabsSDK = class {
|
|
12580
13414
|
constructor() {
|
|
12581
13415
|
this.config = {
|
|
@@ -12584,43 +13418,114 @@ var BentoLabsSDK = class {
|
|
|
12584
13418
|
debug: false,
|
|
12585
13419
|
batchSize: 50,
|
|
12586
13420
|
batchInterval: 1e4,
|
|
12587
|
-
// 10 seconds
|
|
12588
13421
|
enableRecording: true,
|
|
12589
13422
|
maxRetries: 3,
|
|
12590
|
-
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
|
+
}
|
|
12591
13454
|
};
|
|
12592
13455
|
this.sessionId = "";
|
|
12593
13456
|
this.events = [];
|
|
12594
13457
|
this.isRecording = false;
|
|
12595
13458
|
this.batchTimer = null;
|
|
12596
13459
|
this.retryTimer = null;
|
|
12597
|
-
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;
|
|
12598
13476
|
}
|
|
12599
13477
|
/**
|
|
12600
13478
|
* Initialize the BentoLabs SDK
|
|
12601
|
-
* @param apiKey - Your API key for authentication
|
|
12602
|
-
* @param options - Optional configuration options
|
|
12603
13479
|
*/
|
|
12604
13480
|
init(apiKey, options) {
|
|
12605
|
-
var _a2;
|
|
12606
|
-
if (this.isRecording || this.
|
|
13481
|
+
var _a2, _b, _c;
|
|
13482
|
+
if (this.isRecording || this.stopRecordingFn) {
|
|
12607
13483
|
this.stopRecordingInternal();
|
|
12608
13484
|
}
|
|
12609
13485
|
const defaultOptions = {
|
|
12610
13486
|
endpoint: "https://api.bentolabs.ai",
|
|
12611
13487
|
debug: false,
|
|
12612
13488
|
batchSize: 100,
|
|
12613
|
-
|
|
12614
|
-
|
|
12615
|
-
// 30 seconds (increased from 10s)
|
|
13489
|
+
batchInterval: 5e3,
|
|
13490
|
+
// 5 seconds (PostHog-style)
|
|
12616
13491
|
enableRecording: true,
|
|
12617
13492
|
maxRetries: 3,
|
|
12618
|
-
baseRetryDelay: 1e3
|
|
12619
|
-
|
|
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
|
+
}
|
|
12620
13524
|
};
|
|
12621
13525
|
const mergedOptions = __spreadProps(__spreadValues(__spreadValues({}, defaultOptions), options), {
|
|
12622
|
-
|
|
12623
|
-
|
|
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)
|
|
12624
13529
|
});
|
|
12625
13530
|
this.config = {
|
|
12626
13531
|
apiKey,
|
|
@@ -12630,57 +13535,523 @@ var BentoLabsSDK = class {
|
|
|
12630
13535
|
batchInterval: mergedOptions.batchInterval,
|
|
12631
13536
|
enableRecording: mergedOptions.enableRecording,
|
|
12632
13537
|
maxRetries: mergedOptions.maxRetries,
|
|
12633
|
-
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
|
|
12634
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
|
+
}
|
|
12635
13574
|
this.sessionId = this.generateSessionId();
|
|
13575
|
+
this.initialized = true;
|
|
12636
13576
|
if (this.config.debug) {
|
|
12637
13577
|
console.log("[BentoLabsSDK] Initialized with config:", {
|
|
12638
13578
|
apiKey: apiKey.substring(0, 8) + "...",
|
|
12639
13579
|
endpoint: this.config.endpoint,
|
|
12640
13580
|
debug: this.config.debug,
|
|
12641
|
-
sessionId: this.sessionId
|
|
13581
|
+
sessionId: this.sessionId,
|
|
13582
|
+
distinctId: this.distinctId
|
|
12642
13583
|
});
|
|
12643
13584
|
}
|
|
12644
13585
|
this.startRecording();
|
|
12645
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
|
+
}
|
|
12646
13609
|
}
|
|
13610
|
+
// ============================================================================
|
|
13611
|
+
// Identity Methods
|
|
13612
|
+
// ============================================================================
|
|
12647
13613
|
/**
|
|
12648
|
-
*
|
|
13614
|
+
* Identify a user with a distinct ID and optional properties
|
|
12649
13615
|
*/
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
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
|
+
}
|
|
12653
13640
|
}
|
|
12654
13641
|
/**
|
|
12655
|
-
*
|
|
13642
|
+
* Reset the user to an anonymous state
|
|
12656
13643
|
*/
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
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
|
+
}
|
|
12666
13659
|
}
|
|
12667
13660
|
/**
|
|
12668
|
-
*
|
|
13661
|
+
* Get the current distinct ID
|
|
12669
13662
|
*/
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
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;
|
|
12674
13688
|
}
|
|
12675
|
-
return;
|
|
12676
13689
|
}
|
|
13690
|
+
if (Object.keys(newProps).length > 0) {
|
|
13691
|
+
this.register(newProps);
|
|
13692
|
+
}
|
|
13693
|
+
}
|
|
13694
|
+
/**
|
|
13695
|
+
* Remove a super property
|
|
13696
|
+
*/
|
|
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));
|
|
12677
13701
|
if (this.config.debug) {
|
|
12678
|
-
console.log(
|
|
12679
|
-
"[BentoLabsSDK] Starting recording for session:",
|
|
12680
|
-
this.sessionId
|
|
12681
|
-
);
|
|
13702
|
+
console.log("[BentoLabsSDK] Unregistered super property:", propertyName);
|
|
12682
13703
|
}
|
|
12683
|
-
|
|
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) {
|
|
13717
|
+
if (this.config.debug) {
|
|
13718
|
+
console.log("[BentoLabsSDK] Event not captured (opted out):", eventName);
|
|
13719
|
+
}
|
|
13720
|
+
return;
|
|
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
|
+
});
|
|
13738
|
+
if (this.config.debug) {
|
|
13739
|
+
console.log("[BentoLabsSDK] Captured event:", eventName, properties);
|
|
13740
|
+
}
|
|
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 {
|
|
12684
14055
|
if (this.config.debug) {
|
|
12685
14056
|
console.log("[BentoLabsSDK] Calling rrweb record()...");
|
|
12686
14057
|
}
|
|
@@ -12699,7 +14070,6 @@ var BentoLabsSDK = class {
|
|
|
12699
14070
|
recordCanvas: true,
|
|
12700
14071
|
collectFonts: true,
|
|
12701
14072
|
plugins: [],
|
|
12702
|
-
// Enable element context capture for rich metadata on interactions
|
|
12703
14073
|
captureElementContext: true,
|
|
12704
14074
|
elementContextOptions: {
|
|
12705
14075
|
maxTextLength: 500,
|
|
@@ -12707,33 +14077,28 @@ var BentoLabsSDK = class {
|
|
|
12707
14077
|
outerHTMLDepth: 2,
|
|
12708
14078
|
includeInputValues: true
|
|
12709
14079
|
},
|
|
12710
|
-
// Mask password inputs for security
|
|
12711
14080
|
maskInputOptions: {
|
|
12712
14081
|
password: true
|
|
12713
14082
|
},
|
|
12714
|
-
// Sampling and throttling to reduce event volume
|
|
12715
14083
|
sampling: {
|
|
12716
14084
|
mousemove: true,
|
|
12717
|
-
// Sample mouse movements
|
|
12718
14085
|
mouseInteraction: { click: false, dblclick: false },
|
|
12719
|
-
// Capture all clicks
|
|
12720
14086
|
scroll: 150,
|
|
12721
|
-
// Throttle scroll events to 150ms
|
|
12722
14087
|
input: "last"
|
|
12723
|
-
// Only record final input value
|
|
12724
14088
|
},
|
|
12725
14089
|
checkoutEveryNms: 5 * 60 * 1e3
|
|
12726
|
-
// Take full snapshot every 5 minutes
|
|
12727
14090
|
});
|
|
12728
14091
|
if (typeof stopFn === "function") {
|
|
12729
|
-
this.
|
|
14092
|
+
this.stopRecordingFn = stopFn;
|
|
12730
14093
|
this.isRecording = true;
|
|
12731
14094
|
if (this.config.debug) {
|
|
12732
14095
|
console.log("[BentoLabsSDK] Recording started successfully");
|
|
12733
14096
|
}
|
|
12734
14097
|
} else {
|
|
12735
|
-
console.error(
|
|
12736
|
-
|
|
14098
|
+
console.error(
|
|
14099
|
+
"[BentoLabsSDK] rrweb record() did not return a stop function. Recording may not have started properly."
|
|
14100
|
+
);
|
|
14101
|
+
this.stopRecordingFn = null;
|
|
12737
14102
|
this.isRecording = false;
|
|
12738
14103
|
}
|
|
12739
14104
|
} catch (error) {
|
|
@@ -12741,9 +14106,6 @@ var BentoLabsSDK = class {
|
|
|
12741
14106
|
this.isRecording = false;
|
|
12742
14107
|
}
|
|
12743
14108
|
}
|
|
12744
|
-
/**
|
|
12745
|
-
* Start batching events for transmission
|
|
12746
|
-
*/
|
|
12747
14109
|
startBatching() {
|
|
12748
14110
|
if (this.config.debug) {
|
|
12749
14111
|
console.log("[BentoLabsSDK] Starting event batching");
|
|
@@ -12755,31 +14117,22 @@ var BentoLabsSDK = class {
|
|
|
12755
14117
|
this.sendBatch();
|
|
12756
14118
|
}, this.config.batchInterval);
|
|
12757
14119
|
if (this.config.debug) {
|
|
12758
|
-
console.log(
|
|
12759
|
-
`[BentoLabsSDK] Batch timer set for ${this.config.batchInterval}ms intervals`
|
|
12760
|
-
);
|
|
14120
|
+
console.log(`[BentoLabsSDK] Batch timer set for ${this.config.batchInterval}ms intervals`);
|
|
12761
14121
|
}
|
|
12762
14122
|
}
|
|
12763
|
-
/**
|
|
12764
|
-
* Add an event to the events array
|
|
12765
|
-
*/
|
|
12766
14123
|
addEvent(event) {
|
|
14124
|
+
if (this.optedOut) return;
|
|
12767
14125
|
this.events.push(event);
|
|
12768
14126
|
if (this.config.debug) {
|
|
12769
14127
|
console.log("[BentoLabsSDK] Event added:", event.type);
|
|
12770
14128
|
}
|
|
12771
14129
|
if (this.events.length >= this.config.batchSize) {
|
|
12772
14130
|
if (this.config.debug) {
|
|
12773
|
-
console.log(
|
|
12774
|
-
`[BentoLabsSDK] Batch size limit reached (${this.config.batchSize}), sending batch`
|
|
12775
|
-
);
|
|
14131
|
+
console.log(`[BentoLabsSDK] Batch size limit reached (${this.config.batchSize}), sending batch`);
|
|
12776
14132
|
}
|
|
12777
14133
|
this.sendBatch();
|
|
12778
14134
|
}
|
|
12779
14135
|
}
|
|
12780
|
-
/**
|
|
12781
|
-
* Send batched events to the API with exponential backoff retry
|
|
12782
|
-
*/
|
|
12783
14136
|
async sendBatch() {
|
|
12784
14137
|
const now = Date.now();
|
|
12785
14138
|
const readyEvents = this.events.filter((event) => {
|
|
@@ -12797,12 +14150,11 @@ var BentoLabsSDK = class {
|
|
|
12797
14150
|
events: readyEvents,
|
|
12798
14151
|
timestamp: now,
|
|
12799
14152
|
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "Unknown",
|
|
12800
|
-
url: typeof window !== "undefined" ? window.location.href : "Unknown"
|
|
14153
|
+
url: typeof window !== "undefined" ? window.location.href : "Unknown",
|
|
14154
|
+
distinctId: this.distinctId
|
|
12801
14155
|
};
|
|
12802
14156
|
if (this.config.debug) {
|
|
12803
|
-
console.log(
|
|
12804
|
-
`[BentoLabsSDK] Sending batch with ${readyEvents.length} events`
|
|
12805
|
-
);
|
|
14157
|
+
console.log(`[BentoLabsSDK] Sending batch with ${readyEvents.length} events`);
|
|
12806
14158
|
}
|
|
12807
14159
|
try {
|
|
12808
14160
|
const response = await fetch(`${this.config.endpoint}/events/`, {
|
|
@@ -12830,43 +14182,30 @@ var BentoLabsSDK = class {
|
|
|
12830
14182
|
nextRetryTime: now + delay
|
|
12831
14183
|
});
|
|
12832
14184
|
});
|
|
12833
|
-
const eventsToRetry = retryableEvents.filter(
|
|
12834
|
-
(event) => event.retryCount <= this.config.maxRetries
|
|
12835
|
-
);
|
|
14185
|
+
const eventsToRetry = retryableEvents.filter((event) => event.retryCount <= this.config.maxRetries);
|
|
12836
14186
|
const droppedEvents = retryableEvents.length - eventsToRetry.length;
|
|
12837
14187
|
if (droppedEvents > 0 && this.config.debug) {
|
|
12838
|
-
console.log(
|
|
12839
|
-
`[BentoLabsSDK] Dropped ${droppedEvents} events after max retries`
|
|
12840
|
-
);
|
|
14188
|
+
console.log(`[BentoLabsSDK] Dropped ${droppedEvents} events after max retries`);
|
|
12841
14189
|
}
|
|
12842
14190
|
this.events.unshift(...eventsToRetry);
|
|
12843
14191
|
if (this.config.debug && eventsToRetry.length > 0) {
|
|
12844
14192
|
const nextRetryIn = Math.min(...eventsToRetry.map((e) => e.nextRetryTime)) - now;
|
|
12845
|
-
console.log(
|
|
12846
|
-
`[BentoLabsSDK] ${eventsToRetry.length} events re-queued for retry in ${nextRetryIn}ms`
|
|
12847
|
-
);
|
|
14193
|
+
console.log(`[BentoLabsSDK] ${eventsToRetry.length} events re-queued for retry in ${nextRetryIn}ms`);
|
|
12848
14194
|
}
|
|
12849
14195
|
this.scheduleRetry();
|
|
12850
14196
|
}
|
|
12851
14197
|
}
|
|
12852
|
-
/**
|
|
12853
|
-
* Schedule retry attempts for failed events
|
|
12854
|
-
*/
|
|
12855
14198
|
scheduleRetry() {
|
|
12856
14199
|
if (this.retryTimer) {
|
|
12857
14200
|
clearTimeout(this.retryTimer);
|
|
12858
14201
|
this.retryTimer = null;
|
|
12859
14202
|
}
|
|
12860
14203
|
const now = Date.now();
|
|
12861
|
-
const retryableEvents = this.events.filter(
|
|
12862
|
-
(event) => "nextRetryTime" in event
|
|
12863
|
-
);
|
|
14204
|
+
const retryableEvents = this.events.filter((event) => "nextRetryTime" in event);
|
|
12864
14205
|
if (retryableEvents.length === 0) {
|
|
12865
14206
|
return;
|
|
12866
14207
|
}
|
|
12867
|
-
const nextRetryTime = Math.min(
|
|
12868
|
-
...retryableEvents.map((e) => e.nextRetryTime)
|
|
12869
|
-
);
|
|
14208
|
+
const nextRetryTime = Math.min(...retryableEvents.map((e) => e.nextRetryTime));
|
|
12870
14209
|
const delay = Math.max(0, nextRetryTime - now);
|
|
12871
14210
|
if (this.config.debug) {
|
|
12872
14211
|
console.log(`[BentoLabsSDK] Scheduling retry in ${delay}ms`);
|
|
@@ -12875,13 +14214,10 @@ var BentoLabsSDK = class {
|
|
|
12875
14214
|
this.sendBatch();
|
|
12876
14215
|
}, delay);
|
|
12877
14216
|
}
|
|
12878
|
-
/**
|
|
12879
|
-
* Internal method to stop recording without logging (used during re-init)
|
|
12880
|
-
*/
|
|
12881
14217
|
stopRecordingInternal() {
|
|
12882
|
-
if (this.
|
|
12883
|
-
this.
|
|
12884
|
-
this.
|
|
14218
|
+
if (this.stopRecordingFn) {
|
|
14219
|
+
this.stopRecordingFn();
|
|
14220
|
+
this.stopRecordingFn = null;
|
|
12885
14221
|
}
|
|
12886
14222
|
if (this.batchTimer) {
|
|
12887
14223
|
clearInterval(this.batchTimer);
|
|
@@ -12891,86 +14227,115 @@ var BentoLabsSDK = class {
|
|
|
12891
14227
|
clearTimeout(this.retryTimer);
|
|
12892
14228
|
this.retryTimer = null;
|
|
12893
14229
|
}
|
|
14230
|
+
if (this.autocaptureCleanup) {
|
|
14231
|
+
this.autocaptureCleanup();
|
|
14232
|
+
this.autocaptureCleanup = null;
|
|
14233
|
+
}
|
|
12894
14234
|
this.isRecording = false;
|
|
12895
14235
|
}
|
|
12896
|
-
|
|
12897
|
-
|
|
12898
|
-
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
|
|
12902
|
-
|
|
12903
|
-
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
|
|
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
|
+
};
|
|
12907
14309
|
if (this.config.debug) {
|
|
12908
|
-
console.log("[BentoLabsSDK]
|
|
14310
|
+
console.log("[BentoLabsSDK] Autocapture setup complete");
|
|
12909
14311
|
}
|
|
12910
14312
|
}
|
|
12911
|
-
|
|
12912
|
-
|
|
12913
|
-
|
|
12914
|
-
|
|
12915
|
-
return this.sessionId;
|
|
12916
|
-
}
|
|
12917
|
-
/**
|
|
12918
|
-
* Check if recording is active
|
|
12919
|
-
*/
|
|
12920
|
-
isRecordingActive() {
|
|
12921
|
-
return this.isRecording;
|
|
12922
|
-
}
|
|
12923
|
-
/**
|
|
12924
|
-
* Get current configuration (without exposing sensitive data)
|
|
12925
|
-
*/
|
|
12926
|
-
getConfig() {
|
|
12927
|
-
return {
|
|
12928
|
-
apiKey: this.config.apiKey ? this.config.apiKey.substring(0, 8) + "..." : "",
|
|
12929
|
-
endpoint: this.config.endpoint,
|
|
12930
|
-
debug: this.config.debug,
|
|
12931
|
-
batchSize: this.config.batchSize,
|
|
12932
|
-
batchInterval: this.config.batchInterval,
|
|
12933
|
-
enableRecording: this.config.enableRecording,
|
|
12934
|
-
maxRetries: this.config.maxRetries,
|
|
12935
|
-
baseRetryDelay: this.config.baseRetryDelay
|
|
12936
|
-
};
|
|
12937
|
-
}
|
|
12938
|
-
/**
|
|
12939
|
-
* Get current event queue length
|
|
12940
|
-
*/
|
|
12941
|
-
getEventQueueLength() {
|
|
12942
|
-
return this.events.length;
|
|
12943
|
-
}
|
|
12944
|
-
/**
|
|
12945
|
-
* Manually trigger a batch send
|
|
12946
|
-
*/
|
|
12947
|
-
async flushEvents() {
|
|
12948
|
-
await this.sendBatch();
|
|
12949
|
-
}
|
|
12950
|
-
/**
|
|
12951
|
-
* Track a custom event with custom data
|
|
12952
|
-
* @param eventName - Name of the custom event
|
|
12953
|
-
* @param data - Custom event data (will be JSON stringified)
|
|
12954
|
-
*/
|
|
12955
|
-
trackCustomEvent(eventName, data) {
|
|
12956
|
-
if (!this.sessionId) {
|
|
12957
|
-
console.warn("[BentoLabsSDK] Cannot track event: SDK not initialized");
|
|
12958
|
-
return;
|
|
12959
|
-
}
|
|
12960
|
-
this.addEvent({
|
|
12961
|
-
timestamp: Date.now(),
|
|
12962
|
-
type: `custom:${eventName}`,
|
|
12963
|
-
data: data || {},
|
|
12964
|
-
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 : ""
|
|
12965
14317
|
});
|
|
12966
|
-
if (this.
|
|
12967
|
-
|
|
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 = [];
|
|
12968
14332
|
}
|
|
12969
14333
|
}
|
|
12970
14334
|
};
|
|
12971
14335
|
var sdk = new BentoLabsSDK();
|
|
12972
14336
|
if (typeof window !== "undefined") {
|
|
12973
|
-
window.BentoLabsSDK =
|
|
14337
|
+
window.BentoLabsSDK = {
|
|
14338
|
+
// Core methods
|
|
12974
14339
|
init: sdk.init.bind(sdk),
|
|
12975
14340
|
stop: sdk.stop.bind(sdk),
|
|
12976
14341
|
getSessionId: sdk.getSessionId.bind(sdk),
|
|
@@ -12979,8 +14344,34 @@ if (typeof window !== "undefined") {
|
|
|
12979
14344
|
getEventQueueLength: sdk.getEventQueueLength.bind(sdk),
|
|
12980
14345
|
flushEvents: sdk.flushEvents.bind(sdk),
|
|
12981
14346
|
trackCustomEvent: sdk.trackCustomEvent.bind(sdk),
|
|
12982
|
-
|
|
12983
|
-
|
|
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
|
+
};
|
|
12984
14375
|
}
|
|
12985
14376
|
var index_default = sdk;
|
|
12986
14377
|
/*! Bundled license information:
|