@syntrologie/runtime-sdk 2.8.0-canary.7 → 2.8.0-canary.71
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/CAPABILITIES.md +299 -167
- package/README.md +2 -0
- package/dist/actions/schema.d.ts +783 -783
- package/dist/actions/schema.js +3 -3
- package/dist/actions/types.d.ts +1 -1
- package/dist/actions/validation-core.d.ts +24 -0
- package/dist/actions/validation-rules.d.ts +74 -0
- package/dist/actions/validation.d.ts +5 -11
- package/dist/bootstrap-init.d.ts +33 -0
- package/dist/bootstrap-runtime.d.ts +7 -0
- package/dist/bootstrap-types.d.ts +90 -0
- package/dist/bootstrap.d.ts +19 -83
- package/dist/{chunk-R5DNAIRI.js → chunk-77TNZ66J.js} +4 -4
- package/dist/{chunk-R5DNAIRI.js.map → chunk-77TNZ66J.js.map} +2 -2
- package/dist/{chunk-XDYJ64IN.js → chunk-IR6UOR63.js} +4 -4
- package/dist/chunk-IR6UOR63.js.map +7 -0
- package/dist/{chunk-GWF5BTST.js → chunk-WX32GVSP.js} +1855 -783
- package/dist/chunk-WX32GVSP.js.map +7 -0
- package/dist/chunk-YLLWLUQX.js +241 -0
- package/dist/chunk-YLLWLUQX.js.map +7 -0
- package/dist/components/ShadowCanvasOverlay.d.ts +1 -2
- package/dist/components/TileIcon.d.ts +2 -2
- package/dist/components/emojiToIcon.d.ts +24 -0
- package/dist/config/schema.d.ts +147 -136
- package/dist/config/schema.js +2 -2
- package/dist/decisions/schema.d.ts +47 -47
- package/dist/decisions/schema.js +1 -1
- package/dist/events/EventBus.d.ts +27 -1
- package/dist/events/history.d.ts +9 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/events/normalizers/posthog.d.ts +4 -50
- package/dist/events/types.d.ts +30 -23
- package/dist/events/validation.d.ts +7 -0
- package/dist/fetchers/experimentsFetcher.d.ts +3 -3
- package/dist/index.d.ts +0 -2
- package/dist/index.js +1529 -212
- package/dist/index.js.map +4 -4
- package/dist/overlays/runtime/overlay/overlay-runner.d.ts +4 -0
- package/dist/overlays/runtime/overlay/overlay-state.d.ts +21 -0
- package/dist/overlays/types.d.ts +3 -1
- package/dist/react.js +6 -4
- package/dist/react.js.map +2 -2
- package/dist/smart-canvas.esm.js +115 -65
- package/dist/smart-canvas.esm.js.map +4 -4
- package/dist/smart-canvas.js +5901 -3064
- package/dist/smart-canvas.js.map +4 -4
- package/dist/smart-canvas.min.js +115 -65
- package/dist/smart-canvas.min.js.map +4 -4
- package/dist/telemetry/InterventionTracker.d.ts +23 -0
- package/dist/telemetry/adapters/posthog.d.ts +30 -4
- package/dist/telemetry/index.d.ts +1 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/token.d.ts +2 -0
- package/dist/version.d.ts +1 -1
- package/package.json +23 -28
- package/schema/canvas-config.schema.json +1974 -10925
- package/scripts/syntroReactPlugin.mjs +3 -0
- package/scripts/validate-config.mjs +42 -0
- package/dist/chunk-BU4Z6PD7.js +0 -218
- package/dist/chunk-BU4Z6PD7.js.map +0 -7
- package/dist/chunk-GWF5BTST.js.map +0 -7
- package/dist/chunk-XDYJ64IN.js.map +0 -7
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
__privateGet,
|
|
4
4
|
__privateSet,
|
|
5
5
|
__publicField
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YLLWLUQX.js";
|
|
7
7
|
|
|
8
8
|
// ../adaptives/adaptive-content/dist/reconciliation-guard.js
|
|
9
9
|
function guardAgainstReconciliation(container, anchor, reinsertFn, opts) {
|
|
@@ -34,6 +34,11 @@ function guardAgainstReconciliation(container, anchor, reinsertFn, opts) {
|
|
|
34
34
|
debounceTimer = setTimeout(() => {
|
|
35
35
|
if (disconnected)
|
|
36
36
|
return;
|
|
37
|
+
if (!anchor.isConnected) {
|
|
38
|
+
observer.disconnect();
|
|
39
|
+
disconnected = true;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
37
42
|
retries++;
|
|
38
43
|
try {
|
|
39
44
|
reinsertFn();
|
|
@@ -75,7 +80,16 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
|
75
80
|
"sup",
|
|
76
81
|
"sub",
|
|
77
82
|
"a",
|
|
78
|
-
"button"
|
|
83
|
+
"button",
|
|
84
|
+
// SVG elements (for inline Lucide icons in config HTML)
|
|
85
|
+
"svg",
|
|
86
|
+
"path",
|
|
87
|
+
"circle",
|
|
88
|
+
"line",
|
|
89
|
+
"polyline",
|
|
90
|
+
"polygon",
|
|
91
|
+
"rect",
|
|
92
|
+
"g"
|
|
79
93
|
]);
|
|
80
94
|
function sanitizeHtml(html) {
|
|
81
95
|
var _a2;
|
|
@@ -113,6 +127,12 @@ function sanitizeHtml(html) {
|
|
|
113
127
|
}
|
|
114
128
|
}
|
|
115
129
|
}
|
|
130
|
+
const svgs = Array.from(root.querySelectorAll("svg"));
|
|
131
|
+
for (const svg of svgs) {
|
|
132
|
+
if (toRemove.some((el) => svg.contains(el) && el.tagName.toLowerCase() === "script")) {
|
|
133
|
+
toRemove.push(svg);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
116
136
|
for (const el of toRemove) {
|
|
117
137
|
while (el.firstChild) {
|
|
118
138
|
(_a2 = el.parentNode) == null ? void 0 : _a2.insertBefore(el.firstChild, el);
|
|
@@ -213,15 +233,20 @@ var executeInsertHtml = async (action, context) => {
|
|
|
213
233
|
container.removeEventListener("click", deepLinkHandler);
|
|
214
234
|
}
|
|
215
235
|
guardCleanup();
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
restoredEl.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
236
|
+
if (!container.isConnected)
|
|
237
|
+
return;
|
|
238
|
+
try {
|
|
239
|
+
if (action.position === "replace" && originalContent !== null) {
|
|
240
|
+
const restoredEl = document.createElement(anchorEl.tagName);
|
|
241
|
+
restoredEl.innerHTML = originalContent;
|
|
242
|
+
Array.from(anchorEl.attributes).forEach((attr) => {
|
|
243
|
+
restoredEl.setAttribute(attr.name, attr.value);
|
|
244
|
+
});
|
|
245
|
+
container.replaceWith(restoredEl);
|
|
246
|
+
} else {
|
|
247
|
+
container.remove();
|
|
248
|
+
}
|
|
249
|
+
} catch {
|
|
225
250
|
}
|
|
226
251
|
},
|
|
227
252
|
updateFn: (changes) => {
|
|
@@ -251,6 +276,8 @@ var executeSetText = async (action, context) => {
|
|
|
251
276
|
});
|
|
252
277
|
return {
|
|
253
278
|
cleanup: () => {
|
|
279
|
+
if (!anchorEl.isConnected)
|
|
280
|
+
return;
|
|
254
281
|
anchorEl.textContent = originalText;
|
|
255
282
|
},
|
|
256
283
|
updateFn: (changes) => {
|
|
@@ -292,6 +319,8 @@ var executeSetAttr = async (action, context) => {
|
|
|
292
319
|
});
|
|
293
320
|
return {
|
|
294
321
|
cleanup: () => {
|
|
322
|
+
if (!anchorEl.isConnected)
|
|
323
|
+
return;
|
|
295
324
|
if (hadAttribute && originalValue !== null) {
|
|
296
325
|
anchorEl.setAttribute(action.attr, originalValue);
|
|
297
326
|
} else {
|
|
@@ -325,6 +354,8 @@ var executeAddClass = async (action, context) => {
|
|
|
325
354
|
});
|
|
326
355
|
return {
|
|
327
356
|
cleanup: () => {
|
|
357
|
+
if (!anchorEl.isConnected)
|
|
358
|
+
return;
|
|
328
359
|
if (!hadClass) {
|
|
329
360
|
anchorEl.classList.remove(action.className);
|
|
330
361
|
}
|
|
@@ -351,6 +382,8 @@ var executeRemoveClass = async (action, context) => {
|
|
|
351
382
|
});
|
|
352
383
|
return {
|
|
353
384
|
cleanup: () => {
|
|
385
|
+
if (!anchorEl.isConnected)
|
|
386
|
+
return;
|
|
354
387
|
if (hadClass) {
|
|
355
388
|
anchorEl.classList.add(action.className);
|
|
356
389
|
}
|
|
@@ -383,6 +416,8 @@ var executeSetStyle = async (action, context) => {
|
|
|
383
416
|
});
|
|
384
417
|
return {
|
|
385
418
|
cleanup: () => {
|
|
419
|
+
if (!anchorEl.isConnected)
|
|
420
|
+
return;
|
|
386
421
|
for (const [prop, originalValue] of originalStyles) {
|
|
387
422
|
if (originalValue) {
|
|
388
423
|
anchorEl.style.setProperty(prop, originalValue);
|
|
@@ -726,6 +761,10 @@ var CelebrationEngine = class {
|
|
|
726
761
|
this.container = null;
|
|
727
762
|
}
|
|
728
763
|
start(container, effect, config) {
|
|
764
|
+
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
765
|
+
if (prefersReducedMotion) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
729
768
|
this.container = container;
|
|
730
769
|
this.effect = effect;
|
|
731
770
|
this.duration = config.duration;
|
|
@@ -1369,7 +1408,7 @@ var alert = {
|
|
|
1369
1408
|
var tag = {
|
|
1370
1409
|
content: slateGrey[10],
|
|
1371
1410
|
border: slateGrey[4],
|
|
1372
|
-
background:
|
|
1411
|
+
background: slateGrey[3]
|
|
1373
1412
|
};
|
|
1374
1413
|
var menu = {
|
|
1375
1414
|
backgroundDefault: slateGrey[2],
|
|
@@ -1558,10 +1597,10 @@ function showHighlight(anchorEl, overlayRoot, opts) {
|
|
|
1558
1597
|
return;
|
|
1559
1598
|
}
|
|
1560
1599
|
const rect = anchorEl.getBoundingClientRect();
|
|
1561
|
-
const x =
|
|
1562
|
-
const y =
|
|
1563
|
-
const w =
|
|
1564
|
-
const h =
|
|
1600
|
+
const x = rect.left - padding;
|
|
1601
|
+
const y = rect.top - padding;
|
|
1602
|
+
const w = rect.width + padding * 2;
|
|
1603
|
+
const h = rect.height + padding * 2;
|
|
1565
1604
|
Object.assign(ring.style, {
|
|
1566
1605
|
left: `${x}px`,
|
|
1567
1606
|
top: `${y}px`,
|
|
@@ -1610,17 +1649,22 @@ function showHighlight(anchorEl, overlayRoot, opts) {
|
|
|
1610
1649
|
window.addEventListener("scroll", onScroll, true);
|
|
1611
1650
|
window.addEventListener("resize", onResize);
|
|
1612
1651
|
const onKey = (e) => {
|
|
1613
|
-
|
|
1652
|
+
var _a3;
|
|
1653
|
+
if (e.key === "Escape" && onEsc) {
|
|
1654
|
+
(_a3 = opts == null ? void 0 : opts.onDismiss) == null ? void 0 : _a3.call(opts);
|
|
1614
1655
|
handle.destroy();
|
|
1656
|
+
}
|
|
1615
1657
|
};
|
|
1616
1658
|
if (onEsc) {
|
|
1617
1659
|
window.addEventListener("keydown", onKey);
|
|
1618
1660
|
}
|
|
1619
1661
|
const onClick = (event) => {
|
|
1662
|
+
var _a3;
|
|
1620
1663
|
if (blocking) {
|
|
1621
1664
|
event.preventDefault();
|
|
1622
1665
|
event.stopPropagation();
|
|
1623
1666
|
} else if (onClickOutside) {
|
|
1667
|
+
(_a3 = opts == null ? void 0 : opts.onDismiss) == null ? void 0 : _a3.call(opts);
|
|
1624
1668
|
handle.destroy();
|
|
1625
1669
|
}
|
|
1626
1670
|
};
|
|
@@ -1637,8 +1681,14 @@ function showHighlight(anchorEl, overlayRoot, opts) {
|
|
|
1637
1681
|
scrim.style.pointerEvents = "none";
|
|
1638
1682
|
scrim.style.opacity = "0";
|
|
1639
1683
|
setTimeout(() => {
|
|
1640
|
-
|
|
1641
|
-
|
|
1684
|
+
try {
|
|
1685
|
+
scrim.remove();
|
|
1686
|
+
} catch {
|
|
1687
|
+
}
|
|
1688
|
+
try {
|
|
1689
|
+
ring.remove();
|
|
1690
|
+
} catch {
|
|
1691
|
+
}
|
|
1642
1692
|
}, 220);
|
|
1643
1693
|
}
|
|
1644
1694
|
};
|
|
@@ -1666,7 +1716,16 @@ var ALLOWED_TAGS2 = /* @__PURE__ */ new Set([
|
|
|
1666
1716
|
"sup",
|
|
1667
1717
|
"sub",
|
|
1668
1718
|
"a",
|
|
1669
|
-
"button"
|
|
1719
|
+
"button",
|
|
1720
|
+
// SVG elements (for inline Lucide icons in config HTML)
|
|
1721
|
+
"svg",
|
|
1722
|
+
"path",
|
|
1723
|
+
"circle",
|
|
1724
|
+
"line",
|
|
1725
|
+
"polyline",
|
|
1726
|
+
"polygon",
|
|
1727
|
+
"rect",
|
|
1728
|
+
"g"
|
|
1670
1729
|
]);
|
|
1671
1730
|
function sanitizeHtml2(html) {
|
|
1672
1731
|
var _a2;
|
|
@@ -1875,8 +1934,14 @@ var executeModal = async (action, context) => {
|
|
|
1875
1934
|
modal2.style.transform = "translate(-50%, -50%) scale(0.95)";
|
|
1876
1935
|
scrimEl.style.opacity = "0";
|
|
1877
1936
|
setTimeout(() => {
|
|
1878
|
-
|
|
1879
|
-
|
|
1937
|
+
try {
|
|
1938
|
+
modal2.remove();
|
|
1939
|
+
} catch {
|
|
1940
|
+
}
|
|
1941
|
+
try {
|
|
1942
|
+
scrimEl.remove();
|
|
1943
|
+
} catch {
|
|
1944
|
+
}
|
|
1880
1945
|
}, 200);
|
|
1881
1946
|
context.publishEvent("action.modal_dismissed", {
|
|
1882
1947
|
actionClicked
|
|
@@ -1923,10 +1988,12 @@ function getAnchorReference(anchorEl) {
|
|
|
1923
1988
|
}
|
|
1924
1989
|
function showTooltip(anchorEl, overlayRoot, opts) {
|
|
1925
1990
|
var _a2;
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1991
|
+
if (!opts.trigger || opts.trigger === "immediate") {
|
|
1992
|
+
const rect = anchorEl.getBoundingClientRect();
|
|
1993
|
+
const isLargeElement = rect.width > window.innerWidth * 0.8 || rect.height > window.innerHeight * 0.8;
|
|
1994
|
+
if (!isLargeElement) {
|
|
1995
|
+
anchorEl.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
|
|
1996
|
+
}
|
|
1930
1997
|
}
|
|
1931
1998
|
const div = document.createElement("div");
|
|
1932
1999
|
div.className = "syntro-tooltip";
|
|
@@ -2136,7 +2203,12 @@ function showTooltip(anchorEl, overlayRoot, opts) {
|
|
|
2136
2203
|
}
|
|
2137
2204
|
div.style.pointerEvents = "none";
|
|
2138
2205
|
div.style.opacity = "0";
|
|
2139
|
-
setTimeout(() =>
|
|
2206
|
+
setTimeout(() => {
|
|
2207
|
+
try {
|
|
2208
|
+
div.remove();
|
|
2209
|
+
} catch {
|
|
2210
|
+
}
|
|
2211
|
+
}, 200);
|
|
2140
2212
|
}
|
|
2141
2213
|
};
|
|
2142
2214
|
return handle;
|
|
@@ -2169,7 +2241,7 @@ function WorkflowTracker({ workflows, expanded, onStepClick, onDismiss }) {
|
|
|
2169
2241
|
}
|
|
2170
2242
|
|
|
2171
2243
|
// ../adaptives/adaptive-overlays/dist/WorkflowWidget.js
|
|
2172
|
-
function showWorkflowToast(
|
|
2244
|
+
function showWorkflowToast(notification) {
|
|
2173
2245
|
const toast = document.createElement("div");
|
|
2174
2246
|
toast.setAttribute("data-testid", "workflow-toast");
|
|
2175
2247
|
toast.className = "se-fixed se-bottom-4 se-right-4 se-z-50";
|
|
@@ -2203,7 +2275,7 @@ function showWorkflowToast(container, notification) {
|
|
|
2203
2275
|
bodyEl.textContent = notification.body;
|
|
2204
2276
|
toast.appendChild(bodyEl);
|
|
2205
2277
|
}
|
|
2206
|
-
|
|
2278
|
+
document.body.appendChild(toast);
|
|
2207
2279
|
let removeTimer;
|
|
2208
2280
|
const fadeTimer = setTimeout(() => {
|
|
2209
2281
|
toast.style.opacity = "0";
|
|
@@ -2221,7 +2293,7 @@ function extractWorkflowsFromActive(activeActions) {
|
|
|
2221
2293
|
const workflows = /* @__PURE__ */ new Map();
|
|
2222
2294
|
for (const entry of activeActions) {
|
|
2223
2295
|
const action = entry.action;
|
|
2224
|
-
if (action.kind === "
|
|
2296
|
+
if (action.kind === "overlays:tour" && action.workflow && action.tourId) {
|
|
2225
2297
|
const meta = action.workflow;
|
|
2226
2298
|
const rawSteps = action.steps || [];
|
|
2227
2299
|
const steps = rawSteps.map((s) => {
|
|
@@ -2302,10 +2374,10 @@ function WorkflowWidgetInner({ runtime: runtime3 }) {
|
|
|
2302
2374
|
return newEntries.length > 0 ? [...prev, ...newEntries] : prev;
|
|
2303
2375
|
});
|
|
2304
2376
|
for (const [tourId, { meta }] of tourWorkflows) {
|
|
2305
|
-
if (!notifiedRef.current.has(tourId) && meta.notification &&
|
|
2377
|
+
if (!notifiedRef.current.has(tourId) && meta.notification && !dismissed.includes(tourId) && !completed[tourId]) {
|
|
2306
2378
|
notifiedRef.current.add(tourId);
|
|
2307
2379
|
(_c = stateNs == null ? void 0 : stateNs.set) == null ? void 0 : _c.call(stateNs, "notified", [...notifiedRef.current]);
|
|
2308
|
-
const cleanup = showWorkflowToast(
|
|
2380
|
+
const cleanup = showWorkflowToast(meta.notification);
|
|
2309
2381
|
toastCleanupsRef.current.push(cleanup);
|
|
2310
2382
|
}
|
|
2311
2383
|
}
|
|
@@ -2338,8 +2410,8 @@ function WorkflowWidgetInner({ runtime: runtime3 }) {
|
|
|
2338
2410
|
notifiedRef.current.add(tourId);
|
|
2339
2411
|
(_c = stateNs == null ? void 0 : stateNs.set) == null ? void 0 : _c.call(stateNs, "notified", [...notifiedRef.current]);
|
|
2340
2412
|
const workflow = currentWorkflows.get(tourId);
|
|
2341
|
-
if (
|
|
2342
|
-
const cleanup = showWorkflowToast(
|
|
2413
|
+
if (workflow == null ? void 0 : workflow.meta.notification) {
|
|
2414
|
+
const cleanup = showWorkflowToast(workflow.meta.notification);
|
|
2343
2415
|
toastCleanupsRef.current.push(cleanup);
|
|
2344
2416
|
}
|
|
2345
2417
|
}
|
|
@@ -2443,6 +2515,10 @@ var executeHighlight = async (action, context) => {
|
|
|
2443
2515
|
return { cleanup: () => {
|
|
2444
2516
|
} };
|
|
2445
2517
|
}
|
|
2518
|
+
if (anchorEl.getAttribute("data-syntro-highlight-dismissed")) {
|
|
2519
|
+
return { cleanup: () => {
|
|
2520
|
+
} };
|
|
2521
|
+
}
|
|
2446
2522
|
const existing = anchorEl.getAttribute("data-syntro-highlight");
|
|
2447
2523
|
if (existing) {
|
|
2448
2524
|
const prev = context.overlayRoot.querySelectorAll(".syntro-spotlight-scrim, .syntro-spotlight-ring");
|
|
@@ -2465,7 +2541,10 @@ var executeHighlight = async (action, context) => {
|
|
|
2465
2541
|
ringColor,
|
|
2466
2542
|
blocking: (_i = action.blocking) != null ? _i : false,
|
|
2467
2543
|
onClickOutside: (_j = action.onClickOutside) != null ? _j : true,
|
|
2468
|
-
onEsc: (_k = action.onEsc) != null ? _k : true
|
|
2544
|
+
onEsc: (_k = action.onEsc) != null ? _k : true,
|
|
2545
|
+
onDismiss: () => {
|
|
2546
|
+
anchorEl.setAttribute("data-syntro-highlight-dismissed", "true");
|
|
2547
|
+
}
|
|
2469
2548
|
});
|
|
2470
2549
|
context.publishEvent("action.applied", {
|
|
2471
2550
|
id: context.generateId(),
|
|
@@ -2476,6 +2555,7 @@ var executeHighlight = async (action, context) => {
|
|
|
2476
2555
|
cleanup: () => {
|
|
2477
2556
|
handle.destroy();
|
|
2478
2557
|
anchorEl.removeAttribute("data-syntro-highlight");
|
|
2558
|
+
anchorEl.removeAttribute("data-syntro-highlight-dismissed");
|
|
2479
2559
|
}
|
|
2480
2560
|
};
|
|
2481
2561
|
};
|
|
@@ -2565,6 +2645,8 @@ var executePulse = async (action, context) => {
|
|
|
2565
2645
|
return {
|
|
2566
2646
|
cleanup: () => {
|
|
2567
2647
|
clearTimeout(timeoutId);
|
|
2648
|
+
if (!anchorEl.isConnected)
|
|
2649
|
+
return;
|
|
2568
2650
|
anchorEl.style.animation = originalAnimation;
|
|
2569
2651
|
anchorEl.removeAttribute("data-syntro-pulse");
|
|
2570
2652
|
}
|
|
@@ -2634,7 +2716,12 @@ var executeBadge = async (action, context) => {
|
|
|
2634
2716
|
});
|
|
2635
2717
|
return {
|
|
2636
2718
|
cleanup: () => {
|
|
2637
|
-
|
|
2719
|
+
try {
|
|
2720
|
+
badge2.remove();
|
|
2721
|
+
} catch {
|
|
2722
|
+
}
|
|
2723
|
+
if (!anchorEl.isConnected)
|
|
2724
|
+
return;
|
|
2638
2725
|
if (originalPosition !== void 0) {
|
|
2639
2726
|
anchorEl.style.position = originalPosition;
|
|
2640
2727
|
}
|
|
@@ -2729,7 +2816,7 @@ var executors2 = [
|
|
|
2729
2816
|
{ kind: "overlays:badge", executor: executeBadge },
|
|
2730
2817
|
{ kind: "overlays:tooltip", executor: executeTooltip },
|
|
2731
2818
|
{ kind: "overlays:modal", executor: executeModal },
|
|
2732
|
-
{ kind: "
|
|
2819
|
+
{ kind: "overlays:tour", executor: executeTour },
|
|
2733
2820
|
{ kind: "overlays:celebrate", executor: executeCelebrate }
|
|
2734
2821
|
];
|
|
2735
2822
|
var runtime2 = {
|
|
@@ -2849,7 +2936,15 @@ var CORE_ACTION_KINDS = /* @__PURE__ */ new Set([
|
|
|
2849
2936
|
"core:wait",
|
|
2850
2937
|
"core:sequence",
|
|
2851
2938
|
"core:parallel",
|
|
2852
|
-
"
|
|
2939
|
+
"overlays:tour"
|
|
2940
|
+
]);
|
|
2941
|
+
var BUNDLED_APP_IDS = /* @__PURE__ */ new Set([
|
|
2942
|
+
"adaptive-chatbot",
|
|
2943
|
+
"adaptive-content",
|
|
2944
|
+
"adaptive-faq",
|
|
2945
|
+
"adaptive-gamification",
|
|
2946
|
+
"adaptive-nav",
|
|
2947
|
+
"adaptive-overlays"
|
|
2853
2948
|
]);
|
|
2854
2949
|
var NAMESPACE_TO_APP_ID = {
|
|
2855
2950
|
faq: "adaptive-faq",
|
|
@@ -3003,6 +3098,9 @@ function createAppLoader(options) {
|
|
|
3003
3098
|
}
|
|
3004
3099
|
}
|
|
3005
3100
|
}
|
|
3101
|
+
for (const bundled of BUNDLED_APP_IDS) {
|
|
3102
|
+
appIds.delete(bundled);
|
|
3103
|
+
}
|
|
3006
3104
|
return Array.from(appIds);
|
|
3007
3105
|
}
|
|
3008
3106
|
async function loadAppsForConfig(config) {
|
|
@@ -3358,7 +3456,7 @@ function getAntiFlickerSnippet(config = {}) {
|
|
|
3358
3456
|
}
|
|
3359
3457
|
|
|
3360
3458
|
// src/version.ts
|
|
3361
|
-
var SDK_VERSION = "2.8.0-canary.
|
|
3459
|
+
var SDK_VERSION = "2.8.0-canary.71";
|
|
3362
3460
|
|
|
3363
3461
|
// src/types.ts
|
|
3364
3462
|
var SDK_SCHEMA_VERSION = "2.0";
|
|
@@ -3381,7 +3479,8 @@ function resolveVariantConfigs(client, keys, _strategy = "first-match") {
|
|
|
3381
3479
|
...variant.configVersion && { configVersion: variant.configVersion },
|
|
3382
3480
|
...variant.canvasTitle && { canvasTitle: variant.canvasTitle },
|
|
3383
3481
|
...variant.theme && { theme: variant.theme },
|
|
3384
|
-
...variant.launcher && { launcher: variant.launcher }
|
|
3482
|
+
...variant.launcher && { launcher: variant.launcher },
|
|
3483
|
+
...variant.meta && { meta: variant.meta }
|
|
3385
3484
|
};
|
|
3386
3485
|
}
|
|
3387
3486
|
}
|
|
@@ -3509,12 +3608,14 @@ function getCachedConfig(sdkVersion) {
|
|
|
3509
3608
|
var resolveConfigUri = ({
|
|
3510
3609
|
configUri,
|
|
3511
3610
|
experiments,
|
|
3512
|
-
featureKey
|
|
3611
|
+
featureKey
|
|
3513
3612
|
}) => {
|
|
3514
3613
|
var _a2;
|
|
3515
3614
|
if (configUri) return configUri;
|
|
3516
|
-
|
|
3517
|
-
|
|
3615
|
+
if (experiments && featureKey) {
|
|
3616
|
+
const fromFeature = (_a2 = experiments.getFeatureValue) == null ? void 0 : _a2.call(experiments, featureKey, null);
|
|
3617
|
+
if (fromFeature) return fromFeature;
|
|
3618
|
+
}
|
|
3518
3619
|
return void 0;
|
|
3519
3620
|
};
|
|
3520
3621
|
function getVariantFlagKeys(experiments, manifestKey, variantFlagPrefix) {
|
|
@@ -3540,7 +3641,7 @@ var createCanvasConfigFetcher = ({
|
|
|
3540
3641
|
experiments,
|
|
3541
3642
|
featureKey,
|
|
3542
3643
|
credentials,
|
|
3543
|
-
configFeatureKey
|
|
3644
|
+
configFeatureKey,
|
|
3544
3645
|
manifestKey,
|
|
3545
3646
|
variantFlagPrefix,
|
|
3546
3647
|
sdkVersion
|
|
@@ -3641,7 +3742,8 @@ function registerFromTriggerWhen(triggerWhen, accumulator) {
|
|
|
3641
3742
|
if (cond.type === "event_count" && cond.key) {
|
|
3642
3743
|
const counter = cond.counter;
|
|
3643
3744
|
const predicate = counter ? buildPredicate(counter) : () => true;
|
|
3644
|
-
|
|
3745
|
+
const needsTimestamps = typeof cond.withinMs === "number";
|
|
3746
|
+
accumulator.register(cond.key, predicate, needsTimestamps);
|
|
3645
3747
|
}
|
|
3646
3748
|
}
|
|
3647
3749
|
}
|
|
@@ -3734,133 +3836,743 @@ function useShadowRoot() {
|
|
|
3734
3836
|
return ctx;
|
|
3735
3837
|
}
|
|
3736
3838
|
|
|
3737
|
-
//
|
|
3839
|
+
// ../event-processor/dist/types.js
|
|
3840
|
+
var EVENT_SCHEMA_VERSION = "1.0.0";
|
|
3738
3841
|
var StandardEvents = {
|
|
3739
|
-
// UI events (from PostHog autocapture)
|
|
3740
3842
|
UI_CLICK: "ui.click",
|
|
3741
3843
|
UI_SCROLL: "ui.scroll",
|
|
3742
3844
|
UI_INPUT: "ui.input",
|
|
3743
3845
|
UI_CHANGE: "ui.change",
|
|
3744
3846
|
UI_SUBMIT: "ui.submit",
|
|
3745
|
-
// Navigation events
|
|
3746
3847
|
NAV_PAGE_VIEW: "nav.page_view",
|
|
3747
3848
|
NAV_PAGE_LEAVE: "nav.page_leave",
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3849
|
+
UI_HESITATE: "ui.hesitate",
|
|
3850
|
+
UI_RAGE_CLICK: "ui.rage_click",
|
|
3851
|
+
UI_SCROLL_THRASH: "ui.scroll_thrash",
|
|
3852
|
+
UI_FOCUS_BOUNCE: "ui.focus_bounce",
|
|
3853
|
+
UI_IDLE: "ui.idle",
|
|
3854
|
+
UI_HOVER: "ui.hover"
|
|
3855
|
+
};
|
|
3856
|
+
var RRWebSource = {
|
|
3857
|
+
Mutation: 0,
|
|
3858
|
+
MouseMove: 1,
|
|
3859
|
+
MouseInteraction: 2,
|
|
3860
|
+
Scroll: 3,
|
|
3861
|
+
ViewportResize: 4,
|
|
3862
|
+
Input: 5,
|
|
3863
|
+
TouchMove: 6,
|
|
3864
|
+
MediaInteraction: 7,
|
|
3865
|
+
Drag: 12
|
|
3866
|
+
};
|
|
3867
|
+
var RRWebMouseInteraction = {
|
|
3868
|
+
MouseUp: 0,
|
|
3869
|
+
MouseDown: 1,
|
|
3870
|
+
Click: 2,
|
|
3871
|
+
ContextMenu: 3,
|
|
3872
|
+
DblClick: 4,
|
|
3873
|
+
Focus: 5,
|
|
3874
|
+
Blur: 6,
|
|
3875
|
+
TouchStart: 7,
|
|
3876
|
+
TouchEnd: 9
|
|
3877
|
+
};
|
|
3878
|
+
var DEFAULT_DETECTOR_CONFIG = {
|
|
3879
|
+
hesitationMs: 3e3,
|
|
3880
|
+
hesitationRadiusPx: 10,
|
|
3881
|
+
rageClickCount: 3,
|
|
3882
|
+
rageClickWindowMs: 1e3,
|
|
3883
|
+
rageClickRadiusPx: 30,
|
|
3884
|
+
scrollThrashReversals: 3,
|
|
3885
|
+
scrollThrashWindowMs: 2e3,
|
|
3886
|
+
focusBounceMaxInputs: 0,
|
|
3887
|
+
idleMs: 5e3,
|
|
3888
|
+
hoverSampleMs: 100
|
|
3777
3889
|
};
|
|
3778
|
-
var EVENT_SCHEMA_VERSION = "1.0.0";
|
|
3779
3890
|
|
|
3780
|
-
//
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3891
|
+
// ../event-processor/dist/normalizers/posthog.js
|
|
3892
|
+
var POSTHOG_EVENT_MAP = {
|
|
3893
|
+
// NOTE: $autocapture is intentionally NOT in this map.
|
|
3894
|
+
// It's handled below in getEventName() with $event_type refinement
|
|
3895
|
+
// so that change/submit events aren't all mapped to ui.click.
|
|
3896
|
+
$click: StandardEvents.UI_CLICK,
|
|
3897
|
+
$scroll: StandardEvents.UI_SCROLL,
|
|
3898
|
+
$input: StandardEvents.UI_INPUT,
|
|
3899
|
+
$change: StandardEvents.UI_CHANGE,
|
|
3900
|
+
$submit: StandardEvents.UI_SUBMIT,
|
|
3901
|
+
// Navigation events
|
|
3902
|
+
$pageview: StandardEvents.NAV_PAGE_VIEW,
|
|
3903
|
+
$pageleave: StandardEvents.NAV_PAGE_LEAVE,
|
|
3904
|
+
// Session events
|
|
3905
|
+
$session_start: "session.start",
|
|
3906
|
+
// Identify events
|
|
3907
|
+
$identify: "user.identify"
|
|
3908
|
+
};
|
|
3909
|
+
function getEventName(phEvent) {
|
|
3910
|
+
var _a2, _b;
|
|
3911
|
+
const eventName = phEvent.event;
|
|
3912
|
+
if (typeof eventName !== "string") {
|
|
3913
|
+
return "posthog.unknown";
|
|
3914
|
+
}
|
|
3915
|
+
if (POSTHOG_EVENT_MAP[eventName]) {
|
|
3916
|
+
return POSTHOG_EVENT_MAP[eventName];
|
|
3917
|
+
}
|
|
3918
|
+
if (eventName === "$autocapture") {
|
|
3919
|
+
const tagName = (_a2 = phEvent.properties) == null ? void 0 : _a2.$tag_name;
|
|
3920
|
+
const eventType = (_b = phEvent.properties) == null ? void 0 : _b.$event_type;
|
|
3921
|
+
if (eventType === "submit")
|
|
3922
|
+
return StandardEvents.UI_SUBMIT;
|
|
3923
|
+
if (eventType === "change")
|
|
3924
|
+
return StandardEvents.UI_CHANGE;
|
|
3925
|
+
if (tagName === "input" || tagName === "textarea")
|
|
3926
|
+
return StandardEvents.UI_INPUT;
|
|
3927
|
+
return StandardEvents.UI_CLICK;
|
|
3928
|
+
}
|
|
3929
|
+
if (!eventName.startsWith("$")) {
|
|
3930
|
+
return `posthog.${eventName}`;
|
|
3931
|
+
}
|
|
3932
|
+
return eventName.replace("$", "posthog.");
|
|
3804
3933
|
}
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3934
|
+
var INTERACTIVE_TAGS = /* @__PURE__ */ new Set(["a", "button", "input", "select", "textarea"]);
|
|
3935
|
+
function parseElementsChain(chain) {
|
|
3936
|
+
if (!chain)
|
|
3937
|
+
return void 0;
|
|
3938
|
+
return chain.split(";").map((segment) => {
|
|
3939
|
+
const el = {};
|
|
3940
|
+
const colonIdx = segment.indexOf(":");
|
|
3941
|
+
const tagPart = colonIdx >= 0 ? segment.slice(0, colonIdx) : segment;
|
|
3942
|
+
const attrPart = colonIdx >= 0 ? segment.slice(colonIdx + 1) : "";
|
|
3943
|
+
const dotIdx = tagPart.indexOf(".");
|
|
3944
|
+
if (dotIdx >= 0) {
|
|
3945
|
+
el.tag_name = tagPart.slice(0, dotIdx);
|
|
3946
|
+
el.attr__class = tagPart.slice(dotIdx + 1).replace(/\./g, " ");
|
|
3947
|
+
} else {
|
|
3948
|
+
el.tag_name = tagPart;
|
|
3949
|
+
}
|
|
3950
|
+
const attrRegex = /([\w$]+)="([^"]*)"/g;
|
|
3951
|
+
let match;
|
|
3952
|
+
while ((match = attrRegex.exec(attrPart)) !== null) {
|
|
3953
|
+
const [, key, value] = match;
|
|
3954
|
+
if (key === "nth-child" || key === "nth-of-type")
|
|
3955
|
+
continue;
|
|
3956
|
+
el[key] = value;
|
|
3957
|
+
}
|
|
3958
|
+
if (el.text) {
|
|
3959
|
+
el.$el_text = el.text;
|
|
3960
|
+
delete el.text;
|
|
3961
|
+
}
|
|
3962
|
+
return el;
|
|
3810
3963
|
});
|
|
3811
3964
|
}
|
|
3812
|
-
function
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3965
|
+
function resolveInteractiveTag(elements, directTag) {
|
|
3966
|
+
if (directTag && INTERACTIVE_TAGS.has(directTag))
|
|
3967
|
+
return directTag;
|
|
3968
|
+
if (!elements)
|
|
3969
|
+
return directTag;
|
|
3970
|
+
for (const el of elements) {
|
|
3971
|
+
const tag2 = el.tag_name;
|
|
3972
|
+
if (tag2 && INTERACTIVE_TAGS.has(tag2))
|
|
3973
|
+
return tag2;
|
|
3974
|
+
}
|
|
3975
|
+
return directTag;
|
|
3817
3976
|
}
|
|
3818
|
-
function
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3977
|
+
function extractProps(phEvent) {
|
|
3978
|
+
var _a2, _b, _c;
|
|
3979
|
+
const props = {};
|
|
3980
|
+
const phProps = phEvent.properties || {};
|
|
3981
|
+
const elements = (_a2 = phProps.$elements) != null ? _a2 : typeof phProps.$elements_chain === "string" ? parseElementsChain(phProps.$elements_chain) : void 0;
|
|
3982
|
+
const directTag = (_c = phProps.$tag_name) != null ? _c : (_b = elements == null ? void 0 : elements[0]) == null ? void 0 : _b.tag_name;
|
|
3983
|
+
const isClickEvent = phEvent.event === "$autocapture" || phEvent.event === "$click";
|
|
3984
|
+
props.tagName = isClickEvent ? resolveInteractiveTag(elements, directTag) : directTag;
|
|
3985
|
+
if (phProps.$el_text)
|
|
3986
|
+
props.elementText = phProps.$el_text;
|
|
3987
|
+
if (elements)
|
|
3988
|
+
props.elements = elements;
|
|
3989
|
+
if (isClickEvent && !elements) {
|
|
3990
|
+
console.warn(`[PostHogNormalizer] $autocapture click has no element chain. PostHog may have changed wire format. Properties: $elements=${!!phProps.$elements}, $elements_chain=${typeof phProps.$elements_chain}`);
|
|
3991
|
+
}
|
|
3992
|
+
if (phProps.$current_url)
|
|
3993
|
+
props.url = phProps.$current_url;
|
|
3994
|
+
if (phProps.$pathname)
|
|
3995
|
+
props.pathname = phProps.$pathname;
|
|
3996
|
+
if (phProps.$host)
|
|
3997
|
+
props.host = phProps.$host;
|
|
3998
|
+
if (phProps.$viewport_width)
|
|
3999
|
+
props.viewportWidth = phProps.$viewport_width;
|
|
4000
|
+
if (phProps.$viewport_height)
|
|
4001
|
+
props.viewportHeight = phProps.$viewport_height;
|
|
4002
|
+
if (phProps.$session_id)
|
|
4003
|
+
props.sessionId = phProps.$session_id;
|
|
4004
|
+
if (phProps.$scroll_depth)
|
|
4005
|
+
props.scrollDepth = phProps.$scroll_depth;
|
|
4006
|
+
if (phProps.$scroll_percentage)
|
|
4007
|
+
props.scrollPercentage = phProps.$scroll_percentage;
|
|
4008
|
+
props.originalEvent = phEvent.event;
|
|
4009
|
+
return props;
|
|
3823
4010
|
}
|
|
3824
|
-
function
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
4011
|
+
function normalizePostHogEvent(phEvent) {
|
|
4012
|
+
let ts;
|
|
4013
|
+
if (typeof phEvent.timestamp === "number") {
|
|
4014
|
+
ts = phEvent.timestamp;
|
|
4015
|
+
} else if (typeof phEvent.timestamp === "string") {
|
|
4016
|
+
ts = new Date(phEvent.timestamp).getTime();
|
|
4017
|
+
} else {
|
|
4018
|
+
ts = Date.now();
|
|
4019
|
+
}
|
|
4020
|
+
return {
|
|
4021
|
+
ts,
|
|
4022
|
+
name: getEventName(phEvent),
|
|
4023
|
+
source: "posthog",
|
|
4024
|
+
props: extractProps(phEvent),
|
|
4025
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
4026
|
+
};
|
|
3830
4027
|
}
|
|
3831
|
-
function
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
4028
|
+
function shouldNormalizeEvent(phEvent) {
|
|
4029
|
+
const eventName = phEvent.event;
|
|
4030
|
+
if (typeof eventName !== "string")
|
|
4031
|
+
return false;
|
|
4032
|
+
const skipEvents = [
|
|
4033
|
+
"$feature_flag_called",
|
|
4034
|
+
"$feature_flags",
|
|
4035
|
+
"$groups",
|
|
4036
|
+
"$groupidentify",
|
|
4037
|
+
"$set",
|
|
4038
|
+
"$set_once",
|
|
4039
|
+
"$unset",
|
|
4040
|
+
"$create_alias",
|
|
4041
|
+
"$capture_metrics",
|
|
4042
|
+
"$performance_event",
|
|
4043
|
+
"$web_vitals",
|
|
4044
|
+
"$exception",
|
|
4045
|
+
"$dead_click",
|
|
4046
|
+
"$heatmap"
|
|
4047
|
+
];
|
|
4048
|
+
if (skipEvents.includes(eventName)) {
|
|
4049
|
+
return false;
|
|
4050
|
+
}
|
|
4051
|
+
return true;
|
|
3837
4052
|
}
|
|
3838
|
-
function
|
|
3839
|
-
|
|
3840
|
-
|
|
4053
|
+
function createPostHogNormalizer(publishFn) {
|
|
4054
|
+
return (eventName, properties) => {
|
|
4055
|
+
if (typeof eventName !== "string")
|
|
4056
|
+
return;
|
|
4057
|
+
const phEvent = {
|
|
4058
|
+
event: eventName,
|
|
4059
|
+
properties,
|
|
4060
|
+
timestamp: Date.now()
|
|
4061
|
+
};
|
|
4062
|
+
if (shouldNormalizeEvent(phEvent)) {
|
|
4063
|
+
const normalizedEvent = normalizePostHogEvent(phEvent);
|
|
4064
|
+
publishFn(normalizedEvent);
|
|
4065
|
+
}
|
|
4066
|
+
};
|
|
3841
4067
|
}
|
|
3842
|
-
var CanvasEvents = {
|
|
3843
|
-
canvasOpened,
|
|
3844
|
-
canvasClosed,
|
|
3845
|
-
tileViewed,
|
|
3846
|
-
tileExpanded,
|
|
3847
|
-
tileCollapsed,
|
|
3848
|
-
tileAction,
|
|
3849
|
-
overlayStarted,
|
|
3850
|
-
overlayCompleted,
|
|
3851
|
-
overlayDismissed,
|
|
3852
|
-
overlayStepViewed,
|
|
3853
|
-
custom: customCanvasEvent
|
|
3854
|
-
};
|
|
3855
4068
|
|
|
3856
|
-
//
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
4069
|
+
// ../event-processor/dist/detectors/focus-bounce.js
|
|
4070
|
+
var FocusBounceDetector = class {
|
|
4071
|
+
constructor(config, emit2) {
|
|
4072
|
+
this.config = config;
|
|
4073
|
+
this.emit = emit2;
|
|
4074
|
+
this.focused = /* @__PURE__ */ new Map();
|
|
4075
|
+
}
|
|
4076
|
+
ingest(raw) {
|
|
4077
|
+
var _a2, _b;
|
|
4078
|
+
if (raw.type !== 3)
|
|
4079
|
+
return;
|
|
4080
|
+
const ts = raw.timestamp;
|
|
4081
|
+
if (raw.data.source === RRWebSource.MouseInteraction) {
|
|
4082
|
+
const id = (_a2 = raw.data.id) != null ? _a2 : 0;
|
|
4083
|
+
if (raw.data.type === RRWebMouseInteraction.Focus) {
|
|
4084
|
+
this.focused.set(id, { id, focusTs: ts, inputCount: 0 });
|
|
4085
|
+
} else if (raw.data.type === RRWebMouseInteraction.Blur) {
|
|
4086
|
+
const entry = this.focused.get(id);
|
|
4087
|
+
if (entry && entry.inputCount <= this.config.focusBounceMaxInputs) {
|
|
4088
|
+
this.emit({
|
|
4089
|
+
ts,
|
|
4090
|
+
name: StandardEvents.UI_FOCUS_BOUNCE,
|
|
4091
|
+
source: "rrweb",
|
|
4092
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4093
|
+
props: {
|
|
4094
|
+
elementId: id,
|
|
4095
|
+
duration_ms: ts - entry.focusTs
|
|
4096
|
+
}
|
|
4097
|
+
});
|
|
4098
|
+
}
|
|
4099
|
+
this.focused.delete(id);
|
|
4100
|
+
}
|
|
4101
|
+
} else if (raw.data.source === RRWebSource.Input) {
|
|
4102
|
+
const id = (_b = raw.data.id) != null ? _b : 0;
|
|
4103
|
+
const entry = this.focused.get(id);
|
|
4104
|
+
if (entry) {
|
|
4105
|
+
entry.inputCount++;
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
};
|
|
4110
|
+
|
|
4111
|
+
// ../event-processor/dist/detectors/hesitation.js
|
|
4112
|
+
var HesitationDetector = class {
|
|
4113
|
+
constructor(config, emit2) {
|
|
4114
|
+
this.config = config;
|
|
4115
|
+
this.emit = emit2;
|
|
4116
|
+
this.anchorX = 0;
|
|
4117
|
+
this.anchorY = 0;
|
|
4118
|
+
this.anchorTs = 0;
|
|
4119
|
+
this.emitted = false;
|
|
4120
|
+
this.hasPosition = false;
|
|
4121
|
+
}
|
|
4122
|
+
ingest(raw) {
|
|
4123
|
+
var _a2;
|
|
4124
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseMove)
|
|
4125
|
+
return;
|
|
4126
|
+
const positions = raw.data.positions;
|
|
4127
|
+
if (!positions || positions.length === 0)
|
|
4128
|
+
return;
|
|
4129
|
+
const last = positions[positions.length - 1];
|
|
4130
|
+
const ts = raw.timestamp + ((_a2 = last.timeOffset) != null ? _a2 : 0);
|
|
4131
|
+
if (!this.hasPosition) {
|
|
4132
|
+
this.anchorX = last.x;
|
|
4133
|
+
this.anchorY = last.y;
|
|
4134
|
+
this.anchorTs = ts;
|
|
4135
|
+
this.hasPosition = true;
|
|
4136
|
+
this.emitted = false;
|
|
4137
|
+
return;
|
|
4138
|
+
}
|
|
4139
|
+
const dx = last.x - this.anchorX;
|
|
4140
|
+
const dy = last.y - this.anchorY;
|
|
4141
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
4142
|
+
if (dist > this.config.hesitationRadiusPx) {
|
|
4143
|
+
this.anchorX = last.x;
|
|
4144
|
+
this.anchorY = last.y;
|
|
4145
|
+
this.anchorTs = ts;
|
|
4146
|
+
this.emitted = false;
|
|
4147
|
+
}
|
|
4148
|
+
}
|
|
4149
|
+
tick(now) {
|
|
4150
|
+
if (!this.hasPosition || this.emitted)
|
|
4151
|
+
return;
|
|
4152
|
+
const elapsed = now - this.anchorTs;
|
|
4153
|
+
if (elapsed >= this.config.hesitationMs) {
|
|
4154
|
+
this.emit({
|
|
4155
|
+
ts: now,
|
|
4156
|
+
name: StandardEvents.UI_HESITATE,
|
|
4157
|
+
source: "rrweb",
|
|
4158
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4159
|
+
props: {
|
|
4160
|
+
x: this.anchorX,
|
|
4161
|
+
y: this.anchorY,
|
|
4162
|
+
duration_ms: elapsed
|
|
4163
|
+
}
|
|
4164
|
+
});
|
|
4165
|
+
this.emitted = true;
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
};
|
|
4169
|
+
|
|
4170
|
+
// ../event-processor/dist/detectors/hover.js
|
|
4171
|
+
var HoverTracker = class {
|
|
4172
|
+
constructor(config, emit2, elementResolver) {
|
|
4173
|
+
this.config = config;
|
|
4174
|
+
this.emit = emit2;
|
|
4175
|
+
this.elementResolver = elementResolver;
|
|
4176
|
+
this.currentElement = null;
|
|
4177
|
+
this.hoverStartTs = null;
|
|
4178
|
+
this.lastX = 0;
|
|
4179
|
+
this.lastY = 0;
|
|
4180
|
+
this.lastSampleTs = -Infinity;
|
|
4181
|
+
}
|
|
4182
|
+
ingest(raw) {
|
|
4183
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseMove)
|
|
4184
|
+
return;
|
|
4185
|
+
const positions = raw.data.positions;
|
|
4186
|
+
if (!positions || positions.length === 0)
|
|
4187
|
+
return;
|
|
4188
|
+
const last = positions[positions.length - 1];
|
|
4189
|
+
this.lastX = last.x;
|
|
4190
|
+
this.lastY = last.y;
|
|
4191
|
+
}
|
|
4192
|
+
tick(now) {
|
|
4193
|
+
if (!this.elementResolver)
|
|
4194
|
+
return;
|
|
4195
|
+
if (now - this.lastSampleTs < this.config.hoverSampleMs)
|
|
4196
|
+
return;
|
|
4197
|
+
this.lastSampleTs = now;
|
|
4198
|
+
const newElement = this.elementResolver(this.lastX, this.lastY);
|
|
4199
|
+
const newKey = newElement ? elementKey(newElement) : null;
|
|
4200
|
+
const currentKey = this.currentElement ? elementKey(this.currentElement) : null;
|
|
4201
|
+
if (newKey !== currentKey) {
|
|
4202
|
+
if (this.currentElement && this.hoverStartTs !== null) {
|
|
4203
|
+
this.emit({
|
|
4204
|
+
ts: now,
|
|
4205
|
+
name: StandardEvents.UI_HOVER,
|
|
4206
|
+
source: "rrweb",
|
|
4207
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4208
|
+
props: {
|
|
4209
|
+
x: this.lastX,
|
|
4210
|
+
y: this.lastY,
|
|
4211
|
+
duration_ms: now - this.hoverStartTs,
|
|
4212
|
+
element: this.currentElement
|
|
4213
|
+
}
|
|
4214
|
+
});
|
|
4215
|
+
}
|
|
4216
|
+
this.currentElement = newElement;
|
|
4217
|
+
this.hoverStartTs = now;
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
};
|
|
4221
|
+
function elementKey(el) {
|
|
4222
|
+
var _a2, _b, _c;
|
|
4223
|
+
return `${(_a2 = el.tag_name) != null ? _a2 : ""}|${(_b = el.attr__id) != null ? _b : ""}|${((_c = el.classes) != null ? _c : []).join(",")}`;
|
|
4224
|
+
}
|
|
4225
|
+
|
|
4226
|
+
// ../event-processor/dist/detectors/idle.js
|
|
4227
|
+
var IdleDetector = class {
|
|
4228
|
+
constructor(config, emit2) {
|
|
4229
|
+
this.config = config;
|
|
4230
|
+
this.emit = emit2;
|
|
4231
|
+
this.lastActivityTs = null;
|
|
4232
|
+
this.emitted = false;
|
|
4233
|
+
}
|
|
4234
|
+
ingest(raw) {
|
|
4235
|
+
if (raw.type !== 3)
|
|
4236
|
+
return;
|
|
4237
|
+
const src = raw.data.source;
|
|
4238
|
+
if (src === RRWebSource.MouseMove || src === RRWebSource.MouseInteraction || src === RRWebSource.Scroll) {
|
|
4239
|
+
this.lastActivityTs = raw.timestamp;
|
|
4240
|
+
this.emitted = false;
|
|
4241
|
+
}
|
|
4242
|
+
}
|
|
4243
|
+
tick(now) {
|
|
4244
|
+
if (this.lastActivityTs === null || this.emitted)
|
|
4245
|
+
return;
|
|
4246
|
+
if (now - this.lastActivityTs >= this.config.idleMs) {
|
|
4247
|
+
this.emit({
|
|
4248
|
+
ts: now,
|
|
4249
|
+
name: StandardEvents.UI_IDLE,
|
|
4250
|
+
source: "rrweb",
|
|
4251
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4252
|
+
props: {
|
|
4253
|
+
idle_ms: now - this.lastActivityTs
|
|
4254
|
+
}
|
|
4255
|
+
});
|
|
4256
|
+
this.emitted = true;
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
};
|
|
4260
|
+
|
|
4261
|
+
// ../event-processor/dist/detectors/rage-click.js
|
|
4262
|
+
var RageClickDetector = class {
|
|
4263
|
+
constructor(config, emit2) {
|
|
4264
|
+
this.config = config;
|
|
4265
|
+
this.emit = emit2;
|
|
4266
|
+
this.clicks = [];
|
|
4267
|
+
}
|
|
4268
|
+
ingest(raw) {
|
|
4269
|
+
var _a2, _b;
|
|
4270
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseInteraction)
|
|
4271
|
+
return;
|
|
4272
|
+
if (raw.data.type !== RRWebMouseInteraction.Click)
|
|
4273
|
+
return;
|
|
4274
|
+
const x = (_a2 = raw.data.x) != null ? _a2 : 0;
|
|
4275
|
+
const y = (_b = raw.data.y) != null ? _b : 0;
|
|
4276
|
+
const ts = raw.timestamp;
|
|
4277
|
+
const cutoff = ts - this.config.rageClickWindowMs;
|
|
4278
|
+
this.clicks = this.clicks.filter((c) => c.ts >= cutoff);
|
|
4279
|
+
this.clicks.push({ ts, x, y });
|
|
4280
|
+
const nearby = this.clicks.filter((c) => {
|
|
4281
|
+
const dx = c.x - x;
|
|
4282
|
+
const dy = c.y - y;
|
|
4283
|
+
return Math.sqrt(dx * dx + dy * dy) <= this.config.rageClickRadiusPx;
|
|
4284
|
+
});
|
|
4285
|
+
if (nearby.length >= this.config.rageClickCount) {
|
|
4286
|
+
this.emit({
|
|
4287
|
+
ts,
|
|
4288
|
+
name: StandardEvents.UI_RAGE_CLICK,
|
|
4289
|
+
source: "rrweb",
|
|
4290
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4291
|
+
props: {
|
|
4292
|
+
x,
|
|
4293
|
+
y,
|
|
4294
|
+
clickCount: nearby.length,
|
|
4295
|
+
duration_ms: ts - nearby[0].ts
|
|
4296
|
+
}
|
|
4297
|
+
});
|
|
4298
|
+
this.clicks = [];
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
4301
|
+
};
|
|
4302
|
+
|
|
4303
|
+
// ../event-processor/dist/detectors/scroll-thrash.js
|
|
4304
|
+
var ScrollThrashDetector = class {
|
|
4305
|
+
constructor(config, emit2) {
|
|
4306
|
+
this.config = config;
|
|
4307
|
+
this.emit = emit2;
|
|
4308
|
+
this.lastY = null;
|
|
4309
|
+
this.lastDirection = null;
|
|
4310
|
+
this.reversals = [];
|
|
4311
|
+
}
|
|
4312
|
+
ingest(raw) {
|
|
4313
|
+
var _a2;
|
|
4314
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.Scroll)
|
|
4315
|
+
return;
|
|
4316
|
+
const y = (_a2 = raw.data.y) != null ? _a2 : 0;
|
|
4317
|
+
const ts = raw.timestamp;
|
|
4318
|
+
if (this.lastY !== null) {
|
|
4319
|
+
const direction = y > this.lastY ? "down" : y < this.lastY ? "up" : this.lastDirection;
|
|
4320
|
+
if (direction && direction !== this.lastDirection) {
|
|
4321
|
+
const cutoff = ts - this.config.scrollThrashWindowMs;
|
|
4322
|
+
this.reversals = this.reversals.filter((t) => t > cutoff);
|
|
4323
|
+
this.reversals.push(ts);
|
|
4324
|
+
if (this.reversals.length >= this.config.scrollThrashReversals) {
|
|
4325
|
+
this.emit({
|
|
4326
|
+
ts,
|
|
4327
|
+
name: StandardEvents.UI_SCROLL_THRASH,
|
|
4328
|
+
source: "rrweb",
|
|
4329
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4330
|
+
props: {
|
|
4331
|
+
reversals: this.reversals.length,
|
|
4332
|
+
duration_ms: ts - this.reversals[0]
|
|
4333
|
+
}
|
|
4334
|
+
});
|
|
4335
|
+
this.reversals = [];
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
this.lastDirection = direction;
|
|
4339
|
+
}
|
|
4340
|
+
this.lastY = y;
|
|
4341
|
+
}
|
|
4342
|
+
};
|
|
4343
|
+
|
|
4344
|
+
// ../event-processor/dist/processor.js
|
|
4345
|
+
function createEventProcessor(options) {
|
|
4346
|
+
const config = { ...DEFAULT_DETECTOR_CONFIG, ...options == null ? void 0 : options.config };
|
|
4347
|
+
const listeners = [];
|
|
4348
|
+
function emit2(event) {
|
|
4349
|
+
for (const cb of listeners)
|
|
4350
|
+
cb(event);
|
|
4351
|
+
}
|
|
4352
|
+
const hesitation = new HesitationDetector(config, emit2);
|
|
4353
|
+
const rageClick = new RageClickDetector(config, emit2);
|
|
4354
|
+
const scrollThrash = new ScrollThrashDetector(config, emit2);
|
|
4355
|
+
const focusBounce = new FocusBounceDetector(config, emit2);
|
|
4356
|
+
const idle = new IdleDetector(config, emit2);
|
|
4357
|
+
const hover = new HoverTracker(config, emit2, options == null ? void 0 : options.elementResolver);
|
|
4358
|
+
const clickAttrBuffer = [];
|
|
4359
|
+
return {
|
|
4360
|
+
ingest(raw) {
|
|
4361
|
+
if (raw.kind === "posthog") {
|
|
4362
|
+
const { kind: _, ...phEvent } = raw;
|
|
4363
|
+
if (shouldNormalizeEvent(phEvent)) {
|
|
4364
|
+
emit2(normalizePostHogEvent(phEvent));
|
|
4365
|
+
}
|
|
4366
|
+
} else if (raw.kind === "rrweb") {
|
|
4367
|
+
hesitation.ingest(raw);
|
|
4368
|
+
rageClick.ingest(raw);
|
|
4369
|
+
scrollThrash.ingest(raw);
|
|
4370
|
+
focusBounce.ingest(raw);
|
|
4371
|
+
idle.ingest(raw);
|
|
4372
|
+
hover.ingest(raw);
|
|
4373
|
+
}
|
|
4374
|
+
},
|
|
4375
|
+
onEvent(callback) {
|
|
4376
|
+
listeners.push(callback);
|
|
4377
|
+
},
|
|
4378
|
+
tick(timestamp) {
|
|
4379
|
+
hesitation.tick(timestamp);
|
|
4380
|
+
idle.tick(timestamp);
|
|
4381
|
+
hover.tick(timestamp);
|
|
4382
|
+
},
|
|
4383
|
+
enrichClickAttributes(timestamp, elements) {
|
|
4384
|
+
clickAttrBuffer.push({ ts: timestamp, elements });
|
|
4385
|
+
const cutoff = timestamp - 500;
|
|
4386
|
+
while (clickAttrBuffer.length > 0 && clickAttrBuffer[0].ts < cutoff) {
|
|
4387
|
+
clickAttrBuffer.shift();
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
4390
|
+
};
|
|
4391
|
+
}
|
|
4392
|
+
|
|
4393
|
+
// src/events/types.ts
|
|
4394
|
+
var StandardEvents2 = {
|
|
4395
|
+
// UI events (from PostHog autocapture)
|
|
4396
|
+
UI_CLICK: "ui.click",
|
|
4397
|
+
UI_SCROLL: "ui.scroll",
|
|
4398
|
+
UI_INPUT: "ui.input",
|
|
4399
|
+
UI_CHANGE: "ui.change",
|
|
4400
|
+
UI_SUBMIT: "ui.submit",
|
|
4401
|
+
// Navigation events
|
|
4402
|
+
NAV_PAGE_VIEW: "nav.page_view",
|
|
4403
|
+
NAV_PAGE_LEAVE: "nav.page_leave",
|
|
4404
|
+
// Canvas events
|
|
4405
|
+
CANVAS_OPENED: "canvas.opened",
|
|
4406
|
+
CANVAS_CLOSED: "canvas.closed",
|
|
4407
|
+
TILE_VIEWED: "tile.viewed",
|
|
4408
|
+
TILE_EXPANDED: "tile.expanded",
|
|
4409
|
+
TILE_COLLAPSED: "tile.collapsed",
|
|
4410
|
+
TILE_ACTION: "tile.action",
|
|
4411
|
+
// Overlay/tour events
|
|
4412
|
+
OVERLAY_STARTED: "overlay.started",
|
|
4413
|
+
OVERLAY_COMPLETED: "overlay.completed",
|
|
4414
|
+
OVERLAY_DISMISSED: "overlay.dismissed",
|
|
4415
|
+
OVERLAY_STEP_VIEWED: "overlay.step_viewed",
|
|
4416
|
+
// Derived behavioral signals (Phase 3)
|
|
4417
|
+
BEHAVIOR_RAGE_CLICK: "behavior.rage_click",
|
|
4418
|
+
BEHAVIOR_HESITATION: "behavior.hesitation",
|
|
4419
|
+
BEHAVIOR_CONFUSION: "behavior.confusion",
|
|
4420
|
+
// Action events
|
|
4421
|
+
ACTION_APPLIED: "action.applied",
|
|
4422
|
+
ACTION_REVERTED: "action.reverted",
|
|
4423
|
+
ACTION_FAILED: "action.failed",
|
|
4424
|
+
ACTION_CTA_CLICKED: "action.cta_clicked",
|
|
4425
|
+
// Notification events
|
|
4426
|
+
NOTIFICATION_SHOWN: "notification.shown",
|
|
4427
|
+
NOTIFICATION_CLICKED: "notification.clicked",
|
|
4428
|
+
NOTIFICATION_DISMISSED: "notification.dismissed",
|
|
4429
|
+
NOTIFICATION_DEEP_LINK: "notification.deep_link",
|
|
4430
|
+
// Surface events
|
|
4431
|
+
SURFACE_MOUNTED: "surface.mounted",
|
|
4432
|
+
SURFACE_UNMOUNTED: "surface.unmounted"
|
|
4433
|
+
};
|
|
4434
|
+
|
|
4435
|
+
// src/events/normalizers/canvas.ts
|
|
4436
|
+
function createCanvasEvent(name, props) {
|
|
4437
|
+
return {
|
|
4438
|
+
ts: Date.now(),
|
|
4439
|
+
name,
|
|
4440
|
+
source: "canvas",
|
|
4441
|
+
props,
|
|
4442
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
4443
|
+
};
|
|
4444
|
+
}
|
|
4445
|
+
function canvasOpened(surface) {
|
|
4446
|
+
return createCanvasEvent(StandardEvents2.CANVAS_OPENED, { surface });
|
|
4447
|
+
}
|
|
4448
|
+
function canvasClosed(surface) {
|
|
4449
|
+
return createCanvasEvent(StandardEvents2.CANVAS_CLOSED, { surface });
|
|
4450
|
+
}
|
|
4451
|
+
function tileViewed(tileId, surface) {
|
|
4452
|
+
return createCanvasEvent(StandardEvents2.TILE_VIEWED, { tileId, surface });
|
|
4453
|
+
}
|
|
4454
|
+
function tileExpanded(tileId, surface) {
|
|
4455
|
+
return createCanvasEvent(StandardEvents2.TILE_EXPANDED, { tileId, surface });
|
|
4456
|
+
}
|
|
4457
|
+
function tileCollapsed(tileId, surface) {
|
|
4458
|
+
return createCanvasEvent(StandardEvents2.TILE_COLLAPSED, { tileId, surface });
|
|
4459
|
+
}
|
|
4460
|
+
function tileAction(tileId, actionId, surface) {
|
|
4461
|
+
return createCanvasEvent(StandardEvents2.TILE_ACTION, {
|
|
4462
|
+
tileId,
|
|
4463
|
+
actionId,
|
|
4464
|
+
surface
|
|
4465
|
+
});
|
|
4466
|
+
}
|
|
4467
|
+
function overlayStarted(recipeId, recipeName) {
|
|
4468
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_STARTED, {
|
|
4469
|
+
recipeId,
|
|
4470
|
+
recipeName
|
|
4471
|
+
});
|
|
4472
|
+
}
|
|
4473
|
+
function overlayCompleted(recipeId, recipeName) {
|
|
4474
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_COMPLETED, {
|
|
4475
|
+
recipeId,
|
|
4476
|
+
recipeName
|
|
4477
|
+
});
|
|
4478
|
+
}
|
|
4479
|
+
function overlayDismissed(recipeId, recipeName, stepIndex) {
|
|
4480
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_DISMISSED, {
|
|
4481
|
+
recipeId,
|
|
4482
|
+
recipeName,
|
|
4483
|
+
stepIndex
|
|
4484
|
+
});
|
|
4485
|
+
}
|
|
4486
|
+
function overlayStepViewed(recipeId, stepIndex, stepTitle) {
|
|
4487
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_STEP_VIEWED, {
|
|
4488
|
+
recipeId,
|
|
4489
|
+
stepIndex,
|
|
4490
|
+
stepTitle
|
|
4491
|
+
});
|
|
4492
|
+
}
|
|
4493
|
+
function customCanvasEvent(name, props) {
|
|
4494
|
+
const eventName = name.startsWith("canvas.") ? name : `canvas.${name}`;
|
|
4495
|
+
return createCanvasEvent(eventName, props);
|
|
4496
|
+
}
|
|
4497
|
+
var CanvasEvents = {
|
|
4498
|
+
canvasOpened,
|
|
4499
|
+
canvasClosed,
|
|
4500
|
+
tileViewed,
|
|
4501
|
+
tileExpanded,
|
|
4502
|
+
tileCollapsed,
|
|
4503
|
+
tileAction,
|
|
4504
|
+
overlayStarted,
|
|
4505
|
+
overlayCompleted,
|
|
4506
|
+
overlayDismissed,
|
|
4507
|
+
overlayStepViewed,
|
|
4508
|
+
custom: customCanvasEvent
|
|
4509
|
+
};
|
|
4510
|
+
|
|
4511
|
+
// src/components/emojiToIcon.tsx
|
|
4512
|
+
import {
|
|
4513
|
+
AlertTriangle,
|
|
4514
|
+
ArrowRight,
|
|
4515
|
+
Banknote,
|
|
4516
|
+
Bell,
|
|
4517
|
+
BookOpen,
|
|
4518
|
+
CheckCircle,
|
|
4519
|
+
ClipboardList,
|
|
4520
|
+
Compass,
|
|
4521
|
+
FileText,
|
|
4522
|
+
Gamepad2,
|
|
4523
|
+
HelpCircle,
|
|
4524
|
+
Landmark,
|
|
4525
|
+
Layers,
|
|
4526
|
+
Lightbulb,
|
|
4527
|
+
MessageCircle,
|
|
4528
|
+
SkipForward,
|
|
4529
|
+
Sparkles,
|
|
4530
|
+
Timer,
|
|
4531
|
+
Trophy
|
|
4532
|
+
} from "lucide-react";
|
|
4533
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
4534
|
+
var EMOJI_ICON_MAP = {
|
|
4535
|
+
"\u2753": HelpCircle,
|
|
4536
|
+
"\u{1F9ED}": Compass,
|
|
4537
|
+
"\u{1F4DD}": FileText,
|
|
4538
|
+
"\u{1F3AF}": Layers,
|
|
4539
|
+
"\u{1F3C6}": Trophy,
|
|
4540
|
+
"\u2728": Sparkles,
|
|
4541
|
+
"\u{1F4AC}": MessageCircle,
|
|
4542
|
+
"\u{1F3AE}": Gamepad2,
|
|
4543
|
+
"\u{1F4A1}": Lightbulb,
|
|
4544
|
+
"\u{1F4B0}": Banknote,
|
|
4545
|
+
"\u{1F4CB}": ClipboardList,
|
|
4546
|
+
"\u2705": CheckCircle,
|
|
4547
|
+
"\u26A0\uFE0F": AlertTriangle,
|
|
4548
|
+
"\u{1F4B5}": Banknote,
|
|
4549
|
+
"\u{1F3DB}\uFE0F": Landmark,
|
|
4550
|
+
"\u23ED\uFE0F": SkipForward,
|
|
4551
|
+
"\u27A1\uFE0F": ArrowRight,
|
|
4552
|
+
"\u23F1\uFE0F": Timer,
|
|
4553
|
+
"\u{1F4D6}": BookOpen,
|
|
4554
|
+
"\u{1F514}": Bell
|
|
4555
|
+
};
|
|
4556
|
+
function EmojiIcon({
|
|
4557
|
+
emoji,
|
|
4558
|
+
size = 14,
|
|
4559
|
+
color = "currentColor"
|
|
4560
|
+
}) {
|
|
4561
|
+
const Icon = EMOJI_ICON_MAP[emoji];
|
|
4562
|
+
if (!Icon) {
|
|
4563
|
+
return /* @__PURE__ */ jsx2("span", { children: emoji });
|
|
4564
|
+
}
|
|
4565
|
+
return /* @__PURE__ */ jsx2(Icon, { size, color });
|
|
4566
|
+
}
|
|
4567
|
+
|
|
4568
|
+
// src/notifications/NotificationToastStack.tsx
|
|
4569
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
4570
|
+
var TOAST_STYLES_ID = "syntro-toast-styles";
|
|
4571
|
+
var TOAST_CSS = `
|
|
4572
|
+
@keyframes syntro-toast-slide-in {
|
|
4573
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
4574
|
+
to { opacity: 1; transform: translateY(0); }
|
|
4575
|
+
}
|
|
3864
4576
|
@keyframes syntro-toast-progress {
|
|
3865
4577
|
from { width: 100%; }
|
|
3866
4578
|
to { width: 0%; }
|
|
@@ -3891,7 +4603,7 @@ function NotificationToastStack({
|
|
|
3891
4603
|
const { shadowRoot } = useShadowRoot();
|
|
3892
4604
|
ensureToastStyles(shadowRoot);
|
|
3893
4605
|
if (notifications.length === 0) return null;
|
|
3894
|
-
return /* @__PURE__ */
|
|
4606
|
+
return /* @__PURE__ */ jsx3(
|
|
3895
4607
|
"div",
|
|
3896
4608
|
{
|
|
3897
4609
|
"data-testid": "notification-toast-stack",
|
|
@@ -3946,7 +4658,7 @@ function NotificationToastStack({
|
|
|
3946
4658
|
padding: "10px 12px"
|
|
3947
4659
|
},
|
|
3948
4660
|
children: [
|
|
3949
|
-
/* @__PURE__ */
|
|
4661
|
+
/* @__PURE__ */ jsx3(
|
|
3950
4662
|
"div",
|
|
3951
4663
|
{
|
|
3952
4664
|
style: {
|
|
@@ -3960,11 +4672,11 @@ function NotificationToastStack({
|
|
|
3960
4672
|
flexShrink: 0,
|
|
3961
4673
|
fontSize: "14px"
|
|
3962
4674
|
},
|
|
3963
|
-
children: (_a2 = notif.icon) != null ? _a2 : "\u{1F514}"
|
|
4675
|
+
children: /* @__PURE__ */ jsx3(EmojiIcon, { emoji: (_a2 = notif.icon) != null ? _a2 : "\u{1F514}", size: 14 })
|
|
3964
4676
|
}
|
|
3965
4677
|
),
|
|
3966
4678
|
/* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3967
|
-
/* @__PURE__ */
|
|
4679
|
+
/* @__PURE__ */ jsx3(
|
|
3968
4680
|
"div",
|
|
3969
4681
|
{
|
|
3970
4682
|
style: {
|
|
@@ -3979,7 +4691,7 @@ function NotificationToastStack({
|
|
|
3979
4691
|
children: notif.title
|
|
3980
4692
|
}
|
|
3981
4693
|
),
|
|
3982
|
-
notif.body && /* @__PURE__ */
|
|
4694
|
+
notif.body && /* @__PURE__ */ jsx3(
|
|
3983
4695
|
"div",
|
|
3984
4696
|
{
|
|
3985
4697
|
style: {
|
|
@@ -3995,7 +4707,7 @@ function NotificationToastStack({
|
|
|
3995
4707
|
}
|
|
3996
4708
|
)
|
|
3997
4709
|
] }),
|
|
3998
|
-
/* @__PURE__ */
|
|
4710
|
+
/* @__PURE__ */ jsx3(
|
|
3999
4711
|
"button",
|
|
4000
4712
|
{
|
|
4001
4713
|
type: "button",
|
|
@@ -4020,7 +4732,7 @@ function NotificationToastStack({
|
|
|
4020
4732
|
]
|
|
4021
4733
|
}
|
|
4022
4734
|
),
|
|
4023
|
-
/* @__PURE__ */
|
|
4735
|
+
/* @__PURE__ */ jsx3("div", { style: { height: "2px", background: "rgba(0, 0, 0, 0.08)" }, children: /* @__PURE__ */ jsx3(
|
|
4024
4736
|
"div",
|
|
4025
4737
|
{
|
|
4026
4738
|
className: "syntro-toast-progress",
|
|
@@ -4098,7 +4810,7 @@ function useNotifications(eventBus, tiles) {
|
|
|
4098
4810
|
const timerIds = useRef2(/* @__PURE__ */ new Map());
|
|
4099
4811
|
const publishDismissed = useCallback2(
|
|
4100
4812
|
(notif) => {
|
|
4101
|
-
eventBus == null ? void 0 : eventBus.publish(
|
|
4813
|
+
eventBus == null ? void 0 : eventBus.publish(StandardEvents2.NOTIFICATION_DISMISSED, {
|
|
4102
4814
|
notificationId: notif.id,
|
|
4103
4815
|
tileId: notif.tileId,
|
|
4104
4816
|
itemId: notif.itemId
|
|
@@ -4163,7 +4875,7 @@ function useNotifications(eventBus, tiles) {
|
|
|
4163
4875
|
}
|
|
4164
4876
|
return next;
|
|
4165
4877
|
});
|
|
4166
|
-
eventBus.publish(
|
|
4878
|
+
eventBus.publish(StandardEvents2.NOTIFICATION_SHOWN, {
|
|
4167
4879
|
notificationId: matched.id,
|
|
4168
4880
|
tileId: matched.tileId,
|
|
4169
4881
|
itemId: matched.itemId,
|
|
@@ -4234,7 +4946,7 @@ function useNotifyWatcher(runtime3, tiles, appRegistry2) {
|
|
|
4234
4946
|
|
|
4235
4947
|
// src/RuntimeProvider.tsx
|
|
4236
4948
|
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect4, useMemo as useMemo2, useState as useState3 } from "react";
|
|
4237
|
-
import { jsx as
|
|
4949
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
4238
4950
|
var RuntimeReactContext = createContext2({
|
|
4239
4951
|
runtime: null,
|
|
4240
4952
|
context: null
|
|
@@ -4252,7 +4964,7 @@ function RuntimeProvider({ runtime: runtime3, children }) {
|
|
|
4252
4964
|
return unsubscribe;
|
|
4253
4965
|
}, [runtime3]);
|
|
4254
4966
|
const value = useMemo2(() => ({ runtime: runtime3, context }), [runtime3, context]);
|
|
4255
|
-
return /* @__PURE__ */
|
|
4967
|
+
return /* @__PURE__ */ jsx4(RuntimeReactContext.Provider, { value, children });
|
|
4256
4968
|
}
|
|
4257
4969
|
function useRuntime() {
|
|
4258
4970
|
const { runtime: runtime3 } = useContext2(RuntimeReactContext);
|
|
@@ -4326,41 +5038,17 @@ import {
|
|
|
4326
5038
|
} from "react";
|
|
4327
5039
|
|
|
4328
5040
|
// src/components/TileIcon.tsx
|
|
4329
|
-
import {
|
|
4330
|
-
Compass,
|
|
4331
|
-
FileText,
|
|
4332
|
-
Gamepad2,
|
|
4333
|
-
HelpCircle,
|
|
4334
|
-
Layers,
|
|
4335
|
-
MessageCircle,
|
|
4336
|
-
Sparkles,
|
|
4337
|
-
Trophy
|
|
4338
|
-
} from "lucide-react";
|
|
4339
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
4340
|
-
var ICON_MAP = {
|
|
4341
|
-
"\u2753": HelpCircle,
|
|
4342
|
-
"\u{1F9ED}": Compass,
|
|
4343
|
-
"\u{1F4DD}": FileText,
|
|
4344
|
-
"\u{1F3AF}": Layers,
|
|
4345
|
-
"\u{1F3C6}": Trophy,
|
|
4346
|
-
"\u2728": Sparkles,
|
|
4347
|
-
"\u{1F4AC}": MessageCircle,
|
|
4348
|
-
"\u{1F3AE}": Gamepad2
|
|
4349
|
-
};
|
|
5041
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
4350
5042
|
function TileIcon({
|
|
4351
5043
|
emoji,
|
|
4352
5044
|
size = 18,
|
|
4353
5045
|
color = "currentColor"
|
|
4354
5046
|
}) {
|
|
4355
|
-
|
|
4356
|
-
if (!Icon) {
|
|
4357
|
-
return /* @__PURE__ */ jsx4("span", { children: emoji });
|
|
4358
|
-
}
|
|
4359
|
-
return /* @__PURE__ */ jsx4(Icon, { size, color });
|
|
5047
|
+
return /* @__PURE__ */ jsx5(EmojiIcon, { emoji, size, color });
|
|
4360
5048
|
}
|
|
4361
5049
|
|
|
4362
5050
|
// src/components/TileCard.tsx
|
|
4363
|
-
import { jsx as
|
|
5051
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
4364
5052
|
function WidgetMount({ widgetId, props }) {
|
|
4365
5053
|
var _a2;
|
|
4366
5054
|
const runtime3 = useRuntime();
|
|
@@ -4390,7 +5078,6 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4390
5078
|
return () => {
|
|
4391
5079
|
handle.unmount();
|
|
4392
5080
|
handleRef.current = null;
|
|
4393
|
-
container.remove();
|
|
4394
5081
|
};
|
|
4395
5082
|
}, [registry, widgetId, widgetAvailable]);
|
|
4396
5083
|
const propsJson = JSON.stringify(props);
|
|
@@ -4401,7 +5088,7 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4401
5088
|
prevPropsJsonRef.current = propsJson;
|
|
4402
5089
|
(_a3 = handleRef.current) == null ? void 0 : _a3.update(propsRef.current);
|
|
4403
5090
|
}, [propsJson]);
|
|
4404
|
-
if (!registry
|
|
5091
|
+
if (!(registry == null ? void 0 : registry.has(widgetId))) {
|
|
4405
5092
|
return /* @__PURE__ */ jsxs2(
|
|
4406
5093
|
"div",
|
|
4407
5094
|
{
|
|
@@ -4418,8 +5105,21 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4418
5105
|
}
|
|
4419
5106
|
);
|
|
4420
5107
|
}
|
|
4421
|
-
return /* @__PURE__ */
|
|
4422
|
-
}
|
|
5108
|
+
return /* @__PURE__ */ jsx6("div", { ref: parentRef });
|
|
5109
|
+
}
|
|
5110
|
+
var INTERACTION_PATTERNS = [
|
|
5111
|
+
":toggled",
|
|
5112
|
+
":clicked",
|
|
5113
|
+
":feedback",
|
|
5114
|
+
":navigate",
|
|
5115
|
+
":expanded",
|
|
5116
|
+
":collapsed",
|
|
5117
|
+
":dismissed",
|
|
5118
|
+
":submitted",
|
|
5119
|
+
":interacted",
|
|
5120
|
+
":tip_clicked",
|
|
5121
|
+
":tip_focused"
|
|
5122
|
+
];
|
|
4423
5123
|
function TileCard({
|
|
4424
5124
|
config,
|
|
4425
5125
|
surface: _surface,
|
|
@@ -4428,20 +5128,52 @@ function TileCard({
|
|
|
4428
5128
|
}) {
|
|
4429
5129
|
const { title, subtitle, widget, props, icon } = config;
|
|
4430
5130
|
const [, setTick] = useState4(0);
|
|
5131
|
+
const articleRef = useRef4(null);
|
|
4431
5132
|
const runtime3 = useRuntime();
|
|
4432
5133
|
useEffect5(() => {
|
|
4433
5134
|
if (runtime3) setTick((t) => t + 1);
|
|
4434
5135
|
}, [runtime3]);
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
5136
|
+
useEffect5(() => {
|
|
5137
|
+
var _a2;
|
|
5138
|
+
const tracker = typeof window !== "undefined" ? (_a2 = window.SynOS) == null ? void 0 : _a2.interventionTracker : null;
|
|
5139
|
+
if (!articleRef.current || !tracker) return;
|
|
5140
|
+
const observer = new IntersectionObserver(
|
|
5141
|
+
([entry]) => {
|
|
5142
|
+
var _a3;
|
|
5143
|
+
if (entry.isIntersecting) {
|
|
5144
|
+
tracker.trackSeen(config.id, (_a3 = config.widget) != null ? _a3 : "unknown");
|
|
5145
|
+
observer.disconnect();
|
|
5146
|
+
}
|
|
5147
|
+
},
|
|
5148
|
+
{ threshold: 0.5 }
|
|
5149
|
+
);
|
|
5150
|
+
observer.observe(articleRef.current);
|
|
5151
|
+
return () => observer.disconnect();
|
|
5152
|
+
}, [config.id, config.widget]);
|
|
5153
|
+
useEffect5(() => {
|
|
5154
|
+
var _a2;
|
|
5155
|
+
const tracker = typeof window !== "undefined" ? (_a2 = window.SynOS) == null ? void 0 : _a2.interventionTracker : null;
|
|
5156
|
+
if (!(runtime3 == null ? void 0 : runtime3.events) || !tracker) return;
|
|
5157
|
+
return runtime3.events.subscribe((event) => {
|
|
5158
|
+
var _a3, _b;
|
|
5159
|
+
if (!INTERACTION_PATTERNS.some((p) => {
|
|
5160
|
+
var _a4;
|
|
5161
|
+
return (_a4 = event.name) == null ? void 0 : _a4.includes(p);
|
|
5162
|
+
})) return;
|
|
5163
|
+
if (((_a3 = event.props) == null ? void 0 : _a3.instanceId) !== config.id) return;
|
|
5164
|
+
tracker.trackInteracted(config.id, (_b = config.widget) != null ? _b : "unknown", event.name);
|
|
5165
|
+
});
|
|
5166
|
+
}, [runtime3 == null ? void 0 : runtime3.events, config.id, config.widget]);
|
|
5167
|
+
const registration = useMemo3(
|
|
5168
|
+
() => {
|
|
5169
|
+
var _a2, _b;
|
|
5170
|
+
return (_b = (_a2 = runtime3 == null ? void 0 : runtime3.widgets) == null ? void 0 : _a2.getRegistration) == null ? void 0 : _b.call(_a2, widget);
|
|
5171
|
+
},
|
|
5172
|
+
[runtime3 == null ? void 0 : runtime3.widgets, widget]
|
|
5173
|
+
);
|
|
5174
|
+
const resolvedIcon = useMemo3(() => {
|
|
5175
|
+
var _a2, _b;
|
|
5176
|
+
if (icon) return icon;
|
|
4445
5177
|
return (_b = (_a2 = registration == null ? void 0 : registration.metadata) == null ? void 0 : _a2.icon) != null ? _b : "+";
|
|
4446
5178
|
}, [icon, registration]);
|
|
4447
5179
|
const resolvedSubtitle = useMemo3(() => {
|
|
@@ -4485,15 +5217,16 @@ function TileCard({
|
|
|
4485
5217
|
return /* @__PURE__ */ jsxs2(
|
|
4486
5218
|
"article",
|
|
4487
5219
|
{
|
|
5220
|
+
ref: articleRef,
|
|
4488
5221
|
"data-shadow-canvas-id": `tile-${config.id}`,
|
|
4489
5222
|
style: cardStyle,
|
|
4490
5223
|
onMouseEnter,
|
|
4491
5224
|
onMouseLeave,
|
|
4492
5225
|
children: [
|
|
4493
5226
|
/* @__PURE__ */ jsxs2("div", { style: headerStyle, children: [
|
|
4494
|
-
/* @__PURE__ */
|
|
5227
|
+
/* @__PURE__ */ jsx6("div", { style: iconStyle, children: /* @__PURE__ */ jsx6(TileIcon, { emoji: resolvedIcon, size: resolvedSubtitle ? 36 : 24 }) }),
|
|
4495
5228
|
/* @__PURE__ */ jsxs2("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
4496
|
-
/* @__PURE__ */
|
|
5229
|
+
/* @__PURE__ */ jsx6(
|
|
4497
5230
|
"h3",
|
|
4498
5231
|
{
|
|
4499
5232
|
style: {
|
|
@@ -4508,7 +5241,7 @@ function TileCard({
|
|
|
4508
5241
|
children: title != null ? title : widget
|
|
4509
5242
|
}
|
|
4510
5243
|
),
|
|
4511
|
-
resolvedSubtitle && /* @__PURE__ */
|
|
5244
|
+
resolvedSubtitle && /* @__PURE__ */ jsx6(
|
|
4512
5245
|
"p",
|
|
4513
5246
|
{
|
|
4514
5247
|
style: {
|
|
@@ -4525,14 +5258,14 @@ function TileCard({
|
|
|
4525
5258
|
)
|
|
4526
5259
|
] })
|
|
4527
5260
|
] }),
|
|
4528
|
-
/* @__PURE__ */
|
|
5261
|
+
/* @__PURE__ */ jsx6(
|
|
4529
5262
|
"div",
|
|
4530
5263
|
{
|
|
4531
5264
|
style: {
|
|
4532
5265
|
padding: "var(--sc-tile-body-padding, 0 0.75rem 0.5rem)",
|
|
4533
5266
|
borderTop: "1px solid rgba(255, 255, 255, 0.06)"
|
|
4534
5267
|
},
|
|
4535
|
-
children: /* @__PURE__ */
|
|
5268
|
+
children: /* @__PURE__ */ jsx6("div", { style: { paddingTop: "var(--sc-tile-gap, 0.25rem)" }, children: /* @__PURE__ */ jsx6(WidgetMount, { widgetId: widget, props: { ...props, instanceId: config.id } }) })
|
|
4536
5269
|
}
|
|
4537
5270
|
)
|
|
4538
5271
|
]
|
|
@@ -4940,7 +5673,7 @@ function flattenThemeConfig(config) {
|
|
|
4940
5673
|
|
|
4941
5674
|
// src/theme/ThemeProvider.tsx
|
|
4942
5675
|
import { createContext as createContext3, useContext as useContext3, useEffect as useEffect6, useMemo as useMemo4 } from "react";
|
|
4943
|
-
import { jsx as
|
|
5676
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
4944
5677
|
var ThemeContext = createContext3(null);
|
|
4945
5678
|
function ThemeProvider({
|
|
4946
5679
|
children,
|
|
@@ -4971,7 +5704,7 @@ ${cssRules}
|
|
|
4971
5704
|
mode: merged.mode,
|
|
4972
5705
|
cssVariables
|
|
4973
5706
|
};
|
|
4974
|
-
return /* @__PURE__ */
|
|
5707
|
+
return /* @__PURE__ */ jsx7(ThemeContext.Provider, { value, children });
|
|
4975
5708
|
}
|
|
4976
5709
|
function useTheme() {
|
|
4977
5710
|
const context = useContext3(ThemeContext);
|
|
@@ -4982,7 +5715,7 @@ function useTheme() {
|
|
|
4982
5715
|
}
|
|
4983
5716
|
|
|
4984
5717
|
// src/components/ShadowCanvasOverlay.tsx
|
|
4985
|
-
import { Fragment, jsx as
|
|
5718
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4986
5719
|
var LAUNCHER_STYLES_ID = "syntro-launcher-styles";
|
|
4987
5720
|
function ensureLauncherStyles(target, css) {
|
|
4988
5721
|
if (target.querySelector(`#${LAUNCHER_STYLES_ID}`)) return;
|
|
@@ -4996,7 +5729,6 @@ function ShadowCanvasOverlay({
|
|
|
4996
5729
|
onToggle,
|
|
4997
5730
|
telemetry,
|
|
4998
5731
|
launcherLabel: _launcherLabel = "Adaptives",
|
|
4999
|
-
launcherIcon,
|
|
5000
5732
|
launcherAnimate = false,
|
|
5001
5733
|
launcherAnimationStyle: _launcherAnimationStyle = "pulse",
|
|
5002
5734
|
notificationCount: _notificationCount,
|
|
@@ -5007,7 +5739,7 @@ function ShadowCanvasOverlay({
|
|
|
5007
5739
|
canvasTitle,
|
|
5008
5740
|
displayMode = "standard"
|
|
5009
5741
|
}) {
|
|
5010
|
-
var _a2, _b, _c, _d;
|
|
5742
|
+
var _a2, _b, _c, _d, _e;
|
|
5011
5743
|
const [mounted, setMounted] = useState5(false);
|
|
5012
5744
|
const [launcherPos, setLauncherPos] = useState5(null);
|
|
5013
5745
|
const dragRef = useRef5(null);
|
|
@@ -5022,7 +5754,7 @@ function ShadowCanvasOverlay({
|
|
|
5022
5754
|
const handleNotificationClick = useCallback4(
|
|
5023
5755
|
(notif) => {
|
|
5024
5756
|
if (runtime3) {
|
|
5025
|
-
runtime3.events.publish(
|
|
5757
|
+
runtime3.events.publish(StandardEvents2.NOTIFICATION_CLICKED, {
|
|
5026
5758
|
notificationId: notif.id,
|
|
5027
5759
|
tileId: notif.tileId,
|
|
5028
5760
|
itemId: notif.itemId
|
|
@@ -5032,7 +5764,7 @@ function ShadowCanvasOverlay({
|
|
|
5032
5764
|
onToggle();
|
|
5033
5765
|
}
|
|
5034
5766
|
if (runtime3 && notif.tileId) {
|
|
5035
|
-
runtime3.events.publish(
|
|
5767
|
+
runtime3.events.publish(StandardEvents2.NOTIFICATION_DEEP_LINK, {
|
|
5036
5768
|
tileId: notif.tileId,
|
|
5037
5769
|
itemId: notif.itemId
|
|
5038
5770
|
});
|
|
@@ -5105,6 +5837,17 @@ function ShadowCanvasOverlay({
|
|
|
5105
5837
|
}
|
|
5106
5838
|
onToggle();
|
|
5107
5839
|
}, [isOpen, telemetry, runtime3, onToggle]);
|
|
5840
|
+
useEffect7(() => {
|
|
5841
|
+
if (!isOpen) return;
|
|
5842
|
+
const handleOutsideClick = (e) => {
|
|
5843
|
+
const path = e.composedPath();
|
|
5844
|
+
if (containerRef.current && !path.includes(containerRef.current) && launcherRef.current && !path.includes(launcherRef.current)) {
|
|
5845
|
+
toggle2();
|
|
5846
|
+
}
|
|
5847
|
+
};
|
|
5848
|
+
document.addEventListener("mousedown", handleOutsideClick);
|
|
5849
|
+
return () => document.removeEventListener("mousedown", handleOutsideClick);
|
|
5850
|
+
}, [isOpen, toggle2]);
|
|
5108
5851
|
const onLauncherPointerDown = useCallback4((e) => {
|
|
5109
5852
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
5110
5853
|
dragRef.current = {
|
|
@@ -5129,7 +5872,7 @@ function ShadowCanvasOverlay({
|
|
|
5129
5872
|
}
|
|
5130
5873
|
}, []);
|
|
5131
5874
|
const onLauncherPointerUp = useCallback4(
|
|
5132
|
-
(
|
|
5875
|
+
(_e2) => {
|
|
5133
5876
|
const drag = dragRef.current;
|
|
5134
5877
|
dragRef.current = null;
|
|
5135
5878
|
if (drag && !drag.dragged) {
|
|
@@ -5143,6 +5886,7 @@ function ShadowCanvasOverlay({
|
|
|
5143
5886
|
const isPush = config.canvas.layout === "push";
|
|
5144
5887
|
const canvasBorder = (_b = config.canvas.border) != null ? _b : "none";
|
|
5145
5888
|
const containerRef = useRef5(null);
|
|
5889
|
+
const launcherRef = useRef5(null);
|
|
5146
5890
|
const zIndex = 2147483600;
|
|
5147
5891
|
useEffect7(() => {
|
|
5148
5892
|
var _a3, _b2, _c2, _d2;
|
|
@@ -5223,19 +5967,19 @@ function ShadowCanvasOverlay({
|
|
|
5223
5967
|
pointerEvents: "none",
|
|
5224
5968
|
padding: "0"
|
|
5225
5969
|
};
|
|
5226
|
-
const content = /* @__PURE__ */
|
|
5970
|
+
const content = /* @__PURE__ */ jsx8(
|
|
5227
5971
|
"div",
|
|
5228
5972
|
{
|
|
5229
5973
|
"data-shadow-canvas-id": "overlay-root",
|
|
5230
5974
|
style: {
|
|
5231
5975
|
position: "fixed",
|
|
5232
5976
|
inset: 0,
|
|
5233
|
-
pointerEvents:
|
|
5977
|
+
pointerEvents: "none",
|
|
5234
5978
|
zIndex
|
|
5235
5979
|
},
|
|
5236
5980
|
children: /* @__PURE__ */ jsxs3("div", { style: wrapperStyle, children: [
|
|
5237
5981
|
/* @__PURE__ */ jsxs3("div", { ref: containerRef, "data-shadow-canvas-id": "overlay-container", style: containerStyle, children: [
|
|
5238
|
-
isFocused && canvasTitle && /* @__PURE__ */
|
|
5982
|
+
isFocused && canvasTitle && /* @__PURE__ */ jsx8("header", { style: { color: "white", padding: "1.5rem 1.5rem 0" }, children: /* @__PURE__ */ jsx8(
|
|
5239
5983
|
"p",
|
|
5240
5984
|
{
|
|
5241
5985
|
style: {
|
|
@@ -5248,7 +5992,7 @@ function ShadowCanvasOverlay({
|
|
|
5248
5992
|
children: canvasTitle
|
|
5249
5993
|
}
|
|
5250
5994
|
) }),
|
|
5251
|
-
/* @__PURE__ */
|
|
5995
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: 1, overflowY: "auto", padding: isFocused ? "0" : "1rem" }, children: isLoading ? /* @__PURE__ */ jsx8(
|
|
5252
5996
|
"div",
|
|
5253
5997
|
{
|
|
5254
5998
|
style: { color: "var(--sc-overlay-text-color)", padding: isFocused ? "1rem" : "0" },
|
|
@@ -5268,7 +6012,7 @@ function ShadowCanvasOverlay({
|
|
|
5268
6012
|
}
|
|
5269
6013
|
) : isFocused ? (
|
|
5270
6014
|
/* Focused Mode: Render first tile full size */
|
|
5271
|
-
tiles.length > 0 ? /* @__PURE__ */
|
|
6015
|
+
tiles.length > 0 ? /* @__PURE__ */ jsx8(
|
|
5272
6016
|
TileCard,
|
|
5273
6017
|
{
|
|
5274
6018
|
config: tiles[0],
|
|
@@ -5279,7 +6023,7 @@ function ShadowCanvasOverlay({
|
|
|
5279
6023
|
) : null
|
|
5280
6024
|
) : (
|
|
5281
6025
|
/* Standard Mode: Stacked cards — widgets always visible */
|
|
5282
|
-
/* @__PURE__ */
|
|
6026
|
+
/* @__PURE__ */ jsx8(
|
|
5283
6027
|
"div",
|
|
5284
6028
|
{
|
|
5285
6029
|
style: {
|
|
@@ -5288,7 +6032,7 @@ function ShadowCanvasOverlay({
|
|
|
5288
6032
|
gap: "0.75rem",
|
|
5289
6033
|
width: "100%"
|
|
5290
6034
|
},
|
|
5291
|
-
children: tiles.map((tile) => /* @__PURE__ */
|
|
6035
|
+
children: tiles.map((tile) => /* @__PURE__ */ jsx8(
|
|
5292
6036
|
TileCard,
|
|
5293
6037
|
{
|
|
5294
6038
|
config: tile,
|
|
@@ -5303,17 +6047,7 @@ function ShadowCanvasOverlay({
|
|
|
5303
6047
|
) }),
|
|
5304
6048
|
footerSlot
|
|
5305
6049
|
] }),
|
|
5306
|
-
/* @__PURE__ */
|
|
5307
|
-
"div",
|
|
5308
|
-
{
|
|
5309
|
-
onClick: toggle2,
|
|
5310
|
-
style: {
|
|
5311
|
-
flex: "1 1 auto",
|
|
5312
|
-
pointerEvents: isOpen ? "auto" : "none",
|
|
5313
|
-
cursor: "default"
|
|
5314
|
-
}
|
|
5315
|
-
}
|
|
5316
|
-
)
|
|
6050
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: "1 1 auto" } })
|
|
5317
6051
|
] })
|
|
5318
6052
|
}
|
|
5319
6053
|
);
|
|
@@ -5331,7 +6065,7 @@ function ShadowCanvasOverlay({
|
|
|
5331
6065
|
zIndex: zIndex + 47
|
|
5332
6066
|
},
|
|
5333
6067
|
children: [
|
|
5334
|
-
/* @__PURE__ */
|
|
6068
|
+
/* @__PURE__ */ jsx8(
|
|
5335
6069
|
NotificationToastStack,
|
|
5336
6070
|
{
|
|
5337
6071
|
notifications,
|
|
@@ -5343,6 +6077,7 @@ function ShadowCanvasOverlay({
|
|
|
5343
6077
|
/* @__PURE__ */ jsxs3(
|
|
5344
6078
|
"button",
|
|
5345
6079
|
{
|
|
6080
|
+
ref: launcherRef,
|
|
5346
6081
|
type: "button",
|
|
5347
6082
|
"aria-label": "Toggle shadow canvas",
|
|
5348
6083
|
className: launcherAnimate && !isOpen ? "syntro-launcher-animate" : void 0,
|
|
@@ -5401,14 +6136,14 @@ function ShadowCanvasOverlay({
|
|
|
5401
6136
|
focusable: "false",
|
|
5402
6137
|
style: { transition: "transform 200ms ease" },
|
|
5403
6138
|
children: [
|
|
5404
|
-
/* @__PURE__ */
|
|
5405
|
-
/* @__PURE__ */
|
|
6139
|
+
/* @__PURE__ */ jsx8("path", { d: "M18 6L6 18" }),
|
|
6140
|
+
/* @__PURE__ */ jsx8("path", { d: "M6 6l12 12" })
|
|
5406
6141
|
]
|
|
5407
6142
|
}
|
|
5408
|
-
) :
|
|
6143
|
+
) : ((_e = config.launcher) == null ? void 0 : _e.icon) ? /* @__PURE__ */ jsx8(
|
|
5409
6144
|
"img",
|
|
5410
6145
|
{
|
|
5411
|
-
src:
|
|
6146
|
+
src: config.launcher.icon,
|
|
5412
6147
|
alt: "",
|
|
5413
6148
|
"aria-hidden": "true",
|
|
5414
6149
|
style: {
|
|
@@ -5433,16 +6168,16 @@ function ShadowCanvasOverlay({
|
|
|
5433
6168
|
focusable: "false",
|
|
5434
6169
|
style: { transition: "transform 200ms ease" },
|
|
5435
6170
|
children: [
|
|
5436
|
-
/* @__PURE__ */
|
|
5437
|
-
/* @__PURE__ */
|
|
5438
|
-
/* @__PURE__ */
|
|
5439
|
-
/* @__PURE__ */
|
|
5440
|
-
/* @__PURE__ */
|
|
6171
|
+
/* @__PURE__ */ jsx8("path", { d: "M12 3l1.912 5.813a2 2 0 0 0 1.275 1.275L21 12l-5.813 1.912a2 2 0 0 0-1.275 1.275L12 21l-1.912-5.813a2 2 0 0 0-1.275-1.275L3 12l5.813-1.912a2 2 0 0 0 1.275-1.275L12 3Z" }),
|
|
6172
|
+
/* @__PURE__ */ jsx8("path", { d: "M5 3v4" }),
|
|
6173
|
+
/* @__PURE__ */ jsx8("path", { d: "M3 5h4" }),
|
|
6174
|
+
/* @__PURE__ */ jsx8("path", { d: "M19 17v4" }),
|
|
6175
|
+
/* @__PURE__ */ jsx8("path", { d: "M17 19h4" })
|
|
5441
6176
|
]
|
|
5442
6177
|
}
|
|
5443
6178
|
),
|
|
5444
6179
|
!isOpen && notifications.length > 0 && /* @__PURE__ */ jsxs3("div", { style: { position: "absolute", top: -2, right: -2, pointerEvents: "none" }, children: [
|
|
5445
|
-
/* @__PURE__ */
|
|
6180
|
+
/* @__PURE__ */ jsx8(
|
|
5446
6181
|
"span",
|
|
5447
6182
|
{
|
|
5448
6183
|
className: "syntro-badge-ping",
|
|
@@ -5454,7 +6189,7 @@ function ShadowCanvasOverlay({
|
|
|
5454
6189
|
}
|
|
5455
6190
|
}
|
|
5456
6191
|
),
|
|
5457
|
-
/* @__PURE__ */
|
|
6192
|
+
/* @__PURE__ */ jsx8(
|
|
5458
6193
|
"span",
|
|
5459
6194
|
{
|
|
5460
6195
|
className: "syntro-badge-glow",
|
|
@@ -5465,7 +6200,7 @@ function ShadowCanvasOverlay({
|
|
|
5465
6200
|
}
|
|
5466
6201
|
}
|
|
5467
6202
|
),
|
|
5468
|
-
/* @__PURE__ */
|
|
6203
|
+
/* @__PURE__ */ jsx8(
|
|
5469
6204
|
"span",
|
|
5470
6205
|
{
|
|
5471
6206
|
className: "syntro-badge-bounce",
|
|
@@ -5504,6 +6239,14 @@ var sortTiles = (tiles) => [...tiles].sort((a, b) => {
|
|
|
5504
6239
|
var _a2, _b;
|
|
5505
6240
|
return ((_a2 = b.priority) != null ? _a2 : 0) - ((_b = a.priority) != null ? _b : 0);
|
|
5506
6241
|
});
|
|
6242
|
+
function fireTriggeredForTiles(tiles) {
|
|
6243
|
+
var _a2, _b;
|
|
6244
|
+
const tracker = typeof window !== "undefined" ? (_a2 = window.SynOS) == null ? void 0 : _a2.interventionTracker : null;
|
|
6245
|
+
if (!tracker) return;
|
|
6246
|
+
for (const tile of tiles) {
|
|
6247
|
+
tracker.trackTriggered(tile.id, (_b = tile.widget) != null ? _b : "unknown");
|
|
6248
|
+
}
|
|
6249
|
+
}
|
|
5507
6250
|
function useShadowCanvasConfig({
|
|
5508
6251
|
fetcher,
|
|
5509
6252
|
experiments,
|
|
@@ -5526,6 +6269,7 @@ function useShadowCanvasConfig({
|
|
|
5526
6269
|
if (experiments) {
|
|
5527
6270
|
tiles = tiles.filter((tile) => experiments.shouldRenderRectangle(tile));
|
|
5528
6271
|
}
|
|
6272
|
+
fireTriggeredForTiles(tiles);
|
|
5529
6273
|
setState((prev) => ({ ...prev, tiles: sortTiles(tiles) }));
|
|
5530
6274
|
}, [runtime3, experiments]);
|
|
5531
6275
|
const load = useCallback5(async () => {
|
|
@@ -5543,6 +6287,7 @@ function useShadowCanvasConfig({
|
|
|
5543
6287
|
} else if (experiments) {
|
|
5544
6288
|
tiles = tiles.filter((tile) => experiments.shouldRenderRectangle(tile));
|
|
5545
6289
|
}
|
|
6290
|
+
fireTriggeredForTiles(tiles);
|
|
5546
6291
|
debug("SmartCanvas Config", `Tile count after filtering: ${tiles.length}`);
|
|
5547
6292
|
const newActions = response.actions || [];
|
|
5548
6293
|
const newActionsJson = JSON.stringify(newActions);
|
|
@@ -5600,13 +6345,13 @@ function useShadowCanvasConfig({
|
|
|
5600
6345
|
|
|
5601
6346
|
// src/SmartCanvasApp.tsx
|
|
5602
6347
|
import { useEffect as useEffect9, useMemo as useMemo7, useRef as useRef7, useState as useState7 } from "react";
|
|
5603
|
-
import { jsx as
|
|
6348
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
5604
6349
|
function SmartCanvasApp({
|
|
5605
6350
|
controller,
|
|
5606
6351
|
fetcher,
|
|
5607
6352
|
configUri,
|
|
5608
|
-
configUriFeatureKey
|
|
5609
|
-
configFeatureKey
|
|
6353
|
+
configUriFeatureKey,
|
|
6354
|
+
configFeatureKey,
|
|
5610
6355
|
fetchCredentials = "include",
|
|
5611
6356
|
pollIntervalMs,
|
|
5612
6357
|
experiments,
|
|
@@ -5623,7 +6368,7 @@ function SmartCanvasApp({
|
|
|
5623
6368
|
workspaceTheme
|
|
5624
6369
|
}) {
|
|
5625
6370
|
if (runtime3) {
|
|
5626
|
-
return /* @__PURE__ */
|
|
6371
|
+
return /* @__PURE__ */ jsx9(RuntimeProvider, { runtime: runtime3, children: /* @__PURE__ */ jsx9(
|
|
5627
6372
|
SmartCanvasAppInner,
|
|
5628
6373
|
{
|
|
5629
6374
|
controller,
|
|
@@ -5648,7 +6393,7 @@ function SmartCanvasApp({
|
|
|
5648
6393
|
}
|
|
5649
6394
|
) });
|
|
5650
6395
|
}
|
|
5651
|
-
return /* @__PURE__ */
|
|
6396
|
+
return /* @__PURE__ */ jsx9(
|
|
5652
6397
|
SmartCanvasAppInner,
|
|
5653
6398
|
{
|
|
5654
6399
|
controller,
|
|
@@ -5676,10 +6421,10 @@ function SmartCanvasAppInner({
|
|
|
5676
6421
|
controller,
|
|
5677
6422
|
fetcher,
|
|
5678
6423
|
configUri,
|
|
5679
|
-
configUriFeatureKey
|
|
5680
|
-
configFeatureKey
|
|
6424
|
+
configUriFeatureKey,
|
|
6425
|
+
configFeatureKey,
|
|
5681
6426
|
fetchCredentials = "include",
|
|
5682
|
-
pollIntervalMs,
|
|
6427
|
+
pollIntervalMs: _pollIntervalMs,
|
|
5683
6428
|
experiments,
|
|
5684
6429
|
telemetry,
|
|
5685
6430
|
runtime: runtime3,
|
|
@@ -5693,7 +6438,7 @@ function SmartCanvasAppInner({
|
|
|
5693
6438
|
initialBatchHandle,
|
|
5694
6439
|
workspaceTheme
|
|
5695
6440
|
}) {
|
|
5696
|
-
var _a2, _b, _c, _d, _e, _f
|
|
6441
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
5697
6442
|
const [open, setOpen] = useState7(controller.getState().open);
|
|
5698
6443
|
const pageContext = usePageContext();
|
|
5699
6444
|
const [localUrl, setLocalUrl] = useState7(
|
|
@@ -5803,16 +6548,13 @@ function SmartCanvasAppInner({
|
|
|
5803
6548
|
}, [runtime3, controller]);
|
|
5804
6549
|
const { shadowRoot } = useShadowRoot();
|
|
5805
6550
|
const themeConfig = configState.theme;
|
|
5806
|
-
|
|
5807
|
-
return null;
|
|
5808
|
-
}
|
|
5809
|
-
return /* @__PURE__ */ jsx8(
|
|
6551
|
+
return /* @__PURE__ */ jsx9(
|
|
5810
6552
|
ThemeProvider,
|
|
5811
6553
|
{
|
|
5812
6554
|
themeConfig,
|
|
5813
6555
|
workspaceTheme,
|
|
5814
6556
|
shadowRoot,
|
|
5815
|
-
children: /* @__PURE__ */
|
|
6557
|
+
children: !configState.isLoading && !hasContent ? null : /* @__PURE__ */ jsx9(
|
|
5816
6558
|
ShadowCanvasOverlay,
|
|
5817
6559
|
{
|
|
5818
6560
|
tiles: configState.tiles,
|
|
@@ -5821,10 +6563,9 @@ function SmartCanvasAppInner({
|
|
|
5821
6563
|
canvasTitle: configState.canvasTitle,
|
|
5822
6564
|
telemetry,
|
|
5823
6565
|
launcherLabel: launcherLabel != null ? launcherLabel : (_b = configState.launcher) == null ? void 0 : _b.label,
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
notificationCount: (_g = (_f = configState.launcher) == null ? void 0 : _f.notificationCount) != null ? _g : configState.tiles.length,
|
|
6566
|
+
launcherAnimate: (_c = configState.launcher) == null ? void 0 : _c.animate,
|
|
6567
|
+
launcherAnimationStyle: (_d = configState.launcher) == null ? void 0 : _d.animationStyle,
|
|
6568
|
+
notificationCount: (_f = (_e = configState.launcher) == null ? void 0 : _e.notificationCount) != null ? _f : configState.tiles.length,
|
|
5828
6569
|
footerSlot,
|
|
5829
6570
|
isOpen: open,
|
|
5830
6571
|
onToggle: () => controller.toggle(),
|
|
@@ -5837,7 +6578,7 @@ function SmartCanvasAppInner({
|
|
|
5837
6578
|
|
|
5838
6579
|
// src/SmartCanvasElement.tsx
|
|
5839
6580
|
import { createRoot as createRoot2 } from "react-dom/client";
|
|
5840
|
-
import { jsx as
|
|
6581
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
5841
6582
|
var TAG_NAME = "smart-canvas";
|
|
5842
6583
|
var BASE_CSS = `
|
|
5843
6584
|
:host {
|
|
@@ -5938,13 +6679,13 @@ var SmartCanvasElement = class extends HTMLElement {
|
|
|
5938
6679
|
__privateSet(this, _root, createRoot2(__privateGet(this, _mount)));
|
|
5939
6680
|
}
|
|
5940
6681
|
__privateGet(this, _root).render(
|
|
5941
|
-
/* @__PURE__ */
|
|
6682
|
+
/* @__PURE__ */ jsx10(
|
|
5942
6683
|
ShadowRootProvider,
|
|
5943
6684
|
{
|
|
5944
6685
|
shadowRoot: __privateGet(this, _shadow),
|
|
5945
6686
|
portalRoot: __privateGet(this, _portalRoot),
|
|
5946
6687
|
overlayContainer: __privateGet(this, _overlayContainer),
|
|
5947
|
-
children: /* @__PURE__ */
|
|
6688
|
+
children: /* @__PURE__ */ jsx10(SmartCanvasApp, { ...__privateGet(this, _lastAppProps), controller: __privateGet(this, _controller), canvasHost: this })
|
|
5948
6689
|
}
|
|
5949
6690
|
)
|
|
5950
6691
|
);
|
|
@@ -6513,7 +7254,7 @@ var createSmartCanvas = async (config = {}) => {
|
|
|
6513
7254
|
console.log(
|
|
6514
7255
|
"[SmartCanvas] Actions to apply:",
|
|
6515
7256
|
canvasConfig.actions.map(
|
|
6516
|
-
(a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${
|
|
7257
|
+
(a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${a.anchorId.selector}"` : ""}${a.label ? ` "${a.label}"` : ""}`
|
|
6517
7258
|
).join(", ")
|
|
6518
7259
|
);
|
|
6519
7260
|
}
|
|
@@ -6964,17 +7705,18 @@ var PostHogAdapter = class {
|
|
|
6964
7705
|
__publicField(this, "client");
|
|
6965
7706
|
__publicField(this, "featureFlagsCallback");
|
|
6966
7707
|
__publicField(this, "captureCallback");
|
|
6967
|
-
__publicField(this, "
|
|
7708
|
+
__publicField(this, "rrwebCallback");
|
|
6968
7709
|
this.client = options.client;
|
|
6969
7710
|
this.featureFlagsCallback = options.onFeatureFlagsLoaded;
|
|
6970
7711
|
this.captureCallback = options.onCapture;
|
|
7712
|
+
this.rrwebCallback = options.onRRWebEvent;
|
|
6971
7713
|
if (!this.client && options.consent && options.requireExplicitConsent && typeof window !== "undefined" && options.apiKey) {
|
|
6972
7714
|
const consent = options.consent;
|
|
6973
7715
|
const currentStatus = consent.getStatus();
|
|
6974
7716
|
if (currentStatus === "granted") {
|
|
6975
7717
|
this.initPostHog();
|
|
6976
7718
|
}
|
|
6977
|
-
|
|
7719
|
+
consent.subscribe((status) => {
|
|
6978
7720
|
if (status === "granted") {
|
|
6979
7721
|
if (!this.client) {
|
|
6980
7722
|
this.initPostHog();
|
|
@@ -7001,68 +7743,117 @@ var PostHogAdapter = class {
|
|
|
7001
7743
|
if (!options.apiKey) return;
|
|
7002
7744
|
const enableFeatureFlags = (_a2 = options.enableFeatureFlags) != null ? _a2 : true;
|
|
7003
7745
|
const instanceName = `syntro_${options.apiKey.slice(-6) || "sdk"}`;
|
|
7004
|
-
|
|
7005
|
-
options.
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
session_recording: {
|
|
7023
|
-
recordCrossDomainIFrames: true
|
|
7024
|
-
},
|
|
7025
|
-
// Capture performance metrics
|
|
7026
|
-
capture_performance: true,
|
|
7027
|
-
// Enable web vitals
|
|
7028
|
-
enable_recording_console_log: true,
|
|
7029
|
-
// Bootstrap callback for when flags are loaded
|
|
7030
|
-
loaded: (ph) => {
|
|
7031
|
-
if (enableFeatureFlags && this.featureFlagsCallback) {
|
|
7032
|
-
ph.onFeatureFlags(() => {
|
|
7033
|
-
const allFlags = this.getAllFeatureFlags();
|
|
7034
|
-
if (allFlags && this.featureFlagsCallback) {
|
|
7035
|
-
this.featureFlagsCallback(allFlags);
|
|
7036
|
-
}
|
|
7037
|
-
});
|
|
7038
|
-
const existingFlags = this.getAllFeatureFlags();
|
|
7039
|
-
if (existingFlags && Object.keys(existingFlags).length > 0) {
|
|
7040
|
-
this.featureFlagsCallback(existingFlags);
|
|
7041
|
-
}
|
|
7042
|
-
}
|
|
7043
|
-
if (this.captureCallback) {
|
|
7044
|
-
ph.on("eventCaptured", (data) => {
|
|
7045
|
-
var _a3;
|
|
7046
|
-
const eventName = typeof data === "string" ? data : data == null ? void 0 : data.event;
|
|
7047
|
-
const properties = typeof data === "string" ? void 0 : data == null ? void 0 : data.properties;
|
|
7048
|
-
if (typeof eventName === "string") {
|
|
7049
|
-
(_a3 = this.captureCallback) == null ? void 0 : _a3.call(this, eventName, properties);
|
|
7050
|
-
}
|
|
7051
|
-
});
|
|
7052
|
-
}
|
|
7053
|
-
}
|
|
7746
|
+
const initOptions = {
|
|
7747
|
+
api_host: (_b = options.apiHost) != null ? _b : "https://telemetry.syntrologie.com",
|
|
7748
|
+
// Feature flags for segment membership (in_segment_* flags)
|
|
7749
|
+
// When enabled, /decide is called to get segment flags
|
|
7750
|
+
advanced_disable_feature_flags: !enableFeatureFlags,
|
|
7751
|
+
advanced_disable_feature_flags_on_first_load: !enableFeatureFlags,
|
|
7752
|
+
// Full-page tracking - all ON by default
|
|
7753
|
+
autocapture: (_c = options.autocapture) != null ? _c : true,
|
|
7754
|
+
capture_pageview: (_d = options.capturePageview) != null ? _d : "history_change",
|
|
7755
|
+
capture_pageleave: (_e = options.capturePageleave) != null ? _e : true,
|
|
7756
|
+
disable_session_recording: !((_f = options.sessionRecording) != null ? _f : true),
|
|
7757
|
+
// CRITICAL: Disable user agent filtering to allow headless Chrome
|
|
7758
|
+
// PostHog blocks "HeadlessChrome" user agents by default as bot detection
|
|
7759
|
+
// This enables session recording in Playwright/crawler sessions
|
|
7760
|
+
opt_out_useragent_filter: true,
|
|
7761
|
+
// Cross-domain iframe recording for embeds
|
|
7762
|
+
session_recording: {
|
|
7763
|
+
recordCrossDomainIFrames: true
|
|
7054
7764
|
},
|
|
7765
|
+
// Capture performance metrics
|
|
7766
|
+
capture_performance: true,
|
|
7767
|
+
// Enable web vitals
|
|
7768
|
+
enable_recording_console_log: true
|
|
7769
|
+
};
|
|
7770
|
+
const result = posthog.init(
|
|
7771
|
+
options.apiKey,
|
|
7772
|
+
initOptions,
|
|
7055
7773
|
instanceName
|
|
7056
7774
|
);
|
|
7775
|
+
if (result) {
|
|
7776
|
+
this.client = result;
|
|
7777
|
+
}
|
|
7778
|
+
if (this.captureCallback && this.client) {
|
|
7779
|
+
this.client.on("eventCaptured", (...args) => {
|
|
7780
|
+
var _a3;
|
|
7781
|
+
const data = args[0];
|
|
7782
|
+
const eventName = typeof data === "string" ? data : data == null ? void 0 : data.event;
|
|
7783
|
+
const properties = typeof data === "string" ? void 0 : data == null ? void 0 : data.properties;
|
|
7784
|
+
if (typeof eventName === "string") {
|
|
7785
|
+
(_a3 = this.captureCallback) == null ? void 0 : _a3.call(this, eventName, properties);
|
|
7786
|
+
}
|
|
7787
|
+
});
|
|
7788
|
+
}
|
|
7789
|
+
if (enableFeatureFlags && this.featureFlagsCallback && this.client) {
|
|
7790
|
+
this.client.onFeatureFlags(() => {
|
|
7791
|
+
const allFlags = this.getAllFeatureFlags();
|
|
7792
|
+
if (allFlags && this.featureFlagsCallback) {
|
|
7793
|
+
this.featureFlagsCallback(allFlags);
|
|
7794
|
+
}
|
|
7795
|
+
});
|
|
7796
|
+
const existingFlags = this.getAllFeatureFlags();
|
|
7797
|
+
if (existingFlags && Object.keys(existingFlags).length > 0) {
|
|
7798
|
+
this.featureFlagsCallback(existingFlags);
|
|
7799
|
+
}
|
|
7800
|
+
}
|
|
7801
|
+
if (this.rrwebCallback && this.client) {
|
|
7802
|
+
this.setupRRWebIntercept();
|
|
7803
|
+
}
|
|
7804
|
+
}
|
|
7805
|
+
/**
|
|
7806
|
+
* Set up rrweb event interception on PostHog's session recording.
|
|
7807
|
+
*
|
|
7808
|
+
* PostHog lazy-loads the rrweb recorder. The SessionRecording wrapper has
|
|
7809
|
+
* an `onRRwebEmit` method, but rrweb delivers events directly to the
|
|
7810
|
+
* lazy-loaded recorder instance's `onRRwebEmit`, bypassing the wrapper.
|
|
7811
|
+
* We must find and patch the recorder instance, not the wrapper.
|
|
7812
|
+
*
|
|
7813
|
+
* The recorder instance is stored on a minified property of SessionRecording.
|
|
7814
|
+
* We detect it by looking for an object with both `onRRwebEmit` and `start` methods.
|
|
7815
|
+
*/
|
|
7816
|
+
setupRRWebIntercept(retries = 30) {
|
|
7817
|
+
var _a2;
|
|
7818
|
+
const sr = (_a2 = this.client) == null ? void 0 : _a2.sessionRecording;
|
|
7819
|
+
if (!sr) {
|
|
7820
|
+
if (retries > 0) {
|
|
7821
|
+
setTimeout(() => this.setupRRWebIntercept(retries - 1), 500);
|
|
7822
|
+
}
|
|
7823
|
+
return;
|
|
7824
|
+
}
|
|
7825
|
+
let recorder = null;
|
|
7826
|
+
const srRecord = sr;
|
|
7827
|
+
for (const key of Object.getOwnPropertyNames(srRecord)) {
|
|
7828
|
+
const val = srRecord[key];
|
|
7829
|
+
if (val && typeof val === "object" && typeof val.onRRwebEmit === "function" && typeof val.start === "function" && val !== sr) {
|
|
7830
|
+
recorder = val;
|
|
7831
|
+
break;
|
|
7832
|
+
}
|
|
7833
|
+
}
|
|
7834
|
+
if (!recorder) {
|
|
7835
|
+
if (retries > 0) {
|
|
7836
|
+
setTimeout(() => this.setupRRWebIntercept(retries - 1), 500);
|
|
7837
|
+
}
|
|
7838
|
+
return;
|
|
7839
|
+
}
|
|
7840
|
+
const originalEmit = recorder.onRRwebEmit.bind(recorder);
|
|
7841
|
+
recorder.onRRwebEmit = (rawEvent) => {
|
|
7842
|
+
var _a3;
|
|
7843
|
+
(_a3 = this.rrwebCallback) == null ? void 0 : _a3.call(this, { kind: "rrweb", ...rawEvent });
|
|
7844
|
+
originalEmit(rawEvent);
|
|
7845
|
+
};
|
|
7846
|
+
if (typeof window !== "undefined") {
|
|
7847
|
+
window.__RRWEB_INTERCEPT_READY__ = true;
|
|
7848
|
+
}
|
|
7057
7849
|
}
|
|
7058
7850
|
/**
|
|
7059
7851
|
* Get all feature flags from PostHog.
|
|
7060
7852
|
* Used to extract segment membership flags (in_segment_*).
|
|
7061
7853
|
*/
|
|
7062
7854
|
getAllFeatureFlags() {
|
|
7063
|
-
var _a2, _b
|
|
7064
|
-
|
|
7065
|
-
return flags;
|
|
7855
|
+
var _a2, _b;
|
|
7856
|
+
return (_b = (_a2 = this.client) == null ? void 0 : _a2.featureFlags) == null ? void 0 : _b.getFlagVariants();
|
|
7066
7857
|
}
|
|
7067
7858
|
/**
|
|
7068
7859
|
* Get segment membership flags (in_segment_*) from PostHog.
|
|
@@ -7143,6 +7934,59 @@ function createPostHogClient(options = {}) {
|
|
|
7143
7934
|
return new PostHogAdapter(options);
|
|
7144
7935
|
}
|
|
7145
7936
|
|
|
7937
|
+
// src/telemetry/InterventionTracker.ts
|
|
7938
|
+
var InterventionTracker = class {
|
|
7939
|
+
constructor(telemetry, variantId) {
|
|
7940
|
+
__publicField(this, "telemetry");
|
|
7941
|
+
__publicField(this, "variantId");
|
|
7942
|
+
__publicField(this, "seenSet", /* @__PURE__ */ new Set());
|
|
7943
|
+
__publicField(this, "triggeredSet", /* @__PURE__ */ new Set());
|
|
7944
|
+
this.telemetry = telemetry;
|
|
7945
|
+
this.variantId = variantId;
|
|
7946
|
+
}
|
|
7947
|
+
trackServed(tiles, actions) {
|
|
7948
|
+
var _a2, _b;
|
|
7949
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_config_served", {
|
|
7950
|
+
variant_id: this.variantId,
|
|
7951
|
+
tiles,
|
|
7952
|
+
actions
|
|
7953
|
+
});
|
|
7954
|
+
}
|
|
7955
|
+
trackSeen(interventionId, interventionKind) {
|
|
7956
|
+
var _a2, _b;
|
|
7957
|
+
if (this.seenSet.has(interventionId)) return;
|
|
7958
|
+
this.seenSet.add(interventionId);
|
|
7959
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_seen", {
|
|
7960
|
+
variant_id: this.variantId,
|
|
7961
|
+
intervention_id: interventionId,
|
|
7962
|
+
intervention_kind: interventionKind
|
|
7963
|
+
});
|
|
7964
|
+
}
|
|
7965
|
+
trackTriggered(interventionId, interventionKind) {
|
|
7966
|
+
var _a2, _b;
|
|
7967
|
+
if (this.triggeredSet.has(interventionId)) return;
|
|
7968
|
+
this.triggeredSet.add(interventionId);
|
|
7969
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_triggered", {
|
|
7970
|
+
variant_id: this.variantId,
|
|
7971
|
+
intervention_id: interventionId,
|
|
7972
|
+
intervention_kind: interventionKind
|
|
7973
|
+
});
|
|
7974
|
+
}
|
|
7975
|
+
trackInteracted(interventionId, interventionKind, interactionType) {
|
|
7976
|
+
var _a2, _b;
|
|
7977
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_interacted", {
|
|
7978
|
+
variant_id: this.variantId,
|
|
7979
|
+
intervention_id: interventionId,
|
|
7980
|
+
intervention_kind: interventionKind,
|
|
7981
|
+
interaction_type: interactionType
|
|
7982
|
+
});
|
|
7983
|
+
}
|
|
7984
|
+
resetPage() {
|
|
7985
|
+
this.seenSet.clear();
|
|
7986
|
+
this.triggeredSet.clear();
|
|
7987
|
+
}
|
|
7988
|
+
};
|
|
7989
|
+
|
|
7146
7990
|
// src/actions/executors/core-flow.ts
|
|
7147
7991
|
var executeSequence = async (action, context) => {
|
|
7148
7992
|
const handles = [];
|
|
@@ -7413,158 +8257,7 @@ function hasExecutor(kind) {
|
|
|
7413
8257
|
return executorRegistry.has(kind);
|
|
7414
8258
|
}
|
|
7415
8259
|
|
|
7416
|
-
// src/actions/validation.ts
|
|
7417
|
-
var DANGEROUS_ATTRS = /* @__PURE__ */ new Set([
|
|
7418
|
-
"onclick",
|
|
7419
|
-
"onerror",
|
|
7420
|
-
"onload",
|
|
7421
|
-
"onmouseover",
|
|
7422
|
-
"onfocus",
|
|
7423
|
-
"onblur",
|
|
7424
|
-
"onchange",
|
|
7425
|
-
"onsubmit",
|
|
7426
|
-
"onkeydown",
|
|
7427
|
-
"onkeyup",
|
|
7428
|
-
"onkeypress"
|
|
7429
|
-
]);
|
|
7430
|
-
var MAX_HTML_LENGTH = 5e4;
|
|
7431
|
-
var MAX_STYLE_COUNT = 50;
|
|
7432
|
-
function validateAction(action) {
|
|
7433
|
-
const errors = [];
|
|
7434
|
-
const warnings = [];
|
|
7435
|
-
if (!action || typeof action !== "object") {
|
|
7436
|
-
errors.push({
|
|
7437
|
-
code: "INVALID_ACTION",
|
|
7438
|
-
message: "Action must be an object"
|
|
7439
|
-
});
|
|
7440
|
-
return { valid: false, errors, warnings };
|
|
7441
|
-
}
|
|
7442
|
-
const { kind } = action;
|
|
7443
|
-
if (!kind || typeof kind !== "string") {
|
|
7444
|
-
errors.push({
|
|
7445
|
-
code: "MISSING_KIND",
|
|
7446
|
-
message: "Action must have a 'kind' property"
|
|
7447
|
-
});
|
|
7448
|
-
return { valid: false, errors, warnings };
|
|
7449
|
-
}
|
|
7450
|
-
if (!hasExecutor(kind) && kind !== "core:mountWidget") {
|
|
7451
|
-
const registered = executorRegistry.list();
|
|
7452
|
-
console.error(
|
|
7453
|
-
`[ActionValidation] Unknown action kind: "${kind}". Registered kinds (${registered.length}): [${registered.join(", ")}]. This usually means the app that provides "${kind}" hasn't been activated yet, or the executor was never registered in ExecutorRegistry.`
|
|
7454
|
-
);
|
|
7455
|
-
errors.push({
|
|
7456
|
-
code: "UNKNOWN_KIND",
|
|
7457
|
-
message: `Unknown action kind: ${kind}`,
|
|
7458
|
-
field: "kind"
|
|
7459
|
-
});
|
|
7460
|
-
return { valid: false, errors, warnings };
|
|
7461
|
-
}
|
|
7462
|
-
switch (kind) {
|
|
7463
|
-
case "overlays:highlight":
|
|
7464
|
-
case "overlays:pulse":
|
|
7465
|
-
case "navigation:scrollTo":
|
|
7466
|
-
validateAnchorAction(action, errors, warnings);
|
|
7467
|
-
break;
|
|
7468
|
-
case "overlays:badge":
|
|
7469
|
-
validateAnchorAction(action, errors, warnings);
|
|
7470
|
-
validateBadgeAction(action, errors, warnings);
|
|
7471
|
-
break;
|
|
7472
|
-
case "overlays:tooltip":
|
|
7473
|
-
validateAnchorAction(action, errors, warnings);
|
|
7474
|
-
validateTooltipAction(action, errors, warnings);
|
|
7475
|
-
break;
|
|
7476
|
-
case "overlays:modal":
|
|
7477
|
-
validateModalAction(action, errors, warnings);
|
|
7478
|
-
break;
|
|
7479
|
-
case "content:insertHtml":
|
|
7480
|
-
validateAnchorAction(action, errors, warnings);
|
|
7481
|
-
validateInsertHtmlAction(action, errors, warnings);
|
|
7482
|
-
break;
|
|
7483
|
-
case "content:setText":
|
|
7484
|
-
validateAnchorAction(action, errors, warnings);
|
|
7485
|
-
validateSetTextAction(action, errors, warnings);
|
|
7486
|
-
break;
|
|
7487
|
-
case "content:setAttr":
|
|
7488
|
-
validateAnchorAction(action, errors, warnings);
|
|
7489
|
-
validateSetAttrAction(action, errors, warnings);
|
|
7490
|
-
break;
|
|
7491
|
-
case "content:addClass":
|
|
7492
|
-
case "content:removeClass":
|
|
7493
|
-
validateAnchorAction(action, errors, warnings);
|
|
7494
|
-
validateClassAction(action, errors, warnings);
|
|
7495
|
-
break;
|
|
7496
|
-
case "content:setStyle":
|
|
7497
|
-
validateAnchorAction(action, errors, warnings);
|
|
7498
|
-
validateSetStyleAction(action, errors, warnings);
|
|
7499
|
-
break;
|
|
7500
|
-
case "core:mountWidget":
|
|
7501
|
-
validateMountWidgetAction(action, errors, warnings);
|
|
7502
|
-
break;
|
|
7503
|
-
case "core:wait":
|
|
7504
|
-
validateWaitAction(action, errors, warnings);
|
|
7505
|
-
break;
|
|
7506
|
-
case "core:sequence":
|
|
7507
|
-
validateSequenceAction(action, errors, warnings);
|
|
7508
|
-
break;
|
|
7509
|
-
case "core:parallel":
|
|
7510
|
-
validateParallelAction(action, errors, warnings);
|
|
7511
|
-
break;
|
|
7512
|
-
case "core:tour":
|
|
7513
|
-
validateTourAction(action, errors, warnings);
|
|
7514
|
-
break;
|
|
7515
|
-
case "navigation:navigate":
|
|
7516
|
-
validateNavigateAction(action, errors, warnings);
|
|
7517
|
-
break;
|
|
7518
|
-
}
|
|
7519
|
-
return {
|
|
7520
|
-
valid: errors.length === 0,
|
|
7521
|
-
errors,
|
|
7522
|
-
warnings
|
|
7523
|
-
};
|
|
7524
|
-
}
|
|
7525
|
-
function validateAnchorAction(action, errors, warnings) {
|
|
7526
|
-
const anchorId = action.anchorId;
|
|
7527
|
-
if (!anchorId || typeof anchorId !== "object") {
|
|
7528
|
-
errors.push({
|
|
7529
|
-
code: "MISSING_ANCHOR_ID",
|
|
7530
|
-
message: "Action requires an 'anchorId' object with a 'selector' string",
|
|
7531
|
-
field: "anchorId"
|
|
7532
|
-
});
|
|
7533
|
-
return;
|
|
7534
|
-
}
|
|
7535
|
-
if (!anchorId.selector || typeof anchorId.selector !== "string") {
|
|
7536
|
-
errors.push({
|
|
7537
|
-
code: "MISSING_ANCHOR_SELECTOR",
|
|
7538
|
-
message: "anchorId requires a 'selector' string",
|
|
7539
|
-
field: "anchorId.selector"
|
|
7540
|
-
});
|
|
7541
|
-
} else if (anchorId.selector.length > 200) {
|
|
7542
|
-
warnings.push({
|
|
7543
|
-
code: "LONG_ANCHOR_ID",
|
|
7544
|
-
message: "Anchor selector is unusually long",
|
|
7545
|
-
suggestion: "Consider using a shorter, more descriptive selector"
|
|
7546
|
-
});
|
|
7547
|
-
}
|
|
7548
|
-
if (anchorId.route === void 0 || anchorId.route === null) {
|
|
7549
|
-
errors.push({
|
|
7550
|
-
code: "MISSING_ANCHOR_ROUTE",
|
|
7551
|
-
message: `anchorId requires a 'route' (string or array of strings). Use "**" for all routes.`,
|
|
7552
|
-
field: "anchorId.route"
|
|
7553
|
-
});
|
|
7554
|
-
} else {
|
|
7555
|
-
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
7556
|
-
for (const route of routes) {
|
|
7557
|
-
if (typeof route !== "string") {
|
|
7558
|
-
errors.push({
|
|
7559
|
-
code: "INVALID_ANCHOR_ROUTE",
|
|
7560
|
-
message: "anchorId.route must be a string or array of strings",
|
|
7561
|
-
field: "anchorId.route"
|
|
7562
|
-
});
|
|
7563
|
-
break;
|
|
7564
|
-
}
|
|
7565
|
-
}
|
|
7566
|
-
}
|
|
7567
|
-
}
|
|
8260
|
+
// src/actions/validation-rules.ts
|
|
7568
8261
|
function validateBadgeAction(action, errors, warnings) {
|
|
7569
8262
|
if (!action.content || typeof action.content !== "string") {
|
|
7570
8263
|
errors.push({
|
|
@@ -7878,75 +8571,228 @@ function validateModalAction(action, errors, _warnings) {
|
|
|
7878
8571
|
}
|
|
7879
8572
|
}
|
|
7880
8573
|
}
|
|
7881
|
-
function validateTourAction(action, errors, warnings) {
|
|
7882
|
-
if (!action.tourId || typeof action.tourId !== "string") {
|
|
8574
|
+
function validateTourAction(action, errors, warnings) {
|
|
8575
|
+
if (!action.tourId || typeof action.tourId !== "string") {
|
|
8576
|
+
errors.push({
|
|
8577
|
+
code: "MISSING_TOUR_ID",
|
|
8578
|
+
message: "Tour action requires 'tourId' property",
|
|
8579
|
+
field: "tourId"
|
|
8580
|
+
});
|
|
8581
|
+
}
|
|
8582
|
+
if (!action.steps || !Array.isArray(action.steps)) {
|
|
8583
|
+
errors.push({
|
|
8584
|
+
code: "MISSING_STEPS",
|
|
8585
|
+
message: "Tour action requires 'steps' array",
|
|
8586
|
+
field: "steps"
|
|
8587
|
+
});
|
|
8588
|
+
return;
|
|
8589
|
+
}
|
|
8590
|
+
if (action.steps.length === 0) {
|
|
8591
|
+
errors.push({
|
|
8592
|
+
code: "EMPTY_STEPS",
|
|
8593
|
+
message: "Tour must have at least one step",
|
|
8594
|
+
field: "steps"
|
|
8595
|
+
});
|
|
8596
|
+
}
|
|
8597
|
+
const stepIds = /* @__PURE__ */ new Set();
|
|
8598
|
+
for (let i = 0; i < action.steps.length; i++) {
|
|
8599
|
+
const step = action.steps[i];
|
|
8600
|
+
if (!step.id || typeof step.id !== "string") {
|
|
8601
|
+
errors.push({
|
|
8602
|
+
code: "MISSING_STEP_ID",
|
|
8603
|
+
message: `Step at index ${i} requires 'id' property`,
|
|
8604
|
+
field: `steps[${i}].id`
|
|
8605
|
+
});
|
|
8606
|
+
} else {
|
|
8607
|
+
if (stepIds.has(step.id)) {
|
|
8608
|
+
errors.push({
|
|
8609
|
+
code: "DUPLICATE_STEP_ID",
|
|
8610
|
+
message: `Duplicate step ID: ${step.id}`,
|
|
8611
|
+
field: `steps[${i}].id`
|
|
8612
|
+
});
|
|
8613
|
+
}
|
|
8614
|
+
stepIds.add(step.id);
|
|
8615
|
+
}
|
|
8616
|
+
if (!step.action) {
|
|
8617
|
+
errors.push({
|
|
8618
|
+
code: "MISSING_STEP_ACTION",
|
|
8619
|
+
message: `Step at index ${i} requires 'action' property`,
|
|
8620
|
+
field: `steps[${i}].action`
|
|
8621
|
+
});
|
|
8622
|
+
} else {
|
|
8623
|
+
const result = validateAction(step.action);
|
|
8624
|
+
for (const error2 of result.errors) {
|
|
8625
|
+
errors.push({
|
|
8626
|
+
...error2,
|
|
8627
|
+
field: `steps[${i}].action${error2.field ? `.${error2.field}` : ""}`
|
|
8628
|
+
});
|
|
8629
|
+
}
|
|
8630
|
+
for (const warning of result.warnings) {
|
|
8631
|
+
warnings.push(warning);
|
|
8632
|
+
}
|
|
8633
|
+
}
|
|
8634
|
+
if (step.onAction) {
|
|
8635
|
+
for (const [_actionId, targetStepId] of Object.entries(step.onAction)) {
|
|
8636
|
+
if (targetStepId !== "end" && !action.steps.some((s) => s.id === targetStepId)) {
|
|
8637
|
+
warnings.push({
|
|
8638
|
+
code: "UNKNOWN_TARGET_STEP",
|
|
8639
|
+
message: `Step "${step.id}" references unknown target step: ${targetStepId}`,
|
|
8640
|
+
suggestion: `Make sure step "${targetStepId}" exists in the tour`
|
|
8641
|
+
});
|
|
8642
|
+
}
|
|
8643
|
+
}
|
|
8644
|
+
}
|
|
8645
|
+
}
|
|
8646
|
+
}
|
|
8647
|
+
|
|
8648
|
+
// src/actions/validation-core.ts
|
|
8649
|
+
var DANGEROUS_ATTRS = /* @__PURE__ */ new Set([
|
|
8650
|
+
"onclick",
|
|
8651
|
+
"onerror",
|
|
8652
|
+
"onload",
|
|
8653
|
+
"onmouseover",
|
|
8654
|
+
"onfocus",
|
|
8655
|
+
"onblur",
|
|
8656
|
+
"onchange",
|
|
8657
|
+
"onsubmit",
|
|
8658
|
+
"onkeydown",
|
|
8659
|
+
"onkeyup",
|
|
8660
|
+
"onkeypress"
|
|
8661
|
+
]);
|
|
8662
|
+
var MAX_HTML_LENGTH = 5e4;
|
|
8663
|
+
var MAX_STYLE_COUNT = 50;
|
|
8664
|
+
function validateAction(action) {
|
|
8665
|
+
const errors = [];
|
|
8666
|
+
const warnings = [];
|
|
8667
|
+
if (!action || typeof action !== "object") {
|
|
8668
|
+
errors.push({
|
|
8669
|
+
code: "INVALID_ACTION",
|
|
8670
|
+
message: "Action must be an object"
|
|
8671
|
+
});
|
|
8672
|
+
return { valid: false, errors, warnings };
|
|
8673
|
+
}
|
|
8674
|
+
const { kind } = action;
|
|
8675
|
+
if (!kind || typeof kind !== "string") {
|
|
8676
|
+
errors.push({
|
|
8677
|
+
code: "MISSING_KIND",
|
|
8678
|
+
message: "Action must have a 'kind' property"
|
|
8679
|
+
});
|
|
8680
|
+
return { valid: false, errors, warnings };
|
|
8681
|
+
}
|
|
8682
|
+
if (!hasExecutor(kind) && kind !== "core:mountWidget") {
|
|
8683
|
+
const registered = executorRegistry.list();
|
|
8684
|
+
console.error(
|
|
8685
|
+
`[ActionValidation] Unknown action kind: "${kind}". Registered kinds (${registered.length}): [${registered.join(", ")}]. This usually means the app that provides "${kind}" hasn't been activated yet, or the executor was never registered in ExecutorRegistry.`
|
|
8686
|
+
);
|
|
8687
|
+
errors.push({
|
|
8688
|
+
code: "UNKNOWN_KIND",
|
|
8689
|
+
message: `Unknown action kind: ${kind}`,
|
|
8690
|
+
field: "kind"
|
|
8691
|
+
});
|
|
8692
|
+
return { valid: false, errors, warnings };
|
|
8693
|
+
}
|
|
8694
|
+
switch (kind) {
|
|
8695
|
+
case "overlays:highlight":
|
|
8696
|
+
case "overlays:pulse":
|
|
8697
|
+
case "navigation:scrollTo":
|
|
8698
|
+
validateAnchorAction(action, errors, warnings);
|
|
8699
|
+
break;
|
|
8700
|
+
case "overlays:badge":
|
|
8701
|
+
validateAnchorAction(action, errors, warnings);
|
|
8702
|
+
validateBadgeAction(action, errors, warnings);
|
|
8703
|
+
break;
|
|
8704
|
+
case "overlays:tooltip":
|
|
8705
|
+
validateAnchorAction(action, errors, warnings);
|
|
8706
|
+
validateTooltipAction(action, errors, warnings);
|
|
8707
|
+
break;
|
|
8708
|
+
case "overlays:modal":
|
|
8709
|
+
validateModalAction(action, errors, warnings);
|
|
8710
|
+
break;
|
|
8711
|
+
case "content:insertHtml":
|
|
8712
|
+
validateAnchorAction(action, errors, warnings);
|
|
8713
|
+
validateInsertHtmlAction(action, errors, warnings);
|
|
8714
|
+
break;
|
|
8715
|
+
case "content:setText":
|
|
8716
|
+
validateAnchorAction(action, errors, warnings);
|
|
8717
|
+
validateSetTextAction(action, errors, warnings);
|
|
8718
|
+
break;
|
|
8719
|
+
case "content:setAttr":
|
|
8720
|
+
validateAnchorAction(action, errors, warnings);
|
|
8721
|
+
validateSetAttrAction(action, errors, warnings);
|
|
8722
|
+
break;
|
|
8723
|
+
case "content:addClass":
|
|
8724
|
+
case "content:removeClass":
|
|
8725
|
+
validateAnchorAction(action, errors, warnings);
|
|
8726
|
+
validateClassAction(action, errors, warnings);
|
|
8727
|
+
break;
|
|
8728
|
+
case "content:setStyle":
|
|
8729
|
+
validateAnchorAction(action, errors, warnings);
|
|
8730
|
+
validateSetStyleAction(action, errors, warnings);
|
|
8731
|
+
break;
|
|
8732
|
+
case "core:mountWidget":
|
|
8733
|
+
validateMountWidgetAction(action, errors, warnings);
|
|
8734
|
+
break;
|
|
8735
|
+
case "core:wait":
|
|
8736
|
+
validateWaitAction(action, errors, warnings);
|
|
8737
|
+
break;
|
|
8738
|
+
case "core:sequence":
|
|
8739
|
+
validateSequenceAction(action, errors, warnings);
|
|
8740
|
+
break;
|
|
8741
|
+
case "core:parallel":
|
|
8742
|
+
validateParallelAction(action, errors, warnings);
|
|
8743
|
+
break;
|
|
8744
|
+
case "overlays:tour":
|
|
8745
|
+
validateTourAction(action, errors, warnings);
|
|
8746
|
+
break;
|
|
8747
|
+
case "navigation:navigate":
|
|
8748
|
+
validateNavigateAction(action, errors, warnings);
|
|
8749
|
+
break;
|
|
8750
|
+
}
|
|
8751
|
+
return {
|
|
8752
|
+
valid: errors.length === 0,
|
|
8753
|
+
errors,
|
|
8754
|
+
warnings
|
|
8755
|
+
};
|
|
8756
|
+
}
|
|
8757
|
+
function validateAnchorAction(action, errors, warnings) {
|
|
8758
|
+
const anchorId = action.anchorId;
|
|
8759
|
+
if (!anchorId || typeof anchorId !== "object") {
|
|
7883
8760
|
errors.push({
|
|
7884
|
-
code: "
|
|
7885
|
-
message: "
|
|
7886
|
-
field: "
|
|
8761
|
+
code: "MISSING_ANCHOR_ID",
|
|
8762
|
+
message: "Action requires an 'anchorId' object with a 'selector' string",
|
|
8763
|
+
field: "anchorId"
|
|
7887
8764
|
});
|
|
8765
|
+
return;
|
|
7888
8766
|
}
|
|
7889
|
-
if (!
|
|
8767
|
+
if (!anchorId.selector || typeof anchorId.selector !== "string") {
|
|
7890
8768
|
errors.push({
|
|
7891
|
-
code: "
|
|
7892
|
-
message: "
|
|
7893
|
-
field: "
|
|
8769
|
+
code: "MISSING_ANCHOR_SELECTOR",
|
|
8770
|
+
message: "anchorId requires a 'selector' string",
|
|
8771
|
+
field: "anchorId.selector"
|
|
8772
|
+
});
|
|
8773
|
+
} else if (anchorId.selector.length > 200) {
|
|
8774
|
+
warnings.push({
|
|
8775
|
+
code: "LONG_ANCHOR_ID",
|
|
8776
|
+
message: "Anchor selector is unusually long",
|
|
8777
|
+
suggestion: "Consider using a shorter, more descriptive selector"
|
|
7894
8778
|
});
|
|
7895
|
-
return;
|
|
7896
8779
|
}
|
|
7897
|
-
if (
|
|
8780
|
+
if (anchorId.route === void 0 || anchorId.route === null) {
|
|
7898
8781
|
errors.push({
|
|
7899
|
-
code: "
|
|
7900
|
-
message:
|
|
7901
|
-
field: "
|
|
8782
|
+
code: "MISSING_ANCHOR_ROUTE",
|
|
8783
|
+
message: `anchorId requires a 'route' (string or array of strings). Use "**" for all routes.`,
|
|
8784
|
+
field: "anchorId.route"
|
|
7902
8785
|
});
|
|
7903
|
-
}
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
if (!step.id || typeof step.id !== "string") {
|
|
7908
|
-
errors.push({
|
|
7909
|
-
code: "MISSING_STEP_ID",
|
|
7910
|
-
message: `Step at index ${i} requires 'id' property`,
|
|
7911
|
-
field: `steps[${i}].id`
|
|
7912
|
-
});
|
|
7913
|
-
} else {
|
|
7914
|
-
if (stepIds.has(step.id)) {
|
|
7915
|
-
errors.push({
|
|
7916
|
-
code: "DUPLICATE_STEP_ID",
|
|
7917
|
-
message: `Duplicate step ID: ${step.id}`,
|
|
7918
|
-
field: `steps[${i}].id`
|
|
7919
|
-
});
|
|
7920
|
-
}
|
|
7921
|
-
stepIds.add(step.id);
|
|
7922
|
-
}
|
|
7923
|
-
if (!step.action) {
|
|
7924
|
-
errors.push({
|
|
7925
|
-
code: "MISSING_STEP_ACTION",
|
|
7926
|
-
message: `Step at index ${i} requires 'action' property`,
|
|
7927
|
-
field: `steps[${i}].action`
|
|
7928
|
-
});
|
|
7929
|
-
} else {
|
|
7930
|
-
const result = validateAction(step.action);
|
|
7931
|
-
for (const error2 of result.errors) {
|
|
8786
|
+
} else {
|
|
8787
|
+
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
8788
|
+
for (const route of routes) {
|
|
8789
|
+
if (typeof route !== "string") {
|
|
7932
8790
|
errors.push({
|
|
7933
|
-
|
|
7934
|
-
|
|
8791
|
+
code: "INVALID_ANCHOR_ROUTE",
|
|
8792
|
+
message: "anchorId.route must be a string or array of strings",
|
|
8793
|
+
field: "anchorId.route"
|
|
7935
8794
|
});
|
|
7936
|
-
|
|
7937
|
-
for (const warning of result.warnings) {
|
|
7938
|
-
warnings.push(warning);
|
|
7939
|
-
}
|
|
7940
|
-
}
|
|
7941
|
-
if (step.onAction) {
|
|
7942
|
-
for (const [_actionId, targetStepId] of Object.entries(step.onAction)) {
|
|
7943
|
-
if (targetStepId !== "end" && !action.steps.some((s) => s.id === targetStepId)) {
|
|
7944
|
-
warnings.push({
|
|
7945
|
-
code: "UNKNOWN_TARGET_STEP",
|
|
7946
|
-
message: `Step "${step.id}" references unknown target step: ${targetStepId}`,
|
|
7947
|
-
suggestion: `Make sure step "${targetStepId}" exists in the tour`
|
|
7948
|
-
});
|
|
7949
|
-
}
|
|
8795
|
+
break;
|
|
7950
8796
|
}
|
|
7951
8797
|
}
|
|
7952
8798
|
}
|
|
@@ -8097,7 +8943,7 @@ function createActionEngine(options) {
|
|
|
8097
8943
|
}
|
|
8098
8944
|
return executor(action, context);
|
|
8099
8945
|
}
|
|
8100
|
-
function subscribeForReeval(id, action, triggerWhen,
|
|
8946
|
+
function subscribeForReeval(id, action, triggerWhen, _handle) {
|
|
8101
8947
|
if (!runtime3) return;
|
|
8102
8948
|
const unsubs = [];
|
|
8103
8949
|
const onReeval = async () => {
|
|
@@ -8241,13 +9087,9 @@ function createActionEngine(options) {
|
|
|
8241
9087
|
entry2.state = "reverted";
|
|
8242
9088
|
publishEvent("action.reverted", { id, kind: action.kind });
|
|
8243
9089
|
} catch (error2) {
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
kind: action.kind,
|
|
8248
|
-
error: String(error2)
|
|
8249
|
-
});
|
|
8250
|
-
throw error2;
|
|
9090
|
+
console.warn(`[ActionEngine] Cleanup error for ${action.kind} (${id}), ignoring:`, error2);
|
|
9091
|
+
entry2.state = "reverted";
|
|
9092
|
+
publishEvent("action.reverted", { id, kind: action.kind });
|
|
8251
9093
|
} finally {
|
|
8252
9094
|
activeActions.delete(id);
|
|
8253
9095
|
}
|
|
@@ -8291,7 +9133,7 @@ function createActionEngine(options) {
|
|
|
8291
9133
|
errorMessages,
|
|
8292
9134
|
"\nActions:",
|
|
8293
9135
|
actions.map(
|
|
8294
|
-
(a, i) => ` [${i}] ${a.kind} ${a.anchorId ? `anchor="${
|
|
9136
|
+
(a, i) => ` [${i}] ${a.kind} ${a.anchorId ? `anchor="${a.anchorId.selector}"` : ""} ${a.label ? `label="${a.label}"` : ""}`
|
|
8295
9137
|
).join("\n")
|
|
8296
9138
|
);
|
|
8297
9139
|
throw new Error(`Batch validation failed: ${errorMessages}`);
|
|
@@ -8391,6 +9233,7 @@ function createAnchorResolver(opts) {
|
|
|
8391
9233
|
function resolve(selector) {
|
|
8392
9234
|
if (!root) return null;
|
|
8393
9235
|
try {
|
|
9236
|
+
if (root.matches(selector)) return root;
|
|
8394
9237
|
return root.querySelector(selector);
|
|
8395
9238
|
} catch {
|
|
8396
9239
|
return null;
|
|
@@ -8736,7 +9579,7 @@ function createContextManager(options) {
|
|
|
8736
9579
|
|
|
8737
9580
|
// src/decisions/strategies/rules.ts
|
|
8738
9581
|
function evaluateCondition(condition, evalContext) {
|
|
8739
|
-
var _a2, _b, _c, _d, _e
|
|
9582
|
+
var _a2, _b, _c, _d, _e;
|
|
8740
9583
|
const { context, state, events } = evalContext;
|
|
8741
9584
|
switch (condition.type) {
|
|
8742
9585
|
case "page_url": {
|
|
@@ -8750,8 +9593,7 @@ function evaluateCondition(condition, evalContext) {
|
|
|
8750
9593
|
return context.page.routeId === condition.routeId;
|
|
8751
9594
|
}
|
|
8752
9595
|
case "anchor_visible": {
|
|
8753
|
-
const
|
|
8754
|
-
const anchor = (_c = context.anchors) == null ? void 0 : _c.find((a) => a.anchorId === condSelector);
|
|
9596
|
+
const anchor = (_a2 = context.anchors) == null ? void 0 : _a2.find((a) => a.anchorId === condition.anchorId);
|
|
8755
9597
|
switch (condition.state) {
|
|
8756
9598
|
case "visible":
|
|
8757
9599
|
return (anchor == null ? void 0 : anchor.visible) === true;
|
|
@@ -8765,7 +9607,7 @@ function evaluateCondition(condition, evalContext) {
|
|
|
8765
9607
|
}
|
|
8766
9608
|
case "event_occurred": {
|
|
8767
9609
|
if (!events) return false;
|
|
8768
|
-
const withinMs = (
|
|
9610
|
+
const withinMs = (_b = condition.withinMs) != null ? _b : 6e4;
|
|
8769
9611
|
return events.hasRecentEvent(condition.eventName, withinMs);
|
|
8770
9612
|
}
|
|
8771
9613
|
case "state_equals": {
|
|
@@ -8801,17 +9643,17 @@ function evaluateCondition(condition, evalContext) {
|
|
|
8801
9643
|
}
|
|
8802
9644
|
}
|
|
8803
9645
|
case "dismissed": {
|
|
8804
|
-
if (!state) return (
|
|
9646
|
+
if (!state) return (_c = condition.inverted) != null ? _c : false;
|
|
8805
9647
|
const isDismissed = state.isDismissed(condition.key);
|
|
8806
9648
|
return condition.inverted ? !isDismissed : isDismissed;
|
|
8807
9649
|
}
|
|
8808
9650
|
case "cooldown_active": {
|
|
8809
|
-
if (!state) return (
|
|
9651
|
+
if (!state) return (_d = condition.inverted) != null ? _d : false;
|
|
8810
9652
|
const isActive = state.isCooldownActive(condition.key);
|
|
8811
9653
|
return condition.inverted ? !isActive : isActive;
|
|
8812
9654
|
}
|
|
8813
9655
|
case "frequency_limit": {
|
|
8814
|
-
if (!state) return (
|
|
9656
|
+
if (!state) return (_e = condition.inverted) != null ? _e : false;
|
|
8815
9657
|
const count = state.getFrequencyCount(condition.key);
|
|
8816
9658
|
const limitReached = count >= condition.limit;
|
|
8817
9659
|
return condition.inverted ? !limitReached : limitReached;
|
|
@@ -9071,6 +9913,66 @@ function createEventAccumulator(options) {
|
|
|
9071
9913
|
};
|
|
9072
9914
|
}
|
|
9073
9915
|
|
|
9916
|
+
// src/events/validation.ts
|
|
9917
|
+
var APP_PREFIX = "app:";
|
|
9918
|
+
var RESERVED_PREFIX = "syntro:";
|
|
9919
|
+
var SEGMENT_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
9920
|
+
function validateEventName(name) {
|
|
9921
|
+
if (!name) {
|
|
9922
|
+
return { valid: false, reason: "Event name cannot be empty" };
|
|
9923
|
+
}
|
|
9924
|
+
if (name.startsWith(RESERVED_PREFIX)) {
|
|
9925
|
+
return { valid: false, reason: '"syntro:" prefix is reserved for internal SDK events' };
|
|
9926
|
+
}
|
|
9927
|
+
if (!name.startsWith(APP_PREFIX)) {
|
|
9928
|
+
return { valid: false, reason: `Custom events must start with "app:" prefix. Got: "${name}"` };
|
|
9929
|
+
}
|
|
9930
|
+
const segments = name.slice(APP_PREFIX.length).split(":");
|
|
9931
|
+
if (segments.length < 2) {
|
|
9932
|
+
return {
|
|
9933
|
+
valid: false,
|
|
9934
|
+
reason: `Event name must have at least 2 segments after "app:" (app:{category}:{action}). Got: "${name}"`
|
|
9935
|
+
};
|
|
9936
|
+
}
|
|
9937
|
+
for (const segment of segments) {
|
|
9938
|
+
if (!SEGMENT_PATTERN.test(segment)) {
|
|
9939
|
+
return {
|
|
9940
|
+
valid: false,
|
|
9941
|
+
reason: `Segment "${segment}" must be lowercase alphanumeric + underscores. Got: "${name}"`
|
|
9942
|
+
};
|
|
9943
|
+
}
|
|
9944
|
+
}
|
|
9945
|
+
return { valid: true };
|
|
9946
|
+
}
|
|
9947
|
+
function isSerializable(value) {
|
|
9948
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
|
|
9949
|
+
}
|
|
9950
|
+
function checkDepth(obj, maxDepth, current = 0) {
|
|
9951
|
+
if (current >= maxDepth) return false;
|
|
9952
|
+
for (const value of Object.values(obj)) {
|
|
9953
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
9954
|
+
if (!checkDepth(value, maxDepth, current + 1)) return false;
|
|
9955
|
+
}
|
|
9956
|
+
}
|
|
9957
|
+
return true;
|
|
9958
|
+
}
|
|
9959
|
+
function validateProps(props) {
|
|
9960
|
+
if (props === void 0) return { valid: true };
|
|
9961
|
+
if (props === null || typeof props !== "object" || Array.isArray(props)) {
|
|
9962
|
+
return { valid: false, reason: "Props must be a plain object" };
|
|
9963
|
+
}
|
|
9964
|
+
if (!checkDepth(props, 2)) {
|
|
9965
|
+
return { valid: false, reason: "Props nesting depth exceeds 2 levels" };
|
|
9966
|
+
}
|
|
9967
|
+
const stripped = [];
|
|
9968
|
+
for (const [key, value] of Object.entries(props)) {
|
|
9969
|
+
if (value !== null && typeof value === "object") continue;
|
|
9970
|
+
if (!isSerializable(value)) stripped.push(key);
|
|
9971
|
+
}
|
|
9972
|
+
if (stripped.length > 0) return { valid: true, stripped };
|
|
9973
|
+
return { valid: true };
|
|
9974
|
+
}
|
|
9975
|
+
|
|
9074
9976
|
// src/events/EventBus.ts
|
|
9075
9977
|
function matchesFilter(event, filter) {
|
|
9076
9978
|
if (!filter) return true;
|
|
@@ -9102,8 +10004,16 @@ var EventBus = class {
|
|
|
9102
10004
|
__publicField(this, "subscriptions", /* @__PURE__ */ new Set());
|
|
9103
10005
|
__publicField(this, "history", []);
|
|
9104
10006
|
__publicField(this, "maxHistorySize");
|
|
9105
|
-
|
|
10007
|
+
__publicField(this, "debug");
|
|
10008
|
+
__publicField(this, "emitHistory");
|
|
10009
|
+
__publicField(this, "posthogCapture");
|
|
10010
|
+
__publicField(this, "testMode");
|
|
10011
|
+
var _a2, _b, _c, _d, _e;
|
|
9106
10012
|
this.maxHistorySize = (_a2 = options.maxHistorySize) != null ? _a2 : 100;
|
|
10013
|
+
this.debug = (_b = options.debug) != null ? _b : false;
|
|
10014
|
+
this.emitHistory = (_c = options.history) != null ? _c : null;
|
|
10015
|
+
this.posthogCapture = (_d = options.posthogCapture) != null ? _d : null;
|
|
10016
|
+
this.testMode = (_e = options.testMode) != null ? _e : false;
|
|
9107
10017
|
}
|
|
9108
10018
|
/**
|
|
9109
10019
|
* Subscribe to events matching an optional filter.
|
|
@@ -9156,6 +10066,83 @@ var EventBus = class {
|
|
|
9156
10066
|
}
|
|
9157
10067
|
}
|
|
9158
10068
|
}
|
|
10069
|
+
/**
|
|
10070
|
+
* Emit a validated custom event from the host application.
|
|
10071
|
+
*
|
|
10072
|
+
* Custom events must use the `app:` prefix (e.g. `app:cart:abandoned`).
|
|
10073
|
+
* In debug mode, returns an EmitResult with delivery details.
|
|
10074
|
+
* In production mode, returns undefined.
|
|
10075
|
+
*/
|
|
10076
|
+
emit(name, props) {
|
|
10077
|
+
const nameResult = validateEventName(name);
|
|
10078
|
+
if (!nameResult.valid) {
|
|
10079
|
+
console.warn(`[EventBus] emit() rejected: ${nameResult.reason}`);
|
|
10080
|
+
return this.debug ? { delivered: false, matchedRules: [], posthogCaptured: false, listenersNotified: 0 } : void 0;
|
|
10081
|
+
}
|
|
10082
|
+
const propsResult = validateProps(props);
|
|
10083
|
+
if (!propsResult.valid) {
|
|
10084
|
+
console.warn(`[EventBus] emit() rejected props: ${propsResult.reason}`);
|
|
10085
|
+
return this.debug ? { delivered: false, matchedRules: [], posthogCaptured: false, listenersNotified: 0 } : void 0;
|
|
10086
|
+
}
|
|
10087
|
+
const event = {
|
|
10088
|
+
ts: Date.now(),
|
|
10089
|
+
name,
|
|
10090
|
+
source: "custom",
|
|
10091
|
+
props,
|
|
10092
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
10093
|
+
};
|
|
10094
|
+
this.history.push(event);
|
|
10095
|
+
if (this.history.length > this.maxHistorySize) {
|
|
10096
|
+
this.history.shift();
|
|
10097
|
+
}
|
|
10098
|
+
let listenersNotified = 0;
|
|
10099
|
+
for (const subscription of this.subscriptions) {
|
|
10100
|
+
if (matchesFilter(event, subscription.filter)) {
|
|
10101
|
+
try {
|
|
10102
|
+
subscription.callback(event);
|
|
10103
|
+
listenersNotified++;
|
|
10104
|
+
} catch (err) {
|
|
10105
|
+
console.error("[EventBus] Subscriber error:", err);
|
|
10106
|
+
listenersNotified++;
|
|
10107
|
+
}
|
|
10108
|
+
}
|
|
10109
|
+
}
|
|
10110
|
+
let posthogCaptured = false;
|
|
10111
|
+
if (this.posthogCapture && !this.testMode) {
|
|
10112
|
+
try {
|
|
10113
|
+
this.posthogCapture(name, props);
|
|
10114
|
+
posthogCaptured = true;
|
|
10115
|
+
} catch (err) {
|
|
10116
|
+
console.error("[EventBus] PostHog capture error:", err);
|
|
10117
|
+
}
|
|
10118
|
+
}
|
|
10119
|
+
if (this.emitHistory) {
|
|
10120
|
+
this.emitHistory.record({
|
|
10121
|
+
name,
|
|
10122
|
+
props,
|
|
10123
|
+
source: "custom",
|
|
10124
|
+
timestamp: event.ts,
|
|
10125
|
+
matchedRules: []
|
|
10126
|
+
});
|
|
10127
|
+
}
|
|
10128
|
+
if (this.debug) {
|
|
10129
|
+
console.debug("[EventBus] emit()", { name, props, listenersNotified, posthogCaptured });
|
|
10130
|
+
return {
|
|
10131
|
+
delivered: true,
|
|
10132
|
+
matchedRules: [],
|
|
10133
|
+
posthogCaptured,
|
|
10134
|
+
listenersNotified
|
|
10135
|
+
};
|
|
10136
|
+
}
|
|
10137
|
+
return void 0;
|
|
10138
|
+
}
|
|
10139
|
+
/**
|
|
10140
|
+
* Set the PostHog capture function after construction.
|
|
10141
|
+
* Used by bootstrap to wire PostHog after the EventBus is created.
|
|
10142
|
+
*/
|
|
10143
|
+
setPosthogCapture(fn) {
|
|
10144
|
+
this.posthogCapture = fn;
|
|
10145
|
+
}
|
|
9159
10146
|
/**
|
|
9160
10147
|
* Get recent events matching an optional filter.
|
|
9161
10148
|
*/
|
|
@@ -9206,124 +10193,26 @@ function createEventBus(options = {}) {
|
|
|
9206
10193
|
return new EventBus(options);
|
|
9207
10194
|
}
|
|
9208
10195
|
|
|
9209
|
-
// src/events/
|
|
9210
|
-
var
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
$scroll: StandardEvents.UI_SCROLL,
|
|
9216
|
-
$input: StandardEvents.UI_INPUT,
|
|
9217
|
-
$change: StandardEvents.UI_CHANGE,
|
|
9218
|
-
$submit: StandardEvents.UI_SUBMIT,
|
|
9219
|
-
// Navigation events
|
|
9220
|
-
$pageview: StandardEvents.NAV_PAGE_VIEW,
|
|
9221
|
-
$pageleave: StandardEvents.NAV_PAGE_LEAVE,
|
|
9222
|
-
// Session events
|
|
9223
|
-
$session_start: "session.start",
|
|
9224
|
-
// Identify events
|
|
9225
|
-
$identify: "user.identify"
|
|
9226
|
-
};
|
|
9227
|
-
function getEventName(phEvent) {
|
|
9228
|
-
var _a2, _b;
|
|
9229
|
-
const eventName = phEvent.event;
|
|
9230
|
-
if (typeof eventName !== "string") {
|
|
9231
|
-
return "posthog.unknown";
|
|
9232
|
-
}
|
|
9233
|
-
if (POSTHOG_EVENT_MAP[eventName]) {
|
|
9234
|
-
return POSTHOG_EVENT_MAP[eventName];
|
|
9235
|
-
}
|
|
9236
|
-
if (eventName === "$autocapture") {
|
|
9237
|
-
const tagName = (_a2 = phEvent.properties) == null ? void 0 : _a2.$tag_name;
|
|
9238
|
-
const eventType = (_b = phEvent.properties) == null ? void 0 : _b.$event_type;
|
|
9239
|
-
if (eventType === "submit") return StandardEvents.UI_SUBMIT;
|
|
9240
|
-
if (eventType === "change") return StandardEvents.UI_CHANGE;
|
|
9241
|
-
if (tagName === "input" || tagName === "textarea") return StandardEvents.UI_INPUT;
|
|
9242
|
-
return StandardEvents.UI_CLICK;
|
|
9243
|
-
}
|
|
9244
|
-
if (!eventName.startsWith("$")) {
|
|
9245
|
-
return `posthog.${eventName}`;
|
|
10196
|
+
// src/events/history.ts
|
|
10197
|
+
var EventHistory = class {
|
|
10198
|
+
constructor(maxSize = 100) {
|
|
10199
|
+
__publicField(this, "entries", []);
|
|
10200
|
+
__publicField(this, "maxSize");
|
|
10201
|
+
this.maxSize = maxSize;
|
|
9246
10202
|
}
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
const phProps = phEvent.properties || {};
|
|
9253
|
-
const elements = phProps.$elements;
|
|
9254
|
-
if (phProps.$tag_name) {
|
|
9255
|
-
props.tagName = phProps.$tag_name;
|
|
9256
|
-
} else if ((_a2 = elements == null ? void 0 : elements[0]) == null ? void 0 : _a2.tag_name) {
|
|
9257
|
-
props.tagName = elements[0].tag_name;
|
|
9258
|
-
}
|
|
9259
|
-
if (phProps.$el_text) props.elementText = phProps.$el_text;
|
|
9260
|
-
if (elements) props.elements = elements;
|
|
9261
|
-
if (phProps.$current_url) props.url = phProps.$current_url;
|
|
9262
|
-
if (phProps.$pathname) props.pathname = phProps.$pathname;
|
|
9263
|
-
if (phProps.$host) props.host = phProps.$host;
|
|
9264
|
-
if (phProps.$viewport_width) props.viewportWidth = phProps.$viewport_width;
|
|
9265
|
-
if (phProps.$viewport_height) props.viewportHeight = phProps.$viewport_height;
|
|
9266
|
-
if (phProps.$session_id) props.sessionId = phProps.$session_id;
|
|
9267
|
-
if (phProps.$scroll_depth) props.scrollDepth = phProps.$scroll_depth;
|
|
9268
|
-
if (phProps.$scroll_percentage) props.scrollPercentage = phProps.$scroll_percentage;
|
|
9269
|
-
props.originalEvent = phEvent.event;
|
|
9270
|
-
return props;
|
|
9271
|
-
}
|
|
9272
|
-
function normalizePostHogEvent(phEvent) {
|
|
9273
|
-
let ts;
|
|
9274
|
-
if (typeof phEvent.timestamp === "number") {
|
|
9275
|
-
ts = phEvent.timestamp;
|
|
9276
|
-
} else if (typeof phEvent.timestamp === "string") {
|
|
9277
|
-
ts = new Date(phEvent.timestamp).getTime();
|
|
9278
|
-
} else {
|
|
9279
|
-
ts = Date.now();
|
|
10203
|
+
record(entry) {
|
|
10204
|
+
this.entries.push(entry);
|
|
10205
|
+
if (this.maxSize > 0 && this.entries.length > this.maxSize) {
|
|
10206
|
+
this.entries.shift();
|
|
10207
|
+
}
|
|
9280
10208
|
}
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
name: getEventName(phEvent),
|
|
9284
|
-
source: "posthog",
|
|
9285
|
-
props: extractProps(phEvent),
|
|
9286
|
-
schemaVersion: EVENT_SCHEMA_VERSION
|
|
9287
|
-
};
|
|
9288
|
-
}
|
|
9289
|
-
function shouldNormalizeEvent(phEvent) {
|
|
9290
|
-
const eventName = phEvent.event;
|
|
9291
|
-
if (typeof eventName !== "string") return false;
|
|
9292
|
-
const skipEvents = [
|
|
9293
|
-
"$feature_flag_called",
|
|
9294
|
-
"$feature_flags",
|
|
9295
|
-
"$groups",
|
|
9296
|
-
"$groupidentify",
|
|
9297
|
-
"$set",
|
|
9298
|
-
"$set_once",
|
|
9299
|
-
"$unset",
|
|
9300
|
-
"$create_alias",
|
|
9301
|
-
"$capture_metrics",
|
|
9302
|
-
"$performance_event",
|
|
9303
|
-
"$web_vitals",
|
|
9304
|
-
"$exception",
|
|
9305
|
-
"$dead_click",
|
|
9306
|
-
"$heatmap"
|
|
9307
|
-
];
|
|
9308
|
-
if (skipEvents.includes(eventName)) {
|
|
9309
|
-
return false;
|
|
10209
|
+
getAll() {
|
|
10210
|
+
return [...this.entries];
|
|
9310
10211
|
}
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
|
|
9315
|
-
if (typeof eventName !== "string") return;
|
|
9316
|
-
const phEvent = {
|
|
9317
|
-
event: eventName,
|
|
9318
|
-
properties,
|
|
9319
|
-
timestamp: Date.now()
|
|
9320
|
-
};
|
|
9321
|
-
if (shouldNormalizeEvent(phEvent)) {
|
|
9322
|
-
const normalizedEvent = normalizePostHogEvent(phEvent);
|
|
9323
|
-
publishFn(normalizedEvent);
|
|
9324
|
-
}
|
|
9325
|
-
};
|
|
9326
|
-
}
|
|
10212
|
+
clear() {
|
|
10213
|
+
this.entries = [];
|
|
10214
|
+
}
|
|
10215
|
+
};
|
|
9327
10216
|
|
|
9328
10217
|
// src/navigation/NavigationMonitor.ts
|
|
9329
10218
|
var NavigationMonitor = class {
|
|
@@ -10124,9 +11013,18 @@ function createSurfaces(options) {
|
|
|
10124
11013
|
}
|
|
10125
11014
|
async function unmountEntry(entry) {
|
|
10126
11015
|
var _a2;
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
11016
|
+
if (entry.container.isConnected) {
|
|
11017
|
+
await playExitAnimation(entry.container, entry.options.animation);
|
|
11018
|
+
}
|
|
11019
|
+
try {
|
|
11020
|
+
(_a2 = entry.cleanup) == null ? void 0 : _a2.call(entry);
|
|
11021
|
+
} catch (error2) {
|
|
11022
|
+
console.warn("[Surfaces] Cleanup error during unmount, ignoring:", error2);
|
|
11023
|
+
}
|
|
11024
|
+
try {
|
|
11025
|
+
entry.container.remove();
|
|
11026
|
+
} catch {
|
|
11027
|
+
}
|
|
10130
11028
|
mounts.delete(entry.slot);
|
|
10131
11029
|
publishEvent("surface.unmounted", {
|
|
10132
11030
|
slot: entry.slot,
|
|
@@ -10309,7 +11207,9 @@ var WidgetRegistry = class {
|
|
|
10309
11207
|
var _a2;
|
|
10310
11208
|
const mounted = this.mountedWidgets.get(mountId);
|
|
10311
11209
|
if (mounted) {
|
|
10312
|
-
(
|
|
11210
|
+
if (container.isConnected) {
|
|
11211
|
+
(_a2 = mounted.cleanup) == null ? void 0 : _a2.call(mounted);
|
|
11212
|
+
}
|
|
10313
11213
|
this.mountedWidgets.delete(mountId);
|
|
10314
11214
|
container.removeAttribute("data-widget-mount-id");
|
|
10315
11215
|
container.removeAttribute("data-widget-id");
|
|
@@ -10425,7 +11325,16 @@ function matchesAnchorRoute(anchorId) {
|
|
|
10425
11325
|
const pathname = typeof window !== "undefined" ? window.location.pathname : "/";
|
|
10426
11326
|
const normalizedPath = pathname.replace(/\/$/, "") || "/";
|
|
10427
11327
|
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
10428
|
-
return routes.some((pattern) =>
|
|
11328
|
+
return routes.some((pattern) => {
|
|
11329
|
+
let normalized = pattern;
|
|
11330
|
+
if (/^https?:\/\//.test(normalized)) {
|
|
11331
|
+
try {
|
|
11332
|
+
normalized = new URL(normalized).pathname;
|
|
11333
|
+
} catch {
|
|
11334
|
+
}
|
|
11335
|
+
}
|
|
11336
|
+
return matchRoutePattern(normalizedPath, normalized);
|
|
11337
|
+
});
|
|
10429
11338
|
}
|
|
10430
11339
|
function createSmartCanvasRuntime(options = {}) {
|
|
10431
11340
|
var _a2, _b, _c, _d;
|
|
@@ -10597,6 +11506,142 @@ function encodeToken(payload) {
|
|
|
10597
11506
|
return TOKEN_PREFIX + base64;
|
|
10598
11507
|
}
|
|
10599
11508
|
|
|
11509
|
+
// src/bootstrap-init.ts
|
|
11510
|
+
function getEnvVar(name) {
|
|
11511
|
+
if (typeof process !== "undefined" && process.env) {
|
|
11512
|
+
return process.env[name];
|
|
11513
|
+
}
|
|
11514
|
+
try {
|
|
11515
|
+
const meta = (0, eval)("import.meta");
|
|
11516
|
+
if (meta == null ? void 0 : meta.env) {
|
|
11517
|
+
return meta.env[name];
|
|
11518
|
+
}
|
|
11519
|
+
} catch {
|
|
11520
|
+
}
|
|
11521
|
+
return void 0;
|
|
11522
|
+
}
|
|
11523
|
+
var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
|
|
11524
|
+
function loadCachedSegmentAttributes() {
|
|
11525
|
+
if (typeof window === "undefined") return {};
|
|
11526
|
+
try {
|
|
11527
|
+
const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
|
|
11528
|
+
if (cached) {
|
|
11529
|
+
const attrs = JSON.parse(cached);
|
|
11530
|
+
debug("Syntro Bootstrap", "Loaded cached segment attributes:", attrs);
|
|
11531
|
+
return attrs;
|
|
11532
|
+
}
|
|
11533
|
+
} catch (err) {
|
|
11534
|
+
warn("Syntro Bootstrap", "Failed to load cached segment attributes:", err);
|
|
11535
|
+
}
|
|
11536
|
+
return {};
|
|
11537
|
+
}
|
|
11538
|
+
function cacheSegmentAttributes(attrs) {
|
|
11539
|
+
if (typeof window === "undefined") return;
|
|
11540
|
+
try {
|
|
11541
|
+
localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
|
|
11542
|
+
debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
|
|
11543
|
+
} catch (err) {
|
|
11544
|
+
warn("Syntro Bootstrap", "Failed to cache segment attributes:", err);
|
|
11545
|
+
}
|
|
11546
|
+
}
|
|
11547
|
+
function extractSegmentFlags(allFlags) {
|
|
11548
|
+
if (!allFlags) return {};
|
|
11549
|
+
const segmentFlags = {};
|
|
11550
|
+
for (const [key, value] of Object.entries(allFlags)) {
|
|
11551
|
+
if (key.startsWith("in_segment_")) {
|
|
11552
|
+
segmentFlags[key] = value === true;
|
|
11553
|
+
}
|
|
11554
|
+
}
|
|
11555
|
+
return segmentFlags;
|
|
11556
|
+
}
|
|
11557
|
+
function collectBrowserMetadata() {
|
|
11558
|
+
var _a2;
|
|
11559
|
+
if (typeof window === "undefined") return {};
|
|
11560
|
+
const attrs = {};
|
|
11561
|
+
try {
|
|
11562
|
+
const params = new URLSearchParams(window.location.search);
|
|
11563
|
+
for (const key of ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]) {
|
|
11564
|
+
const val = params.get(key);
|
|
11565
|
+
if (val) attrs[key] = val;
|
|
11566
|
+
}
|
|
11567
|
+
} catch {
|
|
11568
|
+
}
|
|
11569
|
+
try {
|
|
11570
|
+
if (navigator.language) attrs.browser_language = navigator.language;
|
|
11571
|
+
if ((_a2 = navigator.languages) == null ? void 0 : _a2.length) attrs.browser_languages = [...navigator.languages];
|
|
11572
|
+
} catch {
|
|
11573
|
+
}
|
|
11574
|
+
try {
|
|
11575
|
+
const w = window.innerWidth;
|
|
11576
|
+
attrs.device_type = w < 768 ? "mobile" : w < 1024 ? "tablet" : "desktop";
|
|
11577
|
+
} catch {
|
|
11578
|
+
}
|
|
11579
|
+
try {
|
|
11580
|
+
if (document.referrer) {
|
|
11581
|
+
attrs.referrer = document.referrer;
|
|
11582
|
+
try {
|
|
11583
|
+
attrs.referrer_hostname = new URL(document.referrer).hostname;
|
|
11584
|
+
} catch {
|
|
11585
|
+
}
|
|
11586
|
+
}
|
|
11587
|
+
} catch {
|
|
11588
|
+
}
|
|
11589
|
+
try {
|
|
11590
|
+
const ua = navigator.userAgent;
|
|
11591
|
+
if (ua.includes("Edg/")) attrs.browser = "Edge";
|
|
11592
|
+
else if (ua.includes("OPR/") || ua.includes("Opera")) attrs.browser = "Opera";
|
|
11593
|
+
else if (ua.includes("Chrome/") && !ua.includes("Chromium")) attrs.browser = "Chrome";
|
|
11594
|
+
else if (ua.includes("Safari/") && !ua.includes("Chrome")) attrs.browser = "Safari";
|
|
11595
|
+
else if (ua.includes("Firefox/")) attrs.browser = "Firefox";
|
|
11596
|
+
if (ua.includes("Windows")) attrs.os = "Windows";
|
|
11597
|
+
else if (ua.includes("iPhone") || ua.includes("iPad")) attrs.os = "iOS";
|
|
11598
|
+
else if (ua.includes("Mac OS X") || ua.includes("Macintosh")) attrs.os = "macOS";
|
|
11599
|
+
else if (ua.includes("Android")) attrs.os = "Android";
|
|
11600
|
+
else if (ua.includes("Linux")) attrs.os = "Linux";
|
|
11601
|
+
} catch {
|
|
11602
|
+
}
|
|
11603
|
+
try {
|
|
11604
|
+
attrs.page_url = window.location.href;
|
|
11605
|
+
attrs.page_path = window.location.pathname;
|
|
11606
|
+
attrs.page_host = window.location.hostname;
|
|
11607
|
+
if (window.location.search) attrs.page_query = window.location.search;
|
|
11608
|
+
} catch {
|
|
11609
|
+
}
|
|
11610
|
+
return attrs;
|
|
11611
|
+
}
|
|
11612
|
+
var GEO_CACHE_KEY = "syntro_geo";
|
|
11613
|
+
var GEO_DEFAULT_HOST = "https://geo.syntrologie.com";
|
|
11614
|
+
async function fetchGeo(geoHost) {
|
|
11615
|
+
if (typeof window === "undefined") return {};
|
|
11616
|
+
try {
|
|
11617
|
+
const cached = localStorage.getItem(GEO_CACHE_KEY);
|
|
11618
|
+
if (cached) {
|
|
11619
|
+
const parsed = JSON.parse(cached);
|
|
11620
|
+
debug("Syntro Bootstrap", "Geo: using cached data:", parsed);
|
|
11621
|
+
return parsed;
|
|
11622
|
+
}
|
|
11623
|
+
} catch {
|
|
11624
|
+
}
|
|
11625
|
+
try {
|
|
11626
|
+
const res = await fetch(geoHost, { signal: AbortSignal.timeout(2e3) });
|
|
11627
|
+
if (res.ok) {
|
|
11628
|
+
const geo = await res.json();
|
|
11629
|
+
const cleaned = {};
|
|
11630
|
+
for (const [k, v] of Object.entries(geo)) {
|
|
11631
|
+
if (typeof v === "string" && v) cleaned[k] = v;
|
|
11632
|
+
}
|
|
11633
|
+
try {
|
|
11634
|
+
localStorage.setItem(GEO_CACHE_KEY, JSON.stringify(cleaned));
|
|
11635
|
+
} catch {
|
|
11636
|
+
}
|
|
11637
|
+
debug("Syntro Bootstrap", "Geo: fetched from worker:", cleaned);
|
|
11638
|
+
return cleaned;
|
|
11639
|
+
}
|
|
11640
|
+
} catch {
|
|
11641
|
+
}
|
|
11642
|
+
return {};
|
|
11643
|
+
}
|
|
11644
|
+
|
|
10600
11645
|
// src/experiments/registry.ts
|
|
10601
11646
|
var adapters = {
|
|
10602
11647
|
growthbook: (config) => createGrowthBookClient({
|
|
@@ -10703,9 +11748,8 @@ var ExperimentsFetcher = class {
|
|
|
10703
11748
|
__publicField(this, "featureKey");
|
|
10704
11749
|
__publicField(this, "manifestKey");
|
|
10705
11750
|
__publicField(this, "variantFlagPrefix");
|
|
10706
|
-
var _a2;
|
|
10707
11751
|
this.client = options.client;
|
|
10708
|
-
this.featureKey =
|
|
11752
|
+
this.featureKey = options.featureKey;
|
|
10709
11753
|
this.manifestKey = options.manifestKey;
|
|
10710
11754
|
this.variantFlagPrefix = options.variantFlagPrefix;
|
|
10711
11755
|
}
|
|
@@ -10734,6 +11778,11 @@ var ExperimentsFetcher = class {
|
|
|
10734
11778
|
};
|
|
10735
11779
|
}
|
|
10736
11780
|
}
|
|
11781
|
+
if (!this.featureKey) {
|
|
11782
|
+
throw new Error(
|
|
11783
|
+
"[SmartCanvas] No featureKey configured and no variant flags found. Ensure at least one config feature flag exists in your experiment platform."
|
|
11784
|
+
);
|
|
11785
|
+
}
|
|
10737
11786
|
const config = (_b = (_a2 = this.client).getFeatureValue) == null ? void 0 : _b.call(_a2, this.featureKey, null);
|
|
10738
11787
|
if (!config || typeof config !== "object") {
|
|
10739
11788
|
throw new Error(
|
|
@@ -10845,95 +11894,9 @@ function createTelemetryClient(provider, config) {
|
|
|
10845
11894
|
return factory(config);
|
|
10846
11895
|
}
|
|
10847
11896
|
|
|
10848
|
-
// src/bootstrap.ts
|
|
10849
|
-
function
|
|
10850
|
-
|
|
10851
|
-
return process.env[name];
|
|
10852
|
-
}
|
|
10853
|
-
try {
|
|
10854
|
-
const meta = (0, eval)("import.meta");
|
|
10855
|
-
if (meta == null ? void 0 : meta.env) {
|
|
10856
|
-
return meta.env[name];
|
|
10857
|
-
}
|
|
10858
|
-
} catch {
|
|
10859
|
-
}
|
|
10860
|
-
return void 0;
|
|
10861
|
-
}
|
|
10862
|
-
var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
|
|
10863
|
-
function loadCachedSegmentAttributes() {
|
|
10864
|
-
if (typeof window === "undefined") return {};
|
|
10865
|
-
try {
|
|
10866
|
-
const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
|
|
10867
|
-
if (cached) {
|
|
10868
|
-
const attrs = JSON.parse(cached);
|
|
10869
|
-
debug("Syntro Bootstrap", "Loaded cached segment attributes:", attrs);
|
|
10870
|
-
return attrs;
|
|
10871
|
-
}
|
|
10872
|
-
} catch (err) {
|
|
10873
|
-
warn("Syntro Bootstrap", "Failed to load cached segment attributes:", err);
|
|
10874
|
-
}
|
|
10875
|
-
return {};
|
|
10876
|
-
}
|
|
10877
|
-
function cacheSegmentAttributes(attrs) {
|
|
10878
|
-
if (typeof window === "undefined") return;
|
|
10879
|
-
try {
|
|
10880
|
-
localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
|
|
10881
|
-
debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
|
|
10882
|
-
} catch (err) {
|
|
10883
|
-
warn("Syntro Bootstrap", "Failed to cache segment attributes:", err);
|
|
10884
|
-
}
|
|
10885
|
-
}
|
|
10886
|
-
function extractSegmentFlags(allFlags) {
|
|
10887
|
-
if (!allFlags) return {};
|
|
10888
|
-
const segmentFlags = {};
|
|
10889
|
-
for (const [key, value] of Object.entries(allFlags)) {
|
|
10890
|
-
if (key.startsWith("in_segment_")) {
|
|
10891
|
-
segmentFlags[key] = value === true;
|
|
10892
|
-
}
|
|
10893
|
-
}
|
|
10894
|
-
return segmentFlags;
|
|
10895
|
-
}
|
|
10896
|
-
function collectBrowserMetadata() {
|
|
10897
|
-
var _a2;
|
|
10898
|
-
if (typeof window === "undefined") return {};
|
|
10899
|
-
const attrs = {};
|
|
10900
|
-
try {
|
|
10901
|
-
const params = new URLSearchParams(window.location.search);
|
|
10902
|
-
for (const key of ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]) {
|
|
10903
|
-
const val = params.get(key);
|
|
10904
|
-
if (val) attrs[key] = val;
|
|
10905
|
-
}
|
|
10906
|
-
} catch {
|
|
10907
|
-
}
|
|
10908
|
-
try {
|
|
10909
|
-
if (navigator.language) attrs.browser_language = navigator.language;
|
|
10910
|
-
if ((_a2 = navigator.languages) == null ? void 0 : _a2.length) attrs.browser_languages = [...navigator.languages];
|
|
10911
|
-
} catch {
|
|
10912
|
-
}
|
|
10913
|
-
try {
|
|
10914
|
-
const w = window.innerWidth;
|
|
10915
|
-
attrs.device_type = w < 768 ? "mobile" : w < 1024 ? "tablet" : "desktop";
|
|
10916
|
-
} catch {
|
|
10917
|
-
}
|
|
10918
|
-
try {
|
|
10919
|
-
if (document.referrer) {
|
|
10920
|
-
attrs.referrer = document.referrer;
|
|
10921
|
-
try {
|
|
10922
|
-
attrs.referrer_hostname = new URL(document.referrer).hostname;
|
|
10923
|
-
} catch {
|
|
10924
|
-
}
|
|
10925
|
-
}
|
|
10926
|
-
} catch {
|
|
10927
|
-
}
|
|
10928
|
-
try {
|
|
10929
|
-
attrs.page_url = window.location.href;
|
|
10930
|
-
attrs.page_path = window.location.pathname;
|
|
10931
|
-
} catch {
|
|
10932
|
-
}
|
|
10933
|
-
return attrs;
|
|
10934
|
-
}
|
|
10935
|
-
async function init(options) {
|
|
10936
|
-
var _a2, _b, _c, _d, _e, _f;
|
|
11897
|
+
// src/bootstrap-runtime.ts
|
|
11898
|
+
async function _initCore(options) {
|
|
11899
|
+
var _a2, _b, _c, _d, _e, _f, _g;
|
|
10937
11900
|
initLogger();
|
|
10938
11901
|
debug("Syntro Bootstrap", "====== INIT ======");
|
|
10939
11902
|
debug("Syntro Bootstrap", "Options:", {
|
|
@@ -10998,17 +11961,59 @@ async function init(options) {
|
|
|
10998
11961
|
const experimentHost = getEnvVar("NEXT_PUBLIC_SYNTRO_EXPERIMENT_HOST") || getEnvVar("VITE_SYNTRO_EXPERIMENT_HOST") || (payload == null ? void 0 : payload.eh);
|
|
10999
11962
|
const telemetryHost = getEnvVar("NEXT_PUBLIC_SYNTRO_TELEMETRY_HOST") || getEnvVar("VITE_SYNTRO_TELEMETRY_HOST") || (payload == null ? void 0 : payload.th);
|
|
11000
11963
|
const editorUrl = getEnvVar("NEXT_PUBLIC_SYNTRO_EDITOR_URL") || getEnvVar("VITE_SYNTRO_EDITOR_URL") || ((_b = options.canvas) == null ? void 0 : _b.editorUrl);
|
|
11964
|
+
const geoHost = (payload == null ? void 0 : payload.g) || getEnvVar("NEXT_PUBLIC_SYNTRO_GEO_HOST") || getEnvVar("VITE_SYNTRO_GEO_HOST") || GEO_DEFAULT_HOST;
|
|
11001
11965
|
const cachedSegmentAttrs = loadCachedSegmentAttributes();
|
|
11002
11966
|
const browserMetadata = collectBrowserMetadata();
|
|
11003
11967
|
const phaseOneAttrs = { ...browserMetadata, ...cachedSegmentAttrs };
|
|
11004
11968
|
debug("Syntro Bootstrap", "Phase 1: Browser metadata:", browserMetadata);
|
|
11005
11969
|
debug("Syntro Bootstrap", "Phase 1: Cached segment attributes:", cachedSegmentAttrs);
|
|
11970
|
+
const geoPromise = fetchGeo(geoHost);
|
|
11006
11971
|
let experiments;
|
|
11007
|
-
const
|
|
11972
|
+
const isDebugOrTest = options.debug || options.testMode;
|
|
11973
|
+
const events = createEventBus({
|
|
11974
|
+
debug: options.debug,
|
|
11975
|
+
history: isDebugOrTest ? new EventHistory(options.testMode ? 0 : 100) : void 0,
|
|
11976
|
+
testMode: options.testMode
|
|
11977
|
+
});
|
|
11008
11978
|
console.log("[Syntro Bootstrap] EventBus created");
|
|
11009
|
-
const
|
|
11010
|
-
|
|
11979
|
+
const processor = createEventProcessor({
|
|
11980
|
+
elementResolver: typeof window !== "undefined" ? (x, y) => {
|
|
11981
|
+
const el = document.elementFromPoint(x, y);
|
|
11982
|
+
if (!el) return null;
|
|
11983
|
+
const info = { tag_name: el.tagName.toLowerCase() };
|
|
11984
|
+
if (el.id) info.attr__id = el.id;
|
|
11985
|
+
if (el.className && typeof el.className === "string") {
|
|
11986
|
+
info.classes = el.className.split(" ").filter(Boolean);
|
|
11987
|
+
}
|
|
11988
|
+
for (const attr of el.attributes) {
|
|
11989
|
+
if (attr.name.startsWith("data-")) info[`attr__${attr.name}`] = attr.value;
|
|
11990
|
+
}
|
|
11991
|
+
return info;
|
|
11992
|
+
} : void 0
|
|
11011
11993
|
});
|
|
11994
|
+
processor.onEvent((event) => events.publishEvent(event));
|
|
11995
|
+
if (typeof window !== "undefined") {
|
|
11996
|
+
setInterval(() => processor.tick(Date.now()), 1e3);
|
|
11997
|
+
document.addEventListener(
|
|
11998
|
+
"click",
|
|
11999
|
+
(e) => {
|
|
12000
|
+
const chain = [];
|
|
12001
|
+
let el = e.target;
|
|
12002
|
+
while (el && el !== document.body) {
|
|
12003
|
+
const info = { tag_name: el.tagName.toLowerCase() };
|
|
12004
|
+
for (const attr of el.attributes) {
|
|
12005
|
+
if (attr.name.startsWith("data-") || attr.name === "id" || attr.name === "class" || attr.name === "aria-label") {
|
|
12006
|
+
info[`attr__${attr.name}`] = attr.value;
|
|
12007
|
+
}
|
|
12008
|
+
}
|
|
12009
|
+
chain.push(info);
|
|
12010
|
+
el = el.parentElement;
|
|
12011
|
+
}
|
|
12012
|
+
processor.enrichClickAttributes(Date.now(), chain);
|
|
12013
|
+
},
|
|
12014
|
+
true
|
|
12015
|
+
);
|
|
12016
|
+
}
|
|
11012
12017
|
const onFeatureFlagsLoaded = (allFlags) => {
|
|
11013
12018
|
var _a3, _b2, _c2;
|
|
11014
12019
|
debug("Syntro Bootstrap", "Phase 2: PostHog feature flags loaded");
|
|
@@ -11031,12 +12036,26 @@ async function init(options) {
|
|
|
11031
12036
|
// undefined falls back to adapter default
|
|
11032
12037
|
// Enable PostHog feature flags for segment membership
|
|
11033
12038
|
enableFeatureFlags: true,
|
|
12039
|
+
// Disable session recording in debug/dev mode (mock telemetry doesn't
|
|
12040
|
+
// support the PostHog recorder extension, causing console errors)
|
|
12041
|
+
sessionRecording: !payload.d,
|
|
11034
12042
|
// Wire up callback for when flags are loaded (Phase 2)
|
|
11035
12043
|
onFeatureFlagsLoaded,
|
|
11036
|
-
// Wire up event capture to feed into
|
|
11037
|
-
onCapture:
|
|
12044
|
+
// Wire up event capture to feed into event processor
|
|
12045
|
+
onCapture: (eventName, properties) => {
|
|
12046
|
+
processor.ingest({ kind: "posthog", event: eventName, properties, timestamp: Date.now() });
|
|
12047
|
+
},
|
|
12048
|
+
// Wire rrweb events for behavioral signal detection
|
|
12049
|
+
onRRWebEvent: (event) => {
|
|
12050
|
+
processor.ingest(event);
|
|
12051
|
+
}
|
|
11038
12052
|
});
|
|
11039
12053
|
console.log(`[Syntro Bootstrap] Telemetry client created (${provider}) with EventBus wiring`);
|
|
12054
|
+
const telemetryForCapture = telemetry;
|
|
12055
|
+
events.setPosthogCapture((name, props) => {
|
|
12056
|
+
var _a3;
|
|
12057
|
+
(_a3 = telemetryForCapture.track) == null ? void 0 : _a3.call(telemetryForCapture, name, props);
|
|
12058
|
+
});
|
|
11040
12059
|
}
|
|
11041
12060
|
let sessionMetrics;
|
|
11042
12061
|
if (payload == null ? void 0 : payload.e) {
|
|
@@ -11129,11 +12148,17 @@ async function init(options) {
|
|
|
11129
12148
|
warn("Syntro Bootstrap", "Failed to load GrowthBook features:", err);
|
|
11130
12149
|
}
|
|
11131
12150
|
}
|
|
12151
|
+
const geoData = await geoPromise;
|
|
12152
|
+
if (experiments && Object.keys(geoData).length > 0) {
|
|
12153
|
+
const mergedAttrs = { ...browserMetadata, ...geoData };
|
|
12154
|
+
debug("Syntro Bootstrap", "Merging geo data into GrowthBook attributes:", geoData);
|
|
12155
|
+
(_f = experiments.setAttributes) == null ? void 0 : _f.call(experiments, mergedAttrs);
|
|
12156
|
+
}
|
|
11132
12157
|
let baseFetcher;
|
|
11133
12158
|
if (options.fetcher) {
|
|
11134
12159
|
baseFetcher = options.fetcher;
|
|
11135
12160
|
} else if (payload == null ? void 0 : payload.f) {
|
|
11136
|
-
const configFetcher = createConfigFetcher(payload.f, (
|
|
12161
|
+
const configFetcher = createConfigFetcher(payload.f, (_g = payload.o) != null ? _g : {});
|
|
11137
12162
|
baseFetcher = async () => {
|
|
11138
12163
|
var _a3;
|
|
11139
12164
|
const result = await configFetcher.fetch();
|
|
@@ -11147,19 +12172,39 @@ async function init(options) {
|
|
|
11147
12172
|
}
|
|
11148
12173
|
const warnedAppFailures = /* @__PURE__ */ new Set();
|
|
11149
12174
|
const appLoadingFetcher = baseFetcher ? async () => {
|
|
11150
|
-
var _a3, _b2, _c2, _d2, _e2, _f2,
|
|
12175
|
+
var _a3, _b2, _c2, _d2, _e2, _f2, _g2, _h, _i, _j, _k, _l;
|
|
11151
12176
|
const config = await baseFetcher();
|
|
12177
|
+
const tileCount = (_b2 = (_a3 = config.tiles) == null ? void 0 : _a3.length) != null ? _b2 : 0;
|
|
12178
|
+
const actionCount = (_d2 = (_c2 = config.actions) == null ? void 0 : _c2.length) != null ? _d2 : 0;
|
|
12179
|
+
const variantId = (_e2 = config.meta) == null ? void 0 : _e2.variant_id;
|
|
12180
|
+
if (tileCount > 0 || actionCount > 0) {
|
|
12181
|
+
if (!variantId) {
|
|
12182
|
+
console.warn(
|
|
12183
|
+
"[Syntro] Config has content but no meta.variant_id \u2014 intervention tracking disabled"
|
|
12184
|
+
);
|
|
12185
|
+
}
|
|
12186
|
+
}
|
|
12187
|
+
if (telemetry && variantId) {
|
|
12188
|
+
const tracker = new InterventionTracker(telemetry, variantId);
|
|
12189
|
+
tracker.trackServed(tileCount, actionCount);
|
|
12190
|
+
if (typeof window !== "undefined") {
|
|
12191
|
+
window.SynOS.interventionTracker = tracker;
|
|
12192
|
+
}
|
|
12193
|
+
runtime3.navigation.subscribe(() => {
|
|
12194
|
+
tracker.resetPage();
|
|
12195
|
+
});
|
|
12196
|
+
}
|
|
11152
12197
|
console.log(
|
|
11153
12198
|
"[Syntro Bootstrap] Config fetched:",
|
|
11154
|
-
`tiles=${(
|
|
11155
|
-
`actions=${(
|
|
11156
|
-
`theme=${(
|
|
12199
|
+
`tiles=${(_g2 = (_f2 = config.tiles) == null ? void 0 : _f2.length) != null ? _g2 : 0},`,
|
|
12200
|
+
`actions=${(_i = (_h = config.actions) == null ? void 0 : _h.length) != null ? _i : 0},`,
|
|
12201
|
+
`theme=${(_k = (_j = config.theme) == null ? void 0 : _j.name) != null ? _k : "none"}`
|
|
11157
12202
|
);
|
|
11158
|
-
if (((
|
|
12203
|
+
if (((_l = config.actions) == null ? void 0 : _l.length) > 0) {
|
|
11159
12204
|
console.log(
|
|
11160
12205
|
"[Syntro Bootstrap] Actions in config:",
|
|
11161
12206
|
config.actions.map(
|
|
11162
|
-
(a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${
|
|
12207
|
+
(a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${a.anchorId.selector}"` : ""}${a.label ? ` "${a.label}"` : ""}`
|
|
11163
12208
|
).join(", ")
|
|
11164
12209
|
);
|
|
11165
12210
|
}
|
|
@@ -11218,10 +12263,33 @@ async function init(options) {
|
|
|
11218
12263
|
});
|
|
11219
12264
|
return { canvas, runtime: runtime3, experiments, telemetry, sessionMetrics, appLoader };
|
|
11220
12265
|
}
|
|
12266
|
+
|
|
12267
|
+
// src/bootstrap.ts
|
|
12268
|
+
async function init(options) {
|
|
12269
|
+
var _a2;
|
|
12270
|
+
try {
|
|
12271
|
+
return await _initCore(options);
|
|
12272
|
+
} catch (err) {
|
|
12273
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12274
|
+
console.warn("[Syntrologie] SDK initialization failed:", message);
|
|
12275
|
+
if (typeof document !== "undefined") {
|
|
12276
|
+
(_a2 = document.getElementById("syntrologie-anti-flicker")) == null ? void 0 : _a2.remove();
|
|
12277
|
+
}
|
|
12278
|
+
return void 0;
|
|
12279
|
+
}
|
|
12280
|
+
}
|
|
12281
|
+
function emit(eventName, props = {}) {
|
|
12282
|
+
var _a2, _b;
|
|
12283
|
+
if (typeof window === "undefined") return;
|
|
12284
|
+
const runtime3 = (_a2 = window.SynOS) == null ? void 0 : _a2.runtime;
|
|
12285
|
+
if (!((_b = runtime3 == null ? void 0 : runtime3.events) == null ? void 0 : _b.publish)) return;
|
|
12286
|
+
runtime3.events.publish({ name: eventName, source: "custom", props });
|
|
12287
|
+
}
|
|
11221
12288
|
var Syntro = {
|
|
11222
12289
|
init,
|
|
11223
12290
|
encodeToken,
|
|
11224
|
-
decodeToken
|
|
12291
|
+
decodeToken,
|
|
12292
|
+
events: { emit }
|
|
11225
12293
|
};
|
|
11226
12294
|
if (typeof window !== "undefined") {
|
|
11227
12295
|
window.Syntro = Syntro;
|
|
@@ -11252,8 +12320,11 @@ export {
|
|
|
11252
12320
|
createSmartCanvasController,
|
|
11253
12321
|
ShadowRootProvider,
|
|
11254
12322
|
useShadowRoot,
|
|
11255
|
-
StandardEvents,
|
|
11256
12323
|
EVENT_SCHEMA_VERSION,
|
|
12324
|
+
normalizePostHogEvent,
|
|
12325
|
+
shouldNormalizeEvent,
|
|
12326
|
+
createPostHogNormalizer,
|
|
12327
|
+
StandardEvents2 as StandardEvents,
|
|
11257
12328
|
CanvasEvents,
|
|
11258
12329
|
NotificationToastStack,
|
|
11259
12330
|
MAX_VISIBLE_TOASTS,
|
|
@@ -11284,6 +12355,7 @@ export {
|
|
|
11284
12355
|
createSessionMetricTracker,
|
|
11285
12356
|
createNoopClient,
|
|
11286
12357
|
createPostHogClient,
|
|
12358
|
+
InterventionTracker,
|
|
11287
12359
|
ExecutorRegistry,
|
|
11288
12360
|
executorRegistry,
|
|
11289
12361
|
getExecutor,
|
|
@@ -11302,11 +12374,11 @@ export {
|
|
|
11302
12374
|
evaluateSync,
|
|
11303
12375
|
createDecisionEngine,
|
|
11304
12376
|
createEventAccumulator,
|
|
12377
|
+
validateEventName,
|
|
12378
|
+
validateProps,
|
|
11305
12379
|
EventBus,
|
|
11306
12380
|
createEventBus,
|
|
11307
|
-
|
|
11308
|
-
shouldNormalizeEvent,
|
|
11309
|
-
createPostHogNormalizer,
|
|
12381
|
+
EventHistory,
|
|
11310
12382
|
NavigationMonitor,
|
|
11311
12383
|
StateStore,
|
|
11312
12384
|
createStateStore,
|
|
@@ -11330,4 +12402,4 @@ export {
|
|
|
11330
12402
|
encodeToken,
|
|
11331
12403
|
Syntro
|
|
11332
12404
|
};
|
|
11333
|
-
//# sourceMappingURL=chunk-
|
|
12405
|
+
//# sourceMappingURL=chunk-WX32GVSP.js.map
|