@sightspool/sdk 0.3.0 → 0.4.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/CHANGELOG.md +15 -0
- package/README.md +111 -333
- package/SECURITY.md +16 -0
- package/dist/index.cjs +159 -1226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -41
- package/dist/index.d.ts +20 -41
- package/dist/index.js +160 -761
- package/dist/index.js.map +1 -1
- package/dist/release.json +21 -0
- package/dist/sdk.global.js +2 -59
- package/dist/sdk.global.js.map +1 -1
- package/dist/source.json +11 -0
- package/package.json +14 -12
- package/site/CNAME +1 -0
- package/site/demo.html +6 -0
- package/site/demo.js +27 -0
- package/site/index.html +74 -0
- package/site/release.js +20 -0
- package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/release.json +21 -0
- package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js +3 -0
- package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js.map +1 -0
- package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/source.json +11 -0
- package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/release.json +21 -0
- package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js +3 -0
- package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js.map +1 -0
- package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/source.json +11 -0
- package/site/styles.css +69 -0
- package/site/trust.html +36 -0
- package/dist/chunk-4PADVIIO.js +0 -41
- package/dist/chunk-4PADVIIO.js.map +0 -1
- package/dist/probe-BNGMQQ5C.js +0 -113
- package/dist/probe-BNGMQQ5C.js.map +0 -1
- package/dist/prompt-GDFYC75D.js +0 -139
- package/dist/prompt-GDFYC75D.js.map +0 -1
- package/dist/survey-CICJQ5VI.js +0 -145
- package/dist/survey-CICJQ5VI.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,808 +1,207 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return "";
|
|
1
|
+
// src/research.ts
|
|
2
|
+
var slot = /* @__PURE__ */ Symbol.for("sightspool.research.runtime.v1");
|
|
3
|
+
var host = () => typeof window === "undefined" ? null : window;
|
|
4
|
+
var current = () => {
|
|
5
|
+
var _a;
|
|
6
|
+
return (_a = host()) == null ? void 0 : _a[slot];
|
|
7
|
+
};
|
|
8
|
+
var eligible = (r) => r.audience === "all_visitors" || r.identified;
|
|
9
|
+
function remove(r) {
|
|
10
|
+
var _a;
|
|
11
|
+
(_a = r.button) == null ? void 0 : _a.remove();
|
|
12
|
+
r.button = null;
|
|
13
|
+
r.offer = null;
|
|
14
|
+
}
|
|
15
|
+
function invalidate(r) {
|
|
16
|
+
var _a;
|
|
17
|
+
r.generation += 1;
|
|
18
|
+
(_a = r.pending) == null ? void 0 : _a.abort();
|
|
19
|
+
r.pending = null;
|
|
20
|
+
remove(r);
|
|
21
|
+
}
|
|
22
|
+
function status(r, value) {
|
|
23
|
+
r.status = value;
|
|
24
|
+
}
|
|
25
|
+
async function check(r) {
|
|
26
|
+
if (r.disposed || r.paused || !eligible(r) || r.pending || document.visibilityState !== "visible") return;
|
|
27
|
+
const generation = r.generation;
|
|
28
|
+
const request = new AbortController();
|
|
29
|
+
r.pending = request;
|
|
30
|
+
const timeout = window.setTimeout(() => request.abort(), 1e4);
|
|
31
|
+
if (!r.button) status(r, "checking");
|
|
32
|
+
try {
|
|
33
|
+
const response = await fetch(r.endpoint + "/widget-offer", {
|
|
34
|
+
method: "POST",
|
|
35
|
+
credentials: "omit",
|
|
36
|
+
cache: "no-store",
|
|
37
|
+
referrerPolicy: "no-referrer",
|
|
38
|
+
headers: { "Content-Type": "application/json" },
|
|
39
|
+
body: JSON.stringify({ operation: "offer", key: r.key, device: r.device }),
|
|
40
|
+
signal: request.signal
|
|
41
|
+
});
|
|
42
|
+
if (!response.ok) throw Error("offer unavailable");
|
|
43
|
+
const result = await response.json();
|
|
44
|
+
if (r.disposed || generation !== r.generation || r.paused || !eligible(r)) return;
|
|
45
|
+
if (result.available !== true || typeof result.offer !== "string" || !result.offer) {
|
|
46
|
+
remove(r);
|
|
47
|
+
status(r, "unavailable");
|
|
48
|
+
return;
|
|
50
49
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
recentClicks = recentClicks.filter((ts) => t - ts <= RAGE_WINDOW_MS);
|
|
61
|
-
recentClicks.push(t);
|
|
62
|
-
const isRage = recentClicks.length >= RAGE_COUNT;
|
|
63
|
-
push(isRage ? "rage_click" : "click", label);
|
|
64
|
-
const routeBefore = currentRoute();
|
|
65
|
-
let mutated = false;
|
|
66
|
-
let observer = null;
|
|
50
|
+
r.offer = result.offer;
|
|
51
|
+
status(r, "available");
|
|
52
|
+
if (r.button) return;
|
|
53
|
+
const button = document.createElement("button");
|
|
54
|
+
button.type = "button";
|
|
55
|
+
button.textContent = "Talk to the founder \xB7 5 min";
|
|
56
|
+
button.setAttribute("aria-label", "Sightspool: join a five-minute user interview");
|
|
57
|
+
button.style.cssText = "position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)";
|
|
58
|
+
button.onclick = () => {
|
|
67
59
|
try {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
} catch (e) {
|
|
73
|
-
}
|
|
74
|
-
window.setTimeout(() => {
|
|
75
|
-
try {
|
|
76
|
-
observer == null ? void 0 : observer.disconnect();
|
|
77
|
-
if (!mutated && currentRoute() === routeBefore && label) {
|
|
78
|
-
push("dead_click", label);
|
|
79
|
-
}
|
|
80
|
-
} catch (e) {
|
|
81
|
-
}
|
|
82
|
-
}, DEAD_CLICK_MS);
|
|
83
|
-
} catch (e) {
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
function onError(ev) {
|
|
87
|
-
try {
|
|
88
|
-
lastError = String(ev.message || "error");
|
|
89
|
-
push("error", lastError);
|
|
90
|
-
} catch (e) {
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function onRejection(ev) {
|
|
94
|
-
try {
|
|
95
|
-
const reason = ev.reason;
|
|
96
|
-
lastError = reason instanceof Error ? reason.message : String(reason);
|
|
97
|
-
push("error", lastError);
|
|
98
|
-
} catch (e) {
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function installRouteTracking() {
|
|
102
|
-
try {
|
|
103
|
-
const fire = () => push("route", currentRoute());
|
|
104
|
-
const origPush = history.pushState;
|
|
105
|
-
const origReplace = history.replaceState;
|
|
106
|
-
history.pushState = function(...args) {
|
|
107
|
-
const r = origPush.apply(this, args);
|
|
108
|
-
fire();
|
|
109
|
-
return r;
|
|
110
|
-
};
|
|
111
|
-
history.replaceState = function(...args) {
|
|
112
|
-
const r = origReplace.apply(this, args);
|
|
113
|
-
fire();
|
|
114
|
-
return r;
|
|
115
|
-
};
|
|
116
|
-
window.addEventListener("popstate", fire);
|
|
117
|
-
cleanups.push(() => {
|
|
118
|
-
history.pushState = origPush;
|
|
119
|
-
history.replaceState = origReplace;
|
|
120
|
-
window.removeEventListener("popstate", fire);
|
|
121
|
-
});
|
|
122
|
-
push("route", currentRoute());
|
|
123
|
-
} catch (e) {
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function installFetchTracking() {
|
|
127
|
-
try {
|
|
128
|
-
if (typeof window.fetch !== "function") return;
|
|
129
|
-
const orig = window.fetch.bind(window);
|
|
130
|
-
window.fetch = async (...args) => {
|
|
131
|
-
try {
|
|
132
|
-
const res = await orig(...args);
|
|
133
|
-
if (!res.ok) push("request_error", `HTTP ${res.status}`);
|
|
134
|
-
return res;
|
|
135
|
-
} catch (err) {
|
|
136
|
-
push("request_error", err instanceof Error ? err.message : "network error");
|
|
137
|
-
throw err;
|
|
60
|
+
if (r.disposed || r.paused || !eligible(r) || !r.offer) return;
|
|
61
|
+
if (r.popup && !r.popup.closed) {
|
|
62
|
+
r.popup.focus();
|
|
63
|
+
return;
|
|
138
64
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
window.fetch = orig;
|
|
142
|
-
});
|
|
143
|
-
} catch (e) {
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return {
|
|
147
|
-
start() {
|
|
148
|
-
if (started || !hasDom()) return;
|
|
149
|
-
started = true;
|
|
150
|
-
try {
|
|
151
|
-
document.addEventListener("click", onClick, true);
|
|
152
|
-
window.addEventListener("error", onError);
|
|
153
|
-
window.addEventListener("unhandledrejection", onRejection);
|
|
154
|
-
cleanups.push(() => {
|
|
155
|
-
document.removeEventListener("click", onClick, true);
|
|
156
|
-
window.removeEventListener("error", onError);
|
|
157
|
-
window.removeEventListener("unhandledrejection", onRejection);
|
|
158
|
-
});
|
|
159
|
-
installRouteTracking();
|
|
160
|
-
installFetchTracking();
|
|
65
|
+
const hash = new URLSearchParams({ offer: r.offer, device: r.device });
|
|
66
|
+
r.popup = window.open(r.endpoint + "/interview-widget#" + hash, "sightspool-interview", "popup,width=520,height=760");
|
|
161
67
|
} catch (e) {
|
|
162
68
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
for (const c of cleanups.splice(0)) {
|
|
167
|
-
try {
|
|
168
|
-
c();
|
|
169
|
-
} catch (e) {
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
trail() {
|
|
174
|
-
return buf.slice();
|
|
175
|
-
},
|
|
176
|
-
route: currentRoute,
|
|
177
|
-
label: currentLabel,
|
|
178
|
-
error() {
|
|
179
|
-
return lastError;
|
|
180
|
-
},
|
|
181
|
-
onEvent(cb) {
|
|
182
|
-
subs.push(cb);
|
|
183
|
-
},
|
|
184
|
-
recordSearch(query, zeroResult) {
|
|
185
|
-
const q = query.trim();
|
|
186
|
-
if (!q) return;
|
|
187
|
-
push(zeroResult ? "zero_result" : "search", q);
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// src/harvest.ts
|
|
193
|
-
var SEARCH_HINT_RE = /search|filter|find|query|command|lookup/i;
|
|
194
|
-
var DEBOUNCE_MS = 800;
|
|
195
|
-
function looksLikeSearch(el) {
|
|
196
|
-
try {
|
|
197
|
-
const input = el;
|
|
198
|
-
if (input.type === "search") return true;
|
|
199
|
-
const role = el.getAttribute("role") || "";
|
|
200
|
-
if (role === "searchbox" || role === "combobox") return true;
|
|
201
|
-
const hay = [
|
|
202
|
-
input.name,
|
|
203
|
-
input.placeholder,
|
|
204
|
-
el.getAttribute("aria-label"),
|
|
205
|
-
el.id,
|
|
206
|
-
el.className
|
|
207
|
-
].filter(Boolean).join(" ");
|
|
208
|
-
return SEARCH_HINT_RE.test(hay);
|
|
69
|
+
};
|
|
70
|
+
r.button = button;
|
|
71
|
+
document.body.appendChild(button);
|
|
209
72
|
} catch (e) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
function createHarvest(capture, opts) {
|
|
214
|
-
var _a2, _b;
|
|
215
|
-
let hint;
|
|
216
|
-
let timer = null;
|
|
217
|
-
let started = false;
|
|
218
|
-
const redactSelectors = (_a2 = opts.redact) != null ? _a2 : [];
|
|
219
|
-
const blockSelectors = (_b = opts.block) != null ? _b : [];
|
|
220
|
-
function onInput(ev) {
|
|
221
|
-
try {
|
|
222
|
-
const target = ev.target;
|
|
223
|
-
if (!target || target.tagName !== "INPUT" && target.tagName !== "TEXTAREA") return;
|
|
224
|
-
if (!looksLikeSearch(target)) return;
|
|
225
|
-
if (isIgnoredElement(target, blockSelectors) || matchesRedactSelector(target, redactSelectors))
|
|
226
|
-
return;
|
|
227
|
-
const value = (target.value || "").trim();
|
|
228
|
-
if (value.length < 2) return;
|
|
229
|
-
if (timer !== null) window.clearTimeout(timer);
|
|
230
|
-
timer = window.setTimeout(() => {
|
|
231
|
-
hint = value;
|
|
232
|
-
capture.recordSearch(value);
|
|
233
|
-
if (opts.debug) console.debug("[sightspool] harvested intent", value);
|
|
234
|
-
}, DEBOUNCE_MS);
|
|
235
|
-
} catch (e) {
|
|
73
|
+
if (!r.disposed && generation === r.generation) {
|
|
74
|
+
remove(r);
|
|
75
|
+
status(r, "error");
|
|
236
76
|
}
|
|
77
|
+
} finally {
|
|
78
|
+
window.clearTimeout(timeout);
|
|
79
|
+
if (r.pending === request) r.pending = null;
|
|
237
80
|
}
|
|
238
|
-
return {
|
|
239
|
-
start() {
|
|
240
|
-
if (started || typeof document === "undefined") return;
|
|
241
|
-
started = true;
|
|
242
|
-
try {
|
|
243
|
-
document.addEventListener("input", onInput, true);
|
|
244
|
-
} catch (e) {
|
|
245
|
-
}
|
|
246
|
-
},
|
|
247
|
-
stop() {
|
|
248
|
-
started = false;
|
|
249
|
-
try {
|
|
250
|
-
document.removeEventListener("input", onInput, true);
|
|
251
|
-
if (timer !== null) window.clearTimeout(timer);
|
|
252
|
-
} catch (e) {
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
lastIntentHint() {
|
|
256
|
-
return hint;
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
81
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const body = { key: opts.key, identity, signals };
|
|
273
|
-
const json = JSON.stringify(body);
|
|
274
|
-
try {
|
|
275
|
-
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
276
|
-
const blob = new Blob([json], { type: "text/plain" });
|
|
277
|
-
const ok = navigator.sendBeacon(url, blob);
|
|
278
|
-
if (ok) {
|
|
279
|
-
if (opts.debug) console.debug("[sightspool] beacon", signals.length);
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
void fetch(url, {
|
|
284
|
-
method: "POST",
|
|
285
|
-
headers: { "Content-Type": "text/plain" },
|
|
286
|
-
body: json,
|
|
287
|
-
keepalive: true,
|
|
288
|
-
mode: "cors",
|
|
289
|
-
credentials: "omit"
|
|
290
|
-
}).catch(() => {
|
|
291
|
-
});
|
|
292
|
-
} catch (e) {
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
function onVisibility() {
|
|
82
|
+
function init(config) {
|
|
83
|
+
try {
|
|
84
|
+
const browser = host();
|
|
85
|
+
if (!browser || !config || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(config.key)) return;
|
|
86
|
+
if (config.audience !== "all_visitors" && config.audience !== "signed_in") return;
|
|
87
|
+
const url = new URL(config.endpoint || "https://www.sightspool.com");
|
|
88
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) return;
|
|
89
|
+
if (url.username || url.password) return;
|
|
90
|
+
const previous = current();
|
|
91
|
+
if (previous && previous.key === config.key && previous.endpoint === url.origin && previous.audience === config.audience) return;
|
|
92
|
+
if (previous) destroy();
|
|
93
|
+
let device = "";
|
|
296
94
|
try {
|
|
297
|
-
|
|
95
|
+
device = sessionStorage.getItem("sightspool-widget-device:" + config.key) || "";
|
|
298
96
|
} catch (e) {
|
|
299
97
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const batch = queue;
|
|
304
|
-
queue = [];
|
|
305
|
-
send(batch);
|
|
306
|
-
}
|
|
307
|
-
return {
|
|
308
|
-
start() {
|
|
309
|
-
if (started || typeof window === "undefined") return;
|
|
310
|
-
started = true;
|
|
98
|
+
if (!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(device)) {
|
|
99
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
100
|
+
device = "ss_fcd_" + btoa(String.fromCharCode(...bytes)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
311
101
|
try {
|
|
312
|
-
|
|
313
|
-
window.addEventListener("pagehide", flush);
|
|
314
|
-
interval = window.setInterval(flush, FLUSH_INTERVAL_MS);
|
|
102
|
+
sessionStorage.setItem("sightspool-widget-device:" + config.key, device);
|
|
315
103
|
} catch (e) {
|
|
316
104
|
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
105
|
+
}
|
|
106
|
+
const r = {
|
|
107
|
+
key: config.key,
|
|
108
|
+
endpoint: url.origin,
|
|
109
|
+
audience: config.audience,
|
|
110
|
+
identified: false,
|
|
111
|
+
paused: false,
|
|
112
|
+
disposed: false,
|
|
113
|
+
generation: 0,
|
|
114
|
+
device,
|
|
115
|
+
offer: null,
|
|
116
|
+
button: null,
|
|
117
|
+
popup: null,
|
|
118
|
+
pending: null,
|
|
119
|
+
timer: 0,
|
|
120
|
+
visibility: () => {
|
|
121
|
+
},
|
|
122
|
+
status: "signed_out"
|
|
123
|
+
};
|
|
124
|
+
browser[slot] = r;
|
|
125
|
+
r.visibility = () => {
|
|
320
126
|
try {
|
|
321
|
-
document.
|
|
322
|
-
|
|
323
|
-
|
|
127
|
+
if (document.visibilityState === "visible") void check(r);
|
|
128
|
+
else {
|
|
129
|
+
invalidate(r);
|
|
130
|
+
status(r, r.paused ? "paused" : eligible(r) ? "unavailable" : "signed_out");
|
|
131
|
+
}
|
|
324
132
|
} catch (e) {
|
|
325
133
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
flush,
|
|
333
|
-
setIdentity(next) {
|
|
334
|
-
identity = next;
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// src/triggers.ts
|
|
340
|
-
var RAGE_CLICK_COUNT = 3;
|
|
341
|
-
var RAGE_WINDOW_MS2 = 1e3;
|
|
342
|
-
var FRICTION_RETRY_COUNT = 3;
|
|
343
|
-
var FRICTION_WINDOW_MS = 8e3;
|
|
344
|
-
function detectFriction(trail, now, windowMs = FRICTION_WINDOW_MS) {
|
|
345
|
-
var _a2;
|
|
346
|
-
const recent = trail.filter((e) => now - e.t <= windowMs);
|
|
347
|
-
if (recent.some((e) => e.type === "error" || e.type === "request_error")) return "error";
|
|
348
|
-
const clicks = recent.filter((e) => e.type === "click" || e.type === "rage_click");
|
|
349
|
-
for (let i = 0; i < clicks.length; i++) {
|
|
350
|
-
const burst = clicks.filter(
|
|
351
|
-
(e) => e.t >= clicks[i].t && e.t - clicks[i].t <= RAGE_WINDOW_MS2
|
|
352
|
-
);
|
|
353
|
-
if (burst.length >= RAGE_CLICK_COUNT) return "rage";
|
|
354
|
-
}
|
|
355
|
-
if (recent.some((e) => e.type === "dead_click")) return "dead_end";
|
|
356
|
-
const byLabel = /* @__PURE__ */ new Map();
|
|
357
|
-
for (const e of clicks) {
|
|
358
|
-
if (!e.label) continue;
|
|
359
|
-
const n = ((_a2 = byLabel.get(e.label)) != null ? _a2 : 0) + 1;
|
|
360
|
-
byLabel.set(e.label, n);
|
|
361
|
-
if (n >= FRICTION_RETRY_COUNT) return "retry";
|
|
362
|
-
}
|
|
363
|
-
return null;
|
|
364
|
-
}
|
|
365
|
-
var DEFAULT_CAPS = {
|
|
366
|
-
maxPromptsPerSession: 1,
|
|
367
|
-
cooldownMs: 5 * 6e4
|
|
368
|
-
};
|
|
369
|
-
function canPrompt(state, now, caps = DEFAULT_CAPS) {
|
|
370
|
-
if (state.promptsShown >= caps.maxPromptsPerSession) return false;
|
|
371
|
-
if (state.lastPromptAt !== null && now - state.lastPromptAt < caps.cooldownMs) return false;
|
|
372
|
-
return true;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// src/intervention.ts
|
|
376
|
-
var RENDERABLE = /* @__PURE__ */ new Set(["survey", "demand_probe"]);
|
|
377
|
-
function str(v, max) {
|
|
378
|
-
if (typeof v !== "string") return void 0;
|
|
379
|
-
const t = v.trim();
|
|
380
|
-
return t ? t.slice(0, max) : void 0;
|
|
381
|
-
}
|
|
382
|
-
function buildServeContext(route, identity) {
|
|
383
|
-
const ctx = {};
|
|
384
|
-
const r = str(route, 500);
|
|
385
|
-
if (r) ctx.route = r;
|
|
386
|
-
const account = str(identity == null ? void 0 : identity.account, 200);
|
|
387
|
-
if (account) ctx.account = account;
|
|
388
|
-
const plan = str(identity == null ? void 0 : identity.plan, 80);
|
|
389
|
-
if (plan) ctx.plan = plan;
|
|
390
|
-
return ctx;
|
|
391
|
-
}
|
|
392
|
-
function normalizeServed(raw) {
|
|
393
|
-
if (!raw || typeof raw !== "object") return null;
|
|
394
|
-
const r = raw;
|
|
395
|
-
const id = str(r.id, 64);
|
|
396
|
-
const type = str(r.type, 40);
|
|
397
|
-
if (!id || !type || !RENDERABLE.has(type)) return null;
|
|
398
|
-
const cfg = r.config && typeof r.config === "object" ? r.config : {};
|
|
399
|
-
if (type === "demand_probe") {
|
|
400
|
-
const label = str(cfg.label, 200);
|
|
401
|
-
const disclosure = str(cfg.disclosure, 300);
|
|
402
|
-
if (!label || !disclosure) return null;
|
|
403
|
-
const rawSlot = str(cfg.slot, 64);
|
|
404
|
-
const slot = rawSlot && /^[a-z0-9][a-z0-9_-]*$/i.test(rawSlot) ? rawSlot : void 0;
|
|
405
|
-
return { id, type, config: { label, disclosure, ...slot ? { slot } : {} } };
|
|
406
|
-
}
|
|
407
|
-
const question = str(cfg.question, 500);
|
|
408
|
-
if (!question) return null;
|
|
409
|
-
const options = Array.isArray(cfg.options) ? cfg.options.map((o) => str(o, 200)).filter((o) => !!o).slice(0, 6) : void 0;
|
|
410
|
-
const config = {
|
|
411
|
-
question,
|
|
412
|
-
...options && options.length ? { options } : {},
|
|
413
|
-
allow_text: cfg.allow_text === true
|
|
414
|
-
};
|
|
415
|
-
return { id, type: "survey", config };
|
|
416
|
-
}
|
|
417
|
-
function pickRespondentKey(userId, persisted, sessionRef) {
|
|
418
|
-
const uid = str(userId, 200);
|
|
419
|
-
if (uid) return uid;
|
|
420
|
-
const p = str(persisted, 200);
|
|
421
|
-
if (p) return p;
|
|
422
|
-
return sessionRef;
|
|
423
|
-
}
|
|
424
|
-
var RK_STORAGE_KEY = "sightspool_rk";
|
|
425
|
-
function getRespondentKey(identity, sessionRef) {
|
|
426
|
-
const uid = str(identity == null ? void 0 : identity.userId, 200);
|
|
427
|
-
if (uid) return uid;
|
|
428
|
-
try {
|
|
429
|
-
let v = localStorage.getItem(RK_STORAGE_KEY);
|
|
430
|
-
if (!v) {
|
|
431
|
-
v = "anon-" + Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
432
|
-
localStorage.setItem(RK_STORAGE_KEY, v);
|
|
433
|
-
}
|
|
434
|
-
return pickRespondentKey(void 0, v, sessionRef);
|
|
435
|
-
} catch (e) {
|
|
436
|
-
return sessionRef;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
function serveUrl(endpoint, path) {
|
|
440
|
-
return `${endpoint.replace(/\/+$/, "")}/api/sdk/${path}`;
|
|
441
|
-
}
|
|
442
|
-
async function fetchIntervention(opts) {
|
|
443
|
-
var _a2;
|
|
444
|
-
try {
|
|
445
|
-
if (typeof fetch !== "function") return null;
|
|
446
|
-
const res = await fetch(serveUrl(opts.endpoint, "serve"), {
|
|
447
|
-
method: "POST",
|
|
448
|
-
headers: { "Content-Type": "text/plain" },
|
|
449
|
-
body: JSON.stringify({
|
|
450
|
-
key: opts.key,
|
|
451
|
-
context: opts.ctx,
|
|
452
|
-
respondent_key: opts.respondentKey
|
|
453
|
-
}),
|
|
454
|
-
mode: "cors",
|
|
455
|
-
credentials: "omit"
|
|
456
|
-
});
|
|
457
|
-
if (!res.ok) return null;
|
|
458
|
-
const data = await res.json();
|
|
459
|
-
const served = normalizeServed(data == null ? void 0 : data.intervention);
|
|
460
|
-
if (opts.debug) console.debug("[sightspool] serve", (_a2 = served == null ? void 0 : served.id) != null ? _a2 : "(none)");
|
|
461
|
-
return served;
|
|
462
|
-
} catch (e) {
|
|
463
|
-
return null;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
function submitResponse(opts) {
|
|
467
|
-
try {
|
|
468
|
-
const url = serveUrl(opts.endpoint, "respond");
|
|
469
|
-
const json = JSON.stringify({
|
|
470
|
-
key: opts.key,
|
|
471
|
-
intervention_id: opts.interventionId,
|
|
472
|
-
response: opts.response,
|
|
473
|
-
respondent_key: opts.respondentKey
|
|
474
|
-
});
|
|
475
|
-
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
476
|
-
const blob = new Blob([json], { type: "text/plain" });
|
|
477
|
-
if (navigator.sendBeacon(url, blob)) return;
|
|
478
|
-
}
|
|
479
|
-
if (typeof fetch === "function") {
|
|
480
|
-
void fetch(url, {
|
|
481
|
-
method: "POST",
|
|
482
|
-
headers: { "Content-Type": "text/plain" },
|
|
483
|
-
body: json,
|
|
484
|
-
keepalive: true,
|
|
485
|
-
mode: "cors",
|
|
486
|
-
credentials: "omit"
|
|
487
|
-
}).catch(() => {
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
} catch (e) {
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// src/env.ts
|
|
495
|
-
var LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1", ""]);
|
|
496
|
-
function isLocalhost(hostname) {
|
|
497
|
-
const h = (hostname != null ? hostname : "").trim().toLowerCase();
|
|
498
|
-
if (LOCAL_HOSTS.has(h)) return true;
|
|
499
|
-
return h.endsWith(".local") || h.endsWith(".localhost");
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// src/index.ts
|
|
503
|
-
var DEFAULT_ENDPOINT = "https://www.sightspool.com";
|
|
504
|
-
var FRICTION_EMIT_COOLDOWN_MS = 3e4;
|
|
505
|
-
var EVENT_DEBOUNCE_MS = 600;
|
|
506
|
-
var SERVE_SETTLE_MS = 2500;
|
|
507
|
-
var MAX_INTERVENTIONS_PER_SESSION = 1;
|
|
508
|
-
function currentHostname() {
|
|
509
|
-
try {
|
|
510
|
-
return typeof location !== "undefined" ? location.hostname : "";
|
|
511
|
-
} catch (e) {
|
|
512
|
-
return "";
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
var ctrl = null;
|
|
516
|
-
function uuid() {
|
|
517
|
-
try {
|
|
518
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
519
|
-
return crypto.randomUUID();
|
|
520
|
-
}
|
|
134
|
+
};
|
|
135
|
+
document.addEventListener("visibilitychange", r.visibility);
|
|
136
|
+
r.timer = window.setInterval(() => {
|
|
137
|
+
void check(r);
|
|
138
|
+
}, 15e3);
|
|
139
|
+
if (eligible(r)) void check(r);
|
|
521
140
|
} catch (e) {
|
|
522
141
|
}
|
|
523
|
-
return "s-" + Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
524
|
-
}
|
|
525
|
-
function deriveCandidates(c) {
|
|
526
|
-
const out = [];
|
|
527
|
-
const hint = c.harvest.lastIntentHint();
|
|
528
|
-
if (hint) out.push(`Searching for \u201C${hint}\u201D`);
|
|
529
|
-
const label = c.capture.label();
|
|
530
|
-
if (label) out.push(`Something on \u201C${label.slice(0, 40)}\u201D`);
|
|
531
|
-
return out;
|
|
532
|
-
}
|
|
533
|
-
function buildSignal(c, trigger, extra = {}) {
|
|
534
|
-
const err = c.capture.error();
|
|
535
|
-
return {
|
|
536
|
-
captured_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
537
|
-
route: c.capture.route(),
|
|
538
|
-
client_label: c.capture.label(),
|
|
539
|
-
trail: c.capture.trail(),
|
|
540
|
-
session_ref: c.sessionRef,
|
|
541
|
-
trigger,
|
|
542
|
-
intent_hint: c.harvest.lastIntentHint(),
|
|
543
|
-
error: err,
|
|
544
|
-
outcome: err || trigger === "friction" ? "failed" : "unknown",
|
|
545
|
-
...extra
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
async function maybePrompt(c, trigger) {
|
|
549
|
-
var _a2;
|
|
550
|
-
const now = Date.now();
|
|
551
|
-
if (canPrompt(c.fatigue, now, DEFAULT_CAPS)) {
|
|
552
|
-
c.fatigue.promptsShown += 1;
|
|
553
|
-
c.fatigue.lastPromptAt = now;
|
|
554
|
-
try {
|
|
555
|
-
const { showPrompt } = await import('./prompt-GDFYC75D.js');
|
|
556
|
-
const result = await showPrompt({ candidates: deriveCandidates(c) });
|
|
557
|
-
c.egress.enqueue(
|
|
558
|
-
buildSignal(c, trigger, {
|
|
559
|
-
answer: result.answer,
|
|
560
|
-
verbatim: result.verbatim,
|
|
561
|
-
intent_hint: (_a2 = result.intent) != null ? _a2 : c.harvest.lastIntentHint(),
|
|
562
|
-
outcome: result.answer === "yes" ? "achieved" : "failed"
|
|
563
|
-
})
|
|
564
|
-
);
|
|
565
|
-
} catch (e) {
|
|
566
|
-
c.egress.enqueue(buildSignal(c, trigger));
|
|
567
|
-
}
|
|
568
|
-
} else {
|
|
569
|
-
c.egress.enqueue(buildSignal(c, trigger));
|
|
570
|
-
}
|
|
571
142
|
}
|
|
572
|
-
|
|
573
|
-
if (!c.running || !c.interventionsEnabled || c.suppressed) return;
|
|
574
|
-
if (c.surveyOnScreen) return;
|
|
575
|
-
if (c.interventionsShown >= MAX_INTERVENTIONS_PER_SESSION) return;
|
|
576
|
-
const now = Date.now();
|
|
577
|
-
if (c.fatigue.lastPromptAt !== null && now - c.fatigue.lastPromptAt < DEFAULT_CAPS.cooldownMs)
|
|
578
|
-
return;
|
|
579
|
-
const respondentKey = getRespondentKey(c.identity, c.sessionRef);
|
|
580
|
-
const served = await fetchIntervention({
|
|
581
|
-
endpoint: c.config.endpoint,
|
|
582
|
-
key: c.config.key,
|
|
583
|
-
ctx: buildServeContext(c.capture.route(), c.identity),
|
|
584
|
-
respondentKey,
|
|
585
|
-
debug: c.config.debug
|
|
586
|
-
});
|
|
587
|
-
if (!served || !c.running) return;
|
|
588
|
-
const prevShown = c.interventionsShown;
|
|
589
|
-
const prevPromptAt = c.fatigue.lastPromptAt;
|
|
590
|
-
c.surveyOnScreen = true;
|
|
591
|
-
c.interventionsShown += 1;
|
|
592
|
-
c.fatigue.lastPromptAt = Date.now();
|
|
143
|
+
function identify(userId) {
|
|
593
144
|
try {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
} else if (result.voted) {
|
|
601
|
-
submitResponse({
|
|
602
|
-
endpoint: c.config.endpoint,
|
|
603
|
-
key: c.config.key,
|
|
604
|
-
interventionId: served.id,
|
|
605
|
-
response: { choice: "vote" },
|
|
606
|
-
respondentKey
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
} else {
|
|
610
|
-
const { showSurvey } = await import('./survey-CICJQ5VI.js');
|
|
611
|
-
const result = await showSurvey(served.config);
|
|
612
|
-
if (!result.dismissed && (result.choice || result.text)) {
|
|
613
|
-
submitResponse({
|
|
614
|
-
endpoint: c.config.endpoint,
|
|
615
|
-
key: c.config.key,
|
|
616
|
-
interventionId: served.id,
|
|
617
|
-
response: { choice: result.choice, text: result.text },
|
|
618
|
-
respondentKey
|
|
619
|
-
});
|
|
620
|
-
}
|
|
145
|
+
const r = current();
|
|
146
|
+
if (!r) return;
|
|
147
|
+
const identified = typeof userId === "string" && userId.trim().length > 0;
|
|
148
|
+
if (!identified && !r.identified) {
|
|
149
|
+
if (!r.paused && eligible(r)) void check(r);
|
|
150
|
+
return;
|
|
621
151
|
}
|
|
152
|
+
invalidate(r);
|
|
153
|
+
r.identified = identified;
|
|
154
|
+
status(r, r.paused ? "paused" : eligible(r) ? "unavailable" : "signed_out");
|
|
155
|
+
if (eligible(r) && !r.paused) void check(r);
|
|
622
156
|
} catch (e) {
|
|
623
|
-
} finally {
|
|
624
|
-
c.surveyOnScreen = false;
|
|
625
157
|
}
|
|
626
158
|
}
|
|
627
|
-
function
|
|
628
|
-
const c = ctrl;
|
|
629
|
-
if (!c || !c.running) return;
|
|
159
|
+
function pause() {
|
|
630
160
|
try {
|
|
631
|
-
const
|
|
632
|
-
if (
|
|
633
|
-
|
|
634
|
-
|
|
161
|
+
const r = current();
|
|
162
|
+
if (r) {
|
|
163
|
+
r.paused = true;
|
|
164
|
+
invalidate(r);
|
|
165
|
+
status(r, "paused");
|
|
635
166
|
}
|
|
636
167
|
} catch (e) {
|
|
637
168
|
}
|
|
638
|
-
if (c.eventTimer !== null) return;
|
|
639
|
-
c.eventTimer = (typeof window !== "undefined" ? window.setTimeout : setTimeout)(() => {
|
|
640
|
-
c.eventTimer = null;
|
|
641
|
-
try {
|
|
642
|
-
const now = Date.now();
|
|
643
|
-
if (now - c.lastFrictionEmitAt < FRICTION_EMIT_COOLDOWN_MS) return;
|
|
644
|
-
const kind = detectFriction(c.capture.trail(), now);
|
|
645
|
-
if (!kind) return;
|
|
646
|
-
c.lastFrictionEmitAt = now;
|
|
647
|
-
void maybePrompt(c, "friction");
|
|
648
|
-
} catch (e) {
|
|
649
|
-
}
|
|
650
|
-
}, EVENT_DEBOUNCE_MS);
|
|
651
|
-
}
|
|
652
|
-
function onExitIntent(ev) {
|
|
653
|
-
const c = ctrl;
|
|
654
|
-
if (!c || !c.running || !c.config.boundaryAsk) return;
|
|
655
|
-
try {
|
|
656
|
-
if (ev.clientY <= 0) void maybePrompt(c, "boundary");
|
|
657
|
-
} catch (e) {
|
|
658
|
-
}
|
|
659
169
|
}
|
|
660
|
-
function
|
|
661
|
-
if (c.running) return;
|
|
662
|
-
if (c.suppressed) {
|
|
663
|
-
if (c.config.debug)
|
|
664
|
-
console.debug(
|
|
665
|
-
"[sightspool] capture suppressed on localhost (set captureOnLocalhost:true to override)"
|
|
666
|
-
);
|
|
667
|
-
return;
|
|
668
|
-
}
|
|
669
|
-
c.running = true;
|
|
670
|
-
c.capture.start();
|
|
671
|
-
c.harvest.start();
|
|
672
|
-
c.egress.start();
|
|
673
|
-
c.capture.onEvent(onCaptureEvent);
|
|
170
|
+
function resume() {
|
|
674
171
|
try {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
try {
|
|
681
|
-
return c.capture.route();
|
|
682
|
-
} catch (e) {
|
|
683
|
-
return null;
|
|
684
|
-
}
|
|
685
|
-
})();
|
|
686
|
-
(typeof window !== "undefined" ? window.setTimeout : setTimeout)(() => {
|
|
687
|
-
void maybeServeIntervention(c);
|
|
688
|
-
}, SERVE_SETTLE_MS);
|
|
689
|
-
}
|
|
690
|
-
if (c.config.debug) console.debug("[sightspool] started", c.sessionRef);
|
|
691
|
-
}
|
|
692
|
-
function init(config) {
|
|
693
|
-
try {
|
|
694
|
-
if (!config || !config.key) {
|
|
695
|
-
console.warn("[sightspool] init: a `key` is required");
|
|
696
|
-
return;
|
|
172
|
+
const r = current();
|
|
173
|
+
if (r) {
|
|
174
|
+
r.paused = false;
|
|
175
|
+
if (!eligible(r)) status(r, "signed_out");
|
|
176
|
+
void check(r);
|
|
697
177
|
}
|
|
698
|
-
if (ctrl) return;
|
|
699
|
-
const endpoint = config.endpoint || DEFAULT_ENDPOINT;
|
|
700
|
-
const privacyOpts = { redact: config.redact, block: config.block };
|
|
701
|
-
const capture = createCapture({ debug: !!config.debug, ...privacyOpts });
|
|
702
|
-
const harvest = createHarvest(capture, { debug: !!config.debug, ...privacyOpts });
|
|
703
|
-
const egress = createEgress({ key: config.key, endpoint, debug: !!config.debug });
|
|
704
|
-
ctrl = {
|
|
705
|
-
config: {
|
|
706
|
-
...config,
|
|
707
|
-
key: config.key,
|
|
708
|
-
endpoint,
|
|
709
|
-
boundaryAsk: config.boundaryAsk !== false,
|
|
710
|
-
debug: !!config.debug
|
|
711
|
-
},
|
|
712
|
-
capture,
|
|
713
|
-
harvest,
|
|
714
|
-
egress,
|
|
715
|
-
identity: {},
|
|
716
|
-
sessionRef: uuid(),
|
|
717
|
-
fatigue: { promptsShown: 0, lastPromptAt: null },
|
|
718
|
-
lastFrictionEmitAt: 0,
|
|
719
|
-
eventTimer: null,
|
|
720
|
-
running: false,
|
|
721
|
-
suppressed: isLocalhost(currentHostname()) && config.captureOnLocalhost !== true,
|
|
722
|
-
interventionsEnabled: config.interventions !== false,
|
|
723
|
-
lastServeRoute: null,
|
|
724
|
-
surveyOnScreen: false,
|
|
725
|
-
interventionsShown: 0
|
|
726
|
-
};
|
|
727
|
-
if (config.consent !== false) startRuntime(ctrl);
|
|
728
|
-
} catch (err) {
|
|
729
|
-
try {
|
|
730
|
-
console.warn("[sightspool] init failed", err);
|
|
731
|
-
} catch (e) {
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
function identify(userId, traits) {
|
|
736
|
-
try {
|
|
737
|
-
if (!ctrl) return;
|
|
738
|
-
ctrl.identity = { userId, account: traits == null ? void 0 : traits.account, plan: traits == null ? void 0 : traits.plan };
|
|
739
|
-
ctrl.egress.setIdentity(ctrl.identity);
|
|
740
|
-
} catch (e) {
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
function start() {
|
|
744
|
-
try {
|
|
745
|
-
if (ctrl) startRuntime(ctrl);
|
|
746
178
|
} catch (e) {
|
|
747
179
|
}
|
|
748
180
|
}
|
|
749
|
-
function
|
|
181
|
+
function destroy() {
|
|
750
182
|
try {
|
|
751
|
-
|
|
752
|
-
if (
|
|
753
|
-
|
|
183
|
+
const r = current();
|
|
184
|
+
if (!r) return;
|
|
185
|
+
r.disposed = true;
|
|
186
|
+
invalidate(r);
|
|
187
|
+
window.clearInterval(r.timer);
|
|
188
|
+
document.removeEventListener("visibilitychange", r.visibility);
|
|
189
|
+
delete host()[slot];
|
|
754
190
|
} catch (e) {
|
|
755
191
|
}
|
|
756
192
|
}
|
|
757
|
-
function
|
|
193
|
+
function getStatus() {
|
|
194
|
+
var _a, _b;
|
|
758
195
|
try {
|
|
759
|
-
|
|
760
|
-
ctrl.running = false;
|
|
761
|
-
ctrl.capture.stop();
|
|
762
|
-
ctrl.harvest.stop();
|
|
763
|
-
ctrl.egress.stop();
|
|
764
|
-
try {
|
|
765
|
-
document.removeEventListener("mouseout", onExitIntent);
|
|
766
|
-
} catch (e) {
|
|
767
|
-
}
|
|
196
|
+
return (_b = (_a = current()) == null ? void 0 : _a.status) != null ? _b : "not_initialized";
|
|
768
197
|
} catch (e) {
|
|
198
|
+
return "error";
|
|
769
199
|
}
|
|
770
200
|
}
|
|
771
|
-
var api = { init, identify, start, stop, consent };
|
|
772
|
-
var src_default = api;
|
|
773
|
-
var _a;
|
|
774
|
-
try {
|
|
775
|
-
if (typeof document !== "undefined") {
|
|
776
|
-
const el = (_a = document.currentScript) != null ? _a : document.querySelector("script[data-sightspool-key]");
|
|
777
|
-
const key = el == null ? void 0 : el.getAttribute("data-sightspool-key");
|
|
778
|
-
if (key) {
|
|
779
|
-
let endpoint = (el == null ? void 0 : el.getAttribute("data-sightspool-endpoint")) || void 0;
|
|
780
|
-
if (!endpoint && (el == null ? void 0 : el.src)) {
|
|
781
|
-
try {
|
|
782
|
-
endpoint = new URL(el.src).origin;
|
|
783
|
-
} catch (e) {
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
const list = (attr) => {
|
|
787
|
-
const raw = el == null ? void 0 : el.getAttribute(attr);
|
|
788
|
-
if (!raw) return void 0;
|
|
789
|
-
const out = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
790
|
-
return out.length ? out : void 0;
|
|
791
|
-
};
|
|
792
|
-
init({
|
|
793
|
-
key,
|
|
794
|
-
endpoint,
|
|
795
|
-
redact: list("data-sightspool-redact"),
|
|
796
|
-
block: list("data-sightspool-block"),
|
|
797
|
-
captureOnLocalhost: (el == null ? void 0 : el.hasAttribute("data-sightspool-capture-localhost")) || void 0,
|
|
798
|
-
interventions: (el == null ? void 0 : el.hasAttribute("data-sightspool-no-interventions")) ? false : void 0,
|
|
799
|
-
debug: (el == null ? void 0 : el.hasAttribute("data-sightspool-debug")) || void 0
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
} catch (e) {
|
|
804
|
-
}
|
|
805
201
|
|
|
806
|
-
|
|
202
|
+
// src/index.ts
|
|
203
|
+
var src_default = { init, identify, pause, resume, destroy, getStatus };
|
|
204
|
+
|
|
205
|
+
export { src_default as default, destroy, getStatus, identify, init, pause, resume };
|
|
807
206
|
//# sourceMappingURL=index.js.map
|
|
808
207
|
//# sourceMappingURL=index.js.map
|