@syntrologie/runtime-sdk 2.8.0-canary.8 → 2.8.0-canary.80
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-OB5AKUQT.js → chunk-EELCEGS7.js} +1868 -731
- package/dist/chunk-EELCEGS7.js.map +7 -0
- package/dist/{chunk-XDYJ64IN.js → chunk-IR6UOR63.js} +4 -4
- package/dist/chunk-IR6UOR63.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/fetchers/mergeConfigs.d.ts +7 -7
- 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 +5982 -3081
- 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-OB5AKUQT.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,14 +3456,20 @@ 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.80";
|
|
3362
3460
|
|
|
3363
3461
|
// src/types.ts
|
|
3364
3462
|
var SDK_SCHEMA_VERSION = "2.0";
|
|
3365
3463
|
|
|
3366
3464
|
// src/fetchers/mergeConfigs.ts
|
|
3367
|
-
function resolveVariantConfigs(client, keys,
|
|
3368
|
-
|
|
3465
|
+
function resolveVariantConfigs(client, keys, strategy = "merge") {
|
|
3466
|
+
if (strategy === "first-match") {
|
|
3467
|
+
return resolveFirstMatch(client, keys);
|
|
3468
|
+
}
|
|
3469
|
+
return resolveMerge(client, keys);
|
|
3470
|
+
}
|
|
3471
|
+
function resolveFirstMatch(client, keys) {
|
|
3472
|
+
var _a2;
|
|
3369
3473
|
for (const key of keys) {
|
|
3370
3474
|
const value = (_a2 = client.getFeatureValue) == null ? void 0 : _a2.call(client, key, null);
|
|
3371
3475
|
if (!value || typeof value !== "object") continue;
|
|
@@ -3373,20 +3477,60 @@ function resolveVariantConfigs(client, keys, _strategy = "first-match") {
|
|
|
3373
3477
|
const hasTiles = variant.tiles && variant.tiles.length > 0;
|
|
3374
3478
|
const hasActions = variant.actions && variant.actions.length > 0;
|
|
3375
3479
|
if (hasTiles || hasActions) {
|
|
3376
|
-
return
|
|
3377
|
-
tiles: (_b = variant.tiles) != null ? _b : [],
|
|
3378
|
-
actions: (_c = variant.actions) != null ? _c : [],
|
|
3379
|
-
fetchedAt: (_d = variant.fetchedAt) != null ? _d : (/* @__PURE__ */ new Date()).toISOString(),
|
|
3380
|
-
...variant.schemaVersion && { schemaVersion: variant.schemaVersion },
|
|
3381
|
-
...variant.configVersion && { configVersion: variant.configVersion },
|
|
3382
|
-
...variant.canvasTitle && { canvasTitle: variant.canvasTitle },
|
|
3383
|
-
...variant.theme && { theme: variant.theme },
|
|
3384
|
-
...variant.launcher && { launcher: variant.launcher }
|
|
3385
|
-
};
|
|
3480
|
+
return buildConfig([variant]);
|
|
3386
3481
|
}
|
|
3387
3482
|
}
|
|
3388
3483
|
return null;
|
|
3389
3484
|
}
|
|
3485
|
+
function resolveMerge(client, keys) {
|
|
3486
|
+
var _a2;
|
|
3487
|
+
const variants = [];
|
|
3488
|
+
for (const key of keys) {
|
|
3489
|
+
const value = (_a2 = client.getFeatureValue) == null ? void 0 : _a2.call(client, key, null);
|
|
3490
|
+
if (!value || typeof value !== "object") continue;
|
|
3491
|
+
const variant = value;
|
|
3492
|
+
const hasTiles = variant.tiles && variant.tiles.length > 0;
|
|
3493
|
+
const hasActions = variant.actions && variant.actions.length > 0;
|
|
3494
|
+
if (hasTiles || hasActions) {
|
|
3495
|
+
variants.push(variant);
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3498
|
+
if (variants.length === 0) return null;
|
|
3499
|
+
return buildConfig(variants);
|
|
3500
|
+
}
|
|
3501
|
+
function buildConfig(variants) {
|
|
3502
|
+
const allTiles = [];
|
|
3503
|
+
const allActions = [];
|
|
3504
|
+
let fetchedAt;
|
|
3505
|
+
let schemaVersion;
|
|
3506
|
+
let configVersion;
|
|
3507
|
+
let canvasTitle;
|
|
3508
|
+
let theme;
|
|
3509
|
+
let launcher;
|
|
3510
|
+
let meta;
|
|
3511
|
+
for (const variant of variants) {
|
|
3512
|
+
if (variant.tiles) allTiles.push(...variant.tiles);
|
|
3513
|
+
if (variant.actions) allActions.push(...variant.actions);
|
|
3514
|
+
fetchedAt != null ? fetchedAt : fetchedAt = variant.fetchedAt;
|
|
3515
|
+
schemaVersion != null ? schemaVersion : schemaVersion = variant.schemaVersion;
|
|
3516
|
+
configVersion != null ? configVersion : configVersion = variant.configVersion;
|
|
3517
|
+
canvasTitle != null ? canvasTitle : canvasTitle = variant.canvasTitle;
|
|
3518
|
+
theme != null ? theme : theme = variant.theme;
|
|
3519
|
+
launcher != null ? launcher : launcher = variant.launcher;
|
|
3520
|
+
meta != null ? meta : meta = variant.meta;
|
|
3521
|
+
}
|
|
3522
|
+
return {
|
|
3523
|
+
tiles: allTiles,
|
|
3524
|
+
actions: allActions,
|
|
3525
|
+
fetchedAt: fetchedAt != null ? fetchedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
3526
|
+
...schemaVersion && { schemaVersion },
|
|
3527
|
+
...configVersion && { configVersion },
|
|
3528
|
+
...canvasTitle && { canvasTitle },
|
|
3529
|
+
...theme && { theme },
|
|
3530
|
+
...launcher && { launcher },
|
|
3531
|
+
...meta && { meta }
|
|
3532
|
+
};
|
|
3533
|
+
}
|
|
3390
3534
|
|
|
3391
3535
|
// src/logger.ts
|
|
3392
3536
|
var debugEnabled = false;
|
|
@@ -3509,12 +3653,14 @@ function getCachedConfig(sdkVersion) {
|
|
|
3509
3653
|
var resolveConfigUri = ({
|
|
3510
3654
|
configUri,
|
|
3511
3655
|
experiments,
|
|
3512
|
-
featureKey
|
|
3656
|
+
featureKey
|
|
3513
3657
|
}) => {
|
|
3514
3658
|
var _a2;
|
|
3515
3659
|
if (configUri) return configUri;
|
|
3516
|
-
|
|
3517
|
-
|
|
3660
|
+
if (experiments && featureKey) {
|
|
3661
|
+
const fromFeature = (_a2 = experiments.getFeatureValue) == null ? void 0 : _a2.call(experiments, featureKey, null);
|
|
3662
|
+
if (fromFeature) return fromFeature;
|
|
3663
|
+
}
|
|
3518
3664
|
return void 0;
|
|
3519
3665
|
};
|
|
3520
3666
|
function getVariantFlagKeys(experiments, manifestKey, variantFlagPrefix) {
|
|
@@ -3540,7 +3686,7 @@ var createCanvasConfigFetcher = ({
|
|
|
3540
3686
|
experiments,
|
|
3541
3687
|
featureKey,
|
|
3542
3688
|
credentials,
|
|
3543
|
-
configFeatureKey
|
|
3689
|
+
configFeatureKey,
|
|
3544
3690
|
manifestKey,
|
|
3545
3691
|
variantFlagPrefix,
|
|
3546
3692
|
sdkVersion
|
|
@@ -3641,7 +3787,8 @@ function registerFromTriggerWhen(triggerWhen, accumulator) {
|
|
|
3641
3787
|
if (cond.type === "event_count" && cond.key) {
|
|
3642
3788
|
const counter = cond.counter;
|
|
3643
3789
|
const predicate = counter ? buildPredicate(counter) : () => true;
|
|
3644
|
-
|
|
3790
|
+
const needsTimestamps = typeof cond.withinMs === "number";
|
|
3791
|
+
accumulator.register(cond.key, predicate, needsTimestamps);
|
|
3645
3792
|
}
|
|
3646
3793
|
}
|
|
3647
3794
|
}
|
|
@@ -3734,113 +3881,666 @@ function useShadowRoot() {
|
|
|
3734
3881
|
return ctx;
|
|
3735
3882
|
}
|
|
3736
3883
|
|
|
3737
|
-
//
|
|
3884
|
+
// ../event-processor/dist/types.js
|
|
3885
|
+
var EVENT_SCHEMA_VERSION = "1.0.0";
|
|
3738
3886
|
var StandardEvents = {
|
|
3739
|
-
// UI events (from PostHog autocapture)
|
|
3740
3887
|
UI_CLICK: "ui.click",
|
|
3741
3888
|
UI_SCROLL: "ui.scroll",
|
|
3742
3889
|
UI_INPUT: "ui.input",
|
|
3743
3890
|
UI_CHANGE: "ui.change",
|
|
3744
3891
|
UI_SUBMIT: "ui.submit",
|
|
3745
|
-
// Navigation events
|
|
3746
3892
|
NAV_PAGE_VIEW: "nav.page_view",
|
|
3747
3893
|
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
|
-
|
|
3894
|
+
UI_HESITATE: "ui.hesitate",
|
|
3895
|
+
UI_RAGE_CLICK: "ui.rage_click",
|
|
3896
|
+
UI_SCROLL_THRASH: "ui.scroll_thrash",
|
|
3897
|
+
UI_FOCUS_BOUNCE: "ui.focus_bounce",
|
|
3898
|
+
UI_IDLE: "ui.idle",
|
|
3899
|
+
UI_HOVER: "ui.hover"
|
|
3900
|
+
};
|
|
3901
|
+
var RRWebSource = {
|
|
3902
|
+
Mutation: 0,
|
|
3903
|
+
MouseMove: 1,
|
|
3904
|
+
MouseInteraction: 2,
|
|
3905
|
+
Scroll: 3,
|
|
3906
|
+
ViewportResize: 4,
|
|
3907
|
+
Input: 5,
|
|
3908
|
+
TouchMove: 6,
|
|
3909
|
+
MediaInteraction: 7,
|
|
3910
|
+
Drag: 12
|
|
3911
|
+
};
|
|
3912
|
+
var RRWebMouseInteraction = {
|
|
3913
|
+
MouseUp: 0,
|
|
3914
|
+
MouseDown: 1,
|
|
3915
|
+
Click: 2,
|
|
3916
|
+
ContextMenu: 3,
|
|
3917
|
+
DblClick: 4,
|
|
3918
|
+
Focus: 5,
|
|
3919
|
+
Blur: 6,
|
|
3920
|
+
TouchStart: 7,
|
|
3921
|
+
TouchEnd: 9
|
|
3922
|
+
};
|
|
3923
|
+
var DEFAULT_DETECTOR_CONFIG = {
|
|
3924
|
+
hesitationMs: 3e3,
|
|
3925
|
+
hesitationRadiusPx: 10,
|
|
3926
|
+
rageClickCount: 3,
|
|
3927
|
+
rageClickWindowMs: 1e3,
|
|
3928
|
+
rageClickRadiusPx: 30,
|
|
3929
|
+
scrollThrashReversals: 3,
|
|
3930
|
+
scrollThrashWindowMs: 2e3,
|
|
3931
|
+
focusBounceMaxInputs: 0,
|
|
3932
|
+
idleMs: 5e3,
|
|
3933
|
+
hoverSampleMs: 100
|
|
3777
3934
|
};
|
|
3778
|
-
var EVENT_SCHEMA_VERSION = "1.0.0";
|
|
3779
3935
|
|
|
3780
|
-
//
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3936
|
+
// ../event-processor/dist/normalizers/posthog.js
|
|
3937
|
+
var POSTHOG_EVENT_MAP = {
|
|
3938
|
+
// NOTE: $autocapture is intentionally NOT in this map.
|
|
3939
|
+
// It's handled below in getEventName() with $event_type refinement
|
|
3940
|
+
// so that change/submit events aren't all mapped to ui.click.
|
|
3941
|
+
$click: StandardEvents.UI_CLICK,
|
|
3942
|
+
$scroll: StandardEvents.UI_SCROLL,
|
|
3943
|
+
$input: StandardEvents.UI_INPUT,
|
|
3944
|
+
$change: StandardEvents.UI_CHANGE,
|
|
3945
|
+
$submit: StandardEvents.UI_SUBMIT,
|
|
3946
|
+
// Navigation events
|
|
3947
|
+
$pageview: StandardEvents.NAV_PAGE_VIEW,
|
|
3948
|
+
$pageleave: StandardEvents.NAV_PAGE_LEAVE,
|
|
3949
|
+
// Session events
|
|
3950
|
+
$session_start: "session.start",
|
|
3951
|
+
// Identify events
|
|
3952
|
+
$identify: "user.identify"
|
|
3953
|
+
};
|
|
3954
|
+
function getEventName(phEvent) {
|
|
3955
|
+
var _a2, _b;
|
|
3956
|
+
const eventName = phEvent.event;
|
|
3957
|
+
if (typeof eventName !== "string") {
|
|
3958
|
+
return "posthog.unknown";
|
|
3959
|
+
}
|
|
3960
|
+
if (POSTHOG_EVENT_MAP[eventName]) {
|
|
3961
|
+
return POSTHOG_EVENT_MAP[eventName];
|
|
3962
|
+
}
|
|
3963
|
+
if (eventName === "$autocapture") {
|
|
3964
|
+
const tagName = (_a2 = phEvent.properties) == null ? void 0 : _a2.$tag_name;
|
|
3965
|
+
const eventType = (_b = phEvent.properties) == null ? void 0 : _b.$event_type;
|
|
3966
|
+
if (eventType === "submit")
|
|
3967
|
+
return StandardEvents.UI_SUBMIT;
|
|
3968
|
+
if (eventType === "change")
|
|
3969
|
+
return StandardEvents.UI_CHANGE;
|
|
3970
|
+
if (tagName === "input" || tagName === "textarea")
|
|
3971
|
+
return StandardEvents.UI_INPUT;
|
|
3972
|
+
return StandardEvents.UI_CLICK;
|
|
3973
|
+
}
|
|
3974
|
+
if (!eventName.startsWith("$")) {
|
|
3975
|
+
return `posthog.${eventName}`;
|
|
3976
|
+
}
|
|
3977
|
+
return eventName.replace("$", "posthog.");
|
|
3804
3978
|
}
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3979
|
+
var INTERACTIVE_TAGS = /* @__PURE__ */ new Set(["a", "button", "input", "select", "textarea"]);
|
|
3980
|
+
function parseElementsChain(chain) {
|
|
3981
|
+
if (!chain)
|
|
3982
|
+
return void 0;
|
|
3983
|
+
return chain.split(";").map((segment) => {
|
|
3984
|
+
const el = {};
|
|
3985
|
+
const colonIdx = segment.indexOf(":");
|
|
3986
|
+
const tagPart = colonIdx >= 0 ? segment.slice(0, colonIdx) : segment;
|
|
3987
|
+
const attrPart = colonIdx >= 0 ? segment.slice(colonIdx + 1) : "";
|
|
3988
|
+
const dotIdx = tagPart.indexOf(".");
|
|
3989
|
+
if (dotIdx >= 0) {
|
|
3990
|
+
el.tag_name = tagPart.slice(0, dotIdx);
|
|
3991
|
+
el.attr__class = tagPart.slice(dotIdx + 1).replace(/\./g, " ");
|
|
3992
|
+
} else {
|
|
3993
|
+
el.tag_name = tagPart;
|
|
3994
|
+
}
|
|
3995
|
+
const attrRegex = /([\w$]+)="([^"]*)"/g;
|
|
3996
|
+
let match;
|
|
3997
|
+
while ((match = attrRegex.exec(attrPart)) !== null) {
|
|
3998
|
+
const [, key, value] = match;
|
|
3999
|
+
if (key === "nth-child" || key === "nth-of-type")
|
|
4000
|
+
continue;
|
|
4001
|
+
el[key] = value;
|
|
4002
|
+
}
|
|
4003
|
+
if (el.text) {
|
|
4004
|
+
el.$el_text = el.text;
|
|
4005
|
+
delete el.text;
|
|
4006
|
+
}
|
|
4007
|
+
return el;
|
|
3810
4008
|
});
|
|
3811
4009
|
}
|
|
3812
|
-
function
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
4010
|
+
function resolveInteractiveTag(elements, directTag) {
|
|
4011
|
+
if (directTag && INTERACTIVE_TAGS.has(directTag))
|
|
4012
|
+
return directTag;
|
|
4013
|
+
if (!elements)
|
|
4014
|
+
return directTag;
|
|
4015
|
+
for (const el of elements) {
|
|
4016
|
+
const tag2 = el.tag_name;
|
|
4017
|
+
if (tag2 && INTERACTIVE_TAGS.has(tag2))
|
|
4018
|
+
return tag2;
|
|
4019
|
+
}
|
|
4020
|
+
return directTag;
|
|
3817
4021
|
}
|
|
3818
|
-
function
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
4022
|
+
function extractProps(phEvent) {
|
|
4023
|
+
var _a2, _b, _c;
|
|
4024
|
+
const props = {};
|
|
4025
|
+
const phProps = phEvent.properties || {};
|
|
4026
|
+
const elements = (_a2 = phProps.$elements) != null ? _a2 : typeof phProps.$elements_chain === "string" ? parseElementsChain(phProps.$elements_chain) : void 0;
|
|
4027
|
+
const directTag = (_c = phProps.$tag_name) != null ? _c : (_b = elements == null ? void 0 : elements[0]) == null ? void 0 : _b.tag_name;
|
|
4028
|
+
const isClickEvent = phEvent.event === "$autocapture" || phEvent.event === "$click";
|
|
4029
|
+
props.tagName = isClickEvent ? resolveInteractiveTag(elements, directTag) : directTag;
|
|
4030
|
+
if (phProps.$el_text)
|
|
4031
|
+
props.elementText = phProps.$el_text;
|
|
4032
|
+
if (elements)
|
|
4033
|
+
props.elements = elements;
|
|
4034
|
+
if (isClickEvent && !elements) {
|
|
4035
|
+
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}`);
|
|
4036
|
+
}
|
|
4037
|
+
if (phProps.$current_url)
|
|
4038
|
+
props.url = phProps.$current_url;
|
|
4039
|
+
if (phProps.$pathname)
|
|
4040
|
+
props.pathname = phProps.$pathname;
|
|
4041
|
+
if (phProps.$host)
|
|
4042
|
+
props.host = phProps.$host;
|
|
4043
|
+
if (phProps.$viewport_width)
|
|
4044
|
+
props.viewportWidth = phProps.$viewport_width;
|
|
4045
|
+
if (phProps.$viewport_height)
|
|
4046
|
+
props.viewportHeight = phProps.$viewport_height;
|
|
4047
|
+
if (phProps.$session_id)
|
|
4048
|
+
props.sessionId = phProps.$session_id;
|
|
4049
|
+
if (phProps.$scroll_depth)
|
|
4050
|
+
props.scrollDepth = phProps.$scroll_depth;
|
|
4051
|
+
if (phProps.$scroll_percentage)
|
|
4052
|
+
props.scrollPercentage = phProps.$scroll_percentage;
|
|
4053
|
+
props.originalEvent = phEvent.event;
|
|
4054
|
+
return props;
|
|
3823
4055
|
}
|
|
3824
|
-
function
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
4056
|
+
function normalizePostHogEvent(phEvent) {
|
|
4057
|
+
let ts;
|
|
4058
|
+
if (typeof phEvent.timestamp === "number") {
|
|
4059
|
+
ts = phEvent.timestamp;
|
|
4060
|
+
} else if (typeof phEvent.timestamp === "string") {
|
|
4061
|
+
ts = new Date(phEvent.timestamp).getTime();
|
|
4062
|
+
} else {
|
|
4063
|
+
ts = Date.now();
|
|
4064
|
+
}
|
|
4065
|
+
return {
|
|
4066
|
+
ts,
|
|
4067
|
+
name: getEventName(phEvent),
|
|
4068
|
+
source: "posthog",
|
|
4069
|
+
props: extractProps(phEvent),
|
|
4070
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
4071
|
+
};
|
|
3830
4072
|
}
|
|
3831
|
-
function
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
4073
|
+
function shouldNormalizeEvent(phEvent) {
|
|
4074
|
+
const eventName = phEvent.event;
|
|
4075
|
+
if (typeof eventName !== "string")
|
|
4076
|
+
return false;
|
|
4077
|
+
const skipEvents = [
|
|
4078
|
+
"$feature_flag_called",
|
|
4079
|
+
"$feature_flags",
|
|
4080
|
+
"$groups",
|
|
4081
|
+
"$groupidentify",
|
|
4082
|
+
"$set",
|
|
4083
|
+
"$set_once",
|
|
4084
|
+
"$unset",
|
|
4085
|
+
"$create_alias",
|
|
4086
|
+
"$capture_metrics",
|
|
4087
|
+
"$performance_event",
|
|
4088
|
+
"$web_vitals",
|
|
4089
|
+
"$exception",
|
|
4090
|
+
"$dead_click",
|
|
4091
|
+
"$heatmap"
|
|
4092
|
+
];
|
|
4093
|
+
if (skipEvents.includes(eventName)) {
|
|
4094
|
+
return false;
|
|
4095
|
+
}
|
|
4096
|
+
return true;
|
|
3837
4097
|
}
|
|
3838
|
-
function
|
|
3839
|
-
|
|
3840
|
-
|
|
4098
|
+
function createPostHogNormalizer(publishFn) {
|
|
4099
|
+
return (eventName, properties) => {
|
|
4100
|
+
if (typeof eventName !== "string")
|
|
4101
|
+
return;
|
|
4102
|
+
const phEvent = {
|
|
4103
|
+
event: eventName,
|
|
4104
|
+
properties,
|
|
4105
|
+
timestamp: Date.now()
|
|
4106
|
+
};
|
|
4107
|
+
if (shouldNormalizeEvent(phEvent)) {
|
|
4108
|
+
const normalizedEvent = normalizePostHogEvent(phEvent);
|
|
4109
|
+
publishFn(normalizedEvent);
|
|
4110
|
+
}
|
|
4111
|
+
};
|
|
3841
4112
|
}
|
|
3842
|
-
|
|
3843
|
-
|
|
4113
|
+
|
|
4114
|
+
// ../event-processor/dist/detectors/focus-bounce.js
|
|
4115
|
+
var FocusBounceDetector = class {
|
|
4116
|
+
constructor(config, emit2) {
|
|
4117
|
+
this.config = config;
|
|
4118
|
+
this.emit = emit2;
|
|
4119
|
+
this.focused = /* @__PURE__ */ new Map();
|
|
4120
|
+
}
|
|
4121
|
+
ingest(raw) {
|
|
4122
|
+
var _a2, _b;
|
|
4123
|
+
if (raw.type !== 3)
|
|
4124
|
+
return;
|
|
4125
|
+
const ts = raw.timestamp;
|
|
4126
|
+
if (raw.data.source === RRWebSource.MouseInteraction) {
|
|
4127
|
+
const id = (_a2 = raw.data.id) != null ? _a2 : 0;
|
|
4128
|
+
if (raw.data.type === RRWebMouseInteraction.Focus) {
|
|
4129
|
+
this.focused.set(id, { id, focusTs: ts, inputCount: 0 });
|
|
4130
|
+
} else if (raw.data.type === RRWebMouseInteraction.Blur) {
|
|
4131
|
+
const entry = this.focused.get(id);
|
|
4132
|
+
if (entry && entry.inputCount <= this.config.focusBounceMaxInputs) {
|
|
4133
|
+
this.emit({
|
|
4134
|
+
ts,
|
|
4135
|
+
name: StandardEvents.UI_FOCUS_BOUNCE,
|
|
4136
|
+
source: "rrweb",
|
|
4137
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4138
|
+
props: {
|
|
4139
|
+
elementId: id,
|
|
4140
|
+
duration_ms: ts - entry.focusTs
|
|
4141
|
+
}
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4144
|
+
this.focused.delete(id);
|
|
4145
|
+
}
|
|
4146
|
+
} else if (raw.data.source === RRWebSource.Input) {
|
|
4147
|
+
const id = (_b = raw.data.id) != null ? _b : 0;
|
|
4148
|
+
const entry = this.focused.get(id);
|
|
4149
|
+
if (entry) {
|
|
4150
|
+
entry.inputCount++;
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
};
|
|
4155
|
+
|
|
4156
|
+
// ../event-processor/dist/detectors/hesitation.js
|
|
4157
|
+
var HesitationDetector = class {
|
|
4158
|
+
constructor(config, emit2) {
|
|
4159
|
+
this.config = config;
|
|
4160
|
+
this.emit = emit2;
|
|
4161
|
+
this.anchorX = 0;
|
|
4162
|
+
this.anchorY = 0;
|
|
4163
|
+
this.anchorTs = 0;
|
|
4164
|
+
this.emitted = false;
|
|
4165
|
+
this.hasPosition = false;
|
|
4166
|
+
}
|
|
4167
|
+
ingest(raw) {
|
|
4168
|
+
var _a2;
|
|
4169
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseMove)
|
|
4170
|
+
return;
|
|
4171
|
+
const positions = raw.data.positions;
|
|
4172
|
+
if (!positions || positions.length === 0)
|
|
4173
|
+
return;
|
|
4174
|
+
const last = positions[positions.length - 1];
|
|
4175
|
+
const ts = raw.timestamp + ((_a2 = last.timeOffset) != null ? _a2 : 0);
|
|
4176
|
+
if (!this.hasPosition) {
|
|
4177
|
+
this.anchorX = last.x;
|
|
4178
|
+
this.anchorY = last.y;
|
|
4179
|
+
this.anchorTs = ts;
|
|
4180
|
+
this.hasPosition = true;
|
|
4181
|
+
this.emitted = false;
|
|
4182
|
+
return;
|
|
4183
|
+
}
|
|
4184
|
+
const dx = last.x - this.anchorX;
|
|
4185
|
+
const dy = last.y - this.anchorY;
|
|
4186
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
4187
|
+
if (dist > this.config.hesitationRadiusPx) {
|
|
4188
|
+
this.anchorX = last.x;
|
|
4189
|
+
this.anchorY = last.y;
|
|
4190
|
+
this.anchorTs = ts;
|
|
4191
|
+
this.emitted = false;
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
tick(now) {
|
|
4195
|
+
if (!this.hasPosition || this.emitted)
|
|
4196
|
+
return;
|
|
4197
|
+
const elapsed = now - this.anchorTs;
|
|
4198
|
+
if (elapsed >= this.config.hesitationMs) {
|
|
4199
|
+
this.emit({
|
|
4200
|
+
ts: now,
|
|
4201
|
+
name: StandardEvents.UI_HESITATE,
|
|
4202
|
+
source: "rrweb",
|
|
4203
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4204
|
+
props: {
|
|
4205
|
+
x: this.anchorX,
|
|
4206
|
+
y: this.anchorY,
|
|
4207
|
+
duration_ms: elapsed
|
|
4208
|
+
}
|
|
4209
|
+
});
|
|
4210
|
+
this.emitted = true;
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
4213
|
+
};
|
|
4214
|
+
|
|
4215
|
+
// ../event-processor/dist/detectors/hover.js
|
|
4216
|
+
var HoverTracker = class {
|
|
4217
|
+
constructor(config, emit2, elementResolver) {
|
|
4218
|
+
this.config = config;
|
|
4219
|
+
this.emit = emit2;
|
|
4220
|
+
this.elementResolver = elementResolver;
|
|
4221
|
+
this.currentElement = null;
|
|
4222
|
+
this.hoverStartTs = null;
|
|
4223
|
+
this.lastX = 0;
|
|
4224
|
+
this.lastY = 0;
|
|
4225
|
+
this.lastSampleTs = -Infinity;
|
|
4226
|
+
}
|
|
4227
|
+
ingest(raw) {
|
|
4228
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseMove)
|
|
4229
|
+
return;
|
|
4230
|
+
const positions = raw.data.positions;
|
|
4231
|
+
if (!positions || positions.length === 0)
|
|
4232
|
+
return;
|
|
4233
|
+
const last = positions[positions.length - 1];
|
|
4234
|
+
this.lastX = last.x;
|
|
4235
|
+
this.lastY = last.y;
|
|
4236
|
+
}
|
|
4237
|
+
tick(now) {
|
|
4238
|
+
if (!this.elementResolver)
|
|
4239
|
+
return;
|
|
4240
|
+
if (now - this.lastSampleTs < this.config.hoverSampleMs)
|
|
4241
|
+
return;
|
|
4242
|
+
this.lastSampleTs = now;
|
|
4243
|
+
const newElement = this.elementResolver(this.lastX, this.lastY);
|
|
4244
|
+
const newKey = newElement ? elementKey(newElement) : null;
|
|
4245
|
+
const currentKey = this.currentElement ? elementKey(this.currentElement) : null;
|
|
4246
|
+
if (newKey !== currentKey) {
|
|
4247
|
+
if (this.currentElement && this.hoverStartTs !== null) {
|
|
4248
|
+
this.emit({
|
|
4249
|
+
ts: now,
|
|
4250
|
+
name: StandardEvents.UI_HOVER,
|
|
4251
|
+
source: "rrweb",
|
|
4252
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4253
|
+
props: {
|
|
4254
|
+
x: this.lastX,
|
|
4255
|
+
y: this.lastY,
|
|
4256
|
+
duration_ms: now - this.hoverStartTs,
|
|
4257
|
+
element: this.currentElement
|
|
4258
|
+
}
|
|
4259
|
+
});
|
|
4260
|
+
}
|
|
4261
|
+
this.currentElement = newElement;
|
|
4262
|
+
this.hoverStartTs = now;
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
};
|
|
4266
|
+
function elementKey(el) {
|
|
4267
|
+
var _a2, _b, _c;
|
|
4268
|
+
return `${(_a2 = el.tag_name) != null ? _a2 : ""}|${(_b = el.attr__id) != null ? _b : ""}|${((_c = el.classes) != null ? _c : []).join(",")}`;
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
// ../event-processor/dist/detectors/idle.js
|
|
4272
|
+
var IdleDetector = class {
|
|
4273
|
+
constructor(config, emit2) {
|
|
4274
|
+
this.config = config;
|
|
4275
|
+
this.emit = emit2;
|
|
4276
|
+
this.lastActivityTs = null;
|
|
4277
|
+
this.emitted = false;
|
|
4278
|
+
}
|
|
4279
|
+
ingest(raw) {
|
|
4280
|
+
if (raw.type !== 3)
|
|
4281
|
+
return;
|
|
4282
|
+
const src = raw.data.source;
|
|
4283
|
+
if (src === RRWebSource.MouseMove || src === RRWebSource.MouseInteraction || src === RRWebSource.Scroll) {
|
|
4284
|
+
this.lastActivityTs = raw.timestamp;
|
|
4285
|
+
this.emitted = false;
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4288
|
+
tick(now) {
|
|
4289
|
+
if (this.lastActivityTs === null || this.emitted)
|
|
4290
|
+
return;
|
|
4291
|
+
if (now - this.lastActivityTs >= this.config.idleMs) {
|
|
4292
|
+
this.emit({
|
|
4293
|
+
ts: now,
|
|
4294
|
+
name: StandardEvents.UI_IDLE,
|
|
4295
|
+
source: "rrweb",
|
|
4296
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4297
|
+
props: {
|
|
4298
|
+
idle_ms: now - this.lastActivityTs
|
|
4299
|
+
}
|
|
4300
|
+
});
|
|
4301
|
+
this.emitted = true;
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
};
|
|
4305
|
+
|
|
4306
|
+
// ../event-processor/dist/detectors/rage-click.js
|
|
4307
|
+
var RageClickDetector = class {
|
|
4308
|
+
constructor(config, emit2) {
|
|
4309
|
+
this.config = config;
|
|
4310
|
+
this.emit = emit2;
|
|
4311
|
+
this.clicks = [];
|
|
4312
|
+
}
|
|
4313
|
+
ingest(raw) {
|
|
4314
|
+
var _a2, _b;
|
|
4315
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseInteraction)
|
|
4316
|
+
return;
|
|
4317
|
+
if (raw.data.type !== RRWebMouseInteraction.Click)
|
|
4318
|
+
return;
|
|
4319
|
+
const x = (_a2 = raw.data.x) != null ? _a2 : 0;
|
|
4320
|
+
const y = (_b = raw.data.y) != null ? _b : 0;
|
|
4321
|
+
const ts = raw.timestamp;
|
|
4322
|
+
const cutoff = ts - this.config.rageClickWindowMs;
|
|
4323
|
+
this.clicks = this.clicks.filter((c) => c.ts >= cutoff);
|
|
4324
|
+
this.clicks.push({ ts, x, y });
|
|
4325
|
+
const nearby = this.clicks.filter((c) => {
|
|
4326
|
+
const dx = c.x - x;
|
|
4327
|
+
const dy = c.y - y;
|
|
4328
|
+
return Math.sqrt(dx * dx + dy * dy) <= this.config.rageClickRadiusPx;
|
|
4329
|
+
});
|
|
4330
|
+
if (nearby.length >= this.config.rageClickCount) {
|
|
4331
|
+
this.emit({
|
|
4332
|
+
ts,
|
|
4333
|
+
name: StandardEvents.UI_RAGE_CLICK,
|
|
4334
|
+
source: "rrweb",
|
|
4335
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4336
|
+
props: {
|
|
4337
|
+
x,
|
|
4338
|
+
y,
|
|
4339
|
+
clickCount: nearby.length,
|
|
4340
|
+
duration_ms: ts - nearby[0].ts
|
|
4341
|
+
}
|
|
4342
|
+
});
|
|
4343
|
+
this.clicks = [];
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
};
|
|
4347
|
+
|
|
4348
|
+
// ../event-processor/dist/detectors/scroll-thrash.js
|
|
4349
|
+
var ScrollThrashDetector = class {
|
|
4350
|
+
constructor(config, emit2) {
|
|
4351
|
+
this.config = config;
|
|
4352
|
+
this.emit = emit2;
|
|
4353
|
+
this.lastY = null;
|
|
4354
|
+
this.lastDirection = null;
|
|
4355
|
+
this.reversals = [];
|
|
4356
|
+
}
|
|
4357
|
+
ingest(raw) {
|
|
4358
|
+
var _a2;
|
|
4359
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.Scroll)
|
|
4360
|
+
return;
|
|
4361
|
+
const y = (_a2 = raw.data.y) != null ? _a2 : 0;
|
|
4362
|
+
const ts = raw.timestamp;
|
|
4363
|
+
if (this.lastY !== null) {
|
|
4364
|
+
const direction = y > this.lastY ? "down" : y < this.lastY ? "up" : this.lastDirection;
|
|
4365
|
+
if (direction && direction !== this.lastDirection) {
|
|
4366
|
+
const cutoff = ts - this.config.scrollThrashWindowMs;
|
|
4367
|
+
this.reversals = this.reversals.filter((t) => t > cutoff);
|
|
4368
|
+
this.reversals.push(ts);
|
|
4369
|
+
if (this.reversals.length >= this.config.scrollThrashReversals) {
|
|
4370
|
+
this.emit({
|
|
4371
|
+
ts,
|
|
4372
|
+
name: StandardEvents.UI_SCROLL_THRASH,
|
|
4373
|
+
source: "rrweb",
|
|
4374
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4375
|
+
props: {
|
|
4376
|
+
reversals: this.reversals.length,
|
|
4377
|
+
duration_ms: ts - this.reversals[0]
|
|
4378
|
+
}
|
|
4379
|
+
});
|
|
4380
|
+
this.reversals = [];
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
this.lastDirection = direction;
|
|
4384
|
+
}
|
|
4385
|
+
this.lastY = y;
|
|
4386
|
+
}
|
|
4387
|
+
};
|
|
4388
|
+
|
|
4389
|
+
// ../event-processor/dist/processor.js
|
|
4390
|
+
function createEventProcessor(options) {
|
|
4391
|
+
const config = { ...DEFAULT_DETECTOR_CONFIG, ...options == null ? void 0 : options.config };
|
|
4392
|
+
const listeners = [];
|
|
4393
|
+
function emit2(event) {
|
|
4394
|
+
for (const cb of listeners)
|
|
4395
|
+
cb(event);
|
|
4396
|
+
}
|
|
4397
|
+
const hesitation = new HesitationDetector(config, emit2);
|
|
4398
|
+
const rageClick = new RageClickDetector(config, emit2);
|
|
4399
|
+
const scrollThrash = new ScrollThrashDetector(config, emit2);
|
|
4400
|
+
const focusBounce = new FocusBounceDetector(config, emit2);
|
|
4401
|
+
const idle = new IdleDetector(config, emit2);
|
|
4402
|
+
const hover = new HoverTracker(config, emit2, options == null ? void 0 : options.elementResolver);
|
|
4403
|
+
const clickAttrBuffer = [];
|
|
4404
|
+
return {
|
|
4405
|
+
ingest(raw) {
|
|
4406
|
+
if (raw.kind === "posthog") {
|
|
4407
|
+
const { kind: _, ...phEvent } = raw;
|
|
4408
|
+
if (shouldNormalizeEvent(phEvent)) {
|
|
4409
|
+
emit2(normalizePostHogEvent(phEvent));
|
|
4410
|
+
}
|
|
4411
|
+
} else if (raw.kind === "rrweb") {
|
|
4412
|
+
hesitation.ingest(raw);
|
|
4413
|
+
rageClick.ingest(raw);
|
|
4414
|
+
scrollThrash.ingest(raw);
|
|
4415
|
+
focusBounce.ingest(raw);
|
|
4416
|
+
idle.ingest(raw);
|
|
4417
|
+
hover.ingest(raw);
|
|
4418
|
+
}
|
|
4419
|
+
},
|
|
4420
|
+
onEvent(callback) {
|
|
4421
|
+
listeners.push(callback);
|
|
4422
|
+
},
|
|
4423
|
+
tick(timestamp) {
|
|
4424
|
+
hesitation.tick(timestamp);
|
|
4425
|
+
idle.tick(timestamp);
|
|
4426
|
+
hover.tick(timestamp);
|
|
4427
|
+
},
|
|
4428
|
+
enrichClickAttributes(timestamp, elements) {
|
|
4429
|
+
clickAttrBuffer.push({ ts: timestamp, elements });
|
|
4430
|
+
const cutoff = timestamp - 500;
|
|
4431
|
+
while (clickAttrBuffer.length > 0 && clickAttrBuffer[0].ts < cutoff) {
|
|
4432
|
+
clickAttrBuffer.shift();
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
};
|
|
4436
|
+
}
|
|
4437
|
+
|
|
4438
|
+
// src/events/types.ts
|
|
4439
|
+
var StandardEvents2 = {
|
|
4440
|
+
// UI events (from PostHog autocapture)
|
|
4441
|
+
UI_CLICK: "ui.click",
|
|
4442
|
+
UI_SCROLL: "ui.scroll",
|
|
4443
|
+
UI_INPUT: "ui.input",
|
|
4444
|
+
UI_CHANGE: "ui.change",
|
|
4445
|
+
UI_SUBMIT: "ui.submit",
|
|
4446
|
+
// Navigation events
|
|
4447
|
+
NAV_PAGE_VIEW: "nav.page_view",
|
|
4448
|
+
NAV_PAGE_LEAVE: "nav.page_leave",
|
|
4449
|
+
// Canvas events
|
|
4450
|
+
CANVAS_OPENED: "canvas.opened",
|
|
4451
|
+
CANVAS_CLOSED: "canvas.closed",
|
|
4452
|
+
TILE_VIEWED: "tile.viewed",
|
|
4453
|
+
TILE_EXPANDED: "tile.expanded",
|
|
4454
|
+
TILE_COLLAPSED: "tile.collapsed",
|
|
4455
|
+
TILE_ACTION: "tile.action",
|
|
4456
|
+
// Overlay/tour events
|
|
4457
|
+
OVERLAY_STARTED: "overlay.started",
|
|
4458
|
+
OVERLAY_COMPLETED: "overlay.completed",
|
|
4459
|
+
OVERLAY_DISMISSED: "overlay.dismissed",
|
|
4460
|
+
OVERLAY_STEP_VIEWED: "overlay.step_viewed",
|
|
4461
|
+
// Derived behavioral signals (Phase 3)
|
|
4462
|
+
BEHAVIOR_RAGE_CLICK: "behavior.rage_click",
|
|
4463
|
+
BEHAVIOR_HESITATION: "behavior.hesitation",
|
|
4464
|
+
BEHAVIOR_CONFUSION: "behavior.confusion",
|
|
4465
|
+
// Action events
|
|
4466
|
+
ACTION_APPLIED: "action.applied",
|
|
4467
|
+
ACTION_REVERTED: "action.reverted",
|
|
4468
|
+
ACTION_FAILED: "action.failed",
|
|
4469
|
+
ACTION_CTA_CLICKED: "action.cta_clicked",
|
|
4470
|
+
// Notification events
|
|
4471
|
+
NOTIFICATION_SHOWN: "notification.shown",
|
|
4472
|
+
NOTIFICATION_CLICKED: "notification.clicked",
|
|
4473
|
+
NOTIFICATION_DISMISSED: "notification.dismissed",
|
|
4474
|
+
NOTIFICATION_DEEP_LINK: "notification.deep_link",
|
|
4475
|
+
// Surface events
|
|
4476
|
+
SURFACE_MOUNTED: "surface.mounted",
|
|
4477
|
+
SURFACE_UNMOUNTED: "surface.unmounted"
|
|
4478
|
+
};
|
|
4479
|
+
|
|
4480
|
+
// src/events/normalizers/canvas.ts
|
|
4481
|
+
function createCanvasEvent(name, props) {
|
|
4482
|
+
return {
|
|
4483
|
+
ts: Date.now(),
|
|
4484
|
+
name,
|
|
4485
|
+
source: "canvas",
|
|
4486
|
+
props,
|
|
4487
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
4488
|
+
};
|
|
4489
|
+
}
|
|
4490
|
+
function canvasOpened(surface) {
|
|
4491
|
+
return createCanvasEvent(StandardEvents2.CANVAS_OPENED, { surface });
|
|
4492
|
+
}
|
|
4493
|
+
function canvasClosed(surface) {
|
|
4494
|
+
return createCanvasEvent(StandardEvents2.CANVAS_CLOSED, { surface });
|
|
4495
|
+
}
|
|
4496
|
+
function tileViewed(tileId, surface) {
|
|
4497
|
+
return createCanvasEvent(StandardEvents2.TILE_VIEWED, { tileId, surface });
|
|
4498
|
+
}
|
|
4499
|
+
function tileExpanded(tileId, surface) {
|
|
4500
|
+
return createCanvasEvent(StandardEvents2.TILE_EXPANDED, { tileId, surface });
|
|
4501
|
+
}
|
|
4502
|
+
function tileCollapsed(tileId, surface) {
|
|
4503
|
+
return createCanvasEvent(StandardEvents2.TILE_COLLAPSED, { tileId, surface });
|
|
4504
|
+
}
|
|
4505
|
+
function tileAction(tileId, actionId, surface) {
|
|
4506
|
+
return createCanvasEvent(StandardEvents2.TILE_ACTION, {
|
|
4507
|
+
tileId,
|
|
4508
|
+
actionId,
|
|
4509
|
+
surface
|
|
4510
|
+
});
|
|
4511
|
+
}
|
|
4512
|
+
function overlayStarted(recipeId, recipeName) {
|
|
4513
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_STARTED, {
|
|
4514
|
+
recipeId,
|
|
4515
|
+
recipeName
|
|
4516
|
+
});
|
|
4517
|
+
}
|
|
4518
|
+
function overlayCompleted(recipeId, recipeName) {
|
|
4519
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_COMPLETED, {
|
|
4520
|
+
recipeId,
|
|
4521
|
+
recipeName
|
|
4522
|
+
});
|
|
4523
|
+
}
|
|
4524
|
+
function overlayDismissed(recipeId, recipeName, stepIndex) {
|
|
4525
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_DISMISSED, {
|
|
4526
|
+
recipeId,
|
|
4527
|
+
recipeName,
|
|
4528
|
+
stepIndex
|
|
4529
|
+
});
|
|
4530
|
+
}
|
|
4531
|
+
function overlayStepViewed(recipeId, stepIndex, stepTitle) {
|
|
4532
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_STEP_VIEWED, {
|
|
4533
|
+
recipeId,
|
|
4534
|
+
stepIndex,
|
|
4535
|
+
stepTitle
|
|
4536
|
+
});
|
|
4537
|
+
}
|
|
4538
|
+
function customCanvasEvent(name, props) {
|
|
4539
|
+
const eventName = name.startsWith("canvas.") ? name : `canvas.${name}`;
|
|
4540
|
+
return createCanvasEvent(eventName, props);
|
|
4541
|
+
}
|
|
4542
|
+
var CanvasEvents = {
|
|
4543
|
+
canvasOpened,
|
|
3844
4544
|
canvasClosed,
|
|
3845
4545
|
tileViewed,
|
|
3846
4546
|
tileExpanded,
|
|
@@ -3853,8 +4553,65 @@ var CanvasEvents = {
|
|
|
3853
4553
|
custom: customCanvasEvent
|
|
3854
4554
|
};
|
|
3855
4555
|
|
|
4556
|
+
// src/components/emojiToIcon.tsx
|
|
4557
|
+
import {
|
|
4558
|
+
AlertTriangle,
|
|
4559
|
+
ArrowRight,
|
|
4560
|
+
Banknote,
|
|
4561
|
+
Bell,
|
|
4562
|
+
BookOpen,
|
|
4563
|
+
CheckCircle,
|
|
4564
|
+
ClipboardList,
|
|
4565
|
+
Compass,
|
|
4566
|
+
FileText,
|
|
4567
|
+
Gamepad2,
|
|
4568
|
+
HelpCircle,
|
|
4569
|
+
Landmark,
|
|
4570
|
+
Layers,
|
|
4571
|
+
Lightbulb,
|
|
4572
|
+
MessageCircle,
|
|
4573
|
+
SkipForward,
|
|
4574
|
+
Sparkles,
|
|
4575
|
+
Timer,
|
|
4576
|
+
Trophy
|
|
4577
|
+
} from "lucide-react";
|
|
4578
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
4579
|
+
var EMOJI_ICON_MAP = {
|
|
4580
|
+
"\u2753": HelpCircle,
|
|
4581
|
+
"\u{1F9ED}": Compass,
|
|
4582
|
+
"\u{1F4DD}": FileText,
|
|
4583
|
+
"\u{1F3AF}": Layers,
|
|
4584
|
+
"\u{1F3C6}": Trophy,
|
|
4585
|
+
"\u2728": Sparkles,
|
|
4586
|
+
"\u{1F4AC}": MessageCircle,
|
|
4587
|
+
"\u{1F3AE}": Gamepad2,
|
|
4588
|
+
"\u{1F4A1}": Lightbulb,
|
|
4589
|
+
"\u{1F4B0}": Banknote,
|
|
4590
|
+
"\u{1F4CB}": ClipboardList,
|
|
4591
|
+
"\u2705": CheckCircle,
|
|
4592
|
+
"\u26A0\uFE0F": AlertTriangle,
|
|
4593
|
+
"\u{1F4B5}": Banknote,
|
|
4594
|
+
"\u{1F3DB}\uFE0F": Landmark,
|
|
4595
|
+
"\u23ED\uFE0F": SkipForward,
|
|
4596
|
+
"\u27A1\uFE0F": ArrowRight,
|
|
4597
|
+
"\u23F1\uFE0F": Timer,
|
|
4598
|
+
"\u{1F4D6}": BookOpen,
|
|
4599
|
+
"\u{1F514}": Bell
|
|
4600
|
+
};
|
|
4601
|
+
function EmojiIcon({
|
|
4602
|
+
emoji,
|
|
4603
|
+
size = 14,
|
|
4604
|
+
color = "currentColor"
|
|
4605
|
+
}) {
|
|
4606
|
+
const Icon = EMOJI_ICON_MAP[emoji];
|
|
4607
|
+
if (!Icon) {
|
|
4608
|
+
return /* @__PURE__ */ jsx2("span", { children: emoji });
|
|
4609
|
+
}
|
|
4610
|
+
return /* @__PURE__ */ jsx2(Icon, { size, color });
|
|
4611
|
+
}
|
|
4612
|
+
|
|
3856
4613
|
// src/notifications/NotificationToastStack.tsx
|
|
3857
|
-
import { jsx as
|
|
4614
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
3858
4615
|
var TOAST_STYLES_ID = "syntro-toast-styles";
|
|
3859
4616
|
var TOAST_CSS = `
|
|
3860
4617
|
@keyframes syntro-toast-slide-in {
|
|
@@ -3891,7 +4648,7 @@ function NotificationToastStack({
|
|
|
3891
4648
|
const { shadowRoot } = useShadowRoot();
|
|
3892
4649
|
ensureToastStyles(shadowRoot);
|
|
3893
4650
|
if (notifications.length === 0) return null;
|
|
3894
|
-
return /* @__PURE__ */
|
|
4651
|
+
return /* @__PURE__ */ jsx3(
|
|
3895
4652
|
"div",
|
|
3896
4653
|
{
|
|
3897
4654
|
"data-testid": "notification-toast-stack",
|
|
@@ -3946,7 +4703,7 @@ function NotificationToastStack({
|
|
|
3946
4703
|
padding: "10px 12px"
|
|
3947
4704
|
},
|
|
3948
4705
|
children: [
|
|
3949
|
-
/* @__PURE__ */
|
|
4706
|
+
/* @__PURE__ */ jsx3(
|
|
3950
4707
|
"div",
|
|
3951
4708
|
{
|
|
3952
4709
|
style: {
|
|
@@ -3960,11 +4717,11 @@ function NotificationToastStack({
|
|
|
3960
4717
|
flexShrink: 0,
|
|
3961
4718
|
fontSize: "14px"
|
|
3962
4719
|
},
|
|
3963
|
-
children: (_a2 = notif.icon) != null ? _a2 : "\u{1F514}"
|
|
4720
|
+
children: /* @__PURE__ */ jsx3(EmojiIcon, { emoji: (_a2 = notif.icon) != null ? _a2 : "\u{1F514}", size: 14 })
|
|
3964
4721
|
}
|
|
3965
4722
|
),
|
|
3966
4723
|
/* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3967
|
-
/* @__PURE__ */
|
|
4724
|
+
/* @__PURE__ */ jsx3(
|
|
3968
4725
|
"div",
|
|
3969
4726
|
{
|
|
3970
4727
|
style: {
|
|
@@ -3979,7 +4736,7 @@ function NotificationToastStack({
|
|
|
3979
4736
|
children: notif.title
|
|
3980
4737
|
}
|
|
3981
4738
|
),
|
|
3982
|
-
notif.body && /* @__PURE__ */
|
|
4739
|
+
notif.body && /* @__PURE__ */ jsx3(
|
|
3983
4740
|
"div",
|
|
3984
4741
|
{
|
|
3985
4742
|
style: {
|
|
@@ -3995,7 +4752,7 @@ function NotificationToastStack({
|
|
|
3995
4752
|
}
|
|
3996
4753
|
)
|
|
3997
4754
|
] }),
|
|
3998
|
-
/* @__PURE__ */
|
|
4755
|
+
/* @__PURE__ */ jsx3(
|
|
3999
4756
|
"button",
|
|
4000
4757
|
{
|
|
4001
4758
|
type: "button",
|
|
@@ -4020,7 +4777,7 @@ function NotificationToastStack({
|
|
|
4020
4777
|
]
|
|
4021
4778
|
}
|
|
4022
4779
|
),
|
|
4023
|
-
/* @__PURE__ */
|
|
4780
|
+
/* @__PURE__ */ jsx3("div", { style: { height: "2px", background: "rgba(0, 0, 0, 0.08)" }, children: /* @__PURE__ */ jsx3(
|
|
4024
4781
|
"div",
|
|
4025
4782
|
{
|
|
4026
4783
|
className: "syntro-toast-progress",
|
|
@@ -4098,7 +4855,7 @@ function useNotifications(eventBus, tiles) {
|
|
|
4098
4855
|
const timerIds = useRef2(/* @__PURE__ */ new Map());
|
|
4099
4856
|
const publishDismissed = useCallback2(
|
|
4100
4857
|
(notif) => {
|
|
4101
|
-
eventBus == null ? void 0 : eventBus.publish(
|
|
4858
|
+
eventBus == null ? void 0 : eventBus.publish(StandardEvents2.NOTIFICATION_DISMISSED, {
|
|
4102
4859
|
notificationId: notif.id,
|
|
4103
4860
|
tileId: notif.tileId,
|
|
4104
4861
|
itemId: notif.itemId
|
|
@@ -4163,7 +4920,7 @@ function useNotifications(eventBus, tiles) {
|
|
|
4163
4920
|
}
|
|
4164
4921
|
return next;
|
|
4165
4922
|
});
|
|
4166
|
-
eventBus.publish(
|
|
4923
|
+
eventBus.publish(StandardEvents2.NOTIFICATION_SHOWN, {
|
|
4167
4924
|
notificationId: matched.id,
|
|
4168
4925
|
tileId: matched.tileId,
|
|
4169
4926
|
itemId: matched.itemId,
|
|
@@ -4234,7 +4991,7 @@ function useNotifyWatcher(runtime3, tiles, appRegistry2) {
|
|
|
4234
4991
|
|
|
4235
4992
|
// src/RuntimeProvider.tsx
|
|
4236
4993
|
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect4, useMemo as useMemo2, useState as useState3 } from "react";
|
|
4237
|
-
import { jsx as
|
|
4994
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
4238
4995
|
var RuntimeReactContext = createContext2({
|
|
4239
4996
|
runtime: null,
|
|
4240
4997
|
context: null
|
|
@@ -4252,7 +5009,7 @@ function RuntimeProvider({ runtime: runtime3, children }) {
|
|
|
4252
5009
|
return unsubscribe;
|
|
4253
5010
|
}, [runtime3]);
|
|
4254
5011
|
const value = useMemo2(() => ({ runtime: runtime3, context }), [runtime3, context]);
|
|
4255
|
-
return /* @__PURE__ */
|
|
5012
|
+
return /* @__PURE__ */ jsx4(RuntimeReactContext.Provider, { value, children });
|
|
4256
5013
|
}
|
|
4257
5014
|
function useRuntime() {
|
|
4258
5015
|
const { runtime: runtime3 } = useContext2(RuntimeReactContext);
|
|
@@ -4326,41 +5083,17 @@ import {
|
|
|
4326
5083
|
} from "react";
|
|
4327
5084
|
|
|
4328
5085
|
// 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
|
-
};
|
|
5086
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
4350
5087
|
function TileIcon({
|
|
4351
5088
|
emoji,
|
|
4352
5089
|
size = 18,
|
|
4353
5090
|
color = "currentColor"
|
|
4354
5091
|
}) {
|
|
4355
|
-
|
|
4356
|
-
if (!Icon) {
|
|
4357
|
-
return /* @__PURE__ */ jsx4("span", { children: emoji });
|
|
4358
|
-
}
|
|
4359
|
-
return /* @__PURE__ */ jsx4(Icon, { size, color });
|
|
5092
|
+
return /* @__PURE__ */ jsx5(EmojiIcon, { emoji, size, color });
|
|
4360
5093
|
}
|
|
4361
5094
|
|
|
4362
5095
|
// src/components/TileCard.tsx
|
|
4363
|
-
import { jsx as
|
|
5096
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
4364
5097
|
function WidgetMount({ widgetId, props }) {
|
|
4365
5098
|
var _a2;
|
|
4366
5099
|
const runtime3 = useRuntime();
|
|
@@ -4390,7 +5123,6 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4390
5123
|
return () => {
|
|
4391
5124
|
handle.unmount();
|
|
4392
5125
|
handleRef.current = null;
|
|
4393
|
-
container.remove();
|
|
4394
5126
|
};
|
|
4395
5127
|
}, [registry, widgetId, widgetAvailable]);
|
|
4396
5128
|
const propsJson = JSON.stringify(props);
|
|
@@ -4401,7 +5133,7 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4401
5133
|
prevPropsJsonRef.current = propsJson;
|
|
4402
5134
|
(_a3 = handleRef.current) == null ? void 0 : _a3.update(propsRef.current);
|
|
4403
5135
|
}, [propsJson]);
|
|
4404
|
-
if (!registry
|
|
5136
|
+
if (!(registry == null ? void 0 : registry.has(widgetId))) {
|
|
4405
5137
|
return /* @__PURE__ */ jsxs2(
|
|
4406
5138
|
"div",
|
|
4407
5139
|
{
|
|
@@ -4418,8 +5150,21 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4418
5150
|
}
|
|
4419
5151
|
);
|
|
4420
5152
|
}
|
|
4421
|
-
return /* @__PURE__ */
|
|
4422
|
-
}
|
|
5153
|
+
return /* @__PURE__ */ jsx6("div", { ref: parentRef });
|
|
5154
|
+
}
|
|
5155
|
+
var INTERACTION_PATTERNS = [
|
|
5156
|
+
":toggled",
|
|
5157
|
+
":clicked",
|
|
5158
|
+
":feedback",
|
|
5159
|
+
":navigate",
|
|
5160
|
+
":expanded",
|
|
5161
|
+
":collapsed",
|
|
5162
|
+
":dismissed",
|
|
5163
|
+
":submitted",
|
|
5164
|
+
":interacted",
|
|
5165
|
+
":tip_clicked",
|
|
5166
|
+
":tip_focused"
|
|
5167
|
+
];
|
|
4423
5168
|
function TileCard({
|
|
4424
5169
|
config,
|
|
4425
5170
|
surface: _surface,
|
|
@@ -4428,10 +5173,42 @@ function TileCard({
|
|
|
4428
5173
|
}) {
|
|
4429
5174
|
const { title, subtitle, widget, props, icon } = config;
|
|
4430
5175
|
const [, setTick] = useState4(0);
|
|
5176
|
+
const articleRef = useRef4(null);
|
|
4431
5177
|
const runtime3 = useRuntime();
|
|
4432
5178
|
useEffect5(() => {
|
|
4433
5179
|
if (runtime3) setTick((t) => t + 1);
|
|
4434
5180
|
}, [runtime3]);
|
|
5181
|
+
useEffect5(() => {
|
|
5182
|
+
var _a2;
|
|
5183
|
+
const tracker = typeof window !== "undefined" ? (_a2 = window.SynOS) == null ? void 0 : _a2.interventionTracker : null;
|
|
5184
|
+
if (!articleRef.current || !tracker) return;
|
|
5185
|
+
const observer = new IntersectionObserver(
|
|
5186
|
+
([entry]) => {
|
|
5187
|
+
var _a3;
|
|
5188
|
+
if (entry.isIntersecting) {
|
|
5189
|
+
tracker.trackSeen(config.id, (_a3 = config.widget) != null ? _a3 : "unknown");
|
|
5190
|
+
observer.disconnect();
|
|
5191
|
+
}
|
|
5192
|
+
},
|
|
5193
|
+
{ threshold: 0.5 }
|
|
5194
|
+
);
|
|
5195
|
+
observer.observe(articleRef.current);
|
|
5196
|
+
return () => observer.disconnect();
|
|
5197
|
+
}, [config.id, config.widget]);
|
|
5198
|
+
useEffect5(() => {
|
|
5199
|
+
var _a2;
|
|
5200
|
+
const tracker = typeof window !== "undefined" ? (_a2 = window.SynOS) == null ? void 0 : _a2.interventionTracker : null;
|
|
5201
|
+
if (!(runtime3 == null ? void 0 : runtime3.events) || !tracker) return;
|
|
5202
|
+
return runtime3.events.subscribe((event) => {
|
|
5203
|
+
var _a3, _b;
|
|
5204
|
+
if (!INTERACTION_PATTERNS.some((p) => {
|
|
5205
|
+
var _a4;
|
|
5206
|
+
return (_a4 = event.name) == null ? void 0 : _a4.includes(p);
|
|
5207
|
+
})) return;
|
|
5208
|
+
if (((_a3 = event.props) == null ? void 0 : _a3.instanceId) !== config.id) return;
|
|
5209
|
+
tracker.trackInteracted(config.id, (_b = config.widget) != null ? _b : "unknown", event.name);
|
|
5210
|
+
});
|
|
5211
|
+
}, [runtime3 == null ? void 0 : runtime3.events, config.id, config.widget]);
|
|
4435
5212
|
const registration = useMemo3(
|
|
4436
5213
|
() => {
|
|
4437
5214
|
var _a2, _b;
|
|
@@ -4485,15 +5262,16 @@ function TileCard({
|
|
|
4485
5262
|
return /* @__PURE__ */ jsxs2(
|
|
4486
5263
|
"article",
|
|
4487
5264
|
{
|
|
5265
|
+
ref: articleRef,
|
|
4488
5266
|
"data-shadow-canvas-id": `tile-${config.id}`,
|
|
4489
5267
|
style: cardStyle,
|
|
4490
5268
|
onMouseEnter,
|
|
4491
5269
|
onMouseLeave,
|
|
4492
5270
|
children: [
|
|
4493
5271
|
/* @__PURE__ */ jsxs2("div", { style: headerStyle, children: [
|
|
4494
|
-
/* @__PURE__ */
|
|
5272
|
+
/* @__PURE__ */ jsx6("div", { style: iconStyle, children: /* @__PURE__ */ jsx6(TileIcon, { emoji: resolvedIcon, size: resolvedSubtitle ? 36 : 24 }) }),
|
|
4495
5273
|
/* @__PURE__ */ jsxs2("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
4496
|
-
/* @__PURE__ */
|
|
5274
|
+
/* @__PURE__ */ jsx6(
|
|
4497
5275
|
"h3",
|
|
4498
5276
|
{
|
|
4499
5277
|
style: {
|
|
@@ -4508,7 +5286,7 @@ function TileCard({
|
|
|
4508
5286
|
children: title != null ? title : widget
|
|
4509
5287
|
}
|
|
4510
5288
|
),
|
|
4511
|
-
resolvedSubtitle && /* @__PURE__ */
|
|
5289
|
+
resolvedSubtitle && /* @__PURE__ */ jsx6(
|
|
4512
5290
|
"p",
|
|
4513
5291
|
{
|
|
4514
5292
|
style: {
|
|
@@ -4525,14 +5303,14 @@ function TileCard({
|
|
|
4525
5303
|
)
|
|
4526
5304
|
] })
|
|
4527
5305
|
] }),
|
|
4528
|
-
/* @__PURE__ */
|
|
5306
|
+
/* @__PURE__ */ jsx6(
|
|
4529
5307
|
"div",
|
|
4530
5308
|
{
|
|
4531
5309
|
style: {
|
|
4532
5310
|
padding: "var(--sc-tile-body-padding, 0 0.75rem 0.5rem)",
|
|
4533
5311
|
borderTop: "1px solid rgba(255, 255, 255, 0.06)"
|
|
4534
5312
|
},
|
|
4535
|
-
children: /* @__PURE__ */
|
|
5313
|
+
children: /* @__PURE__ */ jsx6("div", { style: { paddingTop: "var(--sc-tile-gap, 0.25rem)" }, children: /* @__PURE__ */ jsx6(WidgetMount, { widgetId: widget, props: { ...props, instanceId: config.id } }) })
|
|
4536
5314
|
}
|
|
4537
5315
|
)
|
|
4538
5316
|
]
|
|
@@ -4940,7 +5718,7 @@ function flattenThemeConfig(config) {
|
|
|
4940
5718
|
|
|
4941
5719
|
// src/theme/ThemeProvider.tsx
|
|
4942
5720
|
import { createContext as createContext3, useContext as useContext3, useEffect as useEffect6, useMemo as useMemo4 } from "react";
|
|
4943
|
-
import { jsx as
|
|
5721
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
4944
5722
|
var ThemeContext = createContext3(null);
|
|
4945
5723
|
function ThemeProvider({
|
|
4946
5724
|
children,
|
|
@@ -4971,7 +5749,7 @@ ${cssRules}
|
|
|
4971
5749
|
mode: merged.mode,
|
|
4972
5750
|
cssVariables
|
|
4973
5751
|
};
|
|
4974
|
-
return /* @__PURE__ */
|
|
5752
|
+
return /* @__PURE__ */ jsx7(ThemeContext.Provider, { value, children });
|
|
4975
5753
|
}
|
|
4976
5754
|
function useTheme() {
|
|
4977
5755
|
const context = useContext3(ThemeContext);
|
|
@@ -4982,7 +5760,7 @@ function useTheme() {
|
|
|
4982
5760
|
}
|
|
4983
5761
|
|
|
4984
5762
|
// src/components/ShadowCanvasOverlay.tsx
|
|
4985
|
-
import { Fragment, jsx as
|
|
5763
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4986
5764
|
var LAUNCHER_STYLES_ID = "syntro-launcher-styles";
|
|
4987
5765
|
function ensureLauncherStyles(target, css) {
|
|
4988
5766
|
if (target.querySelector(`#${LAUNCHER_STYLES_ID}`)) return;
|
|
@@ -4996,7 +5774,6 @@ function ShadowCanvasOverlay({
|
|
|
4996
5774
|
onToggle,
|
|
4997
5775
|
telemetry,
|
|
4998
5776
|
launcherLabel: _launcherLabel = "Adaptives",
|
|
4999
|
-
launcherIcon,
|
|
5000
5777
|
launcherAnimate = false,
|
|
5001
5778
|
launcherAnimationStyle: _launcherAnimationStyle = "pulse",
|
|
5002
5779
|
notificationCount: _notificationCount,
|
|
@@ -5007,7 +5784,7 @@ function ShadowCanvasOverlay({
|
|
|
5007
5784
|
canvasTitle,
|
|
5008
5785
|
displayMode = "standard"
|
|
5009
5786
|
}) {
|
|
5010
|
-
var _a2, _b, _c, _d;
|
|
5787
|
+
var _a2, _b, _c, _d, _e;
|
|
5011
5788
|
const [mounted, setMounted] = useState5(false);
|
|
5012
5789
|
const [launcherPos, setLauncherPos] = useState5(null);
|
|
5013
5790
|
const dragRef = useRef5(null);
|
|
@@ -5022,7 +5799,7 @@ function ShadowCanvasOverlay({
|
|
|
5022
5799
|
const handleNotificationClick = useCallback4(
|
|
5023
5800
|
(notif) => {
|
|
5024
5801
|
if (runtime3) {
|
|
5025
|
-
runtime3.events.publish(
|
|
5802
|
+
runtime3.events.publish(StandardEvents2.NOTIFICATION_CLICKED, {
|
|
5026
5803
|
notificationId: notif.id,
|
|
5027
5804
|
tileId: notif.tileId,
|
|
5028
5805
|
itemId: notif.itemId
|
|
@@ -5032,7 +5809,7 @@ function ShadowCanvasOverlay({
|
|
|
5032
5809
|
onToggle();
|
|
5033
5810
|
}
|
|
5034
5811
|
if (runtime3 && notif.tileId) {
|
|
5035
|
-
runtime3.events.publish(
|
|
5812
|
+
runtime3.events.publish(StandardEvents2.NOTIFICATION_DEEP_LINK, {
|
|
5036
5813
|
tileId: notif.tileId,
|
|
5037
5814
|
itemId: notif.itemId
|
|
5038
5815
|
});
|
|
@@ -5105,6 +5882,17 @@ function ShadowCanvasOverlay({
|
|
|
5105
5882
|
}
|
|
5106
5883
|
onToggle();
|
|
5107
5884
|
}, [isOpen, telemetry, runtime3, onToggle]);
|
|
5885
|
+
useEffect7(() => {
|
|
5886
|
+
if (!isOpen) return;
|
|
5887
|
+
const handleOutsideClick = (e) => {
|
|
5888
|
+
const path = e.composedPath();
|
|
5889
|
+
if (containerRef.current && !path.includes(containerRef.current) && launcherRef.current && !path.includes(launcherRef.current)) {
|
|
5890
|
+
toggle2();
|
|
5891
|
+
}
|
|
5892
|
+
};
|
|
5893
|
+
document.addEventListener("mousedown", handleOutsideClick);
|
|
5894
|
+
return () => document.removeEventListener("mousedown", handleOutsideClick);
|
|
5895
|
+
}, [isOpen, toggle2]);
|
|
5108
5896
|
const onLauncherPointerDown = useCallback4((e) => {
|
|
5109
5897
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
5110
5898
|
dragRef.current = {
|
|
@@ -5129,7 +5917,7 @@ function ShadowCanvasOverlay({
|
|
|
5129
5917
|
}
|
|
5130
5918
|
}, []);
|
|
5131
5919
|
const onLauncherPointerUp = useCallback4(
|
|
5132
|
-
(
|
|
5920
|
+
(_e2) => {
|
|
5133
5921
|
const drag = dragRef.current;
|
|
5134
5922
|
dragRef.current = null;
|
|
5135
5923
|
if (drag && !drag.dragged) {
|
|
@@ -5143,6 +5931,7 @@ function ShadowCanvasOverlay({
|
|
|
5143
5931
|
const isPush = config.canvas.layout === "push";
|
|
5144
5932
|
const canvasBorder = (_b = config.canvas.border) != null ? _b : "none";
|
|
5145
5933
|
const containerRef = useRef5(null);
|
|
5934
|
+
const launcherRef = useRef5(null);
|
|
5146
5935
|
const zIndex = 2147483600;
|
|
5147
5936
|
useEffect7(() => {
|
|
5148
5937
|
var _a3, _b2, _c2, _d2;
|
|
@@ -5223,19 +6012,19 @@ function ShadowCanvasOverlay({
|
|
|
5223
6012
|
pointerEvents: "none",
|
|
5224
6013
|
padding: "0"
|
|
5225
6014
|
};
|
|
5226
|
-
const content = /* @__PURE__ */
|
|
6015
|
+
const content = /* @__PURE__ */ jsx8(
|
|
5227
6016
|
"div",
|
|
5228
6017
|
{
|
|
5229
6018
|
"data-shadow-canvas-id": "overlay-root",
|
|
5230
6019
|
style: {
|
|
5231
6020
|
position: "fixed",
|
|
5232
6021
|
inset: 0,
|
|
5233
|
-
pointerEvents:
|
|
6022
|
+
pointerEvents: "none",
|
|
5234
6023
|
zIndex
|
|
5235
6024
|
},
|
|
5236
6025
|
children: /* @__PURE__ */ jsxs3("div", { style: wrapperStyle, children: [
|
|
5237
6026
|
/* @__PURE__ */ jsxs3("div", { ref: containerRef, "data-shadow-canvas-id": "overlay-container", style: containerStyle, children: [
|
|
5238
|
-
isFocused && canvasTitle && /* @__PURE__ */
|
|
6027
|
+
isFocused && canvasTitle && /* @__PURE__ */ jsx8("header", { style: { color: "white", padding: "1.5rem 1.5rem 0" }, children: /* @__PURE__ */ jsx8(
|
|
5239
6028
|
"p",
|
|
5240
6029
|
{
|
|
5241
6030
|
style: {
|
|
@@ -5248,7 +6037,7 @@ function ShadowCanvasOverlay({
|
|
|
5248
6037
|
children: canvasTitle
|
|
5249
6038
|
}
|
|
5250
6039
|
) }),
|
|
5251
|
-
/* @__PURE__ */
|
|
6040
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: 1, overflowY: "auto", padding: isFocused ? "0" : "1rem" }, children: isLoading ? /* @__PURE__ */ jsx8(
|
|
5252
6041
|
"div",
|
|
5253
6042
|
{
|
|
5254
6043
|
style: { color: "var(--sc-overlay-text-color)", padding: isFocused ? "1rem" : "0" },
|
|
@@ -5268,7 +6057,7 @@ function ShadowCanvasOverlay({
|
|
|
5268
6057
|
}
|
|
5269
6058
|
) : isFocused ? (
|
|
5270
6059
|
/* Focused Mode: Render first tile full size */
|
|
5271
|
-
tiles.length > 0 ? /* @__PURE__ */
|
|
6060
|
+
tiles.length > 0 ? /* @__PURE__ */ jsx8(
|
|
5272
6061
|
TileCard,
|
|
5273
6062
|
{
|
|
5274
6063
|
config: tiles[0],
|
|
@@ -5279,7 +6068,7 @@ function ShadowCanvasOverlay({
|
|
|
5279
6068
|
) : null
|
|
5280
6069
|
) : (
|
|
5281
6070
|
/* Standard Mode: Stacked cards — widgets always visible */
|
|
5282
|
-
/* @__PURE__ */
|
|
6071
|
+
/* @__PURE__ */ jsx8(
|
|
5283
6072
|
"div",
|
|
5284
6073
|
{
|
|
5285
6074
|
style: {
|
|
@@ -5288,7 +6077,7 @@ function ShadowCanvasOverlay({
|
|
|
5288
6077
|
gap: "0.75rem",
|
|
5289
6078
|
width: "100%"
|
|
5290
6079
|
},
|
|
5291
|
-
children: tiles.map((tile) => /* @__PURE__ */
|
|
6080
|
+
children: tiles.map((tile) => /* @__PURE__ */ jsx8(
|
|
5292
6081
|
TileCard,
|
|
5293
6082
|
{
|
|
5294
6083
|
config: tile,
|
|
@@ -5303,17 +6092,7 @@ function ShadowCanvasOverlay({
|
|
|
5303
6092
|
) }),
|
|
5304
6093
|
footerSlot
|
|
5305
6094
|
] }),
|
|
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
|
-
)
|
|
6095
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: "1 1 auto" } })
|
|
5317
6096
|
] })
|
|
5318
6097
|
}
|
|
5319
6098
|
);
|
|
@@ -5331,7 +6110,7 @@ function ShadowCanvasOverlay({
|
|
|
5331
6110
|
zIndex: zIndex + 47
|
|
5332
6111
|
},
|
|
5333
6112
|
children: [
|
|
5334
|
-
/* @__PURE__ */
|
|
6113
|
+
/* @__PURE__ */ jsx8(
|
|
5335
6114
|
NotificationToastStack,
|
|
5336
6115
|
{
|
|
5337
6116
|
notifications,
|
|
@@ -5343,6 +6122,7 @@ function ShadowCanvasOverlay({
|
|
|
5343
6122
|
/* @__PURE__ */ jsxs3(
|
|
5344
6123
|
"button",
|
|
5345
6124
|
{
|
|
6125
|
+
ref: launcherRef,
|
|
5346
6126
|
type: "button",
|
|
5347
6127
|
"aria-label": "Toggle shadow canvas",
|
|
5348
6128
|
className: launcherAnimate && !isOpen ? "syntro-launcher-animate" : void 0,
|
|
@@ -5401,14 +6181,14 @@ function ShadowCanvasOverlay({
|
|
|
5401
6181
|
focusable: "false",
|
|
5402
6182
|
style: { transition: "transform 200ms ease" },
|
|
5403
6183
|
children: [
|
|
5404
|
-
/* @__PURE__ */
|
|
5405
|
-
/* @__PURE__ */
|
|
6184
|
+
/* @__PURE__ */ jsx8("path", { d: "M18 6L6 18" }),
|
|
6185
|
+
/* @__PURE__ */ jsx8("path", { d: "M6 6l12 12" })
|
|
5406
6186
|
]
|
|
5407
6187
|
}
|
|
5408
|
-
) :
|
|
6188
|
+
) : ((_e = config.launcher) == null ? void 0 : _e.icon) ? /* @__PURE__ */ jsx8(
|
|
5409
6189
|
"img",
|
|
5410
6190
|
{
|
|
5411
|
-
src:
|
|
6191
|
+
src: config.launcher.icon,
|
|
5412
6192
|
alt: "",
|
|
5413
6193
|
"aria-hidden": "true",
|
|
5414
6194
|
style: {
|
|
@@ -5433,16 +6213,16 @@ function ShadowCanvasOverlay({
|
|
|
5433
6213
|
focusable: "false",
|
|
5434
6214
|
style: { transition: "transform 200ms ease" },
|
|
5435
6215
|
children: [
|
|
5436
|
-
/* @__PURE__ */
|
|
5437
|
-
/* @__PURE__ */
|
|
5438
|
-
/* @__PURE__ */
|
|
5439
|
-
/* @__PURE__ */
|
|
5440
|
-
/* @__PURE__ */
|
|
6216
|
+
/* @__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" }),
|
|
6217
|
+
/* @__PURE__ */ jsx8("path", { d: "M5 3v4" }),
|
|
6218
|
+
/* @__PURE__ */ jsx8("path", { d: "M3 5h4" }),
|
|
6219
|
+
/* @__PURE__ */ jsx8("path", { d: "M19 17v4" }),
|
|
6220
|
+
/* @__PURE__ */ jsx8("path", { d: "M17 19h4" })
|
|
5441
6221
|
]
|
|
5442
6222
|
}
|
|
5443
6223
|
),
|
|
5444
6224
|
!isOpen && notifications.length > 0 && /* @__PURE__ */ jsxs3("div", { style: { position: "absolute", top: -2, right: -2, pointerEvents: "none" }, children: [
|
|
5445
|
-
/* @__PURE__ */
|
|
6225
|
+
/* @__PURE__ */ jsx8(
|
|
5446
6226
|
"span",
|
|
5447
6227
|
{
|
|
5448
6228
|
className: "syntro-badge-ping",
|
|
@@ -5454,7 +6234,7 @@ function ShadowCanvasOverlay({
|
|
|
5454
6234
|
}
|
|
5455
6235
|
}
|
|
5456
6236
|
),
|
|
5457
|
-
/* @__PURE__ */
|
|
6237
|
+
/* @__PURE__ */ jsx8(
|
|
5458
6238
|
"span",
|
|
5459
6239
|
{
|
|
5460
6240
|
className: "syntro-badge-glow",
|
|
@@ -5465,7 +6245,7 @@ function ShadowCanvasOverlay({
|
|
|
5465
6245
|
}
|
|
5466
6246
|
}
|
|
5467
6247
|
),
|
|
5468
|
-
/* @__PURE__ */
|
|
6248
|
+
/* @__PURE__ */ jsx8(
|
|
5469
6249
|
"span",
|
|
5470
6250
|
{
|
|
5471
6251
|
className: "syntro-badge-bounce",
|
|
@@ -5504,6 +6284,14 @@ var sortTiles = (tiles) => [...tiles].sort((a, b) => {
|
|
|
5504
6284
|
var _a2, _b;
|
|
5505
6285
|
return ((_a2 = b.priority) != null ? _a2 : 0) - ((_b = a.priority) != null ? _b : 0);
|
|
5506
6286
|
});
|
|
6287
|
+
function fireTriggeredForTiles(tiles) {
|
|
6288
|
+
var _a2, _b;
|
|
6289
|
+
const tracker = typeof window !== "undefined" ? (_a2 = window.SynOS) == null ? void 0 : _a2.interventionTracker : null;
|
|
6290
|
+
if (!tracker) return;
|
|
6291
|
+
for (const tile of tiles) {
|
|
6292
|
+
tracker.trackTriggered(tile.id, (_b = tile.widget) != null ? _b : "unknown");
|
|
6293
|
+
}
|
|
6294
|
+
}
|
|
5507
6295
|
function useShadowCanvasConfig({
|
|
5508
6296
|
fetcher,
|
|
5509
6297
|
experiments,
|
|
@@ -5526,6 +6314,7 @@ function useShadowCanvasConfig({
|
|
|
5526
6314
|
if (experiments) {
|
|
5527
6315
|
tiles = tiles.filter((tile) => experiments.shouldRenderRectangle(tile));
|
|
5528
6316
|
}
|
|
6317
|
+
fireTriggeredForTiles(tiles);
|
|
5529
6318
|
setState((prev) => ({ ...prev, tiles: sortTiles(tiles) }));
|
|
5530
6319
|
}, [runtime3, experiments]);
|
|
5531
6320
|
const load = useCallback5(async () => {
|
|
@@ -5543,6 +6332,7 @@ function useShadowCanvasConfig({
|
|
|
5543
6332
|
} else if (experiments) {
|
|
5544
6333
|
tiles = tiles.filter((tile) => experiments.shouldRenderRectangle(tile));
|
|
5545
6334
|
}
|
|
6335
|
+
fireTriggeredForTiles(tiles);
|
|
5546
6336
|
debug("SmartCanvas Config", `Tile count after filtering: ${tiles.length}`);
|
|
5547
6337
|
const newActions = response.actions || [];
|
|
5548
6338
|
const newActionsJson = JSON.stringify(newActions);
|
|
@@ -5600,13 +6390,13 @@ function useShadowCanvasConfig({
|
|
|
5600
6390
|
|
|
5601
6391
|
// src/SmartCanvasApp.tsx
|
|
5602
6392
|
import { useEffect as useEffect9, useMemo as useMemo7, useRef as useRef7, useState as useState7 } from "react";
|
|
5603
|
-
import { jsx as
|
|
6393
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
5604
6394
|
function SmartCanvasApp({
|
|
5605
6395
|
controller,
|
|
5606
6396
|
fetcher,
|
|
5607
6397
|
configUri,
|
|
5608
|
-
configUriFeatureKey
|
|
5609
|
-
configFeatureKey
|
|
6398
|
+
configUriFeatureKey,
|
|
6399
|
+
configFeatureKey,
|
|
5610
6400
|
fetchCredentials = "include",
|
|
5611
6401
|
pollIntervalMs,
|
|
5612
6402
|
experiments,
|
|
@@ -5623,7 +6413,7 @@ function SmartCanvasApp({
|
|
|
5623
6413
|
workspaceTheme
|
|
5624
6414
|
}) {
|
|
5625
6415
|
if (runtime3) {
|
|
5626
|
-
return /* @__PURE__ */
|
|
6416
|
+
return /* @__PURE__ */ jsx9(RuntimeProvider, { runtime: runtime3, children: /* @__PURE__ */ jsx9(
|
|
5627
6417
|
SmartCanvasAppInner,
|
|
5628
6418
|
{
|
|
5629
6419
|
controller,
|
|
@@ -5648,7 +6438,7 @@ function SmartCanvasApp({
|
|
|
5648
6438
|
}
|
|
5649
6439
|
) });
|
|
5650
6440
|
}
|
|
5651
|
-
return /* @__PURE__ */
|
|
6441
|
+
return /* @__PURE__ */ jsx9(
|
|
5652
6442
|
SmartCanvasAppInner,
|
|
5653
6443
|
{
|
|
5654
6444
|
controller,
|
|
@@ -5676,10 +6466,10 @@ function SmartCanvasAppInner({
|
|
|
5676
6466
|
controller,
|
|
5677
6467
|
fetcher,
|
|
5678
6468
|
configUri,
|
|
5679
|
-
configUriFeatureKey
|
|
5680
|
-
configFeatureKey
|
|
6469
|
+
configUriFeatureKey,
|
|
6470
|
+
configFeatureKey,
|
|
5681
6471
|
fetchCredentials = "include",
|
|
5682
|
-
pollIntervalMs,
|
|
6472
|
+
pollIntervalMs: _pollIntervalMs,
|
|
5683
6473
|
experiments,
|
|
5684
6474
|
telemetry,
|
|
5685
6475
|
runtime: runtime3,
|
|
@@ -5693,7 +6483,7 @@ function SmartCanvasAppInner({
|
|
|
5693
6483
|
initialBatchHandle,
|
|
5694
6484
|
workspaceTheme
|
|
5695
6485
|
}) {
|
|
5696
|
-
var _a2, _b, _c, _d, _e, _f
|
|
6486
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
5697
6487
|
const [open, setOpen] = useState7(controller.getState().open);
|
|
5698
6488
|
const pageContext = usePageContext();
|
|
5699
6489
|
const [localUrl, setLocalUrl] = useState7(
|
|
@@ -5749,6 +6539,7 @@ function SmartCanvasAppInner({
|
|
|
5749
6539
|
const batchHandleRef = useRef7(initialBatchHandle != null ? initialBatchHandle : null);
|
|
5750
6540
|
const adoptedInitialRef = useRef7(!!initialBatchHandle);
|
|
5751
6541
|
const runVersionRef = useRef7(0);
|
|
6542
|
+
const pendingRevertRef = useRef7(null);
|
|
5752
6543
|
useEffect9(() => {
|
|
5753
6544
|
if (!(runtime3 == null ? void 0 : runtime3.actions)) return;
|
|
5754
6545
|
if (adoptedInitialRef.current) {
|
|
@@ -5760,6 +6551,10 @@ function SmartCanvasAppInner({
|
|
|
5760
6551
|
const version = ++runVersionRef.current;
|
|
5761
6552
|
const stale = () => version !== runVersionRef.current;
|
|
5762
6553
|
const run = async () => {
|
|
6554
|
+
if (pendingRevertRef.current) {
|
|
6555
|
+
await pendingRevertRef.current;
|
|
6556
|
+
pendingRevertRef.current = null;
|
|
6557
|
+
}
|
|
5763
6558
|
if (batchHandleRef.current) {
|
|
5764
6559
|
try {
|
|
5765
6560
|
await batchHandleRef.current.revertAll();
|
|
@@ -5787,7 +6582,7 @@ function SmartCanvasAppInner({
|
|
|
5787
6582
|
run();
|
|
5788
6583
|
return () => {
|
|
5789
6584
|
if (batchHandleRef.current) {
|
|
5790
|
-
batchHandleRef.current.revertAll().catch((err) => {
|
|
6585
|
+
pendingRevertRef.current = batchHandleRef.current.revertAll().catch((err) => {
|
|
5791
6586
|
console.error("[SmartCanvasApp] Failed to revert actions on cleanup:", err);
|
|
5792
6587
|
});
|
|
5793
6588
|
batchHandleRef.current = null;
|
|
@@ -5803,16 +6598,13 @@ function SmartCanvasAppInner({
|
|
|
5803
6598
|
}, [runtime3, controller]);
|
|
5804
6599
|
const { shadowRoot } = useShadowRoot();
|
|
5805
6600
|
const themeConfig = configState.theme;
|
|
5806
|
-
|
|
5807
|
-
return null;
|
|
5808
|
-
}
|
|
5809
|
-
return /* @__PURE__ */ jsx8(
|
|
6601
|
+
return /* @__PURE__ */ jsx9(
|
|
5810
6602
|
ThemeProvider,
|
|
5811
6603
|
{
|
|
5812
6604
|
themeConfig,
|
|
5813
6605
|
workspaceTheme,
|
|
5814
6606
|
shadowRoot,
|
|
5815
|
-
children: /* @__PURE__ */
|
|
6607
|
+
children: !configState.isLoading && !hasContent ? null : /* @__PURE__ */ jsx9(
|
|
5816
6608
|
ShadowCanvasOverlay,
|
|
5817
6609
|
{
|
|
5818
6610
|
tiles: configState.tiles,
|
|
@@ -5821,10 +6613,9 @@ function SmartCanvasAppInner({
|
|
|
5821
6613
|
canvasTitle: configState.canvasTitle,
|
|
5822
6614
|
telemetry,
|
|
5823
6615
|
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,
|
|
6616
|
+
launcherAnimate: (_c = configState.launcher) == null ? void 0 : _c.animate,
|
|
6617
|
+
launcherAnimationStyle: (_d = configState.launcher) == null ? void 0 : _d.animationStyle,
|
|
6618
|
+
notificationCount: (_f = (_e = configState.launcher) == null ? void 0 : _e.notificationCount) != null ? _f : configState.tiles.length,
|
|
5828
6619
|
footerSlot,
|
|
5829
6620
|
isOpen: open,
|
|
5830
6621
|
onToggle: () => controller.toggle(),
|
|
@@ -5837,7 +6628,7 @@ function SmartCanvasAppInner({
|
|
|
5837
6628
|
|
|
5838
6629
|
// src/SmartCanvasElement.tsx
|
|
5839
6630
|
import { createRoot as createRoot2 } from "react-dom/client";
|
|
5840
|
-
import { jsx as
|
|
6631
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
5841
6632
|
var TAG_NAME = "smart-canvas";
|
|
5842
6633
|
var BASE_CSS = `
|
|
5843
6634
|
:host {
|
|
@@ -5938,13 +6729,13 @@ var SmartCanvasElement = class extends HTMLElement {
|
|
|
5938
6729
|
__privateSet(this, _root, createRoot2(__privateGet(this, _mount)));
|
|
5939
6730
|
}
|
|
5940
6731
|
__privateGet(this, _root).render(
|
|
5941
|
-
/* @__PURE__ */
|
|
6732
|
+
/* @__PURE__ */ jsx10(
|
|
5942
6733
|
ShadowRootProvider,
|
|
5943
6734
|
{
|
|
5944
6735
|
shadowRoot: __privateGet(this, _shadow),
|
|
5945
6736
|
portalRoot: __privateGet(this, _portalRoot),
|
|
5946
6737
|
overlayContainer: __privateGet(this, _overlayContainer),
|
|
5947
|
-
children: /* @__PURE__ */
|
|
6738
|
+
children: /* @__PURE__ */ jsx10(SmartCanvasApp, { ...__privateGet(this, _lastAppProps), controller: __privateGet(this, _controller), canvasHost: this })
|
|
5948
6739
|
}
|
|
5949
6740
|
)
|
|
5950
6741
|
);
|
|
@@ -6513,7 +7304,7 @@ var createSmartCanvas = async (config = {}) => {
|
|
|
6513
7304
|
console.log(
|
|
6514
7305
|
"[SmartCanvas] Actions to apply:",
|
|
6515
7306
|
canvasConfig.actions.map(
|
|
6516
|
-
(a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${
|
|
7307
|
+
(a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${a.anchorId.selector}"` : ""}${a.label ? ` "${a.label}"` : ""}`
|
|
6517
7308
|
).join(", ")
|
|
6518
7309
|
);
|
|
6519
7310
|
}
|
|
@@ -6964,17 +7755,18 @@ var PostHogAdapter = class {
|
|
|
6964
7755
|
__publicField(this, "client");
|
|
6965
7756
|
__publicField(this, "featureFlagsCallback");
|
|
6966
7757
|
__publicField(this, "captureCallback");
|
|
6967
|
-
__publicField(this, "
|
|
7758
|
+
__publicField(this, "rrwebCallback");
|
|
6968
7759
|
this.client = options.client;
|
|
6969
7760
|
this.featureFlagsCallback = options.onFeatureFlagsLoaded;
|
|
6970
7761
|
this.captureCallback = options.onCapture;
|
|
7762
|
+
this.rrwebCallback = options.onRRWebEvent;
|
|
6971
7763
|
if (!this.client && options.consent && options.requireExplicitConsent && typeof window !== "undefined" && options.apiKey) {
|
|
6972
7764
|
const consent = options.consent;
|
|
6973
7765
|
const currentStatus = consent.getStatus();
|
|
6974
7766
|
if (currentStatus === "granted") {
|
|
6975
7767
|
this.initPostHog();
|
|
6976
7768
|
}
|
|
6977
|
-
|
|
7769
|
+
consent.subscribe((status) => {
|
|
6978
7770
|
if (status === "granted") {
|
|
6979
7771
|
if (!this.client) {
|
|
6980
7772
|
this.initPostHog();
|
|
@@ -7001,68 +7793,117 @@ var PostHogAdapter = class {
|
|
|
7001
7793
|
if (!options.apiKey) return;
|
|
7002
7794
|
const enableFeatureFlags = (_a2 = options.enableFeatureFlags) != null ? _a2 : true;
|
|
7003
7795
|
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
|
-
}
|
|
7796
|
+
const initOptions = {
|
|
7797
|
+
api_host: (_b = options.apiHost) != null ? _b : "https://telemetry.syntrologie.com",
|
|
7798
|
+
// Feature flags for segment membership (in_segment_* flags)
|
|
7799
|
+
// When enabled, /decide is called to get segment flags
|
|
7800
|
+
advanced_disable_feature_flags: !enableFeatureFlags,
|
|
7801
|
+
advanced_disable_feature_flags_on_first_load: !enableFeatureFlags,
|
|
7802
|
+
// Full-page tracking - all ON by default
|
|
7803
|
+
autocapture: (_c = options.autocapture) != null ? _c : true,
|
|
7804
|
+
capture_pageview: (_d = options.capturePageview) != null ? _d : "history_change",
|
|
7805
|
+
capture_pageleave: (_e = options.capturePageleave) != null ? _e : true,
|
|
7806
|
+
disable_session_recording: !((_f = options.sessionRecording) != null ? _f : true),
|
|
7807
|
+
// CRITICAL: Disable user agent filtering to allow headless Chrome
|
|
7808
|
+
// PostHog blocks "HeadlessChrome" user agents by default as bot detection
|
|
7809
|
+
// This enables session recording in Playwright/crawler sessions
|
|
7810
|
+
opt_out_useragent_filter: true,
|
|
7811
|
+
// Cross-domain iframe recording for embeds
|
|
7812
|
+
session_recording: {
|
|
7813
|
+
recordCrossDomainIFrames: true
|
|
7054
7814
|
},
|
|
7815
|
+
// Capture performance metrics
|
|
7816
|
+
capture_performance: true,
|
|
7817
|
+
// Enable web vitals
|
|
7818
|
+
enable_recording_console_log: true
|
|
7819
|
+
};
|
|
7820
|
+
const result = posthog.init(
|
|
7821
|
+
options.apiKey,
|
|
7822
|
+
initOptions,
|
|
7055
7823
|
instanceName
|
|
7056
7824
|
);
|
|
7825
|
+
if (result) {
|
|
7826
|
+
this.client = result;
|
|
7827
|
+
}
|
|
7828
|
+
if (this.captureCallback && this.client) {
|
|
7829
|
+
this.client.on("eventCaptured", (...args) => {
|
|
7830
|
+
var _a3;
|
|
7831
|
+
const data = args[0];
|
|
7832
|
+
const eventName = typeof data === "string" ? data : data == null ? void 0 : data.event;
|
|
7833
|
+
const properties = typeof data === "string" ? void 0 : data == null ? void 0 : data.properties;
|
|
7834
|
+
if (typeof eventName === "string") {
|
|
7835
|
+
(_a3 = this.captureCallback) == null ? void 0 : _a3.call(this, eventName, properties);
|
|
7836
|
+
}
|
|
7837
|
+
});
|
|
7838
|
+
}
|
|
7839
|
+
if (enableFeatureFlags && this.featureFlagsCallback && this.client) {
|
|
7840
|
+
this.client.onFeatureFlags(() => {
|
|
7841
|
+
const allFlags = this.getAllFeatureFlags();
|
|
7842
|
+
if (allFlags && this.featureFlagsCallback) {
|
|
7843
|
+
this.featureFlagsCallback(allFlags);
|
|
7844
|
+
}
|
|
7845
|
+
});
|
|
7846
|
+
const existingFlags = this.getAllFeatureFlags();
|
|
7847
|
+
if (existingFlags && Object.keys(existingFlags).length > 0) {
|
|
7848
|
+
this.featureFlagsCallback(existingFlags);
|
|
7849
|
+
}
|
|
7850
|
+
}
|
|
7851
|
+
if (this.rrwebCallback && this.client) {
|
|
7852
|
+
this.setupRRWebIntercept();
|
|
7853
|
+
}
|
|
7854
|
+
}
|
|
7855
|
+
/**
|
|
7856
|
+
* Set up rrweb event interception on PostHog's session recording.
|
|
7857
|
+
*
|
|
7858
|
+
* PostHog lazy-loads the rrweb recorder. The SessionRecording wrapper has
|
|
7859
|
+
* an `onRRwebEmit` method, but rrweb delivers events directly to the
|
|
7860
|
+
* lazy-loaded recorder instance's `onRRwebEmit`, bypassing the wrapper.
|
|
7861
|
+
* We must find and patch the recorder instance, not the wrapper.
|
|
7862
|
+
*
|
|
7863
|
+
* The recorder instance is stored on a minified property of SessionRecording.
|
|
7864
|
+
* We detect it by looking for an object with both `onRRwebEmit` and `start` methods.
|
|
7865
|
+
*/
|
|
7866
|
+
setupRRWebIntercept(retries = 30) {
|
|
7867
|
+
var _a2;
|
|
7868
|
+
const sr = (_a2 = this.client) == null ? void 0 : _a2.sessionRecording;
|
|
7869
|
+
if (!sr) {
|
|
7870
|
+
if (retries > 0) {
|
|
7871
|
+
setTimeout(() => this.setupRRWebIntercept(retries - 1), 500);
|
|
7872
|
+
}
|
|
7873
|
+
return;
|
|
7874
|
+
}
|
|
7875
|
+
let recorder = null;
|
|
7876
|
+
const srRecord = sr;
|
|
7877
|
+
for (const key of Object.getOwnPropertyNames(srRecord)) {
|
|
7878
|
+
const val = srRecord[key];
|
|
7879
|
+
if (val && typeof val === "object" && typeof val.onRRwebEmit === "function" && typeof val.start === "function" && val !== sr) {
|
|
7880
|
+
recorder = val;
|
|
7881
|
+
break;
|
|
7882
|
+
}
|
|
7883
|
+
}
|
|
7884
|
+
if (!recorder) {
|
|
7885
|
+
if (retries > 0) {
|
|
7886
|
+
setTimeout(() => this.setupRRWebIntercept(retries - 1), 500);
|
|
7887
|
+
}
|
|
7888
|
+
return;
|
|
7889
|
+
}
|
|
7890
|
+
const originalEmit = recorder.onRRwebEmit.bind(recorder);
|
|
7891
|
+
recorder.onRRwebEmit = (rawEvent) => {
|
|
7892
|
+
var _a3;
|
|
7893
|
+
(_a3 = this.rrwebCallback) == null ? void 0 : _a3.call(this, { kind: "rrweb", ...rawEvent });
|
|
7894
|
+
originalEmit(rawEvent);
|
|
7895
|
+
};
|
|
7896
|
+
if (typeof window !== "undefined") {
|
|
7897
|
+
window.__RRWEB_INTERCEPT_READY__ = true;
|
|
7898
|
+
}
|
|
7057
7899
|
}
|
|
7058
7900
|
/**
|
|
7059
7901
|
* Get all feature flags from PostHog.
|
|
7060
7902
|
* Used to extract segment membership flags (in_segment_*).
|
|
7061
7903
|
*/
|
|
7062
7904
|
getAllFeatureFlags() {
|
|
7063
|
-
var _a2, _b
|
|
7064
|
-
|
|
7065
|
-
return flags;
|
|
7905
|
+
var _a2, _b;
|
|
7906
|
+
return (_b = (_a2 = this.client) == null ? void 0 : _a2.featureFlags) == null ? void 0 : _b.getFlagVariants();
|
|
7066
7907
|
}
|
|
7067
7908
|
/**
|
|
7068
7909
|
* Get segment membership flags (in_segment_*) from PostHog.
|
|
@@ -7143,6 +7984,59 @@ function createPostHogClient(options = {}) {
|
|
|
7143
7984
|
return new PostHogAdapter(options);
|
|
7144
7985
|
}
|
|
7145
7986
|
|
|
7987
|
+
// src/telemetry/InterventionTracker.ts
|
|
7988
|
+
var InterventionTracker = class {
|
|
7989
|
+
constructor(telemetry, variantId) {
|
|
7990
|
+
__publicField(this, "telemetry");
|
|
7991
|
+
__publicField(this, "variantId");
|
|
7992
|
+
__publicField(this, "seenSet", /* @__PURE__ */ new Set());
|
|
7993
|
+
__publicField(this, "triggeredSet", /* @__PURE__ */ new Set());
|
|
7994
|
+
this.telemetry = telemetry;
|
|
7995
|
+
this.variantId = variantId;
|
|
7996
|
+
}
|
|
7997
|
+
trackServed(tiles, actions) {
|
|
7998
|
+
var _a2, _b;
|
|
7999
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_config_served", {
|
|
8000
|
+
variant_id: this.variantId,
|
|
8001
|
+
tiles,
|
|
8002
|
+
actions
|
|
8003
|
+
});
|
|
8004
|
+
}
|
|
8005
|
+
trackSeen(interventionId, interventionKind) {
|
|
8006
|
+
var _a2, _b;
|
|
8007
|
+
if (this.seenSet.has(interventionId)) return;
|
|
8008
|
+
this.seenSet.add(interventionId);
|
|
8009
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_seen", {
|
|
8010
|
+
variant_id: this.variantId,
|
|
8011
|
+
intervention_id: interventionId,
|
|
8012
|
+
intervention_kind: interventionKind
|
|
8013
|
+
});
|
|
8014
|
+
}
|
|
8015
|
+
trackTriggered(interventionId, interventionKind) {
|
|
8016
|
+
var _a2, _b;
|
|
8017
|
+
if (this.triggeredSet.has(interventionId)) return;
|
|
8018
|
+
this.triggeredSet.add(interventionId);
|
|
8019
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_triggered", {
|
|
8020
|
+
variant_id: this.variantId,
|
|
8021
|
+
intervention_id: interventionId,
|
|
8022
|
+
intervention_kind: interventionKind
|
|
8023
|
+
});
|
|
8024
|
+
}
|
|
8025
|
+
trackInteracted(interventionId, interventionKind, interactionType) {
|
|
8026
|
+
var _a2, _b;
|
|
8027
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_interacted", {
|
|
8028
|
+
variant_id: this.variantId,
|
|
8029
|
+
intervention_id: interventionId,
|
|
8030
|
+
intervention_kind: interventionKind,
|
|
8031
|
+
interaction_type: interactionType
|
|
8032
|
+
});
|
|
8033
|
+
}
|
|
8034
|
+
resetPage() {
|
|
8035
|
+
this.seenSet.clear();
|
|
8036
|
+
this.triggeredSet.clear();
|
|
8037
|
+
}
|
|
8038
|
+
};
|
|
8039
|
+
|
|
7146
8040
|
// src/actions/executors/core-flow.ts
|
|
7147
8041
|
var executeSequence = async (action, context) => {
|
|
7148
8042
|
const handles = [];
|
|
@@ -7413,158 +8307,7 @@ function hasExecutor(kind) {
|
|
|
7413
8307
|
return executorRegistry.has(kind);
|
|
7414
8308
|
}
|
|
7415
8309
|
|
|
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
|
-
}
|
|
8310
|
+
// src/actions/validation-rules.ts
|
|
7568
8311
|
function validateBadgeAction(action, errors, warnings) {
|
|
7569
8312
|
if (!action.content || typeof action.content !== "string") {
|
|
7570
8313
|
errors.push({
|
|
@@ -7951,29 +8694,182 @@ function validateTourAction(action, errors, warnings) {
|
|
|
7951
8694
|
}
|
|
7952
8695
|
}
|
|
7953
8696
|
}
|
|
7954
|
-
|
|
7955
|
-
|
|
8697
|
+
|
|
8698
|
+
// src/actions/validation-core.ts
|
|
8699
|
+
var DANGEROUS_ATTRS = /* @__PURE__ */ new Set([
|
|
8700
|
+
"onclick",
|
|
8701
|
+
"onerror",
|
|
8702
|
+
"onload",
|
|
8703
|
+
"onmouseover",
|
|
8704
|
+
"onfocus",
|
|
8705
|
+
"onblur",
|
|
8706
|
+
"onchange",
|
|
8707
|
+
"onsubmit",
|
|
8708
|
+
"onkeydown",
|
|
8709
|
+
"onkeyup",
|
|
8710
|
+
"onkeypress"
|
|
8711
|
+
]);
|
|
8712
|
+
var MAX_HTML_LENGTH = 5e4;
|
|
8713
|
+
var MAX_STYLE_COUNT = 50;
|
|
8714
|
+
function validateAction(action) {
|
|
7956
8715
|
const errors = [];
|
|
7957
8716
|
const warnings = [];
|
|
7958
|
-
if (!
|
|
7959
|
-
console.error("[ActionValidation] validateActions called with non-array:", typeof actions);
|
|
8717
|
+
if (!action || typeof action !== "object") {
|
|
7960
8718
|
errors.push({
|
|
7961
|
-
code: "
|
|
7962
|
-
message: "
|
|
8719
|
+
code: "INVALID_ACTION",
|
|
8720
|
+
message: "Action must be an object"
|
|
7963
8721
|
});
|
|
7964
8722
|
return { valid: false, errors, warnings };
|
|
7965
8723
|
}
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
8724
|
+
const { kind } = action;
|
|
8725
|
+
if (!kind || typeof kind !== "string") {
|
|
8726
|
+
errors.push({
|
|
8727
|
+
code: "MISSING_KIND",
|
|
8728
|
+
message: "Action must have a 'kind' property"
|
|
8729
|
+
});
|
|
8730
|
+
return { valid: false, errors, warnings };
|
|
8731
|
+
}
|
|
8732
|
+
if (!hasExecutor(kind) && kind !== "core:mountWidget") {
|
|
8733
|
+
const registered = executorRegistry.list();
|
|
8734
|
+
console.error(
|
|
8735
|
+
`[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.`
|
|
8736
|
+
);
|
|
8737
|
+
errors.push({
|
|
8738
|
+
code: "UNKNOWN_KIND",
|
|
8739
|
+
message: `Unknown action kind: ${kind}`,
|
|
8740
|
+
field: "kind"
|
|
8741
|
+
});
|
|
8742
|
+
return { valid: false, errors, warnings };
|
|
8743
|
+
}
|
|
8744
|
+
switch (kind) {
|
|
8745
|
+
case "overlays:highlight":
|
|
8746
|
+
case "overlays:pulse":
|
|
8747
|
+
case "navigation:scrollTo":
|
|
8748
|
+
validateAnchorAction(action, errors, warnings);
|
|
8749
|
+
break;
|
|
8750
|
+
case "overlays:badge":
|
|
8751
|
+
validateAnchorAction(action, errors, warnings);
|
|
8752
|
+
validateBadgeAction(action, errors, warnings);
|
|
8753
|
+
break;
|
|
8754
|
+
case "overlays:tooltip":
|
|
8755
|
+
validateAnchorAction(action, errors, warnings);
|
|
8756
|
+
validateTooltipAction(action, errors, warnings);
|
|
8757
|
+
break;
|
|
8758
|
+
case "overlays:modal":
|
|
8759
|
+
validateModalAction(action, errors, warnings);
|
|
8760
|
+
break;
|
|
8761
|
+
case "content:insertHtml":
|
|
8762
|
+
validateAnchorAction(action, errors, warnings);
|
|
8763
|
+
validateInsertHtmlAction(action, errors, warnings);
|
|
8764
|
+
break;
|
|
8765
|
+
case "content:setText":
|
|
8766
|
+
validateAnchorAction(action, errors, warnings);
|
|
8767
|
+
validateSetTextAction(action, errors, warnings);
|
|
8768
|
+
break;
|
|
8769
|
+
case "content:setAttr":
|
|
8770
|
+
validateAnchorAction(action, errors, warnings);
|
|
8771
|
+
validateSetAttrAction(action, errors, warnings);
|
|
8772
|
+
break;
|
|
8773
|
+
case "content:addClass":
|
|
8774
|
+
case "content:removeClass":
|
|
8775
|
+
validateAnchorAction(action, errors, warnings);
|
|
8776
|
+
validateClassAction(action, errors, warnings);
|
|
8777
|
+
break;
|
|
8778
|
+
case "content:setStyle":
|
|
8779
|
+
validateAnchorAction(action, errors, warnings);
|
|
8780
|
+
validateSetStyleAction(action, errors, warnings);
|
|
8781
|
+
break;
|
|
8782
|
+
case "core:mountWidget":
|
|
8783
|
+
validateMountWidgetAction(action, errors, warnings);
|
|
8784
|
+
break;
|
|
8785
|
+
case "core:wait":
|
|
8786
|
+
validateWaitAction(action, errors, warnings);
|
|
8787
|
+
break;
|
|
8788
|
+
case "core:sequence":
|
|
8789
|
+
validateSequenceAction(action, errors, warnings);
|
|
8790
|
+
break;
|
|
8791
|
+
case "core:parallel":
|
|
8792
|
+
validateParallelAction(action, errors, warnings);
|
|
8793
|
+
break;
|
|
8794
|
+
case "overlays:tour":
|
|
8795
|
+
validateTourAction(action, errors, warnings);
|
|
8796
|
+
break;
|
|
8797
|
+
case "navigation:navigate":
|
|
8798
|
+
validateNavigateAction(action, errors, warnings);
|
|
8799
|
+
break;
|
|
8800
|
+
}
|
|
8801
|
+
return {
|
|
8802
|
+
valid: errors.length === 0,
|
|
8803
|
+
errors,
|
|
8804
|
+
warnings
|
|
8805
|
+
};
|
|
8806
|
+
}
|
|
8807
|
+
function validateAnchorAction(action, errors, warnings) {
|
|
8808
|
+
const anchorId = action.anchorId;
|
|
8809
|
+
if (!anchorId || typeof anchorId !== "object") {
|
|
8810
|
+
errors.push({
|
|
8811
|
+
code: "MISSING_ANCHOR_ID",
|
|
8812
|
+
message: "Action requires an 'anchorId' object with a 'selector' string",
|
|
8813
|
+
field: "anchorId"
|
|
8814
|
+
});
|
|
8815
|
+
return;
|
|
8816
|
+
}
|
|
8817
|
+
if (!anchorId.selector || typeof anchorId.selector !== "string") {
|
|
8818
|
+
errors.push({
|
|
8819
|
+
code: "MISSING_ANCHOR_SELECTOR",
|
|
8820
|
+
message: "anchorId requires a 'selector' string",
|
|
8821
|
+
field: "anchorId.selector"
|
|
8822
|
+
});
|
|
8823
|
+
} else if (anchorId.selector.length > 200) {
|
|
8824
|
+
warnings.push({
|
|
8825
|
+
code: "LONG_ANCHOR_ID",
|
|
8826
|
+
message: "Anchor selector is unusually long",
|
|
8827
|
+
suggestion: "Consider using a shorter, more descriptive selector"
|
|
8828
|
+
});
|
|
8829
|
+
}
|
|
8830
|
+
if (anchorId.route === void 0 || anchorId.route === null) {
|
|
8831
|
+
errors.push({
|
|
8832
|
+
code: "MISSING_ANCHOR_ROUTE",
|
|
8833
|
+
message: `anchorId requires a 'route' (string or array of strings). Use "**" for all routes.`,
|
|
8834
|
+
field: "anchorId.route"
|
|
8835
|
+
});
|
|
8836
|
+
} else {
|
|
8837
|
+
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
8838
|
+
for (const route of routes) {
|
|
8839
|
+
if (typeof route !== "string") {
|
|
8840
|
+
errors.push({
|
|
8841
|
+
code: "INVALID_ANCHOR_ROUTE",
|
|
8842
|
+
message: "anchorId.route must be a string or array of strings",
|
|
8843
|
+
field: "anchorId.route"
|
|
8844
|
+
});
|
|
8845
|
+
break;
|
|
8846
|
+
}
|
|
8847
|
+
}
|
|
8848
|
+
}
|
|
8849
|
+
}
|
|
8850
|
+
function validateActions(actions) {
|
|
8851
|
+
var _a2;
|
|
8852
|
+
const errors = [];
|
|
8853
|
+
const warnings = [];
|
|
8854
|
+
if (!Array.isArray(actions)) {
|
|
8855
|
+
console.error("[ActionValidation] validateActions called with non-array:", typeof actions);
|
|
8856
|
+
errors.push({
|
|
8857
|
+
code: "INVALID_ACTIONS",
|
|
8858
|
+
message: "Actions must be an array"
|
|
8859
|
+
});
|
|
8860
|
+
return { valid: false, errors, warnings };
|
|
8861
|
+
}
|
|
8862
|
+
for (let i = 0; i < actions.length; i++) {
|
|
8863
|
+
const result = validateAction(actions[i]);
|
|
8864
|
+
if (!result.valid) {
|
|
8865
|
+
const action = actions[i];
|
|
8866
|
+
console.error(
|
|
8867
|
+
`[ActionValidation] Action [${i}] failed validation:`,
|
|
8868
|
+
`kind="${(_a2 = action == null ? void 0 : action.kind) != null ? _a2 : "undefined"}"`,
|
|
8869
|
+
result.errors.map((e) => `${e.code}: ${e.message}`).join("; "),
|
|
8870
|
+
action
|
|
8871
|
+
);
|
|
8872
|
+
}
|
|
7977
8873
|
for (const error2 of result.errors) {
|
|
7978
8874
|
errors.push({
|
|
7979
8875
|
...error2,
|
|
@@ -8097,7 +8993,7 @@ function createActionEngine(options) {
|
|
|
8097
8993
|
}
|
|
8098
8994
|
return executor(action, context);
|
|
8099
8995
|
}
|
|
8100
|
-
function subscribeForReeval(id, action, triggerWhen,
|
|
8996
|
+
function subscribeForReeval(id, action, triggerWhen, _handle) {
|
|
8101
8997
|
if (!runtime3) return;
|
|
8102
8998
|
const unsubs = [];
|
|
8103
8999
|
const onReeval = async () => {
|
|
@@ -8241,13 +9137,9 @@ function createActionEngine(options) {
|
|
|
8241
9137
|
entry2.state = "reverted";
|
|
8242
9138
|
publishEvent("action.reverted", { id, kind: action.kind });
|
|
8243
9139
|
} catch (error2) {
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
kind: action.kind,
|
|
8248
|
-
error: String(error2)
|
|
8249
|
-
});
|
|
8250
|
-
throw error2;
|
|
9140
|
+
console.warn(`[ActionEngine] Cleanup error for ${action.kind} (${id}), ignoring:`, error2);
|
|
9141
|
+
entry2.state = "reverted";
|
|
9142
|
+
publishEvent("action.reverted", { id, kind: action.kind });
|
|
8251
9143
|
} finally {
|
|
8252
9144
|
activeActions.delete(id);
|
|
8253
9145
|
}
|
|
@@ -8291,7 +9183,7 @@ function createActionEngine(options) {
|
|
|
8291
9183
|
errorMessages,
|
|
8292
9184
|
"\nActions:",
|
|
8293
9185
|
actions.map(
|
|
8294
|
-
(a, i) => ` [${i}] ${a.kind} ${a.anchorId ? `anchor="${
|
|
9186
|
+
(a, i) => ` [${i}] ${a.kind} ${a.anchorId ? `anchor="${a.anchorId.selector}"` : ""} ${a.label ? `label="${a.label}"` : ""}`
|
|
8295
9187
|
).join("\n")
|
|
8296
9188
|
);
|
|
8297
9189
|
throw new Error(`Batch validation failed: ${errorMessages}`);
|
|
@@ -8300,15 +9192,30 @@ function createActionEngine(options) {
|
|
|
8300
9192
|
const handles = [];
|
|
8301
9193
|
const appliedHandles = [];
|
|
8302
9194
|
try {
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
9195
|
+
const results = await Promise.allSettled(actions.map((action) => apply(action)));
|
|
9196
|
+
const errors = [];
|
|
9197
|
+
for (const result of results) {
|
|
9198
|
+
if (result.status === "fulfilled") {
|
|
9199
|
+
handles.push(result.value);
|
|
9200
|
+
appliedHandles.push(result.value);
|
|
9201
|
+
} else {
|
|
9202
|
+
errors.push(
|
|
9203
|
+
result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
9204
|
+
);
|
|
9205
|
+
}
|
|
9206
|
+
}
|
|
9207
|
+
if (errors.length > 0 && appliedHandles.length === 0) {
|
|
9208
|
+
throw errors[0];
|
|
9209
|
+
}
|
|
9210
|
+
if (errors.length > 0) {
|
|
9211
|
+
console.warn(
|
|
9212
|
+
`[ActionEngine] ${errors.length}/${actions.length} action(s) failed in batch:`,
|
|
9213
|
+
errors.map((e) => e.message).join("; ")
|
|
9214
|
+
);
|
|
8307
9215
|
}
|
|
8308
9216
|
} catch (error2) {
|
|
8309
9217
|
console.error(
|
|
8310
|
-
`[ActionEngine] Batch apply FAILED
|
|
8311
|
-
`Successfully applied: ${appliedHandles.length}. Rolling back...`,
|
|
9218
|
+
`[ActionEngine] Batch apply FAILED. Successfully applied: ${appliedHandles.length}. Rolling back...`,
|
|
8312
9219
|
error2
|
|
8313
9220
|
);
|
|
8314
9221
|
for (const handle of appliedHandles) {
|
|
@@ -8391,6 +9298,7 @@ function createAnchorResolver(opts) {
|
|
|
8391
9298
|
function resolve(selector) {
|
|
8392
9299
|
if (!root) return null;
|
|
8393
9300
|
try {
|
|
9301
|
+
if (root.matches(selector)) return root;
|
|
8394
9302
|
return root.querySelector(selector);
|
|
8395
9303
|
} catch {
|
|
8396
9304
|
return null;
|
|
@@ -8736,7 +9644,7 @@ function createContextManager(options) {
|
|
|
8736
9644
|
|
|
8737
9645
|
// src/decisions/strategies/rules.ts
|
|
8738
9646
|
function evaluateCondition(condition, evalContext) {
|
|
8739
|
-
var _a2, _b, _c, _d, _e
|
|
9647
|
+
var _a2, _b, _c, _d, _e;
|
|
8740
9648
|
const { context, state, events } = evalContext;
|
|
8741
9649
|
switch (condition.type) {
|
|
8742
9650
|
case "page_url": {
|
|
@@ -8750,8 +9658,7 @@ function evaluateCondition(condition, evalContext) {
|
|
|
8750
9658
|
return context.page.routeId === condition.routeId;
|
|
8751
9659
|
}
|
|
8752
9660
|
case "anchor_visible": {
|
|
8753
|
-
const
|
|
8754
|
-
const anchor = (_c = context.anchors) == null ? void 0 : _c.find((a) => a.anchorId === condSelector);
|
|
9661
|
+
const anchor = (_a2 = context.anchors) == null ? void 0 : _a2.find((a) => a.anchorId === condition.anchorId);
|
|
8755
9662
|
switch (condition.state) {
|
|
8756
9663
|
case "visible":
|
|
8757
9664
|
return (anchor == null ? void 0 : anchor.visible) === true;
|
|
@@ -8765,7 +9672,7 @@ function evaluateCondition(condition, evalContext) {
|
|
|
8765
9672
|
}
|
|
8766
9673
|
case "event_occurred": {
|
|
8767
9674
|
if (!events) return false;
|
|
8768
|
-
const withinMs = (
|
|
9675
|
+
const withinMs = (_b = condition.withinMs) != null ? _b : 6e4;
|
|
8769
9676
|
return events.hasRecentEvent(condition.eventName, withinMs);
|
|
8770
9677
|
}
|
|
8771
9678
|
case "state_equals": {
|
|
@@ -8801,17 +9708,17 @@ function evaluateCondition(condition, evalContext) {
|
|
|
8801
9708
|
}
|
|
8802
9709
|
}
|
|
8803
9710
|
case "dismissed": {
|
|
8804
|
-
if (!state) return (
|
|
9711
|
+
if (!state) return (_c = condition.inverted) != null ? _c : false;
|
|
8805
9712
|
const isDismissed = state.isDismissed(condition.key);
|
|
8806
9713
|
return condition.inverted ? !isDismissed : isDismissed;
|
|
8807
9714
|
}
|
|
8808
9715
|
case "cooldown_active": {
|
|
8809
|
-
if (!state) return (
|
|
9716
|
+
if (!state) return (_d = condition.inverted) != null ? _d : false;
|
|
8810
9717
|
const isActive = state.isCooldownActive(condition.key);
|
|
8811
9718
|
return condition.inverted ? !isActive : isActive;
|
|
8812
9719
|
}
|
|
8813
9720
|
case "frequency_limit": {
|
|
8814
|
-
if (!state) return (
|
|
9721
|
+
if (!state) return (_e = condition.inverted) != null ? _e : false;
|
|
8815
9722
|
const count = state.getFrequencyCount(condition.key);
|
|
8816
9723
|
const limitReached = count >= condition.limit;
|
|
8817
9724
|
return condition.inverted ? !limitReached : limitReached;
|
|
@@ -9071,6 +9978,66 @@ function createEventAccumulator(options) {
|
|
|
9071
9978
|
};
|
|
9072
9979
|
}
|
|
9073
9980
|
|
|
9981
|
+
// src/events/validation.ts
|
|
9982
|
+
var APP_PREFIX = "app:";
|
|
9983
|
+
var RESERVED_PREFIX = "syntro:";
|
|
9984
|
+
var SEGMENT_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
9985
|
+
function validateEventName(name) {
|
|
9986
|
+
if (!name) {
|
|
9987
|
+
return { valid: false, reason: "Event name cannot be empty" };
|
|
9988
|
+
}
|
|
9989
|
+
if (name.startsWith(RESERVED_PREFIX)) {
|
|
9990
|
+
return { valid: false, reason: '"syntro:" prefix is reserved for internal SDK events' };
|
|
9991
|
+
}
|
|
9992
|
+
if (!name.startsWith(APP_PREFIX)) {
|
|
9993
|
+
return { valid: false, reason: `Custom events must start with "app:" prefix. Got: "${name}"` };
|
|
9994
|
+
}
|
|
9995
|
+
const segments = name.slice(APP_PREFIX.length).split(":");
|
|
9996
|
+
if (segments.length < 2) {
|
|
9997
|
+
return {
|
|
9998
|
+
valid: false,
|
|
9999
|
+
reason: `Event name must have at least 2 segments after "app:" (app:{category}:{action}). Got: "${name}"`
|
|
10000
|
+
};
|
|
10001
|
+
}
|
|
10002
|
+
for (const segment of segments) {
|
|
10003
|
+
if (!SEGMENT_PATTERN.test(segment)) {
|
|
10004
|
+
return {
|
|
10005
|
+
valid: false,
|
|
10006
|
+
reason: `Segment "${segment}" must be lowercase alphanumeric + underscores. Got: "${name}"`
|
|
10007
|
+
};
|
|
10008
|
+
}
|
|
10009
|
+
}
|
|
10010
|
+
return { valid: true };
|
|
10011
|
+
}
|
|
10012
|
+
function isSerializable(value) {
|
|
10013
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
|
|
10014
|
+
}
|
|
10015
|
+
function checkDepth(obj, maxDepth, current = 0) {
|
|
10016
|
+
if (current >= maxDepth) return false;
|
|
10017
|
+
for (const value of Object.values(obj)) {
|
|
10018
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
10019
|
+
if (!checkDepth(value, maxDepth, current + 1)) return false;
|
|
10020
|
+
}
|
|
10021
|
+
}
|
|
10022
|
+
return true;
|
|
10023
|
+
}
|
|
10024
|
+
function validateProps(props) {
|
|
10025
|
+
if (props === void 0) return { valid: true };
|
|
10026
|
+
if (props === null || typeof props !== "object" || Array.isArray(props)) {
|
|
10027
|
+
return { valid: false, reason: "Props must be a plain object" };
|
|
10028
|
+
}
|
|
10029
|
+
if (!checkDepth(props, 2)) {
|
|
10030
|
+
return { valid: false, reason: "Props nesting depth exceeds 2 levels" };
|
|
10031
|
+
}
|
|
10032
|
+
const stripped = [];
|
|
10033
|
+
for (const [key, value] of Object.entries(props)) {
|
|
10034
|
+
if (value !== null && typeof value === "object") continue;
|
|
10035
|
+
if (!isSerializable(value)) stripped.push(key);
|
|
10036
|
+
}
|
|
10037
|
+
if (stripped.length > 0) return { valid: true, stripped };
|
|
10038
|
+
return { valid: true };
|
|
10039
|
+
}
|
|
10040
|
+
|
|
9074
10041
|
// src/events/EventBus.ts
|
|
9075
10042
|
function matchesFilter(event, filter) {
|
|
9076
10043
|
if (!filter) return true;
|
|
@@ -9102,8 +10069,16 @@ var EventBus = class {
|
|
|
9102
10069
|
__publicField(this, "subscriptions", /* @__PURE__ */ new Set());
|
|
9103
10070
|
__publicField(this, "history", []);
|
|
9104
10071
|
__publicField(this, "maxHistorySize");
|
|
9105
|
-
|
|
10072
|
+
__publicField(this, "debug");
|
|
10073
|
+
__publicField(this, "emitHistory");
|
|
10074
|
+
__publicField(this, "posthogCapture");
|
|
10075
|
+
__publicField(this, "testMode");
|
|
10076
|
+
var _a2, _b, _c, _d, _e;
|
|
9106
10077
|
this.maxHistorySize = (_a2 = options.maxHistorySize) != null ? _a2 : 100;
|
|
10078
|
+
this.debug = (_b = options.debug) != null ? _b : false;
|
|
10079
|
+
this.emitHistory = (_c = options.history) != null ? _c : null;
|
|
10080
|
+
this.posthogCapture = (_d = options.posthogCapture) != null ? _d : null;
|
|
10081
|
+
this.testMode = (_e = options.testMode) != null ? _e : false;
|
|
9107
10082
|
}
|
|
9108
10083
|
/**
|
|
9109
10084
|
* Subscribe to events matching an optional filter.
|
|
@@ -9156,6 +10131,83 @@ var EventBus = class {
|
|
|
9156
10131
|
}
|
|
9157
10132
|
}
|
|
9158
10133
|
}
|
|
10134
|
+
/**
|
|
10135
|
+
* Emit a validated custom event from the host application.
|
|
10136
|
+
*
|
|
10137
|
+
* Custom events must use the `app:` prefix (e.g. `app:cart:abandoned`).
|
|
10138
|
+
* In debug mode, returns an EmitResult with delivery details.
|
|
10139
|
+
* In production mode, returns undefined.
|
|
10140
|
+
*/
|
|
10141
|
+
emit(name, props) {
|
|
10142
|
+
const nameResult = validateEventName(name);
|
|
10143
|
+
if (!nameResult.valid) {
|
|
10144
|
+
console.warn(`[EventBus] emit() rejected: ${nameResult.reason}`);
|
|
10145
|
+
return this.debug ? { delivered: false, matchedRules: [], posthogCaptured: false, listenersNotified: 0 } : void 0;
|
|
10146
|
+
}
|
|
10147
|
+
const propsResult = validateProps(props);
|
|
10148
|
+
if (!propsResult.valid) {
|
|
10149
|
+
console.warn(`[EventBus] emit() rejected props: ${propsResult.reason}`);
|
|
10150
|
+
return this.debug ? { delivered: false, matchedRules: [], posthogCaptured: false, listenersNotified: 0 } : void 0;
|
|
10151
|
+
}
|
|
10152
|
+
const event = {
|
|
10153
|
+
ts: Date.now(),
|
|
10154
|
+
name,
|
|
10155
|
+
source: "custom",
|
|
10156
|
+
props,
|
|
10157
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
10158
|
+
};
|
|
10159
|
+
this.history.push(event);
|
|
10160
|
+
if (this.history.length > this.maxHistorySize) {
|
|
10161
|
+
this.history.shift();
|
|
10162
|
+
}
|
|
10163
|
+
let listenersNotified = 0;
|
|
10164
|
+
for (const subscription of this.subscriptions) {
|
|
10165
|
+
if (matchesFilter(event, subscription.filter)) {
|
|
10166
|
+
try {
|
|
10167
|
+
subscription.callback(event);
|
|
10168
|
+
listenersNotified++;
|
|
10169
|
+
} catch (err) {
|
|
10170
|
+
console.error("[EventBus] Subscriber error:", err);
|
|
10171
|
+
listenersNotified++;
|
|
10172
|
+
}
|
|
10173
|
+
}
|
|
10174
|
+
}
|
|
10175
|
+
let posthogCaptured = false;
|
|
10176
|
+
if (this.posthogCapture && !this.testMode) {
|
|
10177
|
+
try {
|
|
10178
|
+
this.posthogCapture(name, props);
|
|
10179
|
+
posthogCaptured = true;
|
|
10180
|
+
} catch (err) {
|
|
10181
|
+
console.error("[EventBus] PostHog capture error:", err);
|
|
10182
|
+
}
|
|
10183
|
+
}
|
|
10184
|
+
if (this.emitHistory) {
|
|
10185
|
+
this.emitHistory.record({
|
|
10186
|
+
name,
|
|
10187
|
+
props,
|
|
10188
|
+
source: "custom",
|
|
10189
|
+
timestamp: event.ts,
|
|
10190
|
+
matchedRules: []
|
|
10191
|
+
});
|
|
10192
|
+
}
|
|
10193
|
+
if (this.debug) {
|
|
10194
|
+
console.debug("[EventBus] emit()", { name, props, listenersNotified, posthogCaptured });
|
|
10195
|
+
return {
|
|
10196
|
+
delivered: true,
|
|
10197
|
+
matchedRules: [],
|
|
10198
|
+
posthogCaptured,
|
|
10199
|
+
listenersNotified
|
|
10200
|
+
};
|
|
10201
|
+
}
|
|
10202
|
+
return void 0;
|
|
10203
|
+
}
|
|
10204
|
+
/**
|
|
10205
|
+
* Set the PostHog capture function after construction.
|
|
10206
|
+
* Used by bootstrap to wire PostHog after the EventBus is created.
|
|
10207
|
+
*/
|
|
10208
|
+
setPosthogCapture(fn) {
|
|
10209
|
+
this.posthogCapture = fn;
|
|
10210
|
+
}
|
|
9159
10211
|
/**
|
|
9160
10212
|
* Get recent events matching an optional filter.
|
|
9161
10213
|
*/
|
|
@@ -9206,124 +10258,26 @@ function createEventBus(options = {}) {
|
|
|
9206
10258
|
return new EventBus(options);
|
|
9207
10259
|
}
|
|
9208
10260
|
|
|
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}`;
|
|
10261
|
+
// src/events/history.ts
|
|
10262
|
+
var EventHistory = class {
|
|
10263
|
+
constructor(maxSize = 100) {
|
|
10264
|
+
__publicField(this, "entries", []);
|
|
10265
|
+
__publicField(this, "maxSize");
|
|
10266
|
+
this.maxSize = maxSize;
|
|
9246
10267
|
}
|
|
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();
|
|
10268
|
+
record(entry) {
|
|
10269
|
+
this.entries.push(entry);
|
|
10270
|
+
if (this.maxSize > 0 && this.entries.length > this.maxSize) {
|
|
10271
|
+
this.entries.shift();
|
|
10272
|
+
}
|
|
9280
10273
|
}
|
|
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;
|
|
10274
|
+
getAll() {
|
|
10275
|
+
return [...this.entries];
|
|
9310
10276
|
}
|
|
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
|
-
}
|
|
10277
|
+
clear() {
|
|
10278
|
+
this.entries = [];
|
|
10279
|
+
}
|
|
10280
|
+
};
|
|
9327
10281
|
|
|
9328
10282
|
// src/navigation/NavigationMonitor.ts
|
|
9329
10283
|
var NavigationMonitor = class {
|
|
@@ -10124,9 +11078,18 @@ function createSurfaces(options) {
|
|
|
10124
11078
|
}
|
|
10125
11079
|
async function unmountEntry(entry) {
|
|
10126
11080
|
var _a2;
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
11081
|
+
if (entry.container.isConnected) {
|
|
11082
|
+
await playExitAnimation(entry.container, entry.options.animation);
|
|
11083
|
+
}
|
|
11084
|
+
try {
|
|
11085
|
+
(_a2 = entry.cleanup) == null ? void 0 : _a2.call(entry);
|
|
11086
|
+
} catch (error2) {
|
|
11087
|
+
console.warn("[Surfaces] Cleanup error during unmount, ignoring:", error2);
|
|
11088
|
+
}
|
|
11089
|
+
try {
|
|
11090
|
+
entry.container.remove();
|
|
11091
|
+
} catch {
|
|
11092
|
+
}
|
|
10130
11093
|
mounts.delete(entry.slot);
|
|
10131
11094
|
publishEvent("surface.unmounted", {
|
|
10132
11095
|
slot: entry.slot,
|
|
@@ -10309,7 +11272,9 @@ var WidgetRegistry = class {
|
|
|
10309
11272
|
var _a2;
|
|
10310
11273
|
const mounted = this.mountedWidgets.get(mountId);
|
|
10311
11274
|
if (mounted) {
|
|
10312
|
-
(
|
|
11275
|
+
if (container.isConnected) {
|
|
11276
|
+
(_a2 = mounted.cleanup) == null ? void 0 : _a2.call(mounted);
|
|
11277
|
+
}
|
|
10313
11278
|
this.mountedWidgets.delete(mountId);
|
|
10314
11279
|
container.removeAttribute("data-widget-mount-id");
|
|
10315
11280
|
container.removeAttribute("data-widget-id");
|
|
@@ -10425,7 +11390,16 @@ function matchesAnchorRoute(anchorId) {
|
|
|
10425
11390
|
const pathname = typeof window !== "undefined" ? window.location.pathname : "/";
|
|
10426
11391
|
const normalizedPath = pathname.replace(/\/$/, "") || "/";
|
|
10427
11392
|
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
10428
|
-
return routes.some((pattern) =>
|
|
11393
|
+
return routes.some((pattern) => {
|
|
11394
|
+
let normalized = pattern;
|
|
11395
|
+
if (/^https?:\/\//.test(normalized)) {
|
|
11396
|
+
try {
|
|
11397
|
+
normalized = new URL(normalized).pathname;
|
|
11398
|
+
} catch {
|
|
11399
|
+
}
|
|
11400
|
+
}
|
|
11401
|
+
return matchRoutePattern(normalizedPath, normalized);
|
|
11402
|
+
});
|
|
10429
11403
|
}
|
|
10430
11404
|
function createSmartCanvasRuntime(options = {}) {
|
|
10431
11405
|
var _a2, _b, _c, _d;
|
|
@@ -10597,6 +11571,142 @@ function encodeToken(payload) {
|
|
|
10597
11571
|
return TOKEN_PREFIX + base64;
|
|
10598
11572
|
}
|
|
10599
11573
|
|
|
11574
|
+
// src/bootstrap-init.ts
|
|
11575
|
+
function getEnvVar(name) {
|
|
11576
|
+
if (typeof process !== "undefined" && process.env) {
|
|
11577
|
+
return process.env[name];
|
|
11578
|
+
}
|
|
11579
|
+
try {
|
|
11580
|
+
const meta = (0, eval)("import.meta");
|
|
11581
|
+
if (meta == null ? void 0 : meta.env) {
|
|
11582
|
+
return meta.env[name];
|
|
11583
|
+
}
|
|
11584
|
+
} catch {
|
|
11585
|
+
}
|
|
11586
|
+
return void 0;
|
|
11587
|
+
}
|
|
11588
|
+
var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
|
|
11589
|
+
function loadCachedSegmentAttributes() {
|
|
11590
|
+
if (typeof window === "undefined") return {};
|
|
11591
|
+
try {
|
|
11592
|
+
const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
|
|
11593
|
+
if (cached) {
|
|
11594
|
+
const attrs = JSON.parse(cached);
|
|
11595
|
+
debug("Syntro Bootstrap", "Loaded cached segment attributes:", attrs);
|
|
11596
|
+
return attrs;
|
|
11597
|
+
}
|
|
11598
|
+
} catch (err) {
|
|
11599
|
+
warn("Syntro Bootstrap", "Failed to load cached segment attributes:", err);
|
|
11600
|
+
}
|
|
11601
|
+
return {};
|
|
11602
|
+
}
|
|
11603
|
+
function cacheSegmentAttributes(attrs) {
|
|
11604
|
+
if (typeof window === "undefined") return;
|
|
11605
|
+
try {
|
|
11606
|
+
localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
|
|
11607
|
+
debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
|
|
11608
|
+
} catch (err) {
|
|
11609
|
+
warn("Syntro Bootstrap", "Failed to cache segment attributes:", err);
|
|
11610
|
+
}
|
|
11611
|
+
}
|
|
11612
|
+
function extractSegmentFlags(allFlags) {
|
|
11613
|
+
if (!allFlags) return {};
|
|
11614
|
+
const segmentFlags = {};
|
|
11615
|
+
for (const [key, value] of Object.entries(allFlags)) {
|
|
11616
|
+
if (key.startsWith("in_segment_")) {
|
|
11617
|
+
segmentFlags[key] = value === true;
|
|
11618
|
+
}
|
|
11619
|
+
}
|
|
11620
|
+
return segmentFlags;
|
|
11621
|
+
}
|
|
11622
|
+
function collectBrowserMetadata() {
|
|
11623
|
+
var _a2;
|
|
11624
|
+
if (typeof window === "undefined") return {};
|
|
11625
|
+
const attrs = {};
|
|
11626
|
+
try {
|
|
11627
|
+
const params = new URLSearchParams(window.location.search);
|
|
11628
|
+
for (const key of ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]) {
|
|
11629
|
+
const val = params.get(key);
|
|
11630
|
+
if (val) attrs[key] = val;
|
|
11631
|
+
}
|
|
11632
|
+
} catch {
|
|
11633
|
+
}
|
|
11634
|
+
try {
|
|
11635
|
+
if (navigator.language) attrs.browser_language = navigator.language;
|
|
11636
|
+
if ((_a2 = navigator.languages) == null ? void 0 : _a2.length) attrs.browser_languages = [...navigator.languages];
|
|
11637
|
+
} catch {
|
|
11638
|
+
}
|
|
11639
|
+
try {
|
|
11640
|
+
const w = window.innerWidth;
|
|
11641
|
+
attrs.device_type = w < 768 ? "mobile" : w < 1024 ? "tablet" : "desktop";
|
|
11642
|
+
} catch {
|
|
11643
|
+
}
|
|
11644
|
+
try {
|
|
11645
|
+
if (document.referrer) {
|
|
11646
|
+
attrs.referrer = document.referrer;
|
|
11647
|
+
try {
|
|
11648
|
+
attrs.referrer_hostname = new URL(document.referrer).hostname;
|
|
11649
|
+
} catch {
|
|
11650
|
+
}
|
|
11651
|
+
}
|
|
11652
|
+
} catch {
|
|
11653
|
+
}
|
|
11654
|
+
try {
|
|
11655
|
+
const ua = navigator.userAgent;
|
|
11656
|
+
if (ua.includes("Edg/")) attrs.browser = "Edge";
|
|
11657
|
+
else if (ua.includes("OPR/") || ua.includes("Opera")) attrs.browser = "Opera";
|
|
11658
|
+
else if (ua.includes("Chrome/") && !ua.includes("Chromium")) attrs.browser = "Chrome";
|
|
11659
|
+
else if (ua.includes("Safari/") && !ua.includes("Chrome")) attrs.browser = "Safari";
|
|
11660
|
+
else if (ua.includes("Firefox/")) attrs.browser = "Firefox";
|
|
11661
|
+
if (ua.includes("Windows")) attrs.os = "Windows";
|
|
11662
|
+
else if (ua.includes("iPhone") || ua.includes("iPad")) attrs.os = "iOS";
|
|
11663
|
+
else if (ua.includes("Mac OS X") || ua.includes("Macintosh")) attrs.os = "macOS";
|
|
11664
|
+
else if (ua.includes("Android")) attrs.os = "Android";
|
|
11665
|
+
else if (ua.includes("Linux")) attrs.os = "Linux";
|
|
11666
|
+
} catch {
|
|
11667
|
+
}
|
|
11668
|
+
try {
|
|
11669
|
+
attrs.page_url = window.location.href;
|
|
11670
|
+
attrs.page_path = window.location.pathname;
|
|
11671
|
+
attrs.page_host = window.location.hostname;
|
|
11672
|
+
if (window.location.search) attrs.page_query = window.location.search;
|
|
11673
|
+
} catch {
|
|
11674
|
+
}
|
|
11675
|
+
return attrs;
|
|
11676
|
+
}
|
|
11677
|
+
var GEO_CACHE_KEY = "syntro_geo";
|
|
11678
|
+
var GEO_DEFAULT_HOST = "https://geo.syntrologie.com";
|
|
11679
|
+
async function fetchGeo(geoHost) {
|
|
11680
|
+
if (typeof window === "undefined") return {};
|
|
11681
|
+
try {
|
|
11682
|
+
const cached = localStorage.getItem(GEO_CACHE_KEY);
|
|
11683
|
+
if (cached) {
|
|
11684
|
+
const parsed = JSON.parse(cached);
|
|
11685
|
+
debug("Syntro Bootstrap", "Geo: using cached data:", parsed);
|
|
11686
|
+
return parsed;
|
|
11687
|
+
}
|
|
11688
|
+
} catch {
|
|
11689
|
+
}
|
|
11690
|
+
try {
|
|
11691
|
+
const res = await fetch(geoHost, { signal: AbortSignal.timeout(2e3) });
|
|
11692
|
+
if (res.ok) {
|
|
11693
|
+
const geo = await res.json();
|
|
11694
|
+
const cleaned = {};
|
|
11695
|
+
for (const [k, v] of Object.entries(geo)) {
|
|
11696
|
+
if (typeof v === "string" && v) cleaned[k] = v;
|
|
11697
|
+
}
|
|
11698
|
+
try {
|
|
11699
|
+
localStorage.setItem(GEO_CACHE_KEY, JSON.stringify(cleaned));
|
|
11700
|
+
} catch {
|
|
11701
|
+
}
|
|
11702
|
+
debug("Syntro Bootstrap", "Geo: fetched from worker:", cleaned);
|
|
11703
|
+
return cleaned;
|
|
11704
|
+
}
|
|
11705
|
+
} catch {
|
|
11706
|
+
}
|
|
11707
|
+
return {};
|
|
11708
|
+
}
|
|
11709
|
+
|
|
10600
11710
|
// src/experiments/registry.ts
|
|
10601
11711
|
var adapters = {
|
|
10602
11712
|
growthbook: (config) => createGrowthBookClient({
|
|
@@ -10703,9 +11813,8 @@ var ExperimentsFetcher = class {
|
|
|
10703
11813
|
__publicField(this, "featureKey");
|
|
10704
11814
|
__publicField(this, "manifestKey");
|
|
10705
11815
|
__publicField(this, "variantFlagPrefix");
|
|
10706
|
-
var _a2;
|
|
10707
11816
|
this.client = options.client;
|
|
10708
|
-
this.featureKey =
|
|
11817
|
+
this.featureKey = options.featureKey;
|
|
10709
11818
|
this.manifestKey = options.manifestKey;
|
|
10710
11819
|
this.variantFlagPrefix = options.variantFlagPrefix;
|
|
10711
11820
|
}
|
|
@@ -10734,6 +11843,11 @@ var ExperimentsFetcher = class {
|
|
|
10734
11843
|
};
|
|
10735
11844
|
}
|
|
10736
11845
|
}
|
|
11846
|
+
if (!this.featureKey) {
|
|
11847
|
+
throw new Error(
|
|
11848
|
+
"[SmartCanvas] No featureKey configured and no variant flags found. Ensure at least one config feature flag exists in your experiment platform."
|
|
11849
|
+
);
|
|
11850
|
+
}
|
|
10737
11851
|
const config = (_b = (_a2 = this.client).getFeatureValue) == null ? void 0 : _b.call(_a2, this.featureKey, null);
|
|
10738
11852
|
if (!config || typeof config !== "object") {
|
|
10739
11853
|
throw new Error(
|
|
@@ -10845,95 +11959,9 @@ function createTelemetryClient(provider, config) {
|
|
|
10845
11959
|
return factory(config);
|
|
10846
11960
|
}
|
|
10847
11961
|
|
|
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;
|
|
11962
|
+
// src/bootstrap-runtime.ts
|
|
11963
|
+
async function _initCore(options) {
|
|
11964
|
+
var _a2, _b, _c, _d, _e, _f, _g;
|
|
10937
11965
|
initLogger();
|
|
10938
11966
|
debug("Syntro Bootstrap", "====== INIT ======");
|
|
10939
11967
|
debug("Syntro Bootstrap", "Options:", {
|
|
@@ -10998,17 +12026,59 @@ async function init(options) {
|
|
|
10998
12026
|
const experimentHost = getEnvVar("NEXT_PUBLIC_SYNTRO_EXPERIMENT_HOST") || getEnvVar("VITE_SYNTRO_EXPERIMENT_HOST") || (payload == null ? void 0 : payload.eh);
|
|
10999
12027
|
const telemetryHost = getEnvVar("NEXT_PUBLIC_SYNTRO_TELEMETRY_HOST") || getEnvVar("VITE_SYNTRO_TELEMETRY_HOST") || (payload == null ? void 0 : payload.th);
|
|
11000
12028
|
const editorUrl = getEnvVar("NEXT_PUBLIC_SYNTRO_EDITOR_URL") || getEnvVar("VITE_SYNTRO_EDITOR_URL") || ((_b = options.canvas) == null ? void 0 : _b.editorUrl);
|
|
12029
|
+
const geoHost = (payload == null ? void 0 : payload.g) || getEnvVar("NEXT_PUBLIC_SYNTRO_GEO_HOST") || getEnvVar("VITE_SYNTRO_GEO_HOST") || GEO_DEFAULT_HOST;
|
|
11001
12030
|
const cachedSegmentAttrs = loadCachedSegmentAttributes();
|
|
11002
12031
|
const browserMetadata = collectBrowserMetadata();
|
|
11003
12032
|
const phaseOneAttrs = { ...browserMetadata, ...cachedSegmentAttrs };
|
|
11004
12033
|
debug("Syntro Bootstrap", "Phase 1: Browser metadata:", browserMetadata);
|
|
11005
12034
|
debug("Syntro Bootstrap", "Phase 1: Cached segment attributes:", cachedSegmentAttrs);
|
|
12035
|
+
const geoPromise = fetchGeo(geoHost);
|
|
11006
12036
|
let experiments;
|
|
11007
|
-
const
|
|
12037
|
+
const isDebugOrTest = options.debug || options.testMode;
|
|
12038
|
+
const events = createEventBus({
|
|
12039
|
+
debug: options.debug,
|
|
12040
|
+
history: isDebugOrTest ? new EventHistory(options.testMode ? 0 : 100) : void 0,
|
|
12041
|
+
testMode: options.testMode
|
|
12042
|
+
});
|
|
11008
12043
|
console.log("[Syntro Bootstrap] EventBus created");
|
|
11009
|
-
const
|
|
11010
|
-
|
|
12044
|
+
const processor = createEventProcessor({
|
|
12045
|
+
elementResolver: typeof window !== "undefined" ? (x, y) => {
|
|
12046
|
+
const el = document.elementFromPoint(x, y);
|
|
12047
|
+
if (!el) return null;
|
|
12048
|
+
const info = { tag_name: el.tagName.toLowerCase() };
|
|
12049
|
+
if (el.id) info.attr__id = el.id;
|
|
12050
|
+
if (el.className && typeof el.className === "string") {
|
|
12051
|
+
info.classes = el.className.split(" ").filter(Boolean);
|
|
12052
|
+
}
|
|
12053
|
+
for (const attr of el.attributes) {
|
|
12054
|
+
if (attr.name.startsWith("data-")) info[`attr__${attr.name}`] = attr.value;
|
|
12055
|
+
}
|
|
12056
|
+
return info;
|
|
12057
|
+
} : void 0
|
|
11011
12058
|
});
|
|
12059
|
+
processor.onEvent((event) => events.publishEvent(event));
|
|
12060
|
+
if (typeof window !== "undefined") {
|
|
12061
|
+
setInterval(() => processor.tick(Date.now()), 1e3);
|
|
12062
|
+
document.addEventListener(
|
|
12063
|
+
"click",
|
|
12064
|
+
(e) => {
|
|
12065
|
+
const chain = [];
|
|
12066
|
+
let el = e.target;
|
|
12067
|
+
while (el && el !== document.body) {
|
|
12068
|
+
const info = { tag_name: el.tagName.toLowerCase() };
|
|
12069
|
+
for (const attr of el.attributes) {
|
|
12070
|
+
if (attr.name.startsWith("data-") || attr.name === "id" || attr.name === "class" || attr.name === "aria-label") {
|
|
12071
|
+
info[`attr__${attr.name}`] = attr.value;
|
|
12072
|
+
}
|
|
12073
|
+
}
|
|
12074
|
+
chain.push(info);
|
|
12075
|
+
el = el.parentElement;
|
|
12076
|
+
}
|
|
12077
|
+
processor.enrichClickAttributes(Date.now(), chain);
|
|
12078
|
+
},
|
|
12079
|
+
true
|
|
12080
|
+
);
|
|
12081
|
+
}
|
|
11012
12082
|
const onFeatureFlagsLoaded = (allFlags) => {
|
|
11013
12083
|
var _a3, _b2, _c2;
|
|
11014
12084
|
debug("Syntro Bootstrap", "Phase 2: PostHog feature flags loaded");
|
|
@@ -11031,12 +12101,26 @@ async function init(options) {
|
|
|
11031
12101
|
// undefined falls back to adapter default
|
|
11032
12102
|
// Enable PostHog feature flags for segment membership
|
|
11033
12103
|
enableFeatureFlags: true,
|
|
12104
|
+
// Disable session recording in debug/dev mode (mock telemetry doesn't
|
|
12105
|
+
// support the PostHog recorder extension, causing console errors)
|
|
12106
|
+
sessionRecording: !payload.d,
|
|
11034
12107
|
// Wire up callback for when flags are loaded (Phase 2)
|
|
11035
12108
|
onFeatureFlagsLoaded,
|
|
11036
|
-
// Wire up event capture to feed into
|
|
11037
|
-
onCapture:
|
|
12109
|
+
// Wire up event capture to feed into event processor
|
|
12110
|
+
onCapture: (eventName, properties) => {
|
|
12111
|
+
processor.ingest({ kind: "posthog", event: eventName, properties, timestamp: Date.now() });
|
|
12112
|
+
},
|
|
12113
|
+
// Wire rrweb events for behavioral signal detection
|
|
12114
|
+
onRRWebEvent: (event) => {
|
|
12115
|
+
processor.ingest(event);
|
|
12116
|
+
}
|
|
11038
12117
|
});
|
|
11039
12118
|
console.log(`[Syntro Bootstrap] Telemetry client created (${provider}) with EventBus wiring`);
|
|
12119
|
+
const telemetryForCapture = telemetry;
|
|
12120
|
+
events.setPosthogCapture((name, props) => {
|
|
12121
|
+
var _a3;
|
|
12122
|
+
(_a3 = telemetryForCapture.track) == null ? void 0 : _a3.call(telemetryForCapture, name, props);
|
|
12123
|
+
});
|
|
11040
12124
|
}
|
|
11041
12125
|
let sessionMetrics;
|
|
11042
12126
|
if (payload == null ? void 0 : payload.e) {
|
|
@@ -11129,11 +12213,17 @@ async function init(options) {
|
|
|
11129
12213
|
warn("Syntro Bootstrap", "Failed to load GrowthBook features:", err);
|
|
11130
12214
|
}
|
|
11131
12215
|
}
|
|
12216
|
+
const geoData = await geoPromise;
|
|
12217
|
+
if (experiments && Object.keys(geoData).length > 0) {
|
|
12218
|
+
const mergedAttrs = { ...browserMetadata, ...geoData };
|
|
12219
|
+
debug("Syntro Bootstrap", "Merging geo data into GrowthBook attributes:", geoData);
|
|
12220
|
+
(_f = experiments.setAttributes) == null ? void 0 : _f.call(experiments, mergedAttrs);
|
|
12221
|
+
}
|
|
11132
12222
|
let baseFetcher;
|
|
11133
12223
|
if (options.fetcher) {
|
|
11134
12224
|
baseFetcher = options.fetcher;
|
|
11135
12225
|
} else if (payload == null ? void 0 : payload.f) {
|
|
11136
|
-
const configFetcher = createConfigFetcher(payload.f, (
|
|
12226
|
+
const configFetcher = createConfigFetcher(payload.f, (_g = payload.o) != null ? _g : {});
|
|
11137
12227
|
baseFetcher = async () => {
|
|
11138
12228
|
var _a3;
|
|
11139
12229
|
const result = await configFetcher.fetch();
|
|
@@ -11147,19 +12237,39 @@ async function init(options) {
|
|
|
11147
12237
|
}
|
|
11148
12238
|
const warnedAppFailures = /* @__PURE__ */ new Set();
|
|
11149
12239
|
const appLoadingFetcher = baseFetcher ? async () => {
|
|
11150
|
-
var _a3, _b2, _c2, _d2, _e2, _f2,
|
|
12240
|
+
var _a3, _b2, _c2, _d2, _e2, _f2, _g2, _h, _i, _j, _k, _l;
|
|
11151
12241
|
const config = await baseFetcher();
|
|
12242
|
+
const tileCount = (_b2 = (_a3 = config.tiles) == null ? void 0 : _a3.length) != null ? _b2 : 0;
|
|
12243
|
+
const actionCount = (_d2 = (_c2 = config.actions) == null ? void 0 : _c2.length) != null ? _d2 : 0;
|
|
12244
|
+
const variantId = (_e2 = config.meta) == null ? void 0 : _e2.variant_id;
|
|
12245
|
+
if (tileCount > 0 || actionCount > 0) {
|
|
12246
|
+
if (!variantId) {
|
|
12247
|
+
console.warn(
|
|
12248
|
+
"[Syntro] Config has content but no meta.variant_id \u2014 intervention tracking disabled"
|
|
12249
|
+
);
|
|
12250
|
+
}
|
|
12251
|
+
}
|
|
12252
|
+
if (telemetry && variantId) {
|
|
12253
|
+
const tracker = new InterventionTracker(telemetry, variantId);
|
|
12254
|
+
tracker.trackServed(tileCount, actionCount);
|
|
12255
|
+
if (typeof window !== "undefined") {
|
|
12256
|
+
window.SynOS.interventionTracker = tracker;
|
|
12257
|
+
}
|
|
12258
|
+
runtime3.navigation.subscribe(() => {
|
|
12259
|
+
tracker.resetPage();
|
|
12260
|
+
});
|
|
12261
|
+
}
|
|
11152
12262
|
console.log(
|
|
11153
12263
|
"[Syntro Bootstrap] Config fetched:",
|
|
11154
|
-
`tiles=${(
|
|
11155
|
-
`actions=${(
|
|
11156
|
-
`theme=${(
|
|
12264
|
+
`tiles=${(_g2 = (_f2 = config.tiles) == null ? void 0 : _f2.length) != null ? _g2 : 0},`,
|
|
12265
|
+
`actions=${(_i = (_h = config.actions) == null ? void 0 : _h.length) != null ? _i : 0},`,
|
|
12266
|
+
`theme=${(_k = (_j = config.theme) == null ? void 0 : _j.name) != null ? _k : "none"}`
|
|
11157
12267
|
);
|
|
11158
|
-
if (((
|
|
12268
|
+
if (((_l = config.actions) == null ? void 0 : _l.length) > 0) {
|
|
11159
12269
|
console.log(
|
|
11160
12270
|
"[Syntro Bootstrap] Actions in config:",
|
|
11161
12271
|
config.actions.map(
|
|
11162
|
-
(a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${
|
|
12272
|
+
(a, i) => `[${i}] ${a.kind}${a.anchorId ? ` anchor="${a.anchorId.selector}"` : ""}${a.label ? ` "${a.label}"` : ""}`
|
|
11163
12273
|
).join(", ")
|
|
11164
12274
|
);
|
|
11165
12275
|
}
|
|
@@ -11218,10 +12328,33 @@ async function init(options) {
|
|
|
11218
12328
|
});
|
|
11219
12329
|
return { canvas, runtime: runtime3, experiments, telemetry, sessionMetrics, appLoader };
|
|
11220
12330
|
}
|
|
12331
|
+
|
|
12332
|
+
// src/bootstrap.ts
|
|
12333
|
+
async function init(options) {
|
|
12334
|
+
var _a2;
|
|
12335
|
+
try {
|
|
12336
|
+
return await _initCore(options);
|
|
12337
|
+
} catch (err) {
|
|
12338
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12339
|
+
console.warn("[Syntrologie] SDK initialization failed:", message);
|
|
12340
|
+
if (typeof document !== "undefined") {
|
|
12341
|
+
(_a2 = document.getElementById("syntrologie-anti-flicker")) == null ? void 0 : _a2.remove();
|
|
12342
|
+
}
|
|
12343
|
+
return void 0;
|
|
12344
|
+
}
|
|
12345
|
+
}
|
|
12346
|
+
function emit(eventName, props = {}) {
|
|
12347
|
+
var _a2, _b;
|
|
12348
|
+
if (typeof window === "undefined") return;
|
|
12349
|
+
const runtime3 = (_a2 = window.SynOS) == null ? void 0 : _a2.runtime;
|
|
12350
|
+
if (!((_b = runtime3 == null ? void 0 : runtime3.events) == null ? void 0 : _b.publish)) return;
|
|
12351
|
+
runtime3.events.publish({ name: eventName, source: "custom", props });
|
|
12352
|
+
}
|
|
11221
12353
|
var Syntro = {
|
|
11222
12354
|
init,
|
|
11223
12355
|
encodeToken,
|
|
11224
|
-
decodeToken
|
|
12356
|
+
decodeToken,
|
|
12357
|
+
events: { emit }
|
|
11225
12358
|
};
|
|
11226
12359
|
if (typeof window !== "undefined") {
|
|
11227
12360
|
window.Syntro = Syntro;
|
|
@@ -11252,8 +12385,11 @@ export {
|
|
|
11252
12385
|
createSmartCanvasController,
|
|
11253
12386
|
ShadowRootProvider,
|
|
11254
12387
|
useShadowRoot,
|
|
11255
|
-
StandardEvents,
|
|
11256
12388
|
EVENT_SCHEMA_VERSION,
|
|
12389
|
+
normalizePostHogEvent,
|
|
12390
|
+
shouldNormalizeEvent,
|
|
12391
|
+
createPostHogNormalizer,
|
|
12392
|
+
StandardEvents2 as StandardEvents,
|
|
11257
12393
|
CanvasEvents,
|
|
11258
12394
|
NotificationToastStack,
|
|
11259
12395
|
MAX_VISIBLE_TOASTS,
|
|
@@ -11284,6 +12420,7 @@ export {
|
|
|
11284
12420
|
createSessionMetricTracker,
|
|
11285
12421
|
createNoopClient,
|
|
11286
12422
|
createPostHogClient,
|
|
12423
|
+
InterventionTracker,
|
|
11287
12424
|
ExecutorRegistry,
|
|
11288
12425
|
executorRegistry,
|
|
11289
12426
|
getExecutor,
|
|
@@ -11302,11 +12439,11 @@ export {
|
|
|
11302
12439
|
evaluateSync,
|
|
11303
12440
|
createDecisionEngine,
|
|
11304
12441
|
createEventAccumulator,
|
|
12442
|
+
validateEventName,
|
|
12443
|
+
validateProps,
|
|
11305
12444
|
EventBus,
|
|
11306
12445
|
createEventBus,
|
|
11307
|
-
|
|
11308
|
-
shouldNormalizeEvent,
|
|
11309
|
-
createPostHogNormalizer,
|
|
12446
|
+
EventHistory,
|
|
11310
12447
|
NavigationMonitor,
|
|
11311
12448
|
StateStore,
|
|
11312
12449
|
createStateStore,
|
|
@@ -11330,4 +12467,4 @@ export {
|
|
|
11330
12467
|
encodeToken,
|
|
11331
12468
|
Syntro
|
|
11332
12469
|
};
|
|
11333
|
-
//# sourceMappingURL=chunk-
|
|
12470
|
+
//# sourceMappingURL=chunk-EELCEGS7.js.map
|