@syntrologie/runtime-sdk 2.8.0-canary.9 → 2.8.0-canary.90
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 +291 -181
- package/README.md +3 -0
- package/dist/actions/schema.d.ts +783 -783
- package/dist/actions/schema.js +3 -3
- package/dist/actions/types.d.ts +3 -3
- 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/anchor/AnchorResolver.d.ts +1 -0
- package/dist/bootstrap-init.d.ts +33 -0
- package/dist/bootstrap-runtime.d.ts +7 -0
- package/dist/bootstrap-types.d.ts +101 -0
- package/dist/bootstrap.d.ts +19 -83
- package/dist/{chunk-R5DNAIRI.js → chunk-77TNZ66J.js} +4 -4
- package/dist/{chunk-R5DNAIRI.js.map → chunk-77TNZ66J.js.map} +2 -2
- package/dist/{chunk-XDYJ64IN.js → chunk-IR6UOR63.js} +4 -4
- package/dist/chunk-IR6UOR63.js.map +7 -0
- package/dist/{chunk-UURRUKSW.js → chunk-TOBT6CVT.js} +1917 -725
- package/dist/chunk-TOBT6CVT.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 +1198 -2035
- 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 +104 -109
- package/dist/smart-canvas.esm.js.map +4 -4
- package/dist/smart-canvas.js +6277 -5463
- package/dist/smart-canvas.js.map +4 -4
- package/dist/smart-canvas.min.js +104 -109
- 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 +2369 -11366
- 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-UURRUKSW.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],
|
|
@@ -1642,8 +1681,14 @@ function showHighlight(anchorEl, overlayRoot, opts) {
|
|
|
1642
1681
|
scrim.style.pointerEvents = "none";
|
|
1643
1682
|
scrim.style.opacity = "0";
|
|
1644
1683
|
setTimeout(() => {
|
|
1645
|
-
|
|
1646
|
-
|
|
1684
|
+
try {
|
|
1685
|
+
scrim.remove();
|
|
1686
|
+
} catch {
|
|
1687
|
+
}
|
|
1688
|
+
try {
|
|
1689
|
+
ring.remove();
|
|
1690
|
+
} catch {
|
|
1691
|
+
}
|
|
1647
1692
|
}, 220);
|
|
1648
1693
|
}
|
|
1649
1694
|
};
|
|
@@ -1671,7 +1716,16 @@ var ALLOWED_TAGS2 = /* @__PURE__ */ new Set([
|
|
|
1671
1716
|
"sup",
|
|
1672
1717
|
"sub",
|
|
1673
1718
|
"a",
|
|
1674
|
-
"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"
|
|
1675
1729
|
]);
|
|
1676
1730
|
function sanitizeHtml2(html) {
|
|
1677
1731
|
var _a2;
|
|
@@ -1880,8 +1934,14 @@ var executeModal = async (action, context) => {
|
|
|
1880
1934
|
modal2.style.transform = "translate(-50%, -50%) scale(0.95)";
|
|
1881
1935
|
scrimEl.style.opacity = "0";
|
|
1882
1936
|
setTimeout(() => {
|
|
1883
|
-
|
|
1884
|
-
|
|
1937
|
+
try {
|
|
1938
|
+
modal2.remove();
|
|
1939
|
+
} catch {
|
|
1940
|
+
}
|
|
1941
|
+
try {
|
|
1942
|
+
scrimEl.remove();
|
|
1943
|
+
} catch {
|
|
1944
|
+
}
|
|
1885
1945
|
}, 200);
|
|
1886
1946
|
context.publishEvent("action.modal_dismissed", {
|
|
1887
1947
|
actionClicked
|
|
@@ -1928,10 +1988,12 @@ function getAnchorReference(anchorEl) {
|
|
|
1928
1988
|
}
|
|
1929
1989
|
function showTooltip(anchorEl, overlayRoot, opts) {
|
|
1930
1990
|
var _a2;
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
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
|
+
}
|
|
1935
1997
|
}
|
|
1936
1998
|
const div = document.createElement("div");
|
|
1937
1999
|
div.className = "syntro-tooltip";
|
|
@@ -2141,7 +2203,12 @@ function showTooltip(anchorEl, overlayRoot, opts) {
|
|
|
2141
2203
|
}
|
|
2142
2204
|
div.style.pointerEvents = "none";
|
|
2143
2205
|
div.style.opacity = "0";
|
|
2144
|
-
setTimeout(() =>
|
|
2206
|
+
setTimeout(() => {
|
|
2207
|
+
try {
|
|
2208
|
+
div.remove();
|
|
2209
|
+
} catch {
|
|
2210
|
+
}
|
|
2211
|
+
}, 200);
|
|
2145
2212
|
}
|
|
2146
2213
|
};
|
|
2147
2214
|
return handle;
|
|
@@ -2174,7 +2241,7 @@ function WorkflowTracker({ workflows, expanded, onStepClick, onDismiss }) {
|
|
|
2174
2241
|
}
|
|
2175
2242
|
|
|
2176
2243
|
// ../adaptives/adaptive-overlays/dist/WorkflowWidget.js
|
|
2177
|
-
function showWorkflowToast(
|
|
2244
|
+
function showWorkflowToast(notification) {
|
|
2178
2245
|
const toast = document.createElement("div");
|
|
2179
2246
|
toast.setAttribute("data-testid", "workflow-toast");
|
|
2180
2247
|
toast.className = "se-fixed se-bottom-4 se-right-4 se-z-50";
|
|
@@ -2208,7 +2275,7 @@ function showWorkflowToast(container, notification) {
|
|
|
2208
2275
|
bodyEl.textContent = notification.body;
|
|
2209
2276
|
toast.appendChild(bodyEl);
|
|
2210
2277
|
}
|
|
2211
|
-
|
|
2278
|
+
document.body.appendChild(toast);
|
|
2212
2279
|
let removeTimer;
|
|
2213
2280
|
const fadeTimer = setTimeout(() => {
|
|
2214
2281
|
toast.style.opacity = "0";
|
|
@@ -2226,7 +2293,7 @@ function extractWorkflowsFromActive(activeActions) {
|
|
|
2226
2293
|
const workflows = /* @__PURE__ */ new Map();
|
|
2227
2294
|
for (const entry of activeActions) {
|
|
2228
2295
|
const action = entry.action;
|
|
2229
|
-
if (action.kind === "
|
|
2296
|
+
if (action.kind === "overlays:tour" && action.workflow && action.tourId) {
|
|
2230
2297
|
const meta = action.workflow;
|
|
2231
2298
|
const rawSteps = action.steps || [];
|
|
2232
2299
|
const steps = rawSteps.map((s) => {
|
|
@@ -2307,10 +2374,10 @@ function WorkflowWidgetInner({ runtime: runtime3 }) {
|
|
|
2307
2374
|
return newEntries.length > 0 ? [...prev, ...newEntries] : prev;
|
|
2308
2375
|
});
|
|
2309
2376
|
for (const [tourId, { meta }] of tourWorkflows) {
|
|
2310
|
-
if (!notifiedRef.current.has(tourId) && meta.notification &&
|
|
2377
|
+
if (!notifiedRef.current.has(tourId) && meta.notification && !dismissed.includes(tourId) && !completed[tourId]) {
|
|
2311
2378
|
notifiedRef.current.add(tourId);
|
|
2312
2379
|
(_c = stateNs == null ? void 0 : stateNs.set) == null ? void 0 : _c.call(stateNs, "notified", [...notifiedRef.current]);
|
|
2313
|
-
const cleanup = showWorkflowToast(
|
|
2380
|
+
const cleanup = showWorkflowToast(meta.notification);
|
|
2314
2381
|
toastCleanupsRef.current.push(cleanup);
|
|
2315
2382
|
}
|
|
2316
2383
|
}
|
|
@@ -2343,8 +2410,8 @@ function WorkflowWidgetInner({ runtime: runtime3 }) {
|
|
|
2343
2410
|
notifiedRef.current.add(tourId);
|
|
2344
2411
|
(_c = stateNs == null ? void 0 : stateNs.set) == null ? void 0 : _c.call(stateNs, "notified", [...notifiedRef.current]);
|
|
2345
2412
|
const workflow = currentWorkflows.get(tourId);
|
|
2346
|
-
if (
|
|
2347
|
-
const cleanup = showWorkflowToast(
|
|
2413
|
+
if (workflow == null ? void 0 : workflow.meta.notification) {
|
|
2414
|
+
const cleanup = showWorkflowToast(workflow.meta.notification);
|
|
2348
2415
|
toastCleanupsRef.current.push(cleanup);
|
|
2349
2416
|
}
|
|
2350
2417
|
}
|
|
@@ -2488,6 +2555,7 @@ var executeHighlight = async (action, context) => {
|
|
|
2488
2555
|
cleanup: () => {
|
|
2489
2556
|
handle.destroy();
|
|
2490
2557
|
anchorEl.removeAttribute("data-syntro-highlight");
|
|
2558
|
+
anchorEl.removeAttribute("data-syntro-highlight-dismissed");
|
|
2491
2559
|
}
|
|
2492
2560
|
};
|
|
2493
2561
|
};
|
|
@@ -2577,6 +2645,8 @@ var executePulse = async (action, context) => {
|
|
|
2577
2645
|
return {
|
|
2578
2646
|
cleanup: () => {
|
|
2579
2647
|
clearTimeout(timeoutId);
|
|
2648
|
+
if (!anchorEl.isConnected)
|
|
2649
|
+
return;
|
|
2580
2650
|
anchorEl.style.animation = originalAnimation;
|
|
2581
2651
|
anchorEl.removeAttribute("data-syntro-pulse");
|
|
2582
2652
|
}
|
|
@@ -2646,7 +2716,12 @@ var executeBadge = async (action, context) => {
|
|
|
2646
2716
|
});
|
|
2647
2717
|
return {
|
|
2648
2718
|
cleanup: () => {
|
|
2649
|
-
|
|
2719
|
+
try {
|
|
2720
|
+
badge2.remove();
|
|
2721
|
+
} catch {
|
|
2722
|
+
}
|
|
2723
|
+
if (!anchorEl.isConnected)
|
|
2724
|
+
return;
|
|
2650
2725
|
if (originalPosition !== void 0) {
|
|
2651
2726
|
anchorEl.style.position = originalPosition;
|
|
2652
2727
|
}
|
|
@@ -2741,7 +2816,7 @@ var executors2 = [
|
|
|
2741
2816
|
{ kind: "overlays:badge", executor: executeBadge },
|
|
2742
2817
|
{ kind: "overlays:tooltip", executor: executeTooltip },
|
|
2743
2818
|
{ kind: "overlays:modal", executor: executeModal },
|
|
2744
|
-
{ kind: "
|
|
2819
|
+
{ kind: "overlays:tour", executor: executeTour },
|
|
2745
2820
|
{ kind: "overlays:celebrate", executor: executeCelebrate }
|
|
2746
2821
|
];
|
|
2747
2822
|
var runtime2 = {
|
|
@@ -2861,7 +2936,15 @@ var CORE_ACTION_KINDS = /* @__PURE__ */ new Set([
|
|
|
2861
2936
|
"core:wait",
|
|
2862
2937
|
"core:sequence",
|
|
2863
2938
|
"core:parallel",
|
|
2864
|
-
"
|
|
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"
|
|
2865
2948
|
]);
|
|
2866
2949
|
var NAMESPACE_TO_APP_ID = {
|
|
2867
2950
|
faq: "adaptive-faq",
|
|
@@ -3015,6 +3098,9 @@ function createAppLoader(options) {
|
|
|
3015
3098
|
}
|
|
3016
3099
|
}
|
|
3017
3100
|
}
|
|
3101
|
+
for (const bundled of BUNDLED_APP_IDS) {
|
|
3102
|
+
appIds.delete(bundled);
|
|
3103
|
+
}
|
|
3018
3104
|
return Array.from(appIds);
|
|
3019
3105
|
}
|
|
3020
3106
|
async function loadAppsForConfig(config) {
|
|
@@ -3370,14 +3456,20 @@ function getAntiFlickerSnippet(config = {}) {
|
|
|
3370
3456
|
}
|
|
3371
3457
|
|
|
3372
3458
|
// src/version.ts
|
|
3373
|
-
var SDK_VERSION = "2.8.0-canary.
|
|
3459
|
+
var SDK_VERSION = "2.8.0-canary.90";
|
|
3374
3460
|
|
|
3375
3461
|
// src/types.ts
|
|
3376
3462
|
var SDK_SCHEMA_VERSION = "2.0";
|
|
3377
3463
|
|
|
3378
3464
|
// src/fetchers/mergeConfigs.ts
|
|
3379
|
-
function resolveVariantConfigs(client, keys,
|
|
3380
|
-
|
|
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;
|
|
3381
3473
|
for (const key of keys) {
|
|
3382
3474
|
const value = (_a2 = client.getFeatureValue) == null ? void 0 : _a2.call(client, key, null);
|
|
3383
3475
|
if (!value || typeof value !== "object") continue;
|
|
@@ -3385,20 +3477,60 @@ function resolveVariantConfigs(client, keys, _strategy = "first-match") {
|
|
|
3385
3477
|
const hasTiles = variant.tiles && variant.tiles.length > 0;
|
|
3386
3478
|
const hasActions = variant.actions && variant.actions.length > 0;
|
|
3387
3479
|
if (hasTiles || hasActions) {
|
|
3388
|
-
return
|
|
3389
|
-
tiles: (_b = variant.tiles) != null ? _b : [],
|
|
3390
|
-
actions: (_c = variant.actions) != null ? _c : [],
|
|
3391
|
-
fetchedAt: (_d = variant.fetchedAt) != null ? _d : (/* @__PURE__ */ new Date()).toISOString(),
|
|
3392
|
-
...variant.schemaVersion && { schemaVersion: variant.schemaVersion },
|
|
3393
|
-
...variant.configVersion && { configVersion: variant.configVersion },
|
|
3394
|
-
...variant.canvasTitle && { canvasTitle: variant.canvasTitle },
|
|
3395
|
-
...variant.theme && { theme: variant.theme },
|
|
3396
|
-
...variant.launcher && { launcher: variant.launcher }
|
|
3397
|
-
};
|
|
3480
|
+
return buildConfig([variant]);
|
|
3398
3481
|
}
|
|
3399
3482
|
}
|
|
3400
3483
|
return null;
|
|
3401
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
|
+
}
|
|
3402
3534
|
|
|
3403
3535
|
// src/logger.ts
|
|
3404
3536
|
var debugEnabled = false;
|
|
@@ -3521,12 +3653,14 @@ function getCachedConfig(sdkVersion) {
|
|
|
3521
3653
|
var resolveConfigUri = ({
|
|
3522
3654
|
configUri,
|
|
3523
3655
|
experiments,
|
|
3524
|
-
featureKey
|
|
3656
|
+
featureKey
|
|
3525
3657
|
}) => {
|
|
3526
3658
|
var _a2;
|
|
3527
3659
|
if (configUri) return configUri;
|
|
3528
|
-
|
|
3529
|
-
|
|
3660
|
+
if (experiments && featureKey) {
|
|
3661
|
+
const fromFeature = (_a2 = experiments.getFeatureValue) == null ? void 0 : _a2.call(experiments, featureKey, null);
|
|
3662
|
+
if (fromFeature) return fromFeature;
|
|
3663
|
+
}
|
|
3530
3664
|
return void 0;
|
|
3531
3665
|
};
|
|
3532
3666
|
function getVariantFlagKeys(experiments, manifestKey, variantFlagPrefix) {
|
|
@@ -3552,7 +3686,7 @@ var createCanvasConfigFetcher = ({
|
|
|
3552
3686
|
experiments,
|
|
3553
3687
|
featureKey,
|
|
3554
3688
|
credentials,
|
|
3555
|
-
configFeatureKey
|
|
3689
|
+
configFeatureKey,
|
|
3556
3690
|
manifestKey,
|
|
3557
3691
|
variantFlagPrefix,
|
|
3558
3692
|
sdkVersion
|
|
@@ -3653,7 +3787,8 @@ function registerFromTriggerWhen(triggerWhen, accumulator) {
|
|
|
3653
3787
|
if (cond.type === "event_count" && cond.key) {
|
|
3654
3788
|
const counter = cond.counter;
|
|
3655
3789
|
const predicate = counter ? buildPredicate(counter) : () => true;
|
|
3656
|
-
|
|
3790
|
+
const needsTimestamps = typeof cond.withinMs === "number";
|
|
3791
|
+
accumulator.register(cond.key, predicate, needsTimestamps);
|
|
3657
3792
|
}
|
|
3658
3793
|
}
|
|
3659
3794
|
}
|
|
@@ -3746,127 +3881,737 @@ function useShadowRoot() {
|
|
|
3746
3881
|
return ctx;
|
|
3747
3882
|
}
|
|
3748
3883
|
|
|
3749
|
-
//
|
|
3884
|
+
// ../event-processor/dist/types.js
|
|
3885
|
+
var EVENT_SCHEMA_VERSION = "1.0.0";
|
|
3750
3886
|
var StandardEvents = {
|
|
3751
|
-
// UI events (from PostHog autocapture)
|
|
3752
3887
|
UI_CLICK: "ui.click",
|
|
3753
3888
|
UI_SCROLL: "ui.scroll",
|
|
3754
3889
|
UI_INPUT: "ui.input",
|
|
3755
3890
|
UI_CHANGE: "ui.change",
|
|
3756
3891
|
UI_SUBMIT: "ui.submit",
|
|
3757
|
-
// Navigation events
|
|
3758
3892
|
NAV_PAGE_VIEW: "nav.page_view",
|
|
3759
3893
|
NAV_PAGE_LEAVE: "nav.page_leave",
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
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
|
|
3789
3934
|
};
|
|
3790
|
-
var EVENT_SCHEMA_VERSION = "1.0.0";
|
|
3791
3935
|
|
|
3792
|
-
//
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
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.");
|
|
3816
3978
|
}
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
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;
|
|
3822
4008
|
});
|
|
3823
4009
|
}
|
|
3824
|
-
function
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
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;
|
|
3829
4021
|
}
|
|
3830
|
-
function
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
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;
|
|
3835
4055
|
}
|
|
3836
|
-
function
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
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
|
+
};
|
|
3842
4072
|
}
|
|
3843
|
-
function
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
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;
|
|
3849
4097
|
}
|
|
3850
|
-
function
|
|
3851
|
-
|
|
3852
|
-
|
|
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
|
+
};
|
|
3853
4112
|
}
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
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,
|
|
4544
|
+
canvasClosed,
|
|
4545
|
+
tileViewed,
|
|
4546
|
+
tileExpanded,
|
|
4547
|
+
tileCollapsed,
|
|
4548
|
+
tileAction,
|
|
4549
|
+
overlayStarted,
|
|
4550
|
+
overlayCompleted,
|
|
3863
4551
|
overlayDismissed,
|
|
3864
4552
|
overlayStepViewed,
|
|
3865
4553
|
custom: customCanvasEvent
|
|
3866
4554
|
};
|
|
3867
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
|
+
|
|
3868
4613
|
// src/notifications/NotificationToastStack.tsx
|
|
3869
|
-
import { jsx as
|
|
4614
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
3870
4615
|
var TOAST_STYLES_ID = "syntro-toast-styles";
|
|
3871
4616
|
var TOAST_CSS = `
|
|
3872
4617
|
@keyframes syntro-toast-slide-in {
|
|
@@ -3903,7 +4648,7 @@ function NotificationToastStack({
|
|
|
3903
4648
|
const { shadowRoot } = useShadowRoot();
|
|
3904
4649
|
ensureToastStyles(shadowRoot);
|
|
3905
4650
|
if (notifications.length === 0) return null;
|
|
3906
|
-
return /* @__PURE__ */
|
|
4651
|
+
return /* @__PURE__ */ jsx3(
|
|
3907
4652
|
"div",
|
|
3908
4653
|
{
|
|
3909
4654
|
"data-testid": "notification-toast-stack",
|
|
@@ -3958,7 +4703,7 @@ function NotificationToastStack({
|
|
|
3958
4703
|
padding: "10px 12px"
|
|
3959
4704
|
},
|
|
3960
4705
|
children: [
|
|
3961
|
-
/* @__PURE__ */
|
|
4706
|
+
/* @__PURE__ */ jsx3(
|
|
3962
4707
|
"div",
|
|
3963
4708
|
{
|
|
3964
4709
|
style: {
|
|
@@ -3972,11 +4717,11 @@ function NotificationToastStack({
|
|
|
3972
4717
|
flexShrink: 0,
|
|
3973
4718
|
fontSize: "14px"
|
|
3974
4719
|
},
|
|
3975
|
-
children: (_a2 = notif.icon) != null ? _a2 : "\u{1F514}"
|
|
4720
|
+
children: /* @__PURE__ */ jsx3(EmojiIcon, { emoji: (_a2 = notif.icon) != null ? _a2 : "\u{1F514}", size: 14 })
|
|
3976
4721
|
}
|
|
3977
4722
|
),
|
|
3978
4723
|
/* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3979
|
-
/* @__PURE__ */
|
|
4724
|
+
/* @__PURE__ */ jsx3(
|
|
3980
4725
|
"div",
|
|
3981
4726
|
{
|
|
3982
4727
|
style: {
|
|
@@ -3991,7 +4736,7 @@ function NotificationToastStack({
|
|
|
3991
4736
|
children: notif.title
|
|
3992
4737
|
}
|
|
3993
4738
|
),
|
|
3994
|
-
notif.body && /* @__PURE__ */
|
|
4739
|
+
notif.body && /* @__PURE__ */ jsx3(
|
|
3995
4740
|
"div",
|
|
3996
4741
|
{
|
|
3997
4742
|
style: {
|
|
@@ -4007,7 +4752,7 @@ function NotificationToastStack({
|
|
|
4007
4752
|
}
|
|
4008
4753
|
)
|
|
4009
4754
|
] }),
|
|
4010
|
-
/* @__PURE__ */
|
|
4755
|
+
/* @__PURE__ */ jsx3(
|
|
4011
4756
|
"button",
|
|
4012
4757
|
{
|
|
4013
4758
|
type: "button",
|
|
@@ -4032,7 +4777,7 @@ function NotificationToastStack({
|
|
|
4032
4777
|
]
|
|
4033
4778
|
}
|
|
4034
4779
|
),
|
|
4035
|
-
/* @__PURE__ */
|
|
4780
|
+
/* @__PURE__ */ jsx3("div", { style: { height: "2px", background: "rgba(0, 0, 0, 0.08)" }, children: /* @__PURE__ */ jsx3(
|
|
4036
4781
|
"div",
|
|
4037
4782
|
{
|
|
4038
4783
|
className: "syntro-toast-progress",
|
|
@@ -4110,7 +4855,7 @@ function useNotifications(eventBus, tiles) {
|
|
|
4110
4855
|
const timerIds = useRef2(/* @__PURE__ */ new Map());
|
|
4111
4856
|
const publishDismissed = useCallback2(
|
|
4112
4857
|
(notif) => {
|
|
4113
|
-
eventBus == null ? void 0 : eventBus.publish(
|
|
4858
|
+
eventBus == null ? void 0 : eventBus.publish(StandardEvents2.NOTIFICATION_DISMISSED, {
|
|
4114
4859
|
notificationId: notif.id,
|
|
4115
4860
|
tileId: notif.tileId,
|
|
4116
4861
|
itemId: notif.itemId
|
|
@@ -4175,7 +4920,7 @@ function useNotifications(eventBus, tiles) {
|
|
|
4175
4920
|
}
|
|
4176
4921
|
return next;
|
|
4177
4922
|
});
|
|
4178
|
-
eventBus.publish(
|
|
4923
|
+
eventBus.publish(StandardEvents2.NOTIFICATION_SHOWN, {
|
|
4179
4924
|
notificationId: matched.id,
|
|
4180
4925
|
tileId: matched.tileId,
|
|
4181
4926
|
itemId: matched.itemId,
|
|
@@ -4246,7 +4991,7 @@ function useNotifyWatcher(runtime3, tiles, appRegistry2) {
|
|
|
4246
4991
|
|
|
4247
4992
|
// src/RuntimeProvider.tsx
|
|
4248
4993
|
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect4, useMemo as useMemo2, useState as useState3 } from "react";
|
|
4249
|
-
import { jsx as
|
|
4994
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
4250
4995
|
var RuntimeReactContext = createContext2({
|
|
4251
4996
|
runtime: null,
|
|
4252
4997
|
context: null
|
|
@@ -4264,7 +5009,7 @@ function RuntimeProvider({ runtime: runtime3, children }) {
|
|
|
4264
5009
|
return unsubscribe;
|
|
4265
5010
|
}, [runtime3]);
|
|
4266
5011
|
const value = useMemo2(() => ({ runtime: runtime3, context }), [runtime3, context]);
|
|
4267
|
-
return /* @__PURE__ */
|
|
5012
|
+
return /* @__PURE__ */ jsx4(RuntimeReactContext.Provider, { value, children });
|
|
4268
5013
|
}
|
|
4269
5014
|
function useRuntime() {
|
|
4270
5015
|
const { runtime: runtime3 } = useContext2(RuntimeReactContext);
|
|
@@ -4338,41 +5083,17 @@ import {
|
|
|
4338
5083
|
} from "react";
|
|
4339
5084
|
|
|
4340
5085
|
// src/components/TileIcon.tsx
|
|
4341
|
-
import {
|
|
4342
|
-
Compass,
|
|
4343
|
-
FileText,
|
|
4344
|
-
Gamepad2,
|
|
4345
|
-
HelpCircle,
|
|
4346
|
-
Layers,
|
|
4347
|
-
MessageCircle,
|
|
4348
|
-
Sparkles,
|
|
4349
|
-
Trophy
|
|
4350
|
-
} from "lucide-react";
|
|
4351
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
4352
|
-
var ICON_MAP = {
|
|
4353
|
-
"\u2753": HelpCircle,
|
|
4354
|
-
"\u{1F9ED}": Compass,
|
|
4355
|
-
"\u{1F4DD}": FileText,
|
|
4356
|
-
"\u{1F3AF}": Layers,
|
|
4357
|
-
"\u{1F3C6}": Trophy,
|
|
4358
|
-
"\u2728": Sparkles,
|
|
4359
|
-
"\u{1F4AC}": MessageCircle,
|
|
4360
|
-
"\u{1F3AE}": Gamepad2
|
|
4361
|
-
};
|
|
5086
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
4362
5087
|
function TileIcon({
|
|
4363
5088
|
emoji,
|
|
4364
5089
|
size = 18,
|
|
4365
5090
|
color = "currentColor"
|
|
4366
5091
|
}) {
|
|
4367
|
-
|
|
4368
|
-
if (!Icon) {
|
|
4369
|
-
return /* @__PURE__ */ jsx4("span", { children: emoji });
|
|
4370
|
-
}
|
|
4371
|
-
return /* @__PURE__ */ jsx4(Icon, { size, color });
|
|
5092
|
+
return /* @__PURE__ */ jsx5(EmojiIcon, { emoji, size, color });
|
|
4372
5093
|
}
|
|
4373
5094
|
|
|
4374
5095
|
// src/components/TileCard.tsx
|
|
4375
|
-
import { jsx as
|
|
5096
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
4376
5097
|
function WidgetMount({ widgetId, props }) {
|
|
4377
5098
|
var _a2;
|
|
4378
5099
|
const runtime3 = useRuntime();
|
|
@@ -4402,7 +5123,6 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4402
5123
|
return () => {
|
|
4403
5124
|
handle.unmount();
|
|
4404
5125
|
handleRef.current = null;
|
|
4405
|
-
container.remove();
|
|
4406
5126
|
};
|
|
4407
5127
|
}, [registry, widgetId, widgetAvailable]);
|
|
4408
5128
|
const propsJson = JSON.stringify(props);
|
|
@@ -4413,7 +5133,7 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4413
5133
|
prevPropsJsonRef.current = propsJson;
|
|
4414
5134
|
(_a3 = handleRef.current) == null ? void 0 : _a3.update(propsRef.current);
|
|
4415
5135
|
}, [propsJson]);
|
|
4416
|
-
if (!registry
|
|
5136
|
+
if (!(registry == null ? void 0 : registry.has(widgetId))) {
|
|
4417
5137
|
return /* @__PURE__ */ jsxs2(
|
|
4418
5138
|
"div",
|
|
4419
5139
|
{
|
|
@@ -4430,8 +5150,21 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4430
5150
|
}
|
|
4431
5151
|
);
|
|
4432
5152
|
}
|
|
4433
|
-
return /* @__PURE__ */
|
|
4434
|
-
}
|
|
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
|
+
];
|
|
4435
5168
|
function TileCard({
|
|
4436
5169
|
config,
|
|
4437
5170
|
surface: _surface,
|
|
@@ -4440,10 +5173,42 @@ function TileCard({
|
|
|
4440
5173
|
}) {
|
|
4441
5174
|
const { title, subtitle, widget, props, icon } = config;
|
|
4442
5175
|
const [, setTick] = useState4(0);
|
|
5176
|
+
const articleRef = useRef4(null);
|
|
4443
5177
|
const runtime3 = useRuntime();
|
|
4444
5178
|
useEffect5(() => {
|
|
4445
5179
|
if (runtime3) setTick((t) => t + 1);
|
|
4446
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]);
|
|
4447
5212
|
const registration = useMemo3(
|
|
4448
5213
|
() => {
|
|
4449
5214
|
var _a2, _b;
|
|
@@ -4497,15 +5262,16 @@ function TileCard({
|
|
|
4497
5262
|
return /* @__PURE__ */ jsxs2(
|
|
4498
5263
|
"article",
|
|
4499
5264
|
{
|
|
5265
|
+
ref: articleRef,
|
|
4500
5266
|
"data-shadow-canvas-id": `tile-${config.id}`,
|
|
4501
5267
|
style: cardStyle,
|
|
4502
5268
|
onMouseEnter,
|
|
4503
5269
|
onMouseLeave,
|
|
4504
5270
|
children: [
|
|
4505
5271
|
/* @__PURE__ */ jsxs2("div", { style: headerStyle, children: [
|
|
4506
|
-
/* @__PURE__ */
|
|
5272
|
+
/* @__PURE__ */ jsx6("div", { style: iconStyle, children: /* @__PURE__ */ jsx6(TileIcon, { emoji: resolvedIcon, size: resolvedSubtitle ? 36 : 24 }) }),
|
|
4507
5273
|
/* @__PURE__ */ jsxs2("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
4508
|
-
/* @__PURE__ */
|
|
5274
|
+
/* @__PURE__ */ jsx6(
|
|
4509
5275
|
"h3",
|
|
4510
5276
|
{
|
|
4511
5277
|
style: {
|
|
@@ -4520,7 +5286,7 @@ function TileCard({
|
|
|
4520
5286
|
children: title != null ? title : widget
|
|
4521
5287
|
}
|
|
4522
5288
|
),
|
|
4523
|
-
resolvedSubtitle && /* @__PURE__ */
|
|
5289
|
+
resolvedSubtitle && /* @__PURE__ */ jsx6(
|
|
4524
5290
|
"p",
|
|
4525
5291
|
{
|
|
4526
5292
|
style: {
|
|
@@ -4537,14 +5303,14 @@ function TileCard({
|
|
|
4537
5303
|
)
|
|
4538
5304
|
] })
|
|
4539
5305
|
] }),
|
|
4540
|
-
/* @__PURE__ */
|
|
5306
|
+
/* @__PURE__ */ jsx6(
|
|
4541
5307
|
"div",
|
|
4542
5308
|
{
|
|
4543
5309
|
style: {
|
|
4544
5310
|
padding: "var(--sc-tile-body-padding, 0 0.75rem 0.5rem)",
|
|
4545
5311
|
borderTop: "1px solid rgba(255, 255, 255, 0.06)"
|
|
4546
5312
|
},
|
|
4547
|
-
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 } }) })
|
|
4548
5314
|
}
|
|
4549
5315
|
)
|
|
4550
5316
|
]
|
|
@@ -4952,7 +5718,7 @@ function flattenThemeConfig(config) {
|
|
|
4952
5718
|
|
|
4953
5719
|
// src/theme/ThemeProvider.tsx
|
|
4954
5720
|
import { createContext as createContext3, useContext as useContext3, useEffect as useEffect6, useMemo as useMemo4 } from "react";
|
|
4955
|
-
import { jsx as
|
|
5721
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
4956
5722
|
var ThemeContext = createContext3(null);
|
|
4957
5723
|
function ThemeProvider({
|
|
4958
5724
|
children,
|
|
@@ -4983,7 +5749,7 @@ ${cssRules}
|
|
|
4983
5749
|
mode: merged.mode,
|
|
4984
5750
|
cssVariables
|
|
4985
5751
|
};
|
|
4986
|
-
return /* @__PURE__ */
|
|
5752
|
+
return /* @__PURE__ */ jsx7(ThemeContext.Provider, { value, children });
|
|
4987
5753
|
}
|
|
4988
5754
|
function useTheme() {
|
|
4989
5755
|
const context = useContext3(ThemeContext);
|
|
@@ -4994,7 +5760,7 @@ function useTheme() {
|
|
|
4994
5760
|
}
|
|
4995
5761
|
|
|
4996
5762
|
// src/components/ShadowCanvasOverlay.tsx
|
|
4997
|
-
import { Fragment, jsx as
|
|
5763
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4998
5764
|
var LAUNCHER_STYLES_ID = "syntro-launcher-styles";
|
|
4999
5765
|
function ensureLauncherStyles(target, css) {
|
|
5000
5766
|
if (target.querySelector(`#${LAUNCHER_STYLES_ID}`)) return;
|
|
@@ -5008,7 +5774,6 @@ function ShadowCanvasOverlay({
|
|
|
5008
5774
|
onToggle,
|
|
5009
5775
|
telemetry,
|
|
5010
5776
|
launcherLabel: _launcherLabel = "Adaptives",
|
|
5011
|
-
launcherIcon,
|
|
5012
5777
|
launcherAnimate = false,
|
|
5013
5778
|
launcherAnimationStyle: _launcherAnimationStyle = "pulse",
|
|
5014
5779
|
notificationCount: _notificationCount,
|
|
@@ -5019,7 +5784,7 @@ function ShadowCanvasOverlay({
|
|
|
5019
5784
|
canvasTitle,
|
|
5020
5785
|
displayMode = "standard"
|
|
5021
5786
|
}) {
|
|
5022
|
-
var _a2, _b, _c, _d;
|
|
5787
|
+
var _a2, _b, _c, _d, _e;
|
|
5023
5788
|
const [mounted, setMounted] = useState5(false);
|
|
5024
5789
|
const [launcherPos, setLauncherPos] = useState5(null);
|
|
5025
5790
|
const dragRef = useRef5(null);
|
|
@@ -5034,7 +5799,7 @@ function ShadowCanvasOverlay({
|
|
|
5034
5799
|
const handleNotificationClick = useCallback4(
|
|
5035
5800
|
(notif) => {
|
|
5036
5801
|
if (runtime3) {
|
|
5037
|
-
runtime3.events.publish(
|
|
5802
|
+
runtime3.events.publish(StandardEvents2.NOTIFICATION_CLICKED, {
|
|
5038
5803
|
notificationId: notif.id,
|
|
5039
5804
|
tileId: notif.tileId,
|
|
5040
5805
|
itemId: notif.itemId
|
|
@@ -5044,7 +5809,7 @@ function ShadowCanvasOverlay({
|
|
|
5044
5809
|
onToggle();
|
|
5045
5810
|
}
|
|
5046
5811
|
if (runtime3 && notif.tileId) {
|
|
5047
|
-
runtime3.events.publish(
|
|
5812
|
+
runtime3.events.publish(StandardEvents2.NOTIFICATION_DEEP_LINK, {
|
|
5048
5813
|
tileId: notif.tileId,
|
|
5049
5814
|
itemId: notif.itemId
|
|
5050
5815
|
});
|
|
@@ -5117,6 +5882,17 @@ function ShadowCanvasOverlay({
|
|
|
5117
5882
|
}
|
|
5118
5883
|
onToggle();
|
|
5119
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]);
|
|
5120
5896
|
const onLauncherPointerDown = useCallback4((e) => {
|
|
5121
5897
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
5122
5898
|
dragRef.current = {
|
|
@@ -5141,7 +5917,7 @@ function ShadowCanvasOverlay({
|
|
|
5141
5917
|
}
|
|
5142
5918
|
}, []);
|
|
5143
5919
|
const onLauncherPointerUp = useCallback4(
|
|
5144
|
-
(
|
|
5920
|
+
(_e2) => {
|
|
5145
5921
|
const drag = dragRef.current;
|
|
5146
5922
|
dragRef.current = null;
|
|
5147
5923
|
if (drag && !drag.dragged) {
|
|
@@ -5155,6 +5931,7 @@ function ShadowCanvasOverlay({
|
|
|
5155
5931
|
const isPush = config.canvas.layout === "push";
|
|
5156
5932
|
const canvasBorder = (_b = config.canvas.border) != null ? _b : "none";
|
|
5157
5933
|
const containerRef = useRef5(null);
|
|
5934
|
+
const launcherRef = useRef5(null);
|
|
5158
5935
|
const zIndex = 2147483600;
|
|
5159
5936
|
useEffect7(() => {
|
|
5160
5937
|
var _a3, _b2, _c2, _d2;
|
|
@@ -5235,19 +6012,19 @@ function ShadowCanvasOverlay({
|
|
|
5235
6012
|
pointerEvents: "none",
|
|
5236
6013
|
padding: "0"
|
|
5237
6014
|
};
|
|
5238
|
-
const content = /* @__PURE__ */
|
|
6015
|
+
const content = /* @__PURE__ */ jsx8(
|
|
5239
6016
|
"div",
|
|
5240
6017
|
{
|
|
5241
6018
|
"data-shadow-canvas-id": "overlay-root",
|
|
5242
6019
|
style: {
|
|
5243
6020
|
position: "fixed",
|
|
5244
6021
|
inset: 0,
|
|
5245
|
-
pointerEvents:
|
|
6022
|
+
pointerEvents: "none",
|
|
5246
6023
|
zIndex
|
|
5247
6024
|
},
|
|
5248
6025
|
children: /* @__PURE__ */ jsxs3("div", { style: wrapperStyle, children: [
|
|
5249
6026
|
/* @__PURE__ */ jsxs3("div", { ref: containerRef, "data-shadow-canvas-id": "overlay-container", style: containerStyle, children: [
|
|
5250
|
-
isFocused && canvasTitle && /* @__PURE__ */
|
|
6027
|
+
isFocused && canvasTitle && /* @__PURE__ */ jsx8("header", { style: { color: "white", padding: "1.5rem 1.5rem 0" }, children: /* @__PURE__ */ jsx8(
|
|
5251
6028
|
"p",
|
|
5252
6029
|
{
|
|
5253
6030
|
style: {
|
|
@@ -5260,7 +6037,7 @@ function ShadowCanvasOverlay({
|
|
|
5260
6037
|
children: canvasTitle
|
|
5261
6038
|
}
|
|
5262
6039
|
) }),
|
|
5263
|
-
/* @__PURE__ */
|
|
6040
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: 1, overflowY: "auto", padding: isFocused ? "0" : "1rem" }, children: isLoading ? /* @__PURE__ */ jsx8(
|
|
5264
6041
|
"div",
|
|
5265
6042
|
{
|
|
5266
6043
|
style: { color: "var(--sc-overlay-text-color)", padding: isFocused ? "1rem" : "0" },
|
|
@@ -5280,7 +6057,7 @@ function ShadowCanvasOverlay({
|
|
|
5280
6057
|
}
|
|
5281
6058
|
) : isFocused ? (
|
|
5282
6059
|
/* Focused Mode: Render first tile full size */
|
|
5283
|
-
tiles.length > 0 ? /* @__PURE__ */
|
|
6060
|
+
tiles.length > 0 ? /* @__PURE__ */ jsx8(
|
|
5284
6061
|
TileCard,
|
|
5285
6062
|
{
|
|
5286
6063
|
config: tiles[0],
|
|
@@ -5291,7 +6068,7 @@ function ShadowCanvasOverlay({
|
|
|
5291
6068
|
) : null
|
|
5292
6069
|
) : (
|
|
5293
6070
|
/* Standard Mode: Stacked cards — widgets always visible */
|
|
5294
|
-
/* @__PURE__ */
|
|
6071
|
+
/* @__PURE__ */ jsx8(
|
|
5295
6072
|
"div",
|
|
5296
6073
|
{
|
|
5297
6074
|
style: {
|
|
@@ -5300,7 +6077,7 @@ function ShadowCanvasOverlay({
|
|
|
5300
6077
|
gap: "0.75rem",
|
|
5301
6078
|
width: "100%"
|
|
5302
6079
|
},
|
|
5303
|
-
children: tiles.map((tile) => /* @__PURE__ */
|
|
6080
|
+
children: tiles.map((tile) => /* @__PURE__ */ jsx8(
|
|
5304
6081
|
TileCard,
|
|
5305
6082
|
{
|
|
5306
6083
|
config: tile,
|
|
@@ -5315,17 +6092,7 @@ function ShadowCanvasOverlay({
|
|
|
5315
6092
|
) }),
|
|
5316
6093
|
footerSlot
|
|
5317
6094
|
] }),
|
|
5318
|
-
/* @__PURE__ */
|
|
5319
|
-
"div",
|
|
5320
|
-
{
|
|
5321
|
-
onClick: toggle2,
|
|
5322
|
-
style: {
|
|
5323
|
-
flex: "1 1 auto",
|
|
5324
|
-
pointerEvents: isOpen ? "auto" : "none",
|
|
5325
|
-
cursor: "default"
|
|
5326
|
-
}
|
|
5327
|
-
}
|
|
5328
|
-
)
|
|
6095
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: "1 1 auto" } })
|
|
5329
6096
|
] })
|
|
5330
6097
|
}
|
|
5331
6098
|
);
|
|
@@ -5343,7 +6110,7 @@ function ShadowCanvasOverlay({
|
|
|
5343
6110
|
zIndex: zIndex + 47
|
|
5344
6111
|
},
|
|
5345
6112
|
children: [
|
|
5346
|
-
/* @__PURE__ */
|
|
6113
|
+
/* @__PURE__ */ jsx8(
|
|
5347
6114
|
NotificationToastStack,
|
|
5348
6115
|
{
|
|
5349
6116
|
notifications,
|
|
@@ -5355,6 +6122,7 @@ function ShadowCanvasOverlay({
|
|
|
5355
6122
|
/* @__PURE__ */ jsxs3(
|
|
5356
6123
|
"button",
|
|
5357
6124
|
{
|
|
6125
|
+
ref: launcherRef,
|
|
5358
6126
|
type: "button",
|
|
5359
6127
|
"aria-label": "Toggle shadow canvas",
|
|
5360
6128
|
className: launcherAnimate && !isOpen ? "syntro-launcher-animate" : void 0,
|
|
@@ -5413,14 +6181,14 @@ function ShadowCanvasOverlay({
|
|
|
5413
6181
|
focusable: "false",
|
|
5414
6182
|
style: { transition: "transform 200ms ease" },
|
|
5415
6183
|
children: [
|
|
5416
|
-
/* @__PURE__ */
|
|
5417
|
-
/* @__PURE__ */
|
|
6184
|
+
/* @__PURE__ */ jsx8("path", { d: "M18 6L6 18" }),
|
|
6185
|
+
/* @__PURE__ */ jsx8("path", { d: "M6 6l12 12" })
|
|
5418
6186
|
]
|
|
5419
6187
|
}
|
|
5420
|
-
) :
|
|
6188
|
+
) : ((_e = config.launcher) == null ? void 0 : _e.icon) ? /* @__PURE__ */ jsx8(
|
|
5421
6189
|
"img",
|
|
5422
6190
|
{
|
|
5423
|
-
src:
|
|
6191
|
+
src: config.launcher.icon,
|
|
5424
6192
|
alt: "",
|
|
5425
6193
|
"aria-hidden": "true",
|
|
5426
6194
|
style: {
|
|
@@ -5445,16 +6213,16 @@ function ShadowCanvasOverlay({
|
|
|
5445
6213
|
focusable: "false",
|
|
5446
6214
|
style: { transition: "transform 200ms ease" },
|
|
5447
6215
|
children: [
|
|
5448
|
-
/* @__PURE__ */
|
|
5449
|
-
/* @__PURE__ */
|
|
5450
|
-
/* @__PURE__ */
|
|
5451
|
-
/* @__PURE__ */
|
|
5452
|
-
/* @__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" })
|
|
5453
6221
|
]
|
|
5454
6222
|
}
|
|
5455
6223
|
),
|
|
5456
6224
|
!isOpen && notifications.length > 0 && /* @__PURE__ */ jsxs3("div", { style: { position: "absolute", top: -2, right: -2, pointerEvents: "none" }, children: [
|
|
5457
|
-
/* @__PURE__ */
|
|
6225
|
+
/* @__PURE__ */ jsx8(
|
|
5458
6226
|
"span",
|
|
5459
6227
|
{
|
|
5460
6228
|
className: "syntro-badge-ping",
|
|
@@ -5466,7 +6234,7 @@ function ShadowCanvasOverlay({
|
|
|
5466
6234
|
}
|
|
5467
6235
|
}
|
|
5468
6236
|
),
|
|
5469
|
-
/* @__PURE__ */
|
|
6237
|
+
/* @__PURE__ */ jsx8(
|
|
5470
6238
|
"span",
|
|
5471
6239
|
{
|
|
5472
6240
|
className: "syntro-badge-glow",
|
|
@@ -5477,7 +6245,7 @@ function ShadowCanvasOverlay({
|
|
|
5477
6245
|
}
|
|
5478
6246
|
}
|
|
5479
6247
|
),
|
|
5480
|
-
/* @__PURE__ */
|
|
6248
|
+
/* @__PURE__ */ jsx8(
|
|
5481
6249
|
"span",
|
|
5482
6250
|
{
|
|
5483
6251
|
className: "syntro-badge-bounce",
|
|
@@ -5516,6 +6284,14 @@ var sortTiles = (tiles) => [...tiles].sort((a, b) => {
|
|
|
5516
6284
|
var _a2, _b;
|
|
5517
6285
|
return ((_a2 = b.priority) != null ? _a2 : 0) - ((_b = a.priority) != null ? _b : 0);
|
|
5518
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
|
+
}
|
|
5519
6295
|
function useShadowCanvasConfig({
|
|
5520
6296
|
fetcher,
|
|
5521
6297
|
experiments,
|
|
@@ -5538,6 +6314,7 @@ function useShadowCanvasConfig({
|
|
|
5538
6314
|
if (experiments) {
|
|
5539
6315
|
tiles = tiles.filter((tile) => experiments.shouldRenderRectangle(tile));
|
|
5540
6316
|
}
|
|
6317
|
+
fireTriggeredForTiles(tiles);
|
|
5541
6318
|
setState((prev) => ({ ...prev, tiles: sortTiles(tiles) }));
|
|
5542
6319
|
}, [runtime3, experiments]);
|
|
5543
6320
|
const load = useCallback5(async () => {
|
|
@@ -5555,6 +6332,7 @@ function useShadowCanvasConfig({
|
|
|
5555
6332
|
} else if (experiments) {
|
|
5556
6333
|
tiles = tiles.filter((tile) => experiments.shouldRenderRectangle(tile));
|
|
5557
6334
|
}
|
|
6335
|
+
fireTriggeredForTiles(tiles);
|
|
5558
6336
|
debug("SmartCanvas Config", `Tile count after filtering: ${tiles.length}`);
|
|
5559
6337
|
const newActions = response.actions || [];
|
|
5560
6338
|
const newActionsJson = JSON.stringify(newActions);
|
|
@@ -5612,13 +6390,13 @@ function useShadowCanvasConfig({
|
|
|
5612
6390
|
|
|
5613
6391
|
// src/SmartCanvasApp.tsx
|
|
5614
6392
|
import { useEffect as useEffect9, useMemo as useMemo7, useRef as useRef7, useState as useState7 } from "react";
|
|
5615
|
-
import { jsx as
|
|
6393
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
5616
6394
|
function SmartCanvasApp({
|
|
5617
6395
|
controller,
|
|
5618
6396
|
fetcher,
|
|
5619
6397
|
configUri,
|
|
5620
|
-
configUriFeatureKey
|
|
5621
|
-
configFeatureKey
|
|
6398
|
+
configUriFeatureKey,
|
|
6399
|
+
configFeatureKey,
|
|
5622
6400
|
fetchCredentials = "include",
|
|
5623
6401
|
pollIntervalMs,
|
|
5624
6402
|
experiments,
|
|
@@ -5635,7 +6413,7 @@ function SmartCanvasApp({
|
|
|
5635
6413
|
workspaceTheme
|
|
5636
6414
|
}) {
|
|
5637
6415
|
if (runtime3) {
|
|
5638
|
-
return /* @__PURE__ */
|
|
6416
|
+
return /* @__PURE__ */ jsx9(RuntimeProvider, { runtime: runtime3, children: /* @__PURE__ */ jsx9(
|
|
5639
6417
|
SmartCanvasAppInner,
|
|
5640
6418
|
{
|
|
5641
6419
|
controller,
|
|
@@ -5660,7 +6438,7 @@ function SmartCanvasApp({
|
|
|
5660
6438
|
}
|
|
5661
6439
|
) });
|
|
5662
6440
|
}
|
|
5663
|
-
return /* @__PURE__ */
|
|
6441
|
+
return /* @__PURE__ */ jsx9(
|
|
5664
6442
|
SmartCanvasAppInner,
|
|
5665
6443
|
{
|
|
5666
6444
|
controller,
|
|
@@ -5688,10 +6466,10 @@ function SmartCanvasAppInner({
|
|
|
5688
6466
|
controller,
|
|
5689
6467
|
fetcher,
|
|
5690
6468
|
configUri,
|
|
5691
|
-
configUriFeatureKey
|
|
5692
|
-
configFeatureKey
|
|
6469
|
+
configUriFeatureKey,
|
|
6470
|
+
configFeatureKey,
|
|
5693
6471
|
fetchCredentials = "include",
|
|
5694
|
-
pollIntervalMs,
|
|
6472
|
+
pollIntervalMs: _pollIntervalMs,
|
|
5695
6473
|
experiments,
|
|
5696
6474
|
telemetry,
|
|
5697
6475
|
runtime: runtime3,
|
|
@@ -5705,7 +6483,7 @@ function SmartCanvasAppInner({
|
|
|
5705
6483
|
initialBatchHandle,
|
|
5706
6484
|
workspaceTheme
|
|
5707
6485
|
}) {
|
|
5708
|
-
var _a2, _b, _c, _d, _e, _f
|
|
6486
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
5709
6487
|
const [open, setOpen] = useState7(controller.getState().open);
|
|
5710
6488
|
const pageContext = usePageContext();
|
|
5711
6489
|
const [localUrl, setLocalUrl] = useState7(
|
|
@@ -5718,21 +6496,9 @@ function SmartCanvasAppInner({
|
|
|
5718
6496
|
const updateUrl = () => setLocalUrl(window.location.href);
|
|
5719
6497
|
window.addEventListener("popstate", updateUrl);
|
|
5720
6498
|
window.addEventListener("hashchange", updateUrl);
|
|
5721
|
-
const originalPushState = history.pushState;
|
|
5722
|
-
const originalReplaceState = history.replaceState;
|
|
5723
|
-
history.pushState = function(...args) {
|
|
5724
|
-
originalPushState.apply(this, args);
|
|
5725
|
-
queueMicrotask(updateUrl);
|
|
5726
|
-
};
|
|
5727
|
-
history.replaceState = function(...args) {
|
|
5728
|
-
originalReplaceState.apply(this, args);
|
|
5729
|
-
queueMicrotask(updateUrl);
|
|
5730
|
-
};
|
|
5731
6499
|
return () => {
|
|
5732
6500
|
window.removeEventListener("popstate", updateUrl);
|
|
5733
6501
|
window.removeEventListener("hashchange", updateUrl);
|
|
5734
|
-
history.pushState = originalPushState;
|
|
5735
|
-
history.replaceState = originalReplaceState;
|
|
5736
6502
|
};
|
|
5737
6503
|
}, [runtime3]);
|
|
5738
6504
|
const derivedFetcher = useMemo7(() => {
|
|
@@ -5761,6 +6527,7 @@ function SmartCanvasAppInner({
|
|
|
5761
6527
|
const batchHandleRef = useRef7(initialBatchHandle != null ? initialBatchHandle : null);
|
|
5762
6528
|
const adoptedInitialRef = useRef7(!!initialBatchHandle);
|
|
5763
6529
|
const runVersionRef = useRef7(0);
|
|
6530
|
+
const pendingRevertRef = useRef7(null);
|
|
5764
6531
|
useEffect9(() => {
|
|
5765
6532
|
if (!(runtime3 == null ? void 0 : runtime3.actions)) return;
|
|
5766
6533
|
if (adoptedInitialRef.current) {
|
|
@@ -5772,6 +6539,14 @@ function SmartCanvasAppInner({
|
|
|
5772
6539
|
const version = ++runVersionRef.current;
|
|
5773
6540
|
const stale = () => version !== runVersionRef.current;
|
|
5774
6541
|
const run = async () => {
|
|
6542
|
+
if (pendingRevertRef.current) {
|
|
6543
|
+
try {
|
|
6544
|
+
await pendingRevertRef.current;
|
|
6545
|
+
} catch (err) {
|
|
6546
|
+
console.error("[SmartCanvasApp] Pending revert failed:", err);
|
|
6547
|
+
}
|
|
6548
|
+
pendingRevertRef.current = null;
|
|
6549
|
+
}
|
|
5775
6550
|
if (batchHandleRef.current) {
|
|
5776
6551
|
try {
|
|
5777
6552
|
await batchHandleRef.current.revertAll();
|
|
@@ -5799,7 +6574,7 @@ function SmartCanvasAppInner({
|
|
|
5799
6574
|
run();
|
|
5800
6575
|
return () => {
|
|
5801
6576
|
if (batchHandleRef.current) {
|
|
5802
|
-
batchHandleRef.current.revertAll().catch((err) => {
|
|
6577
|
+
pendingRevertRef.current = batchHandleRef.current.revertAll().catch((err) => {
|
|
5803
6578
|
console.error("[SmartCanvasApp] Failed to revert actions on cleanup:", err);
|
|
5804
6579
|
});
|
|
5805
6580
|
batchHandleRef.current = null;
|
|
@@ -5815,13 +6590,13 @@ function SmartCanvasAppInner({
|
|
|
5815
6590
|
}, [runtime3, controller]);
|
|
5816
6591
|
const { shadowRoot } = useShadowRoot();
|
|
5817
6592
|
const themeConfig = configState.theme;
|
|
5818
|
-
return /* @__PURE__ */
|
|
6593
|
+
return /* @__PURE__ */ jsx9(
|
|
5819
6594
|
ThemeProvider,
|
|
5820
6595
|
{
|
|
5821
6596
|
themeConfig,
|
|
5822
6597
|
workspaceTheme,
|
|
5823
6598
|
shadowRoot,
|
|
5824
|
-
children: !configState.isLoading && !hasContent ? null : /* @__PURE__ */
|
|
6599
|
+
children: !configState.isLoading && !hasContent ? null : /* @__PURE__ */ jsx9(
|
|
5825
6600
|
ShadowCanvasOverlay,
|
|
5826
6601
|
{
|
|
5827
6602
|
tiles: configState.tiles,
|
|
@@ -5830,10 +6605,9 @@ function SmartCanvasAppInner({
|
|
|
5830
6605
|
canvasTitle: configState.canvasTitle,
|
|
5831
6606
|
telemetry,
|
|
5832
6607
|
launcherLabel: launcherLabel != null ? launcherLabel : (_b = configState.launcher) == null ? void 0 : _b.label,
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
notificationCount: (_g = (_f = configState.launcher) == null ? void 0 : _f.notificationCount) != null ? _g : configState.tiles.length,
|
|
6608
|
+
launcherAnimate: (_c = configState.launcher) == null ? void 0 : _c.animate,
|
|
6609
|
+
launcherAnimationStyle: (_d = configState.launcher) == null ? void 0 : _d.animationStyle,
|
|
6610
|
+
notificationCount: (_f = (_e = configState.launcher) == null ? void 0 : _e.notificationCount) != null ? _f : configState.tiles.length,
|
|
5837
6611
|
footerSlot,
|
|
5838
6612
|
isOpen: open,
|
|
5839
6613
|
onToggle: () => controller.toggle(),
|
|
@@ -5846,7 +6620,7 @@ function SmartCanvasAppInner({
|
|
|
5846
6620
|
|
|
5847
6621
|
// src/SmartCanvasElement.tsx
|
|
5848
6622
|
import { createRoot as createRoot2 } from "react-dom/client";
|
|
5849
|
-
import { jsx as
|
|
6623
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
5850
6624
|
var TAG_NAME = "smart-canvas";
|
|
5851
6625
|
var BASE_CSS = `
|
|
5852
6626
|
:host {
|
|
@@ -5947,13 +6721,13 @@ var SmartCanvasElement = class extends HTMLElement {
|
|
|
5947
6721
|
__privateSet(this, _root, createRoot2(__privateGet(this, _mount)));
|
|
5948
6722
|
}
|
|
5949
6723
|
__privateGet(this, _root).render(
|
|
5950
|
-
/* @__PURE__ */
|
|
6724
|
+
/* @__PURE__ */ jsx10(
|
|
5951
6725
|
ShadowRootProvider,
|
|
5952
6726
|
{
|
|
5953
6727
|
shadowRoot: __privateGet(this, _shadow),
|
|
5954
6728
|
portalRoot: __privateGet(this, _portalRoot),
|
|
5955
6729
|
overlayContainer: __privateGet(this, _overlayContainer),
|
|
5956
|
-
children: /* @__PURE__ */
|
|
6730
|
+
children: /* @__PURE__ */ jsx10(SmartCanvasApp, { ...__privateGet(this, _lastAppProps), controller: __privateGet(this, _controller), canvasHost: this })
|
|
5957
6731
|
}
|
|
5958
6732
|
)
|
|
5959
6733
|
);
|
|
@@ -6973,17 +7747,18 @@ var PostHogAdapter = class {
|
|
|
6973
7747
|
__publicField(this, "client");
|
|
6974
7748
|
__publicField(this, "featureFlagsCallback");
|
|
6975
7749
|
__publicField(this, "captureCallback");
|
|
6976
|
-
__publicField(this, "
|
|
7750
|
+
__publicField(this, "rrwebCallback");
|
|
6977
7751
|
this.client = options.client;
|
|
6978
7752
|
this.featureFlagsCallback = options.onFeatureFlagsLoaded;
|
|
6979
7753
|
this.captureCallback = options.onCapture;
|
|
7754
|
+
this.rrwebCallback = options.onRRWebEvent;
|
|
6980
7755
|
if (!this.client && options.consent && options.requireExplicitConsent && typeof window !== "undefined" && options.apiKey) {
|
|
6981
7756
|
const consent = options.consent;
|
|
6982
7757
|
const currentStatus = consent.getStatus();
|
|
6983
7758
|
if (currentStatus === "granted") {
|
|
6984
7759
|
this.initPostHog();
|
|
6985
7760
|
}
|
|
6986
|
-
|
|
7761
|
+
consent.subscribe((status) => {
|
|
6987
7762
|
if (status === "granted") {
|
|
6988
7763
|
if (!this.client) {
|
|
6989
7764
|
this.initPostHog();
|
|
@@ -7010,68 +7785,119 @@ var PostHogAdapter = class {
|
|
|
7010
7785
|
if (!options.apiKey) return;
|
|
7011
7786
|
const enableFeatureFlags = (_a2 = options.enableFeatureFlags) != null ? _a2 : true;
|
|
7012
7787
|
const instanceName = `syntro_${options.apiKey.slice(-6) || "sdk"}`;
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
},
|
|
7034
|
-
// Capture performance metrics
|
|
7035
|
-
capture_performance: true,
|
|
7036
|
-
// Enable web vitals
|
|
7037
|
-
enable_recording_console_log: true,
|
|
7038
|
-
// Bootstrap callback for when flags are loaded
|
|
7039
|
-
loaded: (ph) => {
|
|
7040
|
-
if (enableFeatureFlags && this.featureFlagsCallback) {
|
|
7041
|
-
ph.onFeatureFlags(() => {
|
|
7042
|
-
const allFlags = this.getAllFeatureFlags();
|
|
7043
|
-
if (allFlags && this.featureFlagsCallback) {
|
|
7044
|
-
this.featureFlagsCallback(allFlags);
|
|
7045
|
-
}
|
|
7046
|
-
});
|
|
7047
|
-
const existingFlags = this.getAllFeatureFlags();
|
|
7048
|
-
if (existingFlags && Object.keys(existingFlags).length > 0) {
|
|
7049
|
-
this.featureFlagsCallback(existingFlags);
|
|
7050
|
-
}
|
|
7051
|
-
}
|
|
7052
|
-
if (this.captureCallback) {
|
|
7053
|
-
ph.on("eventCaptured", (data) => {
|
|
7054
|
-
var _a3;
|
|
7055
|
-
const eventName = typeof data === "string" ? data : data == null ? void 0 : data.event;
|
|
7056
|
-
const properties = typeof data === "string" ? void 0 : data == null ? void 0 : data.properties;
|
|
7057
|
-
if (typeof eventName === "string") {
|
|
7058
|
-
(_a3 = this.captureCallback) == null ? void 0 : _a3.call(this, eventName, properties);
|
|
7059
|
-
}
|
|
7060
|
-
});
|
|
7061
|
-
}
|
|
7062
|
-
}
|
|
7788
|
+
const baseHost = (_b = options.apiHost) != null ? _b : "https://telemetry.syntrologie.com";
|
|
7789
|
+
const apiHost = `${baseHost.replace(/\/$/, "")}/t/${options.apiKey}`;
|
|
7790
|
+
const initOptions = {
|
|
7791
|
+
api_host: apiHost,
|
|
7792
|
+
// Feature flags for segment membership (in_segment_* flags)
|
|
7793
|
+
// When enabled, /decide is called to get segment flags
|
|
7794
|
+
advanced_disable_feature_flags: !enableFeatureFlags,
|
|
7795
|
+
advanced_disable_feature_flags_on_first_load: !enableFeatureFlags,
|
|
7796
|
+
// Full-page tracking - all ON by default
|
|
7797
|
+
autocapture: (_c = options.autocapture) != null ? _c : true,
|
|
7798
|
+
capture_pageview: (_d = options.capturePageview) != null ? _d : "history_change",
|
|
7799
|
+
capture_pageleave: (_e = options.capturePageleave) != null ? _e : true,
|
|
7800
|
+
disable_session_recording: !((_f = options.sessionRecording) != null ? _f : true),
|
|
7801
|
+
// CRITICAL: Disable user agent filtering to allow headless Chrome
|
|
7802
|
+
// PostHog blocks "HeadlessChrome" user agents by default as bot detection
|
|
7803
|
+
// This enables session recording in Playwright/crawler sessions
|
|
7804
|
+
opt_out_useragent_filter: true,
|
|
7805
|
+
// Cross-domain iframe recording for embeds
|
|
7806
|
+
session_recording: {
|
|
7807
|
+
recordCrossDomainIFrames: true
|
|
7063
7808
|
},
|
|
7809
|
+
// Capture performance metrics
|
|
7810
|
+
capture_performance: true,
|
|
7811
|
+
// Enable web vitals
|
|
7812
|
+
enable_recording_console_log: true
|
|
7813
|
+
};
|
|
7814
|
+
const result = posthog.init(
|
|
7815
|
+
options.apiKey,
|
|
7816
|
+
initOptions,
|
|
7064
7817
|
instanceName
|
|
7065
7818
|
);
|
|
7819
|
+
if (result) {
|
|
7820
|
+
this.client = result;
|
|
7821
|
+
}
|
|
7822
|
+
if (this.captureCallback && this.client) {
|
|
7823
|
+
this.client.on("eventCaptured", (...args) => {
|
|
7824
|
+
var _a3;
|
|
7825
|
+
const data = args[0];
|
|
7826
|
+
const eventName = typeof data === "string" ? data : data == null ? void 0 : data.event;
|
|
7827
|
+
const properties = typeof data === "string" ? void 0 : data == null ? void 0 : data.properties;
|
|
7828
|
+
if (typeof eventName === "string") {
|
|
7829
|
+
(_a3 = this.captureCallback) == null ? void 0 : _a3.call(this, eventName, properties);
|
|
7830
|
+
}
|
|
7831
|
+
});
|
|
7832
|
+
}
|
|
7833
|
+
if (enableFeatureFlags && this.featureFlagsCallback && this.client) {
|
|
7834
|
+
this.client.onFeatureFlags(() => {
|
|
7835
|
+
const allFlags = this.getAllFeatureFlags();
|
|
7836
|
+
if (allFlags && this.featureFlagsCallback) {
|
|
7837
|
+
this.featureFlagsCallback(allFlags);
|
|
7838
|
+
}
|
|
7839
|
+
});
|
|
7840
|
+
const existingFlags = this.getAllFeatureFlags();
|
|
7841
|
+
if (existingFlags && Object.keys(existingFlags).length > 0) {
|
|
7842
|
+
this.featureFlagsCallback(existingFlags);
|
|
7843
|
+
}
|
|
7844
|
+
}
|
|
7845
|
+
if (this.rrwebCallback && this.client) {
|
|
7846
|
+
this.setupRRWebIntercept();
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7849
|
+
/**
|
|
7850
|
+
* Set up rrweb event interception on PostHog's session recording.
|
|
7851
|
+
*
|
|
7852
|
+
* PostHog lazy-loads the rrweb recorder. The SessionRecording wrapper has
|
|
7853
|
+
* an `onRRwebEmit` method, but rrweb delivers events directly to the
|
|
7854
|
+
* lazy-loaded recorder instance's `onRRwebEmit`, bypassing the wrapper.
|
|
7855
|
+
* We must find and patch the recorder instance, not the wrapper.
|
|
7856
|
+
*
|
|
7857
|
+
* The recorder instance is stored on a minified property of SessionRecording.
|
|
7858
|
+
* We detect it by looking for an object with both `onRRwebEmit` and `start` methods.
|
|
7859
|
+
*/
|
|
7860
|
+
setupRRWebIntercept(retries = 30) {
|
|
7861
|
+
var _a2;
|
|
7862
|
+
const sr = (_a2 = this.client) == null ? void 0 : _a2.sessionRecording;
|
|
7863
|
+
if (!sr) {
|
|
7864
|
+
if (retries > 0) {
|
|
7865
|
+
setTimeout(() => this.setupRRWebIntercept(retries - 1), 500);
|
|
7866
|
+
}
|
|
7867
|
+
return;
|
|
7868
|
+
}
|
|
7869
|
+
let recorder = null;
|
|
7870
|
+
const srRecord = sr;
|
|
7871
|
+
for (const key of Object.getOwnPropertyNames(srRecord)) {
|
|
7872
|
+
const val = srRecord[key];
|
|
7873
|
+
if (val && typeof val === "object" && typeof val.onRRwebEmit === "function" && typeof val.start === "function" && val !== sr) {
|
|
7874
|
+
recorder = val;
|
|
7875
|
+
break;
|
|
7876
|
+
}
|
|
7877
|
+
}
|
|
7878
|
+
if (!recorder) {
|
|
7879
|
+
if (retries > 0) {
|
|
7880
|
+
setTimeout(() => this.setupRRWebIntercept(retries - 1), 500);
|
|
7881
|
+
}
|
|
7882
|
+
return;
|
|
7883
|
+
}
|
|
7884
|
+
const originalEmit = recorder.onRRwebEmit.bind(recorder);
|
|
7885
|
+
recorder.onRRwebEmit = (rawEvent) => {
|
|
7886
|
+
var _a3;
|
|
7887
|
+
(_a3 = this.rrwebCallback) == null ? void 0 : _a3.call(this, { kind: "rrweb", ...rawEvent });
|
|
7888
|
+
originalEmit(rawEvent);
|
|
7889
|
+
};
|
|
7890
|
+
if (typeof window !== "undefined") {
|
|
7891
|
+
window.__RRWEB_INTERCEPT_READY__ = true;
|
|
7892
|
+
}
|
|
7066
7893
|
}
|
|
7067
7894
|
/**
|
|
7068
7895
|
* Get all feature flags from PostHog.
|
|
7069
7896
|
* Used to extract segment membership flags (in_segment_*).
|
|
7070
7897
|
*/
|
|
7071
7898
|
getAllFeatureFlags() {
|
|
7072
|
-
var _a2, _b
|
|
7073
|
-
|
|
7074
|
-
return flags;
|
|
7899
|
+
var _a2, _b;
|
|
7900
|
+
return (_b = (_a2 = this.client) == null ? void 0 : _a2.featureFlags) == null ? void 0 : _b.getFlagVariants();
|
|
7075
7901
|
}
|
|
7076
7902
|
/**
|
|
7077
7903
|
* Get segment membership flags (in_segment_*) from PostHog.
|
|
@@ -7152,6 +7978,59 @@ function createPostHogClient(options = {}) {
|
|
|
7152
7978
|
return new PostHogAdapter(options);
|
|
7153
7979
|
}
|
|
7154
7980
|
|
|
7981
|
+
// src/telemetry/InterventionTracker.ts
|
|
7982
|
+
var InterventionTracker = class {
|
|
7983
|
+
constructor(telemetry, variantId) {
|
|
7984
|
+
__publicField(this, "telemetry");
|
|
7985
|
+
__publicField(this, "variantId");
|
|
7986
|
+
__publicField(this, "seenSet", /* @__PURE__ */ new Set());
|
|
7987
|
+
__publicField(this, "triggeredSet", /* @__PURE__ */ new Set());
|
|
7988
|
+
this.telemetry = telemetry;
|
|
7989
|
+
this.variantId = variantId;
|
|
7990
|
+
}
|
|
7991
|
+
trackServed(tiles, actions) {
|
|
7992
|
+
var _a2, _b;
|
|
7993
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_config_served", {
|
|
7994
|
+
variant_id: this.variantId,
|
|
7995
|
+
tiles,
|
|
7996
|
+
actions
|
|
7997
|
+
});
|
|
7998
|
+
}
|
|
7999
|
+
trackSeen(interventionId, interventionKind) {
|
|
8000
|
+
var _a2, _b;
|
|
8001
|
+
if (this.seenSet.has(interventionId)) return;
|
|
8002
|
+
this.seenSet.add(interventionId);
|
|
8003
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_seen", {
|
|
8004
|
+
variant_id: this.variantId,
|
|
8005
|
+
intervention_id: interventionId,
|
|
8006
|
+
intervention_kind: interventionKind
|
|
8007
|
+
});
|
|
8008
|
+
}
|
|
8009
|
+
trackTriggered(interventionId, interventionKind) {
|
|
8010
|
+
var _a2, _b;
|
|
8011
|
+
if (this.triggeredSet.has(interventionId)) return;
|
|
8012
|
+
this.triggeredSet.add(interventionId);
|
|
8013
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_triggered", {
|
|
8014
|
+
variant_id: this.variantId,
|
|
8015
|
+
intervention_id: interventionId,
|
|
8016
|
+
intervention_kind: interventionKind
|
|
8017
|
+
});
|
|
8018
|
+
}
|
|
8019
|
+
trackInteracted(interventionId, interventionKind, interactionType) {
|
|
8020
|
+
var _a2, _b;
|
|
8021
|
+
(_b = (_a2 = this.telemetry).track) == null ? void 0 : _b.call(_a2, "syntro_intervention_interacted", {
|
|
8022
|
+
variant_id: this.variantId,
|
|
8023
|
+
intervention_id: interventionId,
|
|
8024
|
+
intervention_kind: interventionKind,
|
|
8025
|
+
interaction_type: interactionType
|
|
8026
|
+
});
|
|
8027
|
+
}
|
|
8028
|
+
resetPage() {
|
|
8029
|
+
this.seenSet.clear();
|
|
8030
|
+
this.triggeredSet.clear();
|
|
8031
|
+
}
|
|
8032
|
+
};
|
|
8033
|
+
|
|
7155
8034
|
// src/actions/executors/core-flow.ts
|
|
7156
8035
|
var executeSequence = async (action, context) => {
|
|
7157
8036
|
const handles = [];
|
|
@@ -7422,158 +8301,7 @@ function hasExecutor(kind) {
|
|
|
7422
8301
|
return executorRegistry.has(kind);
|
|
7423
8302
|
}
|
|
7424
8303
|
|
|
7425
|
-
// src/actions/validation.ts
|
|
7426
|
-
var DANGEROUS_ATTRS = /* @__PURE__ */ new Set([
|
|
7427
|
-
"onclick",
|
|
7428
|
-
"onerror",
|
|
7429
|
-
"onload",
|
|
7430
|
-
"onmouseover",
|
|
7431
|
-
"onfocus",
|
|
7432
|
-
"onblur",
|
|
7433
|
-
"onchange",
|
|
7434
|
-
"onsubmit",
|
|
7435
|
-
"onkeydown",
|
|
7436
|
-
"onkeyup",
|
|
7437
|
-
"onkeypress"
|
|
7438
|
-
]);
|
|
7439
|
-
var MAX_HTML_LENGTH = 5e4;
|
|
7440
|
-
var MAX_STYLE_COUNT = 50;
|
|
7441
|
-
function validateAction(action) {
|
|
7442
|
-
const errors = [];
|
|
7443
|
-
const warnings = [];
|
|
7444
|
-
if (!action || typeof action !== "object") {
|
|
7445
|
-
errors.push({
|
|
7446
|
-
code: "INVALID_ACTION",
|
|
7447
|
-
message: "Action must be an object"
|
|
7448
|
-
});
|
|
7449
|
-
return { valid: false, errors, warnings };
|
|
7450
|
-
}
|
|
7451
|
-
const { kind } = action;
|
|
7452
|
-
if (!kind || typeof kind !== "string") {
|
|
7453
|
-
errors.push({
|
|
7454
|
-
code: "MISSING_KIND",
|
|
7455
|
-
message: "Action must have a 'kind' property"
|
|
7456
|
-
});
|
|
7457
|
-
return { valid: false, errors, warnings };
|
|
7458
|
-
}
|
|
7459
|
-
if (!hasExecutor(kind) && kind !== "core:mountWidget") {
|
|
7460
|
-
const registered = executorRegistry.list();
|
|
7461
|
-
console.error(
|
|
7462
|
-
`[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.`
|
|
7463
|
-
);
|
|
7464
|
-
errors.push({
|
|
7465
|
-
code: "UNKNOWN_KIND",
|
|
7466
|
-
message: `Unknown action kind: ${kind}`,
|
|
7467
|
-
field: "kind"
|
|
7468
|
-
});
|
|
7469
|
-
return { valid: false, errors, warnings };
|
|
7470
|
-
}
|
|
7471
|
-
switch (kind) {
|
|
7472
|
-
case "overlays:highlight":
|
|
7473
|
-
case "overlays:pulse":
|
|
7474
|
-
case "navigation:scrollTo":
|
|
7475
|
-
validateAnchorAction(action, errors, warnings);
|
|
7476
|
-
break;
|
|
7477
|
-
case "overlays:badge":
|
|
7478
|
-
validateAnchorAction(action, errors, warnings);
|
|
7479
|
-
validateBadgeAction(action, errors, warnings);
|
|
7480
|
-
break;
|
|
7481
|
-
case "overlays:tooltip":
|
|
7482
|
-
validateAnchorAction(action, errors, warnings);
|
|
7483
|
-
validateTooltipAction(action, errors, warnings);
|
|
7484
|
-
break;
|
|
7485
|
-
case "overlays:modal":
|
|
7486
|
-
validateModalAction(action, errors, warnings);
|
|
7487
|
-
break;
|
|
7488
|
-
case "content:insertHtml":
|
|
7489
|
-
validateAnchorAction(action, errors, warnings);
|
|
7490
|
-
validateInsertHtmlAction(action, errors, warnings);
|
|
7491
|
-
break;
|
|
7492
|
-
case "content:setText":
|
|
7493
|
-
validateAnchorAction(action, errors, warnings);
|
|
7494
|
-
validateSetTextAction(action, errors, warnings);
|
|
7495
|
-
break;
|
|
7496
|
-
case "content:setAttr":
|
|
7497
|
-
validateAnchorAction(action, errors, warnings);
|
|
7498
|
-
validateSetAttrAction(action, errors, warnings);
|
|
7499
|
-
break;
|
|
7500
|
-
case "content:addClass":
|
|
7501
|
-
case "content:removeClass":
|
|
7502
|
-
validateAnchorAction(action, errors, warnings);
|
|
7503
|
-
validateClassAction(action, errors, warnings);
|
|
7504
|
-
break;
|
|
7505
|
-
case "content:setStyle":
|
|
7506
|
-
validateAnchorAction(action, errors, warnings);
|
|
7507
|
-
validateSetStyleAction(action, errors, warnings);
|
|
7508
|
-
break;
|
|
7509
|
-
case "core:mountWidget":
|
|
7510
|
-
validateMountWidgetAction(action, errors, warnings);
|
|
7511
|
-
break;
|
|
7512
|
-
case "core:wait":
|
|
7513
|
-
validateWaitAction(action, errors, warnings);
|
|
7514
|
-
break;
|
|
7515
|
-
case "core:sequence":
|
|
7516
|
-
validateSequenceAction(action, errors, warnings);
|
|
7517
|
-
break;
|
|
7518
|
-
case "core:parallel":
|
|
7519
|
-
validateParallelAction(action, errors, warnings);
|
|
7520
|
-
break;
|
|
7521
|
-
case "core:tour":
|
|
7522
|
-
validateTourAction(action, errors, warnings);
|
|
7523
|
-
break;
|
|
7524
|
-
case "navigation:navigate":
|
|
7525
|
-
validateNavigateAction(action, errors, warnings);
|
|
7526
|
-
break;
|
|
7527
|
-
}
|
|
7528
|
-
return {
|
|
7529
|
-
valid: errors.length === 0,
|
|
7530
|
-
errors,
|
|
7531
|
-
warnings
|
|
7532
|
-
};
|
|
7533
|
-
}
|
|
7534
|
-
function validateAnchorAction(action, errors, warnings) {
|
|
7535
|
-
const anchorId = action.anchorId;
|
|
7536
|
-
if (!anchorId || typeof anchorId !== "object") {
|
|
7537
|
-
errors.push({
|
|
7538
|
-
code: "MISSING_ANCHOR_ID",
|
|
7539
|
-
message: "Action requires an 'anchorId' object with a 'selector' string",
|
|
7540
|
-
field: "anchorId"
|
|
7541
|
-
});
|
|
7542
|
-
return;
|
|
7543
|
-
}
|
|
7544
|
-
if (!anchorId.selector || typeof anchorId.selector !== "string") {
|
|
7545
|
-
errors.push({
|
|
7546
|
-
code: "MISSING_ANCHOR_SELECTOR",
|
|
7547
|
-
message: "anchorId requires a 'selector' string",
|
|
7548
|
-
field: "anchorId.selector"
|
|
7549
|
-
});
|
|
7550
|
-
} else if (anchorId.selector.length > 200) {
|
|
7551
|
-
warnings.push({
|
|
7552
|
-
code: "LONG_ANCHOR_ID",
|
|
7553
|
-
message: "Anchor selector is unusually long",
|
|
7554
|
-
suggestion: "Consider using a shorter, more descriptive selector"
|
|
7555
|
-
});
|
|
7556
|
-
}
|
|
7557
|
-
if (anchorId.route === void 0 || anchorId.route === null) {
|
|
7558
|
-
errors.push({
|
|
7559
|
-
code: "MISSING_ANCHOR_ROUTE",
|
|
7560
|
-
message: `anchorId requires a 'route' (string or array of strings). Use "**" for all routes.`,
|
|
7561
|
-
field: "anchorId.route"
|
|
7562
|
-
});
|
|
7563
|
-
} else {
|
|
7564
|
-
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
7565
|
-
for (const route of routes) {
|
|
7566
|
-
if (typeof route !== "string") {
|
|
7567
|
-
errors.push({
|
|
7568
|
-
code: "INVALID_ANCHOR_ROUTE",
|
|
7569
|
-
message: "anchorId.route must be a string or array of strings",
|
|
7570
|
-
field: "anchorId.route"
|
|
7571
|
-
});
|
|
7572
|
-
break;
|
|
7573
|
-
}
|
|
7574
|
-
}
|
|
7575
|
-
}
|
|
7576
|
-
}
|
|
8304
|
+
// src/actions/validation-rules.ts
|
|
7577
8305
|
function validateBadgeAction(action, errors, warnings) {
|
|
7578
8306
|
if (!action.content || typeof action.content !== "string") {
|
|
7579
8307
|
errors.push({
|
|
@@ -7960,19 +8688,172 @@ function validateTourAction(action, errors, warnings) {
|
|
|
7960
8688
|
}
|
|
7961
8689
|
}
|
|
7962
8690
|
}
|
|
7963
|
-
|
|
7964
|
-
|
|
8691
|
+
|
|
8692
|
+
// src/actions/validation-core.ts
|
|
8693
|
+
var DANGEROUS_ATTRS = /* @__PURE__ */ new Set([
|
|
8694
|
+
"onclick",
|
|
8695
|
+
"onerror",
|
|
8696
|
+
"onload",
|
|
8697
|
+
"onmouseover",
|
|
8698
|
+
"onfocus",
|
|
8699
|
+
"onblur",
|
|
8700
|
+
"onchange",
|
|
8701
|
+
"onsubmit",
|
|
8702
|
+
"onkeydown",
|
|
8703
|
+
"onkeyup",
|
|
8704
|
+
"onkeypress"
|
|
8705
|
+
]);
|
|
8706
|
+
var MAX_HTML_LENGTH = 5e4;
|
|
8707
|
+
var MAX_STYLE_COUNT = 50;
|
|
8708
|
+
function validateAction(action) {
|
|
7965
8709
|
const errors = [];
|
|
7966
8710
|
const warnings = [];
|
|
7967
|
-
if (!
|
|
7968
|
-
console.error("[ActionValidation] validateActions called with non-array:", typeof actions);
|
|
8711
|
+
if (!action || typeof action !== "object") {
|
|
7969
8712
|
errors.push({
|
|
7970
|
-
code: "
|
|
7971
|
-
message: "
|
|
8713
|
+
code: "INVALID_ACTION",
|
|
8714
|
+
message: "Action must be an object"
|
|
7972
8715
|
});
|
|
7973
8716
|
return { valid: false, errors, warnings };
|
|
7974
8717
|
}
|
|
7975
|
-
|
|
8718
|
+
const { kind } = action;
|
|
8719
|
+
if (!kind || typeof kind !== "string") {
|
|
8720
|
+
errors.push({
|
|
8721
|
+
code: "MISSING_KIND",
|
|
8722
|
+
message: "Action must have a 'kind' property"
|
|
8723
|
+
});
|
|
8724
|
+
return { valid: false, errors, warnings };
|
|
8725
|
+
}
|
|
8726
|
+
if (!hasExecutor(kind) && kind !== "core:mountWidget") {
|
|
8727
|
+
const registered = executorRegistry.list();
|
|
8728
|
+
console.error(
|
|
8729
|
+
`[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.`
|
|
8730
|
+
);
|
|
8731
|
+
errors.push({
|
|
8732
|
+
code: "UNKNOWN_KIND",
|
|
8733
|
+
message: `Unknown action kind: ${kind}`,
|
|
8734
|
+
field: "kind"
|
|
8735
|
+
});
|
|
8736
|
+
return { valid: false, errors, warnings };
|
|
8737
|
+
}
|
|
8738
|
+
switch (kind) {
|
|
8739
|
+
case "overlays:highlight":
|
|
8740
|
+
case "overlays:pulse":
|
|
8741
|
+
case "navigation:scrollTo":
|
|
8742
|
+
validateAnchorAction(action, errors, warnings);
|
|
8743
|
+
break;
|
|
8744
|
+
case "overlays:badge":
|
|
8745
|
+
validateAnchorAction(action, errors, warnings);
|
|
8746
|
+
validateBadgeAction(action, errors, warnings);
|
|
8747
|
+
break;
|
|
8748
|
+
case "overlays:tooltip":
|
|
8749
|
+
validateAnchorAction(action, errors, warnings);
|
|
8750
|
+
validateTooltipAction(action, errors, warnings);
|
|
8751
|
+
break;
|
|
8752
|
+
case "overlays:modal":
|
|
8753
|
+
validateModalAction(action, errors, warnings);
|
|
8754
|
+
break;
|
|
8755
|
+
case "content:insertHtml":
|
|
8756
|
+
validateAnchorAction(action, errors, warnings);
|
|
8757
|
+
validateInsertHtmlAction(action, errors, warnings);
|
|
8758
|
+
break;
|
|
8759
|
+
case "content:setText":
|
|
8760
|
+
validateAnchorAction(action, errors, warnings);
|
|
8761
|
+
validateSetTextAction(action, errors, warnings);
|
|
8762
|
+
break;
|
|
8763
|
+
case "content:setAttr":
|
|
8764
|
+
validateAnchorAction(action, errors, warnings);
|
|
8765
|
+
validateSetAttrAction(action, errors, warnings);
|
|
8766
|
+
break;
|
|
8767
|
+
case "content:addClass":
|
|
8768
|
+
case "content:removeClass":
|
|
8769
|
+
validateAnchorAction(action, errors, warnings);
|
|
8770
|
+
validateClassAction(action, errors, warnings);
|
|
8771
|
+
break;
|
|
8772
|
+
case "content:setStyle":
|
|
8773
|
+
validateAnchorAction(action, errors, warnings);
|
|
8774
|
+
validateSetStyleAction(action, errors, warnings);
|
|
8775
|
+
break;
|
|
8776
|
+
case "core:mountWidget":
|
|
8777
|
+
validateMountWidgetAction(action, errors, warnings);
|
|
8778
|
+
break;
|
|
8779
|
+
case "core:wait":
|
|
8780
|
+
validateWaitAction(action, errors, warnings);
|
|
8781
|
+
break;
|
|
8782
|
+
case "core:sequence":
|
|
8783
|
+
validateSequenceAction(action, errors, warnings);
|
|
8784
|
+
break;
|
|
8785
|
+
case "core:parallel":
|
|
8786
|
+
validateParallelAction(action, errors, warnings);
|
|
8787
|
+
break;
|
|
8788
|
+
case "overlays:tour":
|
|
8789
|
+
validateTourAction(action, errors, warnings);
|
|
8790
|
+
break;
|
|
8791
|
+
case "navigation:navigate":
|
|
8792
|
+
validateNavigateAction(action, errors, warnings);
|
|
8793
|
+
break;
|
|
8794
|
+
}
|
|
8795
|
+
return {
|
|
8796
|
+
valid: errors.length === 0,
|
|
8797
|
+
errors,
|
|
8798
|
+
warnings
|
|
8799
|
+
};
|
|
8800
|
+
}
|
|
8801
|
+
function validateAnchorAction(action, errors, warnings) {
|
|
8802
|
+
const anchorId = action.anchorId;
|
|
8803
|
+
if (!anchorId || typeof anchorId !== "object") {
|
|
8804
|
+
errors.push({
|
|
8805
|
+
code: "MISSING_ANCHOR_ID",
|
|
8806
|
+
message: "Action requires an 'anchorId' object with a 'selector' string",
|
|
8807
|
+
field: "anchorId"
|
|
8808
|
+
});
|
|
8809
|
+
return;
|
|
8810
|
+
}
|
|
8811
|
+
if (!anchorId.selector || typeof anchorId.selector !== "string") {
|
|
8812
|
+
errors.push({
|
|
8813
|
+
code: "MISSING_ANCHOR_SELECTOR",
|
|
8814
|
+
message: "anchorId requires a 'selector' string",
|
|
8815
|
+
field: "anchorId.selector"
|
|
8816
|
+
});
|
|
8817
|
+
} else if (anchorId.selector.length > 200) {
|
|
8818
|
+
warnings.push({
|
|
8819
|
+
code: "LONG_ANCHOR_ID",
|
|
8820
|
+
message: "Anchor selector is unusually long",
|
|
8821
|
+
suggestion: "Consider using a shorter, more descriptive selector"
|
|
8822
|
+
});
|
|
8823
|
+
}
|
|
8824
|
+
if (anchorId.route === void 0 || anchorId.route === null) {
|
|
8825
|
+
errors.push({
|
|
8826
|
+
code: "MISSING_ANCHOR_ROUTE",
|
|
8827
|
+
message: `anchorId requires a 'route' (string or array of strings). Use "**" for all routes.`,
|
|
8828
|
+
field: "anchorId.route"
|
|
8829
|
+
});
|
|
8830
|
+
} else {
|
|
8831
|
+
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
8832
|
+
for (const route of routes) {
|
|
8833
|
+
if (typeof route !== "string") {
|
|
8834
|
+
errors.push({
|
|
8835
|
+
code: "INVALID_ANCHOR_ROUTE",
|
|
8836
|
+
message: "anchorId.route must be a string or array of strings",
|
|
8837
|
+
field: "anchorId.route"
|
|
8838
|
+
});
|
|
8839
|
+
break;
|
|
8840
|
+
}
|
|
8841
|
+
}
|
|
8842
|
+
}
|
|
8843
|
+
}
|
|
8844
|
+
function validateActions(actions) {
|
|
8845
|
+
var _a2;
|
|
8846
|
+
const errors = [];
|
|
8847
|
+
const warnings = [];
|
|
8848
|
+
if (!Array.isArray(actions)) {
|
|
8849
|
+
console.error("[ActionValidation] validateActions called with non-array:", typeof actions);
|
|
8850
|
+
errors.push({
|
|
8851
|
+
code: "INVALID_ACTIONS",
|
|
8852
|
+
message: "Actions must be an array"
|
|
8853
|
+
});
|
|
8854
|
+
return { valid: false, errors, warnings };
|
|
8855
|
+
}
|
|
8856
|
+
for (let i = 0; i < actions.length; i++) {
|
|
7976
8857
|
const result = validateAction(actions[i]);
|
|
7977
8858
|
if (!result.valid) {
|
|
7978
8859
|
const action = actions[i];
|
|
@@ -8106,7 +8987,7 @@ function createActionEngine(options) {
|
|
|
8106
8987
|
}
|
|
8107
8988
|
return executor(action, context);
|
|
8108
8989
|
}
|
|
8109
|
-
function subscribeForReeval(id, action, triggerWhen,
|
|
8990
|
+
function subscribeForReeval(id, action, triggerWhen, _handle) {
|
|
8110
8991
|
if (!runtime3) return;
|
|
8111
8992
|
const unsubs = [];
|
|
8112
8993
|
const onReeval = async () => {
|
|
@@ -8250,13 +9131,9 @@ function createActionEngine(options) {
|
|
|
8250
9131
|
entry2.state = "reverted";
|
|
8251
9132
|
publishEvent("action.reverted", { id, kind: action.kind });
|
|
8252
9133
|
} catch (error2) {
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
kind: action.kind,
|
|
8257
|
-
error: String(error2)
|
|
8258
|
-
});
|
|
8259
|
-
throw error2;
|
|
9134
|
+
console.warn(`[ActionEngine] Cleanup error for ${action.kind} (${id}), ignoring:`, error2);
|
|
9135
|
+
entry2.state = "reverted";
|
|
9136
|
+
publishEvent("action.reverted", { id, kind: action.kind });
|
|
8260
9137
|
} finally {
|
|
8261
9138
|
activeActions.delete(id);
|
|
8262
9139
|
}
|
|
@@ -8309,15 +9186,30 @@ function createActionEngine(options) {
|
|
|
8309
9186
|
const handles = [];
|
|
8310
9187
|
const appliedHandles = [];
|
|
8311
9188
|
try {
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
9189
|
+
const results = await Promise.allSettled(actions.map((action) => apply(action)));
|
|
9190
|
+
const errors = [];
|
|
9191
|
+
for (const result of results) {
|
|
9192
|
+
if (result.status === "fulfilled") {
|
|
9193
|
+
handles.push(result.value);
|
|
9194
|
+
appliedHandles.push(result.value);
|
|
9195
|
+
} else {
|
|
9196
|
+
errors.push(
|
|
9197
|
+
result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
9198
|
+
);
|
|
9199
|
+
}
|
|
9200
|
+
}
|
|
9201
|
+
if (errors.length > 0 && appliedHandles.length === 0) {
|
|
9202
|
+
throw errors[0];
|
|
9203
|
+
}
|
|
9204
|
+
if (errors.length > 0) {
|
|
9205
|
+
console.warn(
|
|
9206
|
+
`[ActionEngine] ${errors.length}/${actions.length} action(s) failed in batch:`,
|
|
9207
|
+
errors.map((e) => e.message).join("; ")
|
|
9208
|
+
);
|
|
8316
9209
|
}
|
|
8317
9210
|
} catch (error2) {
|
|
8318
9211
|
console.error(
|
|
8319
|
-
`[ActionEngine] Batch apply FAILED
|
|
8320
|
-
`Successfully applied: ${appliedHandles.length}. Rolling back...`,
|
|
9212
|
+
`[ActionEngine] Batch apply FAILED. Successfully applied: ${appliedHandles.length}. Rolling back...`,
|
|
8321
9213
|
error2
|
|
8322
9214
|
);
|
|
8323
9215
|
for (const handle of appliedHandles) {
|
|
@@ -8358,7 +9250,7 @@ function createActionEngine(options) {
|
|
|
8358
9250
|
state: entry.state
|
|
8359
9251
|
}));
|
|
8360
9252
|
}
|
|
8361
|
-
function destroy() {
|
|
9253
|
+
async function destroy() {
|
|
8362
9254
|
for (const unsubs of conditionalUnsubs.values()) {
|
|
8363
9255
|
for (const unsub of unsubs) {
|
|
8364
9256
|
try {
|
|
@@ -8368,16 +9260,27 @@ function createActionEngine(options) {
|
|
|
8368
9260
|
}
|
|
8369
9261
|
}
|
|
8370
9262
|
conditionalUnsubs.clear();
|
|
9263
|
+
const cleanupPromises = [];
|
|
8371
9264
|
for (const entry of activeActions.values()) {
|
|
8372
9265
|
if (entry.state === "applied") {
|
|
8373
9266
|
try {
|
|
8374
|
-
entry.cleanup();
|
|
9267
|
+
const result = entry.cleanup();
|
|
9268
|
+
if (result && typeof result.then === "function") {
|
|
9269
|
+
cleanupPromises.push(
|
|
9270
|
+
result.catch((error2) => {
|
|
9271
|
+
console.error(`[ActionEngine] Error during async cleanup:`, error2);
|
|
9272
|
+
})
|
|
9273
|
+
);
|
|
9274
|
+
}
|
|
8375
9275
|
} catch (error2) {
|
|
8376
9276
|
console.error(`[ActionEngine] Error during cleanup:`, error2);
|
|
8377
9277
|
}
|
|
8378
9278
|
}
|
|
8379
9279
|
}
|
|
8380
9280
|
activeActions.clear();
|
|
9281
|
+
if (cleanupPromises.length > 0) {
|
|
9282
|
+
await Promise.all(cleanupPromises);
|
|
9283
|
+
}
|
|
8381
9284
|
}
|
|
8382
9285
|
return {
|
|
8383
9286
|
apply,
|
|
@@ -8400,6 +9303,7 @@ function createAnchorResolver(opts) {
|
|
|
8400
9303
|
function resolve(selector) {
|
|
8401
9304
|
if (!root) return null;
|
|
8402
9305
|
try {
|
|
9306
|
+
if (root.matches(selector)) return root;
|
|
8403
9307
|
return root.querySelector(selector);
|
|
8404
9308
|
} catch {
|
|
8405
9309
|
return null;
|
|
@@ -9079,6 +9983,66 @@ function createEventAccumulator(options) {
|
|
|
9079
9983
|
};
|
|
9080
9984
|
}
|
|
9081
9985
|
|
|
9986
|
+
// src/events/validation.ts
|
|
9987
|
+
var APP_PREFIX = "app:";
|
|
9988
|
+
var RESERVED_PREFIX = "syntro:";
|
|
9989
|
+
var SEGMENT_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
9990
|
+
function validateEventName(name) {
|
|
9991
|
+
if (!name) {
|
|
9992
|
+
return { valid: false, reason: "Event name cannot be empty" };
|
|
9993
|
+
}
|
|
9994
|
+
if (name.startsWith(RESERVED_PREFIX)) {
|
|
9995
|
+
return { valid: false, reason: '"syntro:" prefix is reserved for internal SDK events' };
|
|
9996
|
+
}
|
|
9997
|
+
if (!name.startsWith(APP_PREFIX)) {
|
|
9998
|
+
return { valid: false, reason: `Custom events must start with "app:" prefix. Got: "${name}"` };
|
|
9999
|
+
}
|
|
10000
|
+
const segments = name.slice(APP_PREFIX.length).split(":");
|
|
10001
|
+
if (segments.length < 2) {
|
|
10002
|
+
return {
|
|
10003
|
+
valid: false,
|
|
10004
|
+
reason: `Event name must have at least 2 segments after "app:" (app:{category}:{action}). Got: "${name}"`
|
|
10005
|
+
};
|
|
10006
|
+
}
|
|
10007
|
+
for (const segment of segments) {
|
|
10008
|
+
if (!SEGMENT_PATTERN.test(segment)) {
|
|
10009
|
+
return {
|
|
10010
|
+
valid: false,
|
|
10011
|
+
reason: `Segment "${segment}" must be lowercase alphanumeric + underscores. Got: "${name}"`
|
|
10012
|
+
};
|
|
10013
|
+
}
|
|
10014
|
+
}
|
|
10015
|
+
return { valid: true };
|
|
10016
|
+
}
|
|
10017
|
+
function isSerializable(value) {
|
|
10018
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
|
|
10019
|
+
}
|
|
10020
|
+
function checkDepth(obj, maxDepth, current = 0) {
|
|
10021
|
+
if (current >= maxDepth) return false;
|
|
10022
|
+
for (const value of Object.values(obj)) {
|
|
10023
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
10024
|
+
if (!checkDepth(value, maxDepth, current + 1)) return false;
|
|
10025
|
+
}
|
|
10026
|
+
}
|
|
10027
|
+
return true;
|
|
10028
|
+
}
|
|
10029
|
+
function validateProps(props) {
|
|
10030
|
+
if (props === void 0) return { valid: true };
|
|
10031
|
+
if (props === null || typeof props !== "object" || Array.isArray(props)) {
|
|
10032
|
+
return { valid: false, reason: "Props must be a plain object" };
|
|
10033
|
+
}
|
|
10034
|
+
if (!checkDepth(props, 2)) {
|
|
10035
|
+
return { valid: false, reason: "Props nesting depth exceeds 2 levels" };
|
|
10036
|
+
}
|
|
10037
|
+
const stripped = [];
|
|
10038
|
+
for (const [key, value] of Object.entries(props)) {
|
|
10039
|
+
if (value !== null && typeof value === "object") continue;
|
|
10040
|
+
if (!isSerializable(value)) stripped.push(key);
|
|
10041
|
+
}
|
|
10042
|
+
if (stripped.length > 0) return { valid: true, stripped };
|
|
10043
|
+
return { valid: true };
|
|
10044
|
+
}
|
|
10045
|
+
|
|
9082
10046
|
// src/events/EventBus.ts
|
|
9083
10047
|
function matchesFilter(event, filter) {
|
|
9084
10048
|
if (!filter) return true;
|
|
@@ -9110,8 +10074,16 @@ var EventBus = class {
|
|
|
9110
10074
|
__publicField(this, "subscriptions", /* @__PURE__ */ new Set());
|
|
9111
10075
|
__publicField(this, "history", []);
|
|
9112
10076
|
__publicField(this, "maxHistorySize");
|
|
9113
|
-
|
|
10077
|
+
__publicField(this, "debug");
|
|
10078
|
+
__publicField(this, "emitHistory");
|
|
10079
|
+
__publicField(this, "posthogCapture");
|
|
10080
|
+
__publicField(this, "testMode");
|
|
10081
|
+
var _a2, _b, _c, _d, _e;
|
|
9114
10082
|
this.maxHistorySize = (_a2 = options.maxHistorySize) != null ? _a2 : 100;
|
|
10083
|
+
this.debug = (_b = options.debug) != null ? _b : false;
|
|
10084
|
+
this.emitHistory = (_c = options.history) != null ? _c : null;
|
|
10085
|
+
this.posthogCapture = (_d = options.posthogCapture) != null ? _d : null;
|
|
10086
|
+
this.testMode = (_e = options.testMode) != null ? _e : false;
|
|
9115
10087
|
}
|
|
9116
10088
|
/**
|
|
9117
10089
|
* Subscribe to events matching an optional filter.
|
|
@@ -9164,6 +10136,83 @@ var EventBus = class {
|
|
|
9164
10136
|
}
|
|
9165
10137
|
}
|
|
9166
10138
|
}
|
|
10139
|
+
/**
|
|
10140
|
+
* Emit a validated custom event from the host application.
|
|
10141
|
+
*
|
|
10142
|
+
* Custom events must use the `app:` prefix (e.g. `app:cart:abandoned`).
|
|
10143
|
+
* In debug mode, returns an EmitResult with delivery details.
|
|
10144
|
+
* In production mode, returns undefined.
|
|
10145
|
+
*/
|
|
10146
|
+
emit(name, props) {
|
|
10147
|
+
const nameResult = validateEventName(name);
|
|
10148
|
+
if (!nameResult.valid) {
|
|
10149
|
+
console.warn(`[EventBus] emit() rejected: ${nameResult.reason}`);
|
|
10150
|
+
return this.debug ? { delivered: false, matchedRules: [], posthogCaptured: false, listenersNotified: 0 } : void 0;
|
|
10151
|
+
}
|
|
10152
|
+
const propsResult = validateProps(props);
|
|
10153
|
+
if (!propsResult.valid) {
|
|
10154
|
+
console.warn(`[EventBus] emit() rejected props: ${propsResult.reason}`);
|
|
10155
|
+
return this.debug ? { delivered: false, matchedRules: [], posthogCaptured: false, listenersNotified: 0 } : void 0;
|
|
10156
|
+
}
|
|
10157
|
+
const event = {
|
|
10158
|
+
ts: Date.now(),
|
|
10159
|
+
name,
|
|
10160
|
+
source: "custom",
|
|
10161
|
+
props,
|
|
10162
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
10163
|
+
};
|
|
10164
|
+
this.history.push(event);
|
|
10165
|
+
if (this.history.length > this.maxHistorySize) {
|
|
10166
|
+
this.history.shift();
|
|
10167
|
+
}
|
|
10168
|
+
let listenersNotified = 0;
|
|
10169
|
+
for (const subscription of this.subscriptions) {
|
|
10170
|
+
if (matchesFilter(event, subscription.filter)) {
|
|
10171
|
+
try {
|
|
10172
|
+
subscription.callback(event);
|
|
10173
|
+
listenersNotified++;
|
|
10174
|
+
} catch (err) {
|
|
10175
|
+
console.error("[EventBus] Subscriber error:", err);
|
|
10176
|
+
listenersNotified++;
|
|
10177
|
+
}
|
|
10178
|
+
}
|
|
10179
|
+
}
|
|
10180
|
+
let posthogCaptured = false;
|
|
10181
|
+
if (this.posthogCapture && !this.testMode) {
|
|
10182
|
+
try {
|
|
10183
|
+
this.posthogCapture(name, props);
|
|
10184
|
+
posthogCaptured = true;
|
|
10185
|
+
} catch (err) {
|
|
10186
|
+
console.error("[EventBus] PostHog capture error:", err);
|
|
10187
|
+
}
|
|
10188
|
+
}
|
|
10189
|
+
if (this.emitHistory) {
|
|
10190
|
+
this.emitHistory.record({
|
|
10191
|
+
name,
|
|
10192
|
+
props,
|
|
10193
|
+
source: "custom",
|
|
10194
|
+
timestamp: event.ts,
|
|
10195
|
+
matchedRules: []
|
|
10196
|
+
});
|
|
10197
|
+
}
|
|
10198
|
+
if (this.debug) {
|
|
10199
|
+
console.debug("[EventBus] emit()", { name, props, listenersNotified, posthogCaptured });
|
|
10200
|
+
return {
|
|
10201
|
+
delivered: true,
|
|
10202
|
+
matchedRules: [],
|
|
10203
|
+
posthogCaptured,
|
|
10204
|
+
listenersNotified
|
|
10205
|
+
};
|
|
10206
|
+
}
|
|
10207
|
+
return void 0;
|
|
10208
|
+
}
|
|
10209
|
+
/**
|
|
10210
|
+
* Set the PostHog capture function after construction.
|
|
10211
|
+
* Used by bootstrap to wire PostHog after the EventBus is created.
|
|
10212
|
+
*/
|
|
10213
|
+
setPosthogCapture(fn) {
|
|
10214
|
+
this.posthogCapture = fn;
|
|
10215
|
+
}
|
|
9167
10216
|
/**
|
|
9168
10217
|
* Get recent events matching an optional filter.
|
|
9169
10218
|
*/
|
|
@@ -9214,124 +10263,26 @@ function createEventBus(options = {}) {
|
|
|
9214
10263
|
return new EventBus(options);
|
|
9215
10264
|
}
|
|
9216
10265
|
|
|
9217
|
-
// src/events/
|
|
9218
|
-
var
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
$scroll: StandardEvents.UI_SCROLL,
|
|
9224
|
-
$input: StandardEvents.UI_INPUT,
|
|
9225
|
-
$change: StandardEvents.UI_CHANGE,
|
|
9226
|
-
$submit: StandardEvents.UI_SUBMIT,
|
|
9227
|
-
// Navigation events
|
|
9228
|
-
$pageview: StandardEvents.NAV_PAGE_VIEW,
|
|
9229
|
-
$pageleave: StandardEvents.NAV_PAGE_LEAVE,
|
|
9230
|
-
// Session events
|
|
9231
|
-
$session_start: "session.start",
|
|
9232
|
-
// Identify events
|
|
9233
|
-
$identify: "user.identify"
|
|
9234
|
-
};
|
|
9235
|
-
function getEventName(phEvent) {
|
|
9236
|
-
var _a2, _b;
|
|
9237
|
-
const eventName = phEvent.event;
|
|
9238
|
-
if (typeof eventName !== "string") {
|
|
9239
|
-
return "posthog.unknown";
|
|
10266
|
+
// src/events/history.ts
|
|
10267
|
+
var EventHistory = class {
|
|
10268
|
+
constructor(maxSize = 100) {
|
|
10269
|
+
__publicField(this, "entries", []);
|
|
10270
|
+
__publicField(this, "maxSize");
|
|
10271
|
+
this.maxSize = maxSize;
|
|
9240
10272
|
}
|
|
9241
|
-
|
|
9242
|
-
|
|
10273
|
+
record(entry) {
|
|
10274
|
+
this.entries.push(entry);
|
|
10275
|
+
if (this.maxSize > 0 && this.entries.length > this.maxSize) {
|
|
10276
|
+
this.entries.shift();
|
|
10277
|
+
}
|
|
9243
10278
|
}
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
const eventType = (_b = phEvent.properties) == null ? void 0 : _b.$event_type;
|
|
9247
|
-
if (eventType === "submit") return StandardEvents.UI_SUBMIT;
|
|
9248
|
-
if (eventType === "change") return StandardEvents.UI_CHANGE;
|
|
9249
|
-
if (tagName === "input" || tagName === "textarea") return StandardEvents.UI_INPUT;
|
|
9250
|
-
return StandardEvents.UI_CLICK;
|
|
10279
|
+
getAll() {
|
|
10280
|
+
return [...this.entries];
|
|
9251
10281
|
}
|
|
9252
|
-
|
|
9253
|
-
|
|
10282
|
+
clear() {
|
|
10283
|
+
this.entries = [];
|
|
9254
10284
|
}
|
|
9255
|
-
|
|
9256
|
-
}
|
|
9257
|
-
function extractProps(phEvent) {
|
|
9258
|
-
var _a2;
|
|
9259
|
-
const props = {};
|
|
9260
|
-
const phProps = phEvent.properties || {};
|
|
9261
|
-
const elements = phProps.$elements;
|
|
9262
|
-
if (phProps.$tag_name) {
|
|
9263
|
-
props.tagName = phProps.$tag_name;
|
|
9264
|
-
} else if ((_a2 = elements == null ? void 0 : elements[0]) == null ? void 0 : _a2.tag_name) {
|
|
9265
|
-
props.tagName = elements[0].tag_name;
|
|
9266
|
-
}
|
|
9267
|
-
if (phProps.$el_text) props.elementText = phProps.$el_text;
|
|
9268
|
-
if (elements) props.elements = elements;
|
|
9269
|
-
if (phProps.$current_url) props.url = phProps.$current_url;
|
|
9270
|
-
if (phProps.$pathname) props.pathname = phProps.$pathname;
|
|
9271
|
-
if (phProps.$host) props.host = phProps.$host;
|
|
9272
|
-
if (phProps.$viewport_width) props.viewportWidth = phProps.$viewport_width;
|
|
9273
|
-
if (phProps.$viewport_height) props.viewportHeight = phProps.$viewport_height;
|
|
9274
|
-
if (phProps.$session_id) props.sessionId = phProps.$session_id;
|
|
9275
|
-
if (phProps.$scroll_depth) props.scrollDepth = phProps.$scroll_depth;
|
|
9276
|
-
if (phProps.$scroll_percentage) props.scrollPercentage = phProps.$scroll_percentage;
|
|
9277
|
-
props.originalEvent = phEvent.event;
|
|
9278
|
-
return props;
|
|
9279
|
-
}
|
|
9280
|
-
function normalizePostHogEvent(phEvent) {
|
|
9281
|
-
let ts;
|
|
9282
|
-
if (typeof phEvent.timestamp === "number") {
|
|
9283
|
-
ts = phEvent.timestamp;
|
|
9284
|
-
} else if (typeof phEvent.timestamp === "string") {
|
|
9285
|
-
ts = new Date(phEvent.timestamp).getTime();
|
|
9286
|
-
} else {
|
|
9287
|
-
ts = Date.now();
|
|
9288
|
-
}
|
|
9289
|
-
return {
|
|
9290
|
-
ts,
|
|
9291
|
-
name: getEventName(phEvent),
|
|
9292
|
-
source: "posthog",
|
|
9293
|
-
props: extractProps(phEvent),
|
|
9294
|
-
schemaVersion: EVENT_SCHEMA_VERSION
|
|
9295
|
-
};
|
|
9296
|
-
}
|
|
9297
|
-
function shouldNormalizeEvent(phEvent) {
|
|
9298
|
-
const eventName = phEvent.event;
|
|
9299
|
-
if (typeof eventName !== "string") return false;
|
|
9300
|
-
const skipEvents = [
|
|
9301
|
-
"$feature_flag_called",
|
|
9302
|
-
"$feature_flags",
|
|
9303
|
-
"$groups",
|
|
9304
|
-
"$groupidentify",
|
|
9305
|
-
"$set",
|
|
9306
|
-
"$set_once",
|
|
9307
|
-
"$unset",
|
|
9308
|
-
"$create_alias",
|
|
9309
|
-
"$capture_metrics",
|
|
9310
|
-
"$performance_event",
|
|
9311
|
-
"$web_vitals",
|
|
9312
|
-
"$exception",
|
|
9313
|
-
"$dead_click",
|
|
9314
|
-
"$heatmap"
|
|
9315
|
-
];
|
|
9316
|
-
if (skipEvents.includes(eventName)) {
|
|
9317
|
-
return false;
|
|
9318
|
-
}
|
|
9319
|
-
return true;
|
|
9320
|
-
}
|
|
9321
|
-
function createPostHogNormalizer(publishFn) {
|
|
9322
|
-
return (eventName, properties) => {
|
|
9323
|
-
if (typeof eventName !== "string") return;
|
|
9324
|
-
const phEvent = {
|
|
9325
|
-
event: eventName,
|
|
9326
|
-
properties,
|
|
9327
|
-
timestamp: Date.now()
|
|
9328
|
-
};
|
|
9329
|
-
if (shouldNormalizeEvent(phEvent)) {
|
|
9330
|
-
const normalizedEvent = normalizePostHogEvent(phEvent);
|
|
9331
|
-
publishFn(normalizedEvent);
|
|
9332
|
-
}
|
|
9333
|
-
};
|
|
9334
|
-
}
|
|
10285
|
+
};
|
|
9335
10286
|
|
|
9336
10287
|
// src/navigation/NavigationMonitor.ts
|
|
9337
10288
|
var NavigationMonitor = class {
|
|
@@ -10132,9 +11083,18 @@ function createSurfaces(options) {
|
|
|
10132
11083
|
}
|
|
10133
11084
|
async function unmountEntry(entry) {
|
|
10134
11085
|
var _a2;
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
11086
|
+
if (entry.container.isConnected) {
|
|
11087
|
+
await playExitAnimation(entry.container, entry.options.animation);
|
|
11088
|
+
}
|
|
11089
|
+
try {
|
|
11090
|
+
(_a2 = entry.cleanup) == null ? void 0 : _a2.call(entry);
|
|
11091
|
+
} catch (error2) {
|
|
11092
|
+
console.warn("[Surfaces] Cleanup error during unmount, ignoring:", error2);
|
|
11093
|
+
}
|
|
11094
|
+
try {
|
|
11095
|
+
entry.container.remove();
|
|
11096
|
+
} catch {
|
|
11097
|
+
}
|
|
10138
11098
|
mounts.delete(entry.slot);
|
|
10139
11099
|
publishEvent("surface.unmounted", {
|
|
10140
11100
|
slot: entry.slot,
|
|
@@ -10317,7 +11277,9 @@ var WidgetRegistry = class {
|
|
|
10317
11277
|
var _a2;
|
|
10318
11278
|
const mounted = this.mountedWidgets.get(mountId);
|
|
10319
11279
|
if (mounted) {
|
|
10320
|
-
(
|
|
11280
|
+
if (container.isConnected) {
|
|
11281
|
+
(_a2 = mounted.cleanup) == null ? void 0 : _a2.call(mounted);
|
|
11282
|
+
}
|
|
10321
11283
|
this.mountedWidgets.delete(mountId);
|
|
10322
11284
|
container.removeAttribute("data-widget-mount-id");
|
|
10323
11285
|
container.removeAttribute("data-widget-id");
|
|
@@ -10433,7 +11395,16 @@ function matchesAnchorRoute(anchorId) {
|
|
|
10433
11395
|
const pathname = typeof window !== "undefined" ? window.location.pathname : "/";
|
|
10434
11396
|
const normalizedPath = pathname.replace(/\/$/, "") || "/";
|
|
10435
11397
|
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
10436
|
-
return routes.some((pattern) =>
|
|
11398
|
+
return routes.some((pattern) => {
|
|
11399
|
+
let normalized = pattern;
|
|
11400
|
+
if (/^https?:\/\//.test(normalized)) {
|
|
11401
|
+
try {
|
|
11402
|
+
normalized = new URL(normalized).pathname;
|
|
11403
|
+
} catch {
|
|
11404
|
+
}
|
|
11405
|
+
}
|
|
11406
|
+
return matchRoutePattern(normalizedPath, normalized);
|
|
11407
|
+
});
|
|
10437
11408
|
}
|
|
10438
11409
|
function createSmartCanvasRuntime(options = {}) {
|
|
10439
11410
|
var _a2, _b, _c, _d;
|
|
@@ -10605,6 +11576,155 @@ function encodeToken(payload) {
|
|
|
10605
11576
|
return TOKEN_PREFIX + base64;
|
|
10606
11577
|
}
|
|
10607
11578
|
|
|
11579
|
+
// src/bootstrap-init.ts
|
|
11580
|
+
function getEnvVar(name) {
|
|
11581
|
+
if (typeof process !== "undefined" && process.env) {
|
|
11582
|
+
return process.env[name];
|
|
11583
|
+
}
|
|
11584
|
+
try {
|
|
11585
|
+
const meta = (0, eval)("import.meta");
|
|
11586
|
+
if (meta == null ? void 0 : meta.env) {
|
|
11587
|
+
return meta.env[name];
|
|
11588
|
+
}
|
|
11589
|
+
} catch {
|
|
11590
|
+
}
|
|
11591
|
+
return void 0;
|
|
11592
|
+
}
|
|
11593
|
+
var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
|
|
11594
|
+
function loadCachedSegmentAttributes() {
|
|
11595
|
+
if (typeof window === "undefined") return {};
|
|
11596
|
+
try {
|
|
11597
|
+
const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
|
|
11598
|
+
if (cached) {
|
|
11599
|
+
const attrs = JSON.parse(cached);
|
|
11600
|
+
debug("Syntro Bootstrap", "Loaded cached segment attributes:", attrs);
|
|
11601
|
+
return attrs;
|
|
11602
|
+
}
|
|
11603
|
+
} catch (err) {
|
|
11604
|
+
warn("Syntro Bootstrap", "Failed to load cached segment attributes:", err);
|
|
11605
|
+
}
|
|
11606
|
+
return {};
|
|
11607
|
+
}
|
|
11608
|
+
function cacheSegmentAttributes(attrs) {
|
|
11609
|
+
if (typeof window === "undefined") return;
|
|
11610
|
+
try {
|
|
11611
|
+
localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
|
|
11612
|
+
debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
|
|
11613
|
+
} catch (err) {
|
|
11614
|
+
warn("Syntro Bootstrap", "Failed to cache segment attributes:", err);
|
|
11615
|
+
}
|
|
11616
|
+
}
|
|
11617
|
+
function extractSegmentFlags(allFlags) {
|
|
11618
|
+
if (!allFlags) return {};
|
|
11619
|
+
const segmentFlags = {};
|
|
11620
|
+
for (const [key, value] of Object.entries(allFlags)) {
|
|
11621
|
+
if (key.startsWith("in_segment_")) {
|
|
11622
|
+
segmentFlags[key] = value === true;
|
|
11623
|
+
}
|
|
11624
|
+
}
|
|
11625
|
+
return segmentFlags;
|
|
11626
|
+
}
|
|
11627
|
+
function collectBrowserMetadata() {
|
|
11628
|
+
var _a2, _b;
|
|
11629
|
+
if (typeof window === "undefined") return {};
|
|
11630
|
+
const attrs = {};
|
|
11631
|
+
try {
|
|
11632
|
+
const params = new URLSearchParams(window.location.search);
|
|
11633
|
+
for (const key of ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]) {
|
|
11634
|
+
const val = params.get(key);
|
|
11635
|
+
if (val) attrs[key] = val;
|
|
11636
|
+
}
|
|
11637
|
+
} catch {
|
|
11638
|
+
}
|
|
11639
|
+
try {
|
|
11640
|
+
if (navigator.language) attrs.browser_language = navigator.language;
|
|
11641
|
+
if ((_a2 = navigator.languages) == null ? void 0 : _a2.length) attrs.browser_languages = [...navigator.languages];
|
|
11642
|
+
} catch {
|
|
11643
|
+
}
|
|
11644
|
+
try {
|
|
11645
|
+
const w = window.innerWidth;
|
|
11646
|
+
attrs.device_type = w < 768 ? "mobile" : w < 1024 ? "tablet" : "desktop";
|
|
11647
|
+
} catch {
|
|
11648
|
+
}
|
|
11649
|
+
try {
|
|
11650
|
+
if (document.referrer) {
|
|
11651
|
+
attrs.referrer = document.referrer;
|
|
11652
|
+
try {
|
|
11653
|
+
attrs.referrer_hostname = new URL(document.referrer).hostname;
|
|
11654
|
+
} catch {
|
|
11655
|
+
}
|
|
11656
|
+
}
|
|
11657
|
+
} catch {
|
|
11658
|
+
}
|
|
11659
|
+
try {
|
|
11660
|
+
const ua = navigator.userAgent;
|
|
11661
|
+
if (ua.includes("Edg/")) attrs.browser = "Edge";
|
|
11662
|
+
else if (ua.includes("OPR/") || ua.includes("Opera")) attrs.browser = "Opera";
|
|
11663
|
+
else if (ua.includes("Chrome/") && !ua.includes("Chromium")) attrs.browser = "Chrome";
|
|
11664
|
+
else if (ua.includes("Safari/") && !ua.includes("Chrome")) attrs.browser = "Safari";
|
|
11665
|
+
else if (ua.includes("Firefox/")) attrs.browser = "Firefox";
|
|
11666
|
+
if (ua.includes("Windows")) attrs.os = "Windows";
|
|
11667
|
+
else if (ua.includes("iPhone") || ua.includes("iPad")) attrs.os = "iOS";
|
|
11668
|
+
else if (ua.includes("Mac OS X") || ua.includes("Macintosh")) attrs.os = "macOS";
|
|
11669
|
+
else if (ua.includes("Android")) attrs.os = "Android";
|
|
11670
|
+
else if (ua.includes("Linux")) attrs.os = "Linux";
|
|
11671
|
+
} catch {
|
|
11672
|
+
}
|
|
11673
|
+
try {
|
|
11674
|
+
attrs.page_url = window.location.href;
|
|
11675
|
+
attrs.page_path = window.location.pathname;
|
|
11676
|
+
attrs.page_host = window.location.hostname;
|
|
11677
|
+
if (window.location.search) attrs.page_query = window.location.search;
|
|
11678
|
+
} catch {
|
|
11679
|
+
}
|
|
11680
|
+
try {
|
|
11681
|
+
const tg = (_b = window.Telegram) == null ? void 0 : _b.WebApp;
|
|
11682
|
+
if (tg) {
|
|
11683
|
+
attrs.surface_type = "telegram";
|
|
11684
|
+
attrs.surface_host = tg.platform || "unknown";
|
|
11685
|
+
} else {
|
|
11686
|
+
attrs.surface_type = "web";
|
|
11687
|
+
attrs.surface_host = "web";
|
|
11688
|
+
}
|
|
11689
|
+
} catch {
|
|
11690
|
+
attrs.surface_type = "web";
|
|
11691
|
+
attrs.surface_host = "web";
|
|
11692
|
+
}
|
|
11693
|
+
return attrs;
|
|
11694
|
+
}
|
|
11695
|
+
var GEO_CACHE_KEY = "syntro_geo";
|
|
11696
|
+
var GEO_DEFAULT_HOST = "https://geo.syntrologie.com";
|
|
11697
|
+
async function fetchGeo(geoHost) {
|
|
11698
|
+
if (typeof window === "undefined") return {};
|
|
11699
|
+
try {
|
|
11700
|
+
const cached = localStorage.getItem(GEO_CACHE_KEY);
|
|
11701
|
+
if (cached) {
|
|
11702
|
+
const parsed = JSON.parse(cached);
|
|
11703
|
+
debug("Syntro Bootstrap", "Geo: using cached data:", parsed);
|
|
11704
|
+
return parsed;
|
|
11705
|
+
}
|
|
11706
|
+
} catch {
|
|
11707
|
+
}
|
|
11708
|
+
try {
|
|
11709
|
+
const res = await fetch(geoHost, { signal: AbortSignal.timeout(2e3) });
|
|
11710
|
+
if (res.ok) {
|
|
11711
|
+
const geo = await res.json();
|
|
11712
|
+
const cleaned = {};
|
|
11713
|
+
for (const [k, v] of Object.entries(geo)) {
|
|
11714
|
+
if (typeof v === "string" && v) cleaned[k] = v;
|
|
11715
|
+
}
|
|
11716
|
+
try {
|
|
11717
|
+
localStorage.setItem(GEO_CACHE_KEY, JSON.stringify(cleaned));
|
|
11718
|
+
} catch {
|
|
11719
|
+
}
|
|
11720
|
+
debug("Syntro Bootstrap", "Geo: fetched from worker:", cleaned);
|
|
11721
|
+
return cleaned;
|
|
11722
|
+
}
|
|
11723
|
+
} catch {
|
|
11724
|
+
}
|
|
11725
|
+
return {};
|
|
11726
|
+
}
|
|
11727
|
+
|
|
10608
11728
|
// src/experiments/registry.ts
|
|
10609
11729
|
var adapters = {
|
|
10610
11730
|
growthbook: (config) => createGrowthBookClient({
|
|
@@ -10711,9 +11831,8 @@ var ExperimentsFetcher = class {
|
|
|
10711
11831
|
__publicField(this, "featureKey");
|
|
10712
11832
|
__publicField(this, "manifestKey");
|
|
10713
11833
|
__publicField(this, "variantFlagPrefix");
|
|
10714
|
-
var _a2;
|
|
10715
11834
|
this.client = options.client;
|
|
10716
|
-
this.featureKey =
|
|
11835
|
+
this.featureKey = options.featureKey;
|
|
10717
11836
|
this.manifestKey = options.manifestKey;
|
|
10718
11837
|
this.variantFlagPrefix = options.variantFlagPrefix;
|
|
10719
11838
|
}
|
|
@@ -10742,6 +11861,11 @@ var ExperimentsFetcher = class {
|
|
|
10742
11861
|
};
|
|
10743
11862
|
}
|
|
10744
11863
|
}
|
|
11864
|
+
if (!this.featureKey) {
|
|
11865
|
+
throw new Error(
|
|
11866
|
+
"[SmartCanvas] No featureKey configured and no variant flags found. Ensure at least one config feature flag exists in your experiment platform."
|
|
11867
|
+
);
|
|
11868
|
+
}
|
|
10745
11869
|
const config = (_b = (_a2 = this.client).getFeatureValue) == null ? void 0 : _b.call(_a2, this.featureKey, null);
|
|
10746
11870
|
if (!config || typeof config !== "object") {
|
|
10747
11871
|
throw new Error(
|
|
@@ -10853,95 +11977,9 @@ function createTelemetryClient(provider, config) {
|
|
|
10853
11977
|
return factory(config);
|
|
10854
11978
|
}
|
|
10855
11979
|
|
|
10856
|
-
// src/bootstrap.ts
|
|
10857
|
-
function
|
|
10858
|
-
|
|
10859
|
-
return process.env[name];
|
|
10860
|
-
}
|
|
10861
|
-
try {
|
|
10862
|
-
const meta = (0, eval)("import.meta");
|
|
10863
|
-
if (meta == null ? void 0 : meta.env) {
|
|
10864
|
-
return meta.env[name];
|
|
10865
|
-
}
|
|
10866
|
-
} catch {
|
|
10867
|
-
}
|
|
10868
|
-
return void 0;
|
|
10869
|
-
}
|
|
10870
|
-
var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
|
|
10871
|
-
function loadCachedSegmentAttributes() {
|
|
10872
|
-
if (typeof window === "undefined") return {};
|
|
10873
|
-
try {
|
|
10874
|
-
const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
|
|
10875
|
-
if (cached) {
|
|
10876
|
-
const attrs = JSON.parse(cached);
|
|
10877
|
-
debug("Syntro Bootstrap", "Loaded cached segment attributes:", attrs);
|
|
10878
|
-
return attrs;
|
|
10879
|
-
}
|
|
10880
|
-
} catch (err) {
|
|
10881
|
-
warn("Syntro Bootstrap", "Failed to load cached segment attributes:", err);
|
|
10882
|
-
}
|
|
10883
|
-
return {};
|
|
10884
|
-
}
|
|
10885
|
-
function cacheSegmentAttributes(attrs) {
|
|
10886
|
-
if (typeof window === "undefined") return;
|
|
10887
|
-
try {
|
|
10888
|
-
localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
|
|
10889
|
-
debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
|
|
10890
|
-
} catch (err) {
|
|
10891
|
-
warn("Syntro Bootstrap", "Failed to cache segment attributes:", err);
|
|
10892
|
-
}
|
|
10893
|
-
}
|
|
10894
|
-
function extractSegmentFlags(allFlags) {
|
|
10895
|
-
if (!allFlags) return {};
|
|
10896
|
-
const segmentFlags = {};
|
|
10897
|
-
for (const [key, value] of Object.entries(allFlags)) {
|
|
10898
|
-
if (key.startsWith("in_segment_")) {
|
|
10899
|
-
segmentFlags[key] = value === true;
|
|
10900
|
-
}
|
|
10901
|
-
}
|
|
10902
|
-
return segmentFlags;
|
|
10903
|
-
}
|
|
10904
|
-
function collectBrowserMetadata() {
|
|
10905
|
-
var _a2;
|
|
10906
|
-
if (typeof window === "undefined") return {};
|
|
10907
|
-
const attrs = {};
|
|
10908
|
-
try {
|
|
10909
|
-
const params = new URLSearchParams(window.location.search);
|
|
10910
|
-
for (const key of ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]) {
|
|
10911
|
-
const val = params.get(key);
|
|
10912
|
-
if (val) attrs[key] = val;
|
|
10913
|
-
}
|
|
10914
|
-
} catch {
|
|
10915
|
-
}
|
|
10916
|
-
try {
|
|
10917
|
-
if (navigator.language) attrs.browser_language = navigator.language;
|
|
10918
|
-
if ((_a2 = navigator.languages) == null ? void 0 : _a2.length) attrs.browser_languages = [...navigator.languages];
|
|
10919
|
-
} catch {
|
|
10920
|
-
}
|
|
10921
|
-
try {
|
|
10922
|
-
const w = window.innerWidth;
|
|
10923
|
-
attrs.device_type = w < 768 ? "mobile" : w < 1024 ? "tablet" : "desktop";
|
|
10924
|
-
} catch {
|
|
10925
|
-
}
|
|
10926
|
-
try {
|
|
10927
|
-
if (document.referrer) {
|
|
10928
|
-
attrs.referrer = document.referrer;
|
|
10929
|
-
try {
|
|
10930
|
-
attrs.referrer_hostname = new URL(document.referrer).hostname;
|
|
10931
|
-
} catch {
|
|
10932
|
-
}
|
|
10933
|
-
}
|
|
10934
|
-
} catch {
|
|
10935
|
-
}
|
|
10936
|
-
try {
|
|
10937
|
-
attrs.page_url = window.location.href;
|
|
10938
|
-
attrs.page_path = window.location.pathname;
|
|
10939
|
-
} catch {
|
|
10940
|
-
}
|
|
10941
|
-
return attrs;
|
|
10942
|
-
}
|
|
10943
|
-
async function init(options) {
|
|
10944
|
-
var _a2, _b, _c, _d, _e, _f;
|
|
11980
|
+
// src/bootstrap-runtime.ts
|
|
11981
|
+
async function _initCore(options) {
|
|
11982
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
10945
11983
|
initLogger();
|
|
10946
11984
|
debug("Syntro Bootstrap", "====== INIT ======");
|
|
10947
11985
|
debug("Syntro Bootstrap", "Options:", {
|
|
@@ -11006,17 +12044,95 @@ async function init(options) {
|
|
|
11006
12044
|
const experimentHost = getEnvVar("NEXT_PUBLIC_SYNTRO_EXPERIMENT_HOST") || getEnvVar("VITE_SYNTRO_EXPERIMENT_HOST") || (payload == null ? void 0 : payload.eh);
|
|
11007
12045
|
const telemetryHost = getEnvVar("NEXT_PUBLIC_SYNTRO_TELEMETRY_HOST") || getEnvVar("VITE_SYNTRO_TELEMETRY_HOST") || (payload == null ? void 0 : payload.th);
|
|
11008
12046
|
const editorUrl = getEnvVar("NEXT_PUBLIC_SYNTRO_EDITOR_URL") || getEnvVar("VITE_SYNTRO_EDITOR_URL") || ((_b = options.canvas) == null ? void 0 : _b.editorUrl);
|
|
12047
|
+
const geoHost = (payload == null ? void 0 : payload.g) || getEnvVar("NEXT_PUBLIC_SYNTRO_GEO_HOST") || getEnvVar("VITE_SYNTRO_GEO_HOST") || GEO_DEFAULT_HOST;
|
|
11009
12048
|
const cachedSegmentAttrs = loadCachedSegmentAttributes();
|
|
11010
12049
|
const browserMetadata = collectBrowserMetadata();
|
|
11011
|
-
const
|
|
12050
|
+
const appSignals = (_c = options.appSignals) != null ? _c : {};
|
|
12051
|
+
const phaseOneAttrs = { ...browserMetadata, ...cachedSegmentAttrs, ...appSignals };
|
|
11012
12052
|
debug("Syntro Bootstrap", "Phase 1: Browser metadata:", browserMetadata);
|
|
11013
12053
|
debug("Syntro Bootstrap", "Phase 1: Cached segment attributes:", cachedSegmentAttrs);
|
|
12054
|
+
if (Object.keys(appSignals).length > 0) {
|
|
12055
|
+
debug("Syntro Bootstrap", "Phase 1: App signals:", appSignals);
|
|
12056
|
+
}
|
|
12057
|
+
const geoPromise = fetchGeo(geoHost);
|
|
12058
|
+
const mcpPromise = (() => {
|
|
12059
|
+
try {
|
|
12060
|
+
if (typeof window === "undefined" || window.self === window.top) return Promise.resolve(null);
|
|
12061
|
+
} catch {
|
|
12062
|
+
}
|
|
12063
|
+
return new Promise((resolve) => {
|
|
12064
|
+
const timer = setTimeout(() => {
|
|
12065
|
+
window.removeEventListener("message", handler);
|
|
12066
|
+
resolve(null);
|
|
12067
|
+
}, 500);
|
|
12068
|
+
function handler(event) {
|
|
12069
|
+
var _a3;
|
|
12070
|
+
const data = event.data;
|
|
12071
|
+
if ((data == null ? void 0 : data.jsonrpc) === "2.0" && (data == null ? void 0 : data.id) === 1 && ((_a3 = data == null ? void 0 : data.result) == null ? void 0 : _a3.hostInfo)) {
|
|
12072
|
+
clearTimeout(timer);
|
|
12073
|
+
window.removeEventListener("message", handler);
|
|
12074
|
+
resolve(data.result.hostInfo);
|
|
12075
|
+
}
|
|
12076
|
+
}
|
|
12077
|
+
window.addEventListener("message", handler);
|
|
12078
|
+
try {
|
|
12079
|
+
window.parent.postMessage(
|
|
12080
|
+
{ jsonrpc: "2.0", id: 1, method: "ui/initialize", params: { capabilities: {} } },
|
|
12081
|
+
"*"
|
|
12082
|
+
);
|
|
12083
|
+
} catch {
|
|
12084
|
+
clearTimeout(timer);
|
|
12085
|
+
window.removeEventListener("message", handler);
|
|
12086
|
+
resolve(null);
|
|
12087
|
+
}
|
|
12088
|
+
});
|
|
12089
|
+
})();
|
|
11014
12090
|
let experiments;
|
|
11015
|
-
const
|
|
12091
|
+
const isDebugOrTest = options.debug || options.testMode;
|
|
12092
|
+
const events = createEventBus({
|
|
12093
|
+
debug: options.debug,
|
|
12094
|
+
history: isDebugOrTest ? new EventHistory(options.testMode ? 0 : 100) : void 0,
|
|
12095
|
+
testMode: options.testMode
|
|
12096
|
+
});
|
|
11016
12097
|
console.log("[Syntro Bootstrap] EventBus created");
|
|
11017
|
-
const
|
|
11018
|
-
|
|
12098
|
+
const processor = createEventProcessor({
|
|
12099
|
+
elementResolver: typeof window !== "undefined" ? (x, y) => {
|
|
12100
|
+
const el = document.elementFromPoint(x, y);
|
|
12101
|
+
if (!el) return null;
|
|
12102
|
+
const info = { tag_name: el.tagName.toLowerCase() };
|
|
12103
|
+
if (el.id) info.attr__id = el.id;
|
|
12104
|
+
if (el.className && typeof el.className === "string") {
|
|
12105
|
+
info.classes = el.className.split(" ").filter(Boolean);
|
|
12106
|
+
}
|
|
12107
|
+
for (const attr of el.attributes) {
|
|
12108
|
+
if (attr.name.startsWith("data-")) info[`attr__${attr.name}`] = attr.value;
|
|
12109
|
+
}
|
|
12110
|
+
return info;
|
|
12111
|
+
} : void 0
|
|
11019
12112
|
});
|
|
12113
|
+
processor.onEvent((event) => events.publishEvent(event));
|
|
12114
|
+
if (typeof window !== "undefined") {
|
|
12115
|
+
setInterval(() => processor.tick(Date.now()), 1e3);
|
|
12116
|
+
document.addEventListener(
|
|
12117
|
+
"click",
|
|
12118
|
+
(e) => {
|
|
12119
|
+
const chain = [];
|
|
12120
|
+
let el = e.target;
|
|
12121
|
+
while (el && el !== document.body) {
|
|
12122
|
+
const info = { tag_name: el.tagName.toLowerCase() };
|
|
12123
|
+
for (const attr of el.attributes) {
|
|
12124
|
+
if (attr.name.startsWith("data-") || attr.name === "id" || attr.name === "class" || attr.name === "aria-label") {
|
|
12125
|
+
info[`attr__${attr.name}`] = attr.value;
|
|
12126
|
+
}
|
|
12127
|
+
}
|
|
12128
|
+
chain.push(info);
|
|
12129
|
+
el = el.parentElement;
|
|
12130
|
+
}
|
|
12131
|
+
processor.enrichClickAttributes(Date.now(), chain);
|
|
12132
|
+
},
|
|
12133
|
+
true
|
|
12134
|
+
);
|
|
12135
|
+
}
|
|
11020
12136
|
const onFeatureFlagsLoaded = (allFlags) => {
|
|
11021
12137
|
var _a3, _b2, _c2;
|
|
11022
12138
|
debug("Syntro Bootstrap", "Phase 2: PostHog feature flags loaded");
|
|
@@ -11025,7 +12141,7 @@ async function init(options) {
|
|
|
11025
12141
|
cacheSegmentAttributes(segmentFlags);
|
|
11026
12142
|
if (experiments) {
|
|
11027
12143
|
const sessionAttrs = (_b2 = (_a3 = sessionMetrics == null ? void 0 : sessionMetrics.getAll) == null ? void 0 : _a3.call(sessionMetrics)) != null ? _b2 : {};
|
|
11028
|
-
const updatedAttrs = { ...browserMetadata, ...sessionAttrs, ...segmentFlags };
|
|
12144
|
+
const updatedAttrs = { ...browserMetadata, ...sessionAttrs, ...segmentFlags, ...appSignals };
|
|
11029
12145
|
debug("Syntro Bootstrap", "Updating GrowthBook with attributes:", updatedAttrs);
|
|
11030
12146
|
(_c2 = experiments.setAttributes) == null ? void 0 : _c2.call(experiments, updatedAttrs);
|
|
11031
12147
|
}
|
|
@@ -11039,12 +12155,28 @@ async function init(options) {
|
|
|
11039
12155
|
// undefined falls back to adapter default
|
|
11040
12156
|
// Enable PostHog feature flags for segment membership
|
|
11041
12157
|
enableFeatureFlags: true,
|
|
12158
|
+
sessionRecording: true,
|
|
11042
12159
|
// Wire up callback for when flags are loaded (Phase 2)
|
|
11043
12160
|
onFeatureFlagsLoaded,
|
|
11044
|
-
// Wire up event capture to feed into
|
|
11045
|
-
onCapture:
|
|
12161
|
+
// Wire up event capture to feed into event processor
|
|
12162
|
+
onCapture: (eventName, properties) => {
|
|
12163
|
+
processor.ingest({ kind: "posthog", event: eventName, properties, timestamp: Date.now() });
|
|
12164
|
+
},
|
|
12165
|
+
// Wire rrweb events for behavioral signal detection
|
|
12166
|
+
onRRWebEvent: (event) => {
|
|
12167
|
+
processor.ingest(event);
|
|
12168
|
+
}
|
|
11046
12169
|
});
|
|
11047
12170
|
console.log(`[Syntro Bootstrap] Telemetry client created (${provider}) with EventBus wiring`);
|
|
12171
|
+
if (Object.keys(appSignals).length > 0) {
|
|
12172
|
+
(_d = telemetry.register) == null ? void 0 : _d.call(telemetry, appSignals);
|
|
12173
|
+
debug("Syntro Bootstrap", "Registered app signals as super properties:", appSignals);
|
|
12174
|
+
}
|
|
12175
|
+
const telemetryForCapture = telemetry;
|
|
12176
|
+
events.setPosthogCapture((name, props) => {
|
|
12177
|
+
var _a3;
|
|
12178
|
+
(_a3 = telemetryForCapture.track) == null ? void 0 : _a3.call(telemetryForCapture, name, props);
|
|
12179
|
+
});
|
|
11048
12180
|
}
|
|
11049
12181
|
let sessionMetrics;
|
|
11050
12182
|
if (payload == null ? void 0 : payload.e) {
|
|
@@ -11110,7 +12242,7 @@ async function init(options) {
|
|
|
11110
12242
|
};
|
|
11111
12243
|
debug("Syntro Bootstrap", "Global SynOS object exposed");
|
|
11112
12244
|
}
|
|
11113
|
-
const registeredApps = (
|
|
12245
|
+
const registeredApps = (_g = (_f = (_e = runtime3.apps).list) == null ? void 0 : _f.call(_e)) != null ? _g : [];
|
|
11114
12246
|
console.log(
|
|
11115
12247
|
`[DIAG] Activation loop: ${registeredApps.length} apps in registry:`,
|
|
11116
12248
|
registeredApps.map((a) => `${a.manifest.id}(${a.state})`).join(", ")
|
|
@@ -11137,11 +12269,24 @@ async function init(options) {
|
|
|
11137
12269
|
warn("Syntro Bootstrap", "Failed to load GrowthBook features:", err);
|
|
11138
12270
|
}
|
|
11139
12271
|
}
|
|
12272
|
+
const geoData = await geoPromise;
|
|
12273
|
+
if (experiments && Object.keys(geoData).length > 0) {
|
|
12274
|
+
const mergedAttrs = { ...browserMetadata, ...geoData, ...appSignals };
|
|
12275
|
+
debug("Syntro Bootstrap", "Merging geo data into GrowthBook attributes:", geoData);
|
|
12276
|
+
(_h = experiments.setAttributes) == null ? void 0 : _h.call(experiments, mergedAttrs);
|
|
12277
|
+
}
|
|
12278
|
+
const mcpHost = await mcpPromise;
|
|
12279
|
+
if (mcpHost && experiments) {
|
|
12280
|
+
browserMetadata.surface_type = "mcp-app";
|
|
12281
|
+
browserMetadata.surface_host = mcpHost.name;
|
|
12282
|
+
(_i = experiments.setAttributes) == null ? void 0 : _i.call(experiments, { ...browserMetadata, ...geoData });
|
|
12283
|
+
debug("Syntro Bootstrap", "MCP App detected:", mcpHost.name);
|
|
12284
|
+
}
|
|
11140
12285
|
let baseFetcher;
|
|
11141
12286
|
if (options.fetcher) {
|
|
11142
12287
|
baseFetcher = options.fetcher;
|
|
11143
12288
|
} else if (payload == null ? void 0 : payload.f) {
|
|
11144
|
-
const configFetcher = createConfigFetcher(payload.f, (
|
|
12289
|
+
const configFetcher = createConfigFetcher(payload.f, (_j = payload.o) != null ? _j : {});
|
|
11145
12290
|
baseFetcher = async () => {
|
|
11146
12291
|
var _a3;
|
|
11147
12292
|
const result = await configFetcher.fetch();
|
|
@@ -11155,15 +12300,35 @@ async function init(options) {
|
|
|
11155
12300
|
}
|
|
11156
12301
|
const warnedAppFailures = /* @__PURE__ */ new Set();
|
|
11157
12302
|
const appLoadingFetcher = baseFetcher ? async () => {
|
|
11158
|
-
var _a3, _b2, _c2, _d2, _e2, _f2,
|
|
12303
|
+
var _a3, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k, _l;
|
|
11159
12304
|
const config = await baseFetcher();
|
|
12305
|
+
const tileCount = (_b2 = (_a3 = config.tiles) == null ? void 0 : _a3.length) != null ? _b2 : 0;
|
|
12306
|
+
const actionCount = (_d2 = (_c2 = config.actions) == null ? void 0 : _c2.length) != null ? _d2 : 0;
|
|
12307
|
+
const variantId = (_e2 = config.meta) == null ? void 0 : _e2.variant_id;
|
|
12308
|
+
if (tileCount > 0 || actionCount > 0) {
|
|
12309
|
+
if (!variantId) {
|
|
12310
|
+
console.warn(
|
|
12311
|
+
"[Syntro] Config has content but no meta.variant_id \u2014 intervention tracking disabled"
|
|
12312
|
+
);
|
|
12313
|
+
}
|
|
12314
|
+
}
|
|
12315
|
+
if (telemetry && variantId) {
|
|
12316
|
+
const tracker = new InterventionTracker(telemetry, variantId);
|
|
12317
|
+
tracker.trackServed(tileCount, actionCount);
|
|
12318
|
+
if (typeof window !== "undefined") {
|
|
12319
|
+
window.SynOS.interventionTracker = tracker;
|
|
12320
|
+
}
|
|
12321
|
+
runtime3.navigation.subscribe(() => {
|
|
12322
|
+
tracker.resetPage();
|
|
12323
|
+
});
|
|
12324
|
+
}
|
|
11160
12325
|
console.log(
|
|
11161
12326
|
"[Syntro Bootstrap] Config fetched:",
|
|
11162
|
-
`tiles=${(
|
|
11163
|
-
`actions=${(
|
|
11164
|
-
`theme=${(
|
|
12327
|
+
`tiles=${(_g2 = (_f2 = config.tiles) == null ? void 0 : _f2.length) != null ? _g2 : 0},`,
|
|
12328
|
+
`actions=${(_i2 = (_h2 = config.actions) == null ? void 0 : _h2.length) != null ? _i2 : 0},`,
|
|
12329
|
+
`theme=${(_k = (_j2 = config.theme) == null ? void 0 : _j2.name) != null ? _k : "none"}`
|
|
11165
12330
|
);
|
|
11166
|
-
if (((
|
|
12331
|
+
if (((_l = config.actions) == null ? void 0 : _l.length) > 0) {
|
|
11167
12332
|
console.log(
|
|
11168
12333
|
"[Syntro Bootstrap] Actions in config:",
|
|
11169
12334
|
config.actions.map(
|
|
@@ -11226,10 +12391,33 @@ async function init(options) {
|
|
|
11226
12391
|
});
|
|
11227
12392
|
return { canvas, runtime: runtime3, experiments, telemetry, sessionMetrics, appLoader };
|
|
11228
12393
|
}
|
|
12394
|
+
|
|
12395
|
+
// src/bootstrap.ts
|
|
12396
|
+
async function init(options) {
|
|
12397
|
+
var _a2;
|
|
12398
|
+
try {
|
|
12399
|
+
return await _initCore(options);
|
|
12400
|
+
} catch (err) {
|
|
12401
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12402
|
+
console.warn("[Syntrologie] SDK initialization failed:", message);
|
|
12403
|
+
if (typeof document !== "undefined") {
|
|
12404
|
+
(_a2 = document.getElementById("syntrologie-anti-flicker")) == null ? void 0 : _a2.remove();
|
|
12405
|
+
}
|
|
12406
|
+
return void 0;
|
|
12407
|
+
}
|
|
12408
|
+
}
|
|
12409
|
+
function emit(eventName, props = {}) {
|
|
12410
|
+
var _a2, _b;
|
|
12411
|
+
if (typeof window === "undefined") return;
|
|
12412
|
+
const runtime3 = (_a2 = window.SynOS) == null ? void 0 : _a2.runtime;
|
|
12413
|
+
if (!((_b = runtime3 == null ? void 0 : runtime3.events) == null ? void 0 : _b.publish)) return;
|
|
12414
|
+
runtime3.events.publish({ name: eventName, source: "custom", props });
|
|
12415
|
+
}
|
|
11229
12416
|
var Syntro = {
|
|
11230
12417
|
init,
|
|
11231
12418
|
encodeToken,
|
|
11232
|
-
decodeToken
|
|
12419
|
+
decodeToken,
|
|
12420
|
+
events: { emit }
|
|
11233
12421
|
};
|
|
11234
12422
|
if (typeof window !== "undefined") {
|
|
11235
12423
|
window.Syntro = Syntro;
|
|
@@ -11260,8 +12448,11 @@ export {
|
|
|
11260
12448
|
createSmartCanvasController,
|
|
11261
12449
|
ShadowRootProvider,
|
|
11262
12450
|
useShadowRoot,
|
|
11263
|
-
StandardEvents,
|
|
11264
12451
|
EVENT_SCHEMA_VERSION,
|
|
12452
|
+
normalizePostHogEvent,
|
|
12453
|
+
shouldNormalizeEvent,
|
|
12454
|
+
createPostHogNormalizer,
|
|
12455
|
+
StandardEvents2 as StandardEvents,
|
|
11265
12456
|
CanvasEvents,
|
|
11266
12457
|
NotificationToastStack,
|
|
11267
12458
|
MAX_VISIBLE_TOASTS,
|
|
@@ -11292,6 +12483,7 @@ export {
|
|
|
11292
12483
|
createSessionMetricTracker,
|
|
11293
12484
|
createNoopClient,
|
|
11294
12485
|
createPostHogClient,
|
|
12486
|
+
InterventionTracker,
|
|
11295
12487
|
ExecutorRegistry,
|
|
11296
12488
|
executorRegistry,
|
|
11297
12489
|
getExecutor,
|
|
@@ -11310,11 +12502,11 @@ export {
|
|
|
11310
12502
|
evaluateSync,
|
|
11311
12503
|
createDecisionEngine,
|
|
11312
12504
|
createEventAccumulator,
|
|
12505
|
+
validateEventName,
|
|
12506
|
+
validateProps,
|
|
11313
12507
|
EventBus,
|
|
11314
12508
|
createEventBus,
|
|
11315
|
-
|
|
11316
|
-
shouldNormalizeEvent,
|
|
11317
|
-
createPostHogNormalizer,
|
|
12509
|
+
EventHistory,
|
|
11318
12510
|
NavigationMonitor,
|
|
11319
12511
|
StateStore,
|
|
11320
12512
|
createStateStore,
|
|
@@ -11338,4 +12530,4 @@ export {
|
|
|
11338
12530
|
encodeToken,
|
|
11339
12531
|
Syntro
|
|
11340
12532
|
};
|
|
11341
|
-
//# sourceMappingURL=chunk-
|
|
12533
|
+
//# sourceMappingURL=chunk-TOBT6CVT.js.map
|