@sightspool/sdk 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +128 -329
- package/SECURITY.md +16 -0
- package/dist/index.cjs +230 -1225
- 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 +228 -757
- 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 +36 -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/781ab339e13fe18b86b56cc9d84dd308bebf6482a885c8aae46a8b3b84801f6e/release.json +21 -0
- package/site/releases/0.4.0/781ab339e13fe18b86b56cc9d84dd308bebf6482a885c8aae46a8b3b84801f6e/sdk.global.js +3 -0
- package/site/releases/0.4.0/781ab339e13fe18b86b56cc9d84dd308bebf6482a885c8aae46a8b3b84801f6e/sdk.global.js.map +1 -0
- package/site/releases/0.4.0/781ab339e13fe18b86b56cc9d84dd308bebf6482a885c8aae46a8b3b84801f6e/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,279 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
+
if (r.frame) return;
|
|
12
|
+
(_a = r.button) == null ? void 0 : _a.remove();
|
|
13
|
+
r.button = null;
|
|
14
|
+
r.offer = null;
|
|
10
15
|
}
|
|
11
|
-
function
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
let started = false;
|
|
18
|
-
const subs = [];
|
|
19
|
-
const cleanups = [];
|
|
20
|
-
let recentClicks = [];
|
|
21
|
-
function notify() {
|
|
22
|
-
for (const cb of subs) {
|
|
23
|
-
try {
|
|
24
|
-
cb();
|
|
25
|
-
} catch (e) {
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function push(type, label) {
|
|
30
|
-
try {
|
|
31
|
-
buf.push({ t: Date.now(), type, label: label ? redactText(label) : void 0 });
|
|
32
|
-
if (buf.length > TRAIL_MAX) buf = buf.slice(-TRAIL_MAX);
|
|
33
|
-
if (opts.debug) console.debug("[sightspool] event", type, label);
|
|
34
|
-
notify();
|
|
35
|
-
} catch (e) {
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function currentRoute() {
|
|
39
|
-
try {
|
|
40
|
-
return location.pathname + location.search;
|
|
41
|
-
} catch (e) {
|
|
42
|
-
return "";
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function currentLabel() {
|
|
46
|
-
try {
|
|
47
|
-
return document.title || "";
|
|
48
|
-
} catch (e) {
|
|
49
|
-
return "";
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function onClick(ev) {
|
|
53
|
-
var _a3;
|
|
54
|
-
try {
|
|
55
|
-
const target = ev.target;
|
|
56
|
-
if (isIgnoredElement(target, blockSelectors)) return;
|
|
57
|
-
const text = target && (((_a3 = target.getAttribute) == null ? void 0 : _a3.call(target, "aria-label")) || target.textContent) || "";
|
|
58
|
-
const label = matchesRedactSelector(target, redactSelectors) ? REDACTED : text.trim().slice(0, 60);
|
|
59
|
-
const t = Date.now();
|
|
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;
|
|
67
|
-
try {
|
|
68
|
-
observer = new MutationObserver(() => {
|
|
69
|
-
mutated = true;
|
|
70
|
-
});
|
|
71
|
-
observer.observe(document.body, { childList: true, subtree: true, attributes: true });
|
|
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;
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
cleanups.push(() => {
|
|
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();
|
|
161
|
-
} catch (e) {
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
stop() {
|
|
165
|
-
started = false;
|
|
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
|
-
};
|
|
16
|
+
function invalidate(r) {
|
|
17
|
+
var _a;
|
|
18
|
+
r.generation += 1;
|
|
19
|
+
(_a = r.pending) == null ? void 0 : _a.abort();
|
|
20
|
+
r.pending = null;
|
|
21
|
+
remove(r);
|
|
190
22
|
}
|
|
191
|
-
|
|
192
|
-
|
|
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);
|
|
209
|
-
} catch (e) {
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
23
|
+
function status(r, value) {
|
|
24
|
+
r.status = value;
|
|
212
25
|
}
|
|
213
|
-
function
|
|
214
|
-
var
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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) {
|
|
236
|
-
}
|
|
237
|
-
}
|
|
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
|
-
};
|
|
26
|
+
function expand(r, expanded) {
|
|
27
|
+
var _a;
|
|
28
|
+
if (!r.panel || !r.frame || !r.button) return;
|
|
29
|
+
r.expanded = expanded;
|
|
30
|
+
r.panel.hidden = !expanded;
|
|
31
|
+
r.panel.style.display = expanded ? "flex" : "none";
|
|
32
|
+
r.button.hidden = expanded;
|
|
33
|
+
r.button.setAttribute("aria-expanded", String(expanded));
|
|
34
|
+
if (expanded) {
|
|
35
|
+
(_a = r.panel.querySelector("button")) == null ? void 0 : _a.focus();
|
|
36
|
+
} else r.button.focus();
|
|
259
37
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
function createEgress(opts) {
|
|
265
|
-
let queue = [];
|
|
266
|
-
let identity;
|
|
267
|
-
let interval = null;
|
|
268
|
-
let started = false;
|
|
269
|
-
const url = `${opts.endpoint.replace(/\/+$/, "")}/api/sdk/ingest`;
|
|
270
|
-
function send(signals) {
|
|
271
|
-
if (signals.length === 0) return;
|
|
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() {
|
|
296
|
-
try {
|
|
297
|
-
if (document.visibilityState === "hidden") flush();
|
|
298
|
-
} catch (e) {
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
function flush() {
|
|
302
|
-
if (queue.length === 0) return;
|
|
303
|
-
const batch = queue;
|
|
304
|
-
queue = [];
|
|
305
|
-
send(batch);
|
|
38
|
+
function openPanel(r) {
|
|
39
|
+
if (r.frame) {
|
|
40
|
+
expand(r, true);
|
|
41
|
+
return;
|
|
306
42
|
}
|
|
307
|
-
return
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
43
|
+
if (!r.offer || !r.button) return;
|
|
44
|
+
const panel = document.createElement("section");
|
|
45
|
+
panel.id = "sightspool-interview-panel";
|
|
46
|
+
panel.setAttribute("role", "dialog");
|
|
47
|
+
panel.setAttribute("aria-label", "Sightspool interview");
|
|
48
|
+
panel.style.cssText = "position:fixed;bottom:16px;right:16px;z-index:2147483001;box-sizing:border-box;width:420px;max-width:calc(100% - 32px);height:680px;max-height:calc(100dvh - 32px);border:1px solid #e6dfe3;border-radius:20px;background:#fff;color:#262024;box-shadow:0 12px 50px #0003;overflow:hidden;font:14px system-ui;display:flex;flex-direction:column";
|
|
49
|
+
const header = document.createElement("div");
|
|
50
|
+
header.style.cssText = "display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;border-bottom:1px solid #eee;flex-shrink:0";
|
|
51
|
+
const title = document.createElement("strong");
|
|
52
|
+
title.textContent = "Sightspool";
|
|
53
|
+
const minimize = document.createElement("button");
|
|
54
|
+
minimize.type = "button";
|
|
55
|
+
minimize.textContent = "Minimize";
|
|
56
|
+
minimize.style.cssText = "font:inherit;color:inherit;background:#fff;border:1px solid #d6cbd1;border-radius:8px;padding:8px 12px;cursor:pointer";
|
|
57
|
+
const hide = () => {
|
|
58
|
+
expand(r, false);
|
|
59
|
+
};
|
|
60
|
+
minimize.onclick = hide;
|
|
61
|
+
header.appendChild(title);
|
|
62
|
+
header.appendChild(minimize);
|
|
63
|
+
panel.appendChild(header);
|
|
64
|
+
const frame = document.createElement("iframe");
|
|
65
|
+
frame.title = "Sightspool research conversation";
|
|
66
|
+
frame.allow = "microphone; autoplay";
|
|
67
|
+
frame.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms");
|
|
68
|
+
frame.referrerPolicy = "no-referrer";
|
|
69
|
+
frame.style.cssText = "display:block;width:100%;flex:1;min-height:0;border:0;background:#fff";
|
|
70
|
+
const url = new URL(r.endpoint + "/interview-widget");
|
|
71
|
+
url.searchParams.set("key", r.key);
|
|
72
|
+
url.hash = new URLSearchParams({ offer: r.offer, device: r.device }).toString();
|
|
73
|
+
frame.src = url.href;
|
|
74
|
+
panel.appendChild(frame);
|
|
75
|
+
panel.onkeydown = (event) => {
|
|
76
|
+
if (event.key === "Escape") {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
hide();
|
|
335
79
|
}
|
|
336
80
|
};
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
var
|
|
341
|
-
|
|
342
|
-
|
|
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
|
|
81
|
+
r.panel = panel;
|
|
82
|
+
r.frame = frame;
|
|
83
|
+
r.message = (event) => {
|
|
84
|
+
var _a;
|
|
85
|
+
if (event.source !== frame.contentWindow || event.origin !== r.endpoint || ((_a = event.data) == null ? void 0 : _a.type) !== "sightspool:panel:minimize") return;
|
|
86
|
+
hide();
|
|
414
87
|
};
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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}`;
|
|
88
|
+
window.addEventListener("message", r.message);
|
|
89
|
+
r.button.textContent = "Return to interview";
|
|
90
|
+
r.button.setAttribute("aria-label", "Sightspool: return to your interview");
|
|
91
|
+
r.button.setAttribute("aria-controls", panel.id);
|
|
92
|
+
r.button.onclick = () => {
|
|
93
|
+
expand(r, true);
|
|
94
|
+
};
|
|
95
|
+
document.body.appendChild(panel);
|
|
96
|
+
expand(r, true);
|
|
441
97
|
}
|
|
442
|
-
async function
|
|
443
|
-
|
|
98
|
+
async function check(r) {
|
|
99
|
+
if (r.frame || r.disposed || r.paused || !eligible(r) || r.pending || document.visibilityState !== "visible") return;
|
|
100
|
+
const generation = r.generation;
|
|
101
|
+
const request = new AbortController();
|
|
102
|
+
r.pending = request;
|
|
103
|
+
const timeout = window.setTimeout(() => request.abort(), 1e4);
|
|
104
|
+
if (!r.button) status(r, "checking");
|
|
444
105
|
try {
|
|
445
|
-
|
|
446
|
-
const res = await fetch(serveUrl(opts.endpoint, "serve"), {
|
|
106
|
+
const response = await fetch(r.endpoint + "/widget-offer", {
|
|
447
107
|
method: "POST",
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
mode: "cors",
|
|
455
|
-
credentials: "omit"
|
|
108
|
+
credentials: "omit",
|
|
109
|
+
cache: "no-store",
|
|
110
|
+
referrerPolicy: "no-referrer",
|
|
111
|
+
headers: { "Content-Type": "application/json" },
|
|
112
|
+
body: JSON.stringify({ operation: "offer", key: r.key, device: r.device }),
|
|
113
|
+
signal: request.signal
|
|
456
114
|
});
|
|
457
|
-
if (!
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
if (
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
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
|
-
}
|
|
521
|
-
} catch (e) {
|
|
522
|
-
}
|
|
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));
|
|
115
|
+
if (!response.ok) throw Error("offer unavailable");
|
|
116
|
+
const result = await response.json();
|
|
117
|
+
if (r.disposed || generation !== r.generation || r.paused || !eligible(r)) return;
|
|
118
|
+
if (result.available !== true || typeof result.offer !== "string" || !result.offer) {
|
|
119
|
+
remove(r);
|
|
120
|
+
status(r, "unavailable");
|
|
121
|
+
return;
|
|
567
122
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
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();
|
|
593
|
-
try {
|
|
594
|
-
if (served.type === "demand_probe") {
|
|
595
|
-
const { showProbe } = await import('./probe-BNGMQQ5C.js');
|
|
596
|
-
const result = await showProbe(served.config);
|
|
597
|
-
if (!result.mounted) {
|
|
598
|
-
c.interventionsShown = prevShown;
|
|
599
|
-
c.fatigue.lastPromptAt = prevPromptAt;
|
|
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
|
-
});
|
|
123
|
+
r.offer = result.offer;
|
|
124
|
+
status(r, "available");
|
|
125
|
+
if (r.button) return;
|
|
126
|
+
const button = document.createElement("button");
|
|
127
|
+
button.type = "button";
|
|
128
|
+
button.textContent = "Share your experience \xB7 5 min";
|
|
129
|
+
button.setAttribute("aria-label", "Sightspool: join a five-minute user interview");
|
|
130
|
+
button.style.cssText = "position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:999px;background:#ad1668;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)";
|
|
131
|
+
button.onclick = () => {
|
|
132
|
+
try {
|
|
133
|
+
if (r.disposed || r.paused || !eligible(r) || !r.offer) return;
|
|
134
|
+
openPanel(r);
|
|
135
|
+
} catch (e) {
|
|
620
136
|
}
|
|
621
|
-
}
|
|
137
|
+
};
|
|
138
|
+
r.button = button;
|
|
139
|
+
document.body.appendChild(button);
|
|
622
140
|
} catch (e) {
|
|
141
|
+
if (!r.disposed && generation === r.generation) {
|
|
142
|
+
remove(r);
|
|
143
|
+
status(r, "error");
|
|
144
|
+
}
|
|
623
145
|
} finally {
|
|
624
|
-
|
|
146
|
+
window.clearTimeout(timeout);
|
|
147
|
+
if (r.pending === request) r.pending = null;
|
|
625
148
|
}
|
|
626
149
|
}
|
|
627
|
-
function
|
|
628
|
-
const c = ctrl;
|
|
629
|
-
if (!c || !c.running) return;
|
|
150
|
+
function init(config) {
|
|
630
151
|
try {
|
|
631
|
-
const
|
|
632
|
-
if (
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
152
|
+
const browser = host();
|
|
153
|
+
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;
|
|
154
|
+
if (config.audience !== "all_visitors" && config.audience !== "signed_in") return;
|
|
155
|
+
const url = new URL(config.endpoint || "https://www.sightspool.com");
|
|
156
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) return;
|
|
157
|
+
if (url.username || url.password) return;
|
|
158
|
+
const previous = current();
|
|
159
|
+
if (previous && previous.key === config.key && previous.endpoint === url.origin && previous.audience === config.audience) return;
|
|
160
|
+
if (previous == null ? void 0 : previous.frame) return;
|
|
161
|
+
if (previous) destroy();
|
|
162
|
+
let device = "";
|
|
641
163
|
try {
|
|
642
|
-
|
|
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");
|
|
164
|
+
device = sessionStorage.getItem("sightspool-widget-device:" + config.key) || "";
|
|
648
165
|
} catch (e) {
|
|
649
166
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
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
|
-
}
|
|
660
|
-
function startRuntime(c) {
|
|
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);
|
|
674
|
-
try {
|
|
675
|
-
document.addEventListener("mouseout", onExitIntent);
|
|
676
|
-
} catch (e) {
|
|
677
|
-
}
|
|
678
|
-
if (c.interventionsEnabled) {
|
|
679
|
-
c.lastServeRoute = (() => {
|
|
167
|
+
if (!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(device)) {
|
|
168
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
169
|
+
device = "ss_fcd_" + btoa(String.fromCharCode(...bytes)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
680
170
|
try {
|
|
681
|
-
|
|
171
|
+
sessionStorage.setItem("sightspool-widget-device:" + config.key, device);
|
|
682
172
|
} catch (e) {
|
|
683
|
-
return null;
|
|
684
173
|
}
|
|
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;
|
|
697
174
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
175
|
+
const r = {
|
|
176
|
+
key: config.key,
|
|
177
|
+
endpoint: url.origin,
|
|
178
|
+
audience: config.audience,
|
|
179
|
+
identified: false,
|
|
180
|
+
paused: false,
|
|
181
|
+
disposed: false,
|
|
182
|
+
generation: 0,
|
|
183
|
+
device,
|
|
184
|
+
offer: null,
|
|
185
|
+
button: null,
|
|
186
|
+
panel: null,
|
|
187
|
+
frame: null,
|
|
188
|
+
expanded: false,
|
|
189
|
+
message: null,
|
|
190
|
+
pending: null,
|
|
191
|
+
timer: 0,
|
|
192
|
+
visibility: () => {
|
|
711
193
|
},
|
|
712
|
-
|
|
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
|
|
194
|
+
status: "signed_out"
|
|
726
195
|
};
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
196
|
+
browser[slot] = r;
|
|
197
|
+
r.visibility = () => {
|
|
198
|
+
try {
|
|
199
|
+
if (document.visibilityState === "visible") void check(r);
|
|
200
|
+
else {
|
|
201
|
+
invalidate(r);
|
|
202
|
+
status(r, r.paused ? "paused" : eligible(r) ? "unavailable" : "signed_out");
|
|
203
|
+
}
|
|
204
|
+
} catch (e) {
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
document.addEventListener("visibilitychange", r.visibility);
|
|
208
|
+
r.timer = window.setInterval(() => {
|
|
209
|
+
void check(r);
|
|
210
|
+
}, 15e3);
|
|
211
|
+
if (eligible(r)) void check(r);
|
|
212
|
+
} catch (e) {
|
|
733
213
|
}
|
|
734
214
|
}
|
|
735
|
-
function identify(userId
|
|
215
|
+
function identify(userId) {
|
|
736
216
|
try {
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
217
|
+
const r = current();
|
|
218
|
+
if (!r) return;
|
|
219
|
+
const identified = typeof userId === "string" && userId.trim().length > 0;
|
|
220
|
+
if (!identified && !r.identified) {
|
|
221
|
+
if (!r.paused && eligible(r)) void check(r);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
invalidate(r);
|
|
225
|
+
r.identified = identified;
|
|
226
|
+
status(r, r.paused ? "paused" : eligible(r) ? "unavailable" : "signed_out");
|
|
227
|
+
if (eligible(r) && !r.paused) void check(r);
|
|
740
228
|
} catch (e) {
|
|
741
229
|
}
|
|
742
230
|
}
|
|
743
|
-
function
|
|
231
|
+
function pause() {
|
|
744
232
|
try {
|
|
745
|
-
|
|
233
|
+
const r = current();
|
|
234
|
+
if (r) {
|
|
235
|
+
r.paused = true;
|
|
236
|
+
invalidate(r);
|
|
237
|
+
status(r, "paused");
|
|
238
|
+
}
|
|
746
239
|
} catch (e) {
|
|
747
240
|
}
|
|
748
241
|
}
|
|
749
|
-
function
|
|
242
|
+
function resume() {
|
|
750
243
|
try {
|
|
751
|
-
|
|
752
|
-
if (
|
|
753
|
-
|
|
244
|
+
const r = current();
|
|
245
|
+
if (r) {
|
|
246
|
+
r.paused = false;
|
|
247
|
+
if (!eligible(r)) status(r, "signed_out");
|
|
248
|
+
void check(r);
|
|
249
|
+
}
|
|
754
250
|
} catch (e) {
|
|
755
251
|
}
|
|
756
252
|
}
|
|
757
|
-
function
|
|
253
|
+
function destroy() {
|
|
758
254
|
try {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
} catch (e) {
|
|
767
|
-
}
|
|
255
|
+
const r = current();
|
|
256
|
+
if (!r) return;
|
|
257
|
+
r.disposed = true;
|
|
258
|
+
invalidate(r);
|
|
259
|
+
window.clearInterval(r.timer);
|
|
260
|
+
document.removeEventListener("visibilitychange", r.visibility);
|
|
261
|
+
if (!r.frame) delete host()[slot];
|
|
768
262
|
} catch (e) {
|
|
769
263
|
}
|
|
770
264
|
}
|
|
771
|
-
|
|
772
|
-
var
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
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
|
-
}
|
|
265
|
+
function getStatus() {
|
|
266
|
+
var _a, _b;
|
|
267
|
+
try {
|
|
268
|
+
return (_b = (_a = current()) == null ? void 0 : _a.status) != null ? _b : "not_initialized";
|
|
269
|
+
} catch (e) {
|
|
270
|
+
return "error";
|
|
802
271
|
}
|
|
803
|
-
} catch (e) {
|
|
804
272
|
}
|
|
805
273
|
|
|
806
|
-
|
|
274
|
+
// src/index.ts
|
|
275
|
+
var src_default = { init, identify, pause, resume, destroy, getStatus };
|
|
276
|
+
|
|
277
|
+
export { src_default as default, destroy, getStatus, identify, init, pause, resume };
|
|
807
278
|
//# sourceMappingURL=index.js.map
|
|
808
279
|
//# sourceMappingURL=index.js.map
|