@syntrologie/runtime-sdk 2.11.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CAPABILITIES.md +176 -117
- package/README.md +2 -0
- package/dist/actions/schema.d.ts +7 -7
- package/dist/actions/schema.js +3 -4
- package/dist/actions/types.d.ts +1 -1
- package/dist/actions/validation-core.d.ts +24 -0
- package/dist/actions/validation-rules.d.ts +74 -0
- package/dist/actions/validation.d.ts +5 -11
- package/dist/bootstrap-init.d.ts +33 -0
- package/dist/bootstrap-runtime.d.ts +7 -0
- package/dist/bootstrap-types.d.ts +90 -0
- package/dist/bootstrap.d.ts +17 -83
- package/dist/{chunk-Q77NT67W.js → chunk-BU4Z6PD7.js} +16 -1
- package/dist/{chunk-Q77NT67W.js.map → chunk-BU4Z6PD7.js.map} +1 -1
- package/dist/{chunk-H3FAYTUV.js → chunk-J2LGX2PV.js} +1216 -394
- package/dist/chunk-J2LGX2PV.js.map +7 -0
- package/dist/{chunk-NBFQGKSV.js → chunk-L6RJMBR2.js} +4 -4
- package/dist/{chunk-NBFQGKSV.js.map → chunk-L6RJMBR2.js.map} +2 -2
- package/dist/{chunk-37TTQRH5.js → chunk-XDYJ64IN.js} +2 -2
- package/dist/config/schema.js +2 -3
- package/dist/decisions/schema.js +1 -2
- 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/types.d.ts +24 -0
- package/dist/events/validation.d.ts +7 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.js +1131 -2039
- 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 -5
- package/dist/react.js.map +2 -2
- package/dist/smart-canvas.esm.js +92 -108
- package/dist/smart-canvas.esm.js.map +4 -4
- package/dist/smart-canvas.js +4649 -4957
- package/dist/smart-canvas.js.map +4 -4
- package/dist/smart-canvas.min.js +92 -108
- package/dist/smart-canvas.min.js.map +4 -4
- package/dist/telemetry/adapters/posthog.d.ts +5 -10
- 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 -29
- package/schema/canvas-config.schema.json +1 -1
- package/scripts/syntroReactPlugin.mjs +3 -0
- package/scripts/validate-config.mjs +42 -0
- package/dist/chunk-H3FAYTUV.js.map +0 -7
- package/dist/chunk-JMHRHAEL.js +0 -18
- package/dist/chunk-JMHRHAEL.js.map +0 -7
- package/dist/replayMirror-QZ3GQ527.js +0 -32
- package/dist/replayMirror-QZ3GQ527.js.map +0 -7
- package/dist/telemetry/replayMirror.d.ts +0 -7
- /package/dist/{chunk-37TTQRH5.js.map → chunk-XDYJ64IN.js.map} +0 -0
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
__privateGet,
|
|
4
4
|
__privateSet,
|
|
5
5
|
__publicField
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-BU4Z6PD7.js";
|
|
7
7
|
|
|
8
8
|
// ../adaptives/adaptive-content/dist/reconciliation-guard.js
|
|
9
9
|
function guardAgainstReconciliation(container, anchor, reinsertFn, opts) {
|
|
@@ -127,6 +127,12 @@ function sanitizeHtml(html) {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
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
|
+
}
|
|
130
136
|
for (const el of toRemove) {
|
|
131
137
|
while (el.firstChild) {
|
|
132
138
|
(_a2 = el.parentNode) == null ? void 0 : _a2.insertBefore(el.firstChild, el);
|
|
@@ -755,6 +761,10 @@ var CelebrationEngine = class {
|
|
|
755
761
|
this.container = null;
|
|
756
762
|
}
|
|
757
763
|
start(container, effect, config) {
|
|
764
|
+
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
765
|
+
if (prefersReducedMotion) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
758
768
|
this.container = container;
|
|
759
769
|
this.effect = effect;
|
|
760
770
|
this.duration = config.duration;
|
|
@@ -1398,7 +1408,7 @@ var alert = {
|
|
|
1398
1408
|
var tag = {
|
|
1399
1409
|
content: slateGrey[10],
|
|
1400
1410
|
border: slateGrey[4],
|
|
1401
|
-
background:
|
|
1411
|
+
background: slateGrey[3]
|
|
1402
1412
|
};
|
|
1403
1413
|
var menu = {
|
|
1404
1414
|
backgroundDefault: slateGrey[2],
|
|
@@ -2283,7 +2293,7 @@ function extractWorkflowsFromActive(activeActions) {
|
|
|
2283
2293
|
const workflows = /* @__PURE__ */ new Map();
|
|
2284
2294
|
for (const entry of activeActions) {
|
|
2285
2295
|
const action = entry.action;
|
|
2286
|
-
if (action.kind === "
|
|
2296
|
+
if (action.kind === "overlays:tour" && action.workflow && action.tourId) {
|
|
2287
2297
|
const meta = action.workflow;
|
|
2288
2298
|
const rawSteps = action.steps || [];
|
|
2289
2299
|
const steps = rawSteps.map((s) => {
|
|
@@ -2806,7 +2816,7 @@ var executors2 = [
|
|
|
2806
2816
|
{ kind: "overlays:badge", executor: executeBadge },
|
|
2807
2817
|
{ kind: "overlays:tooltip", executor: executeTooltip },
|
|
2808
2818
|
{ kind: "overlays:modal", executor: executeModal },
|
|
2809
|
-
{ kind: "
|
|
2819
|
+
{ kind: "overlays:tour", executor: executeTour },
|
|
2810
2820
|
{ kind: "overlays:celebrate", executor: executeCelebrate }
|
|
2811
2821
|
];
|
|
2812
2822
|
var runtime2 = {
|
|
@@ -2926,7 +2936,15 @@ var CORE_ACTION_KINDS = /* @__PURE__ */ new Set([
|
|
|
2926
2936
|
"core:wait",
|
|
2927
2937
|
"core:sequence",
|
|
2928
2938
|
"core:parallel",
|
|
2929
|
-
"
|
|
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"
|
|
2930
2948
|
]);
|
|
2931
2949
|
var NAMESPACE_TO_APP_ID = {
|
|
2932
2950
|
faq: "adaptive-faq",
|
|
@@ -3080,6 +3098,9 @@ function createAppLoader(options) {
|
|
|
3080
3098
|
}
|
|
3081
3099
|
}
|
|
3082
3100
|
}
|
|
3101
|
+
for (const bundled of BUNDLED_APP_IDS) {
|
|
3102
|
+
appIds.delete(bundled);
|
|
3103
|
+
}
|
|
3083
3104
|
return Array.from(appIds);
|
|
3084
3105
|
}
|
|
3085
3106
|
async function loadAppsForConfig(config) {
|
|
@@ -3435,7 +3456,7 @@ function getAntiFlickerSnippet(config = {}) {
|
|
|
3435
3456
|
}
|
|
3436
3457
|
|
|
3437
3458
|
// src/version.ts
|
|
3438
|
-
var SDK_VERSION = "2.
|
|
3459
|
+
var SDK_VERSION = "2.12.0";
|
|
3439
3460
|
|
|
3440
3461
|
// src/types.ts
|
|
3441
3462
|
var SDK_SCHEMA_VERSION = "2.0";
|
|
@@ -3586,12 +3607,15 @@ function getCachedConfig(sdkVersion) {
|
|
|
3586
3607
|
var resolveConfigUri = ({
|
|
3587
3608
|
configUri,
|
|
3588
3609
|
experiments,
|
|
3589
|
-
featureKey
|
|
3610
|
+
featureKey
|
|
3590
3611
|
}) => {
|
|
3591
3612
|
var _a2;
|
|
3592
3613
|
if (configUri) return configUri;
|
|
3593
|
-
|
|
3594
|
-
|
|
3614
|
+
if (experiments) {
|
|
3615
|
+
const key = featureKey != null ? featureKey : "smart-canvas-config";
|
|
3616
|
+
const fromFeature = (_a2 = experiments.getFeatureValue) == null ? void 0 : _a2.call(experiments, key, null);
|
|
3617
|
+
if (fromFeature) return fromFeature;
|
|
3618
|
+
}
|
|
3595
3619
|
return void 0;
|
|
3596
3620
|
};
|
|
3597
3621
|
function getVariantFlagKeys(experiments, manifestKey, variantFlagPrefix) {
|
|
@@ -3617,14 +3641,15 @@ var createCanvasConfigFetcher = ({
|
|
|
3617
3641
|
experiments,
|
|
3618
3642
|
featureKey,
|
|
3619
3643
|
credentials,
|
|
3620
|
-
configFeatureKey
|
|
3644
|
+
configFeatureKey,
|
|
3621
3645
|
manifestKey,
|
|
3622
3646
|
variantFlagPrefix,
|
|
3623
3647
|
sdkVersion
|
|
3624
3648
|
}) => async () => {
|
|
3625
3649
|
var _a2;
|
|
3626
|
-
|
|
3627
|
-
|
|
3650
|
+
const effectiveConfigKey = configFeatureKey != null ? configFeatureKey : "smart-canvas-config";
|
|
3651
|
+
if (experiments) {
|
|
3652
|
+
const directConfig = (_a2 = experiments.getFeatureValue) == null ? void 0 : _a2.call(experiments, effectiveConfigKey, null);
|
|
3628
3653
|
if (directConfig && typeof directConfig === "object") {
|
|
3629
3654
|
debug("SmartCanvas Config", "Resolved config directly from feature flag", directConfig);
|
|
3630
3655
|
return directConfig;
|
|
@@ -3812,9 +3837,529 @@ function useShadowRoot() {
|
|
|
3812
3837
|
return ctx;
|
|
3813
3838
|
}
|
|
3814
3839
|
|
|
3815
|
-
//
|
|
3816
|
-
|
|
3840
|
+
// ../event-processor/dist/types.js
|
|
3841
|
+
var EVENT_SCHEMA_VERSION = "1.0.0";
|
|
3817
3842
|
var StandardEvents = {
|
|
3843
|
+
UI_CLICK: "ui.click",
|
|
3844
|
+
UI_SCROLL: "ui.scroll",
|
|
3845
|
+
UI_INPUT: "ui.input",
|
|
3846
|
+
UI_CHANGE: "ui.change",
|
|
3847
|
+
UI_SUBMIT: "ui.submit",
|
|
3848
|
+
NAV_PAGE_VIEW: "nav.page_view",
|
|
3849
|
+
NAV_PAGE_LEAVE: "nav.page_leave",
|
|
3850
|
+
UI_HESITATE: "ui.hesitate",
|
|
3851
|
+
UI_RAGE_CLICK: "ui.rage_click",
|
|
3852
|
+
UI_SCROLL_THRASH: "ui.scroll_thrash",
|
|
3853
|
+
UI_FOCUS_BOUNCE: "ui.focus_bounce",
|
|
3854
|
+
UI_IDLE: "ui.idle",
|
|
3855
|
+
UI_HOVER: "ui.hover"
|
|
3856
|
+
};
|
|
3857
|
+
var RRWebSource = {
|
|
3858
|
+
Mutation: 0,
|
|
3859
|
+
MouseMove: 1,
|
|
3860
|
+
MouseInteraction: 2,
|
|
3861
|
+
Scroll: 3,
|
|
3862
|
+
ViewportResize: 4,
|
|
3863
|
+
Input: 5,
|
|
3864
|
+
TouchMove: 6,
|
|
3865
|
+
MediaInteraction: 7,
|
|
3866
|
+
Drag: 12
|
|
3867
|
+
};
|
|
3868
|
+
var RRWebMouseInteraction = {
|
|
3869
|
+
MouseUp: 0,
|
|
3870
|
+
MouseDown: 1,
|
|
3871
|
+
Click: 2,
|
|
3872
|
+
ContextMenu: 3,
|
|
3873
|
+
DblClick: 4,
|
|
3874
|
+
Focus: 5,
|
|
3875
|
+
Blur: 6,
|
|
3876
|
+
TouchStart: 7,
|
|
3877
|
+
TouchEnd: 9
|
|
3878
|
+
};
|
|
3879
|
+
var DEFAULT_DETECTOR_CONFIG = {
|
|
3880
|
+
hesitationMs: 3e3,
|
|
3881
|
+
hesitationRadiusPx: 10,
|
|
3882
|
+
rageClickCount: 3,
|
|
3883
|
+
rageClickWindowMs: 1e3,
|
|
3884
|
+
rageClickRadiusPx: 30,
|
|
3885
|
+
scrollThrashReversals: 3,
|
|
3886
|
+
scrollThrashWindowMs: 2e3,
|
|
3887
|
+
focusBounceMaxInputs: 0,
|
|
3888
|
+
idleMs: 5e3,
|
|
3889
|
+
hoverSampleMs: 100
|
|
3890
|
+
};
|
|
3891
|
+
|
|
3892
|
+
// ../event-processor/dist/normalizers/posthog.js
|
|
3893
|
+
var POSTHOG_EVENT_MAP = {
|
|
3894
|
+
// NOTE: $autocapture is intentionally NOT in this map.
|
|
3895
|
+
// It's handled below in getEventName() with $event_type refinement
|
|
3896
|
+
// so that change/submit events aren't all mapped to ui.click.
|
|
3897
|
+
$click: StandardEvents.UI_CLICK,
|
|
3898
|
+
$scroll: StandardEvents.UI_SCROLL,
|
|
3899
|
+
$input: StandardEvents.UI_INPUT,
|
|
3900
|
+
$change: StandardEvents.UI_CHANGE,
|
|
3901
|
+
$submit: StandardEvents.UI_SUBMIT,
|
|
3902
|
+
// Navigation events
|
|
3903
|
+
$pageview: StandardEvents.NAV_PAGE_VIEW,
|
|
3904
|
+
$pageleave: StandardEvents.NAV_PAGE_LEAVE,
|
|
3905
|
+
// Session events
|
|
3906
|
+
$session_start: "session.start",
|
|
3907
|
+
// Identify events
|
|
3908
|
+
$identify: "user.identify"
|
|
3909
|
+
};
|
|
3910
|
+
function getEventName(phEvent) {
|
|
3911
|
+
var _a2, _b;
|
|
3912
|
+
const eventName = phEvent.event;
|
|
3913
|
+
if (typeof eventName !== "string") {
|
|
3914
|
+
return "posthog.unknown";
|
|
3915
|
+
}
|
|
3916
|
+
if (POSTHOG_EVENT_MAP[eventName]) {
|
|
3917
|
+
return POSTHOG_EVENT_MAP[eventName];
|
|
3918
|
+
}
|
|
3919
|
+
if (eventName === "$autocapture") {
|
|
3920
|
+
const tagName = (_a2 = phEvent.properties) == null ? void 0 : _a2.$tag_name;
|
|
3921
|
+
const eventType = (_b = phEvent.properties) == null ? void 0 : _b.$event_type;
|
|
3922
|
+
if (eventType === "submit")
|
|
3923
|
+
return StandardEvents.UI_SUBMIT;
|
|
3924
|
+
if (eventType === "change")
|
|
3925
|
+
return StandardEvents.UI_CHANGE;
|
|
3926
|
+
if (tagName === "input" || tagName === "textarea")
|
|
3927
|
+
return StandardEvents.UI_INPUT;
|
|
3928
|
+
return StandardEvents.UI_CLICK;
|
|
3929
|
+
}
|
|
3930
|
+
if (!eventName.startsWith("$")) {
|
|
3931
|
+
return `posthog.${eventName}`;
|
|
3932
|
+
}
|
|
3933
|
+
return eventName.replace("$", "posthog.");
|
|
3934
|
+
}
|
|
3935
|
+
var INTERACTIVE_TAGS = /* @__PURE__ */ new Set(["a", "button", "input", "select", "textarea"]);
|
|
3936
|
+
function resolveInteractiveTag(elements, directTag) {
|
|
3937
|
+
if (directTag && INTERACTIVE_TAGS.has(directTag))
|
|
3938
|
+
return directTag;
|
|
3939
|
+
if (!elements)
|
|
3940
|
+
return directTag;
|
|
3941
|
+
for (const el of elements) {
|
|
3942
|
+
const tag2 = el.tag_name;
|
|
3943
|
+
if (tag2 && INTERACTIVE_TAGS.has(tag2))
|
|
3944
|
+
return tag2;
|
|
3945
|
+
}
|
|
3946
|
+
return directTag;
|
|
3947
|
+
}
|
|
3948
|
+
function extractProps(phEvent) {
|
|
3949
|
+
var _a2, _b;
|
|
3950
|
+
const props = {};
|
|
3951
|
+
const phProps = phEvent.properties || {};
|
|
3952
|
+
const elements = phProps.$elements;
|
|
3953
|
+
const directTag = (_b = phProps.$tag_name) != null ? _b : (_a2 = elements == null ? void 0 : elements[0]) == null ? void 0 : _a2.tag_name;
|
|
3954
|
+
const isClickEvent = phEvent.event === "$autocapture" || phEvent.event === "$click";
|
|
3955
|
+
props.tagName = isClickEvent ? resolveInteractiveTag(elements, directTag) : directTag;
|
|
3956
|
+
if (phProps.$el_text)
|
|
3957
|
+
props.elementText = phProps.$el_text;
|
|
3958
|
+
if (elements)
|
|
3959
|
+
props.elements = elements;
|
|
3960
|
+
if (phProps.$current_url)
|
|
3961
|
+
props.url = phProps.$current_url;
|
|
3962
|
+
if (phProps.$pathname)
|
|
3963
|
+
props.pathname = phProps.$pathname;
|
|
3964
|
+
if (phProps.$host)
|
|
3965
|
+
props.host = phProps.$host;
|
|
3966
|
+
if (phProps.$viewport_width)
|
|
3967
|
+
props.viewportWidth = phProps.$viewport_width;
|
|
3968
|
+
if (phProps.$viewport_height)
|
|
3969
|
+
props.viewportHeight = phProps.$viewport_height;
|
|
3970
|
+
if (phProps.$session_id)
|
|
3971
|
+
props.sessionId = phProps.$session_id;
|
|
3972
|
+
if (phProps.$scroll_depth)
|
|
3973
|
+
props.scrollDepth = phProps.$scroll_depth;
|
|
3974
|
+
if (phProps.$scroll_percentage)
|
|
3975
|
+
props.scrollPercentage = phProps.$scroll_percentage;
|
|
3976
|
+
props.originalEvent = phEvent.event;
|
|
3977
|
+
return props;
|
|
3978
|
+
}
|
|
3979
|
+
function normalizePostHogEvent(phEvent) {
|
|
3980
|
+
let ts;
|
|
3981
|
+
if (typeof phEvent.timestamp === "number") {
|
|
3982
|
+
ts = phEvent.timestamp;
|
|
3983
|
+
} else if (typeof phEvent.timestamp === "string") {
|
|
3984
|
+
ts = new Date(phEvent.timestamp).getTime();
|
|
3985
|
+
} else {
|
|
3986
|
+
ts = Date.now();
|
|
3987
|
+
}
|
|
3988
|
+
return {
|
|
3989
|
+
ts,
|
|
3990
|
+
name: getEventName(phEvent),
|
|
3991
|
+
source: "posthog",
|
|
3992
|
+
props: extractProps(phEvent),
|
|
3993
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
3994
|
+
};
|
|
3995
|
+
}
|
|
3996
|
+
function shouldNormalizeEvent(phEvent) {
|
|
3997
|
+
const eventName = phEvent.event;
|
|
3998
|
+
if (typeof eventName !== "string")
|
|
3999
|
+
return false;
|
|
4000
|
+
const skipEvents = [
|
|
4001
|
+
"$feature_flag_called",
|
|
4002
|
+
"$feature_flags",
|
|
4003
|
+
"$groups",
|
|
4004
|
+
"$groupidentify",
|
|
4005
|
+
"$set",
|
|
4006
|
+
"$set_once",
|
|
4007
|
+
"$unset",
|
|
4008
|
+
"$create_alias",
|
|
4009
|
+
"$capture_metrics",
|
|
4010
|
+
"$performance_event",
|
|
4011
|
+
"$web_vitals",
|
|
4012
|
+
"$exception",
|
|
4013
|
+
"$dead_click",
|
|
4014
|
+
"$heatmap"
|
|
4015
|
+
];
|
|
4016
|
+
if (skipEvents.includes(eventName)) {
|
|
4017
|
+
return false;
|
|
4018
|
+
}
|
|
4019
|
+
return true;
|
|
4020
|
+
}
|
|
4021
|
+
function createPostHogNormalizer(publishFn) {
|
|
4022
|
+
return (eventName, properties) => {
|
|
4023
|
+
if (typeof eventName !== "string")
|
|
4024
|
+
return;
|
|
4025
|
+
const phEvent = {
|
|
4026
|
+
event: eventName,
|
|
4027
|
+
properties,
|
|
4028
|
+
timestamp: Date.now()
|
|
4029
|
+
};
|
|
4030
|
+
if (shouldNormalizeEvent(phEvent)) {
|
|
4031
|
+
const normalizedEvent = normalizePostHogEvent(phEvent);
|
|
4032
|
+
publishFn(normalizedEvent);
|
|
4033
|
+
}
|
|
4034
|
+
};
|
|
4035
|
+
}
|
|
4036
|
+
|
|
4037
|
+
// ../event-processor/dist/detectors/focus-bounce.js
|
|
4038
|
+
var FocusBounceDetector = class {
|
|
4039
|
+
constructor(config, emit2) {
|
|
4040
|
+
this.config = config;
|
|
4041
|
+
this.emit = emit2;
|
|
4042
|
+
this.focused = /* @__PURE__ */ new Map();
|
|
4043
|
+
}
|
|
4044
|
+
ingest(raw) {
|
|
4045
|
+
var _a2, _b;
|
|
4046
|
+
if (raw.type !== 3)
|
|
4047
|
+
return;
|
|
4048
|
+
const ts = raw.timestamp;
|
|
4049
|
+
if (raw.data.source === RRWebSource.MouseInteraction) {
|
|
4050
|
+
const id = (_a2 = raw.data.id) != null ? _a2 : 0;
|
|
4051
|
+
if (raw.data.type === RRWebMouseInteraction.Focus) {
|
|
4052
|
+
this.focused.set(id, { id, focusTs: ts, inputCount: 0 });
|
|
4053
|
+
} else if (raw.data.type === RRWebMouseInteraction.Blur) {
|
|
4054
|
+
const entry = this.focused.get(id);
|
|
4055
|
+
if (entry && entry.inputCount <= this.config.focusBounceMaxInputs) {
|
|
4056
|
+
this.emit({
|
|
4057
|
+
ts,
|
|
4058
|
+
name: StandardEvents.UI_FOCUS_BOUNCE,
|
|
4059
|
+
source: "rrweb",
|
|
4060
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4061
|
+
props: {
|
|
4062
|
+
elementId: id,
|
|
4063
|
+
duration_ms: ts - entry.focusTs
|
|
4064
|
+
}
|
|
4065
|
+
});
|
|
4066
|
+
}
|
|
4067
|
+
this.focused.delete(id);
|
|
4068
|
+
}
|
|
4069
|
+
} else if (raw.data.source === RRWebSource.Input) {
|
|
4070
|
+
const id = (_b = raw.data.id) != null ? _b : 0;
|
|
4071
|
+
const entry = this.focused.get(id);
|
|
4072
|
+
if (entry) {
|
|
4073
|
+
entry.inputCount++;
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
};
|
|
4078
|
+
|
|
4079
|
+
// ../event-processor/dist/detectors/hesitation.js
|
|
4080
|
+
var HesitationDetector = class {
|
|
4081
|
+
constructor(config, emit2) {
|
|
4082
|
+
this.config = config;
|
|
4083
|
+
this.emit = emit2;
|
|
4084
|
+
this.anchorX = 0;
|
|
4085
|
+
this.anchorY = 0;
|
|
4086
|
+
this.anchorTs = 0;
|
|
4087
|
+
this.emitted = false;
|
|
4088
|
+
this.hasPosition = false;
|
|
4089
|
+
}
|
|
4090
|
+
ingest(raw) {
|
|
4091
|
+
var _a2;
|
|
4092
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseMove)
|
|
4093
|
+
return;
|
|
4094
|
+
const positions = raw.data.positions;
|
|
4095
|
+
if (!positions || positions.length === 0)
|
|
4096
|
+
return;
|
|
4097
|
+
const last = positions[positions.length - 1];
|
|
4098
|
+
const ts = raw.timestamp + ((_a2 = last.timeOffset) != null ? _a2 : 0);
|
|
4099
|
+
if (!this.hasPosition) {
|
|
4100
|
+
this.anchorX = last.x;
|
|
4101
|
+
this.anchorY = last.y;
|
|
4102
|
+
this.anchorTs = ts;
|
|
4103
|
+
this.hasPosition = true;
|
|
4104
|
+
this.emitted = false;
|
|
4105
|
+
return;
|
|
4106
|
+
}
|
|
4107
|
+
const dx = last.x - this.anchorX;
|
|
4108
|
+
const dy = last.y - this.anchorY;
|
|
4109
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
4110
|
+
if (dist > this.config.hesitationRadiusPx) {
|
|
4111
|
+
this.anchorX = last.x;
|
|
4112
|
+
this.anchorY = last.y;
|
|
4113
|
+
this.anchorTs = ts;
|
|
4114
|
+
this.emitted = false;
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
tick(now) {
|
|
4118
|
+
if (!this.hasPosition || this.emitted)
|
|
4119
|
+
return;
|
|
4120
|
+
const elapsed = now - this.anchorTs;
|
|
4121
|
+
if (elapsed >= this.config.hesitationMs) {
|
|
4122
|
+
this.emit({
|
|
4123
|
+
ts: now,
|
|
4124
|
+
name: StandardEvents.UI_HESITATE,
|
|
4125
|
+
source: "rrweb",
|
|
4126
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4127
|
+
props: {
|
|
4128
|
+
x: this.anchorX,
|
|
4129
|
+
y: this.anchorY,
|
|
4130
|
+
duration_ms: elapsed
|
|
4131
|
+
}
|
|
4132
|
+
});
|
|
4133
|
+
this.emitted = true;
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
};
|
|
4137
|
+
|
|
4138
|
+
// ../event-processor/dist/detectors/hover.js
|
|
4139
|
+
var HoverTracker = class {
|
|
4140
|
+
constructor(config, emit2, elementResolver) {
|
|
4141
|
+
this.config = config;
|
|
4142
|
+
this.emit = emit2;
|
|
4143
|
+
this.elementResolver = elementResolver;
|
|
4144
|
+
this.currentElement = null;
|
|
4145
|
+
this.hoverStartTs = null;
|
|
4146
|
+
this.lastX = 0;
|
|
4147
|
+
this.lastY = 0;
|
|
4148
|
+
this.lastSampleTs = -Infinity;
|
|
4149
|
+
}
|
|
4150
|
+
ingest(raw) {
|
|
4151
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseMove)
|
|
4152
|
+
return;
|
|
4153
|
+
const positions = raw.data.positions;
|
|
4154
|
+
if (!positions || positions.length === 0)
|
|
4155
|
+
return;
|
|
4156
|
+
const last = positions[positions.length - 1];
|
|
4157
|
+
this.lastX = last.x;
|
|
4158
|
+
this.lastY = last.y;
|
|
4159
|
+
}
|
|
4160
|
+
tick(now) {
|
|
4161
|
+
if (!this.elementResolver)
|
|
4162
|
+
return;
|
|
4163
|
+
if (now - this.lastSampleTs < this.config.hoverSampleMs)
|
|
4164
|
+
return;
|
|
4165
|
+
this.lastSampleTs = now;
|
|
4166
|
+
const newElement = this.elementResolver(this.lastX, this.lastY);
|
|
4167
|
+
const newKey = newElement ? elementKey(newElement) : null;
|
|
4168
|
+
const currentKey = this.currentElement ? elementKey(this.currentElement) : null;
|
|
4169
|
+
if (newKey !== currentKey) {
|
|
4170
|
+
if (this.currentElement && this.hoverStartTs !== null) {
|
|
4171
|
+
this.emit({
|
|
4172
|
+
ts: now,
|
|
4173
|
+
name: StandardEvents.UI_HOVER,
|
|
4174
|
+
source: "rrweb",
|
|
4175
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4176
|
+
props: {
|
|
4177
|
+
x: this.lastX,
|
|
4178
|
+
y: this.lastY,
|
|
4179
|
+
duration_ms: now - this.hoverStartTs,
|
|
4180
|
+
element: this.currentElement
|
|
4181
|
+
}
|
|
4182
|
+
});
|
|
4183
|
+
}
|
|
4184
|
+
this.currentElement = newElement;
|
|
4185
|
+
this.hoverStartTs = now;
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
};
|
|
4189
|
+
function elementKey(el) {
|
|
4190
|
+
var _a2, _b, _c;
|
|
4191
|
+
return `${(_a2 = el.tag_name) != null ? _a2 : ""}|${(_b = el.attr__id) != null ? _b : ""}|${((_c = el.classes) != null ? _c : []).join(",")}`;
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4194
|
+
// ../event-processor/dist/detectors/idle.js
|
|
4195
|
+
var IdleDetector = class {
|
|
4196
|
+
constructor(config, emit2) {
|
|
4197
|
+
this.config = config;
|
|
4198
|
+
this.emit = emit2;
|
|
4199
|
+
this.lastActivityTs = null;
|
|
4200
|
+
this.emitted = false;
|
|
4201
|
+
}
|
|
4202
|
+
ingest(raw) {
|
|
4203
|
+
if (raw.type !== 3)
|
|
4204
|
+
return;
|
|
4205
|
+
const src = raw.data.source;
|
|
4206
|
+
if (src === RRWebSource.MouseMove || src === RRWebSource.MouseInteraction || src === RRWebSource.Scroll) {
|
|
4207
|
+
this.lastActivityTs = raw.timestamp;
|
|
4208
|
+
this.emitted = false;
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
tick(now) {
|
|
4212
|
+
if (this.lastActivityTs === null || this.emitted)
|
|
4213
|
+
return;
|
|
4214
|
+
if (now - this.lastActivityTs >= this.config.idleMs) {
|
|
4215
|
+
this.emit({
|
|
4216
|
+
ts: now,
|
|
4217
|
+
name: StandardEvents.UI_IDLE,
|
|
4218
|
+
source: "rrweb",
|
|
4219
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4220
|
+
props: {
|
|
4221
|
+
idle_ms: now - this.lastActivityTs
|
|
4222
|
+
}
|
|
4223
|
+
});
|
|
4224
|
+
this.emitted = true;
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4227
|
+
};
|
|
4228
|
+
|
|
4229
|
+
// ../event-processor/dist/detectors/rage-click.js
|
|
4230
|
+
var RageClickDetector = class {
|
|
4231
|
+
constructor(config, emit2) {
|
|
4232
|
+
this.config = config;
|
|
4233
|
+
this.emit = emit2;
|
|
4234
|
+
this.clicks = [];
|
|
4235
|
+
}
|
|
4236
|
+
ingest(raw) {
|
|
4237
|
+
var _a2, _b;
|
|
4238
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.MouseInteraction)
|
|
4239
|
+
return;
|
|
4240
|
+
if (raw.data.type !== RRWebMouseInteraction.Click)
|
|
4241
|
+
return;
|
|
4242
|
+
const x = (_a2 = raw.data.x) != null ? _a2 : 0;
|
|
4243
|
+
const y = (_b = raw.data.y) != null ? _b : 0;
|
|
4244
|
+
const ts = raw.timestamp;
|
|
4245
|
+
const cutoff = ts - this.config.rageClickWindowMs;
|
|
4246
|
+
this.clicks = this.clicks.filter((c) => c.ts >= cutoff);
|
|
4247
|
+
this.clicks.push({ ts, x, y });
|
|
4248
|
+
const nearby = this.clicks.filter((c) => {
|
|
4249
|
+
const dx = c.x - x;
|
|
4250
|
+
const dy = c.y - y;
|
|
4251
|
+
return Math.sqrt(dx * dx + dy * dy) <= this.config.rageClickRadiusPx;
|
|
4252
|
+
});
|
|
4253
|
+
if (nearby.length >= this.config.rageClickCount) {
|
|
4254
|
+
this.emit({
|
|
4255
|
+
ts,
|
|
4256
|
+
name: StandardEvents.UI_RAGE_CLICK,
|
|
4257
|
+
source: "rrweb",
|
|
4258
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4259
|
+
props: {
|
|
4260
|
+
x,
|
|
4261
|
+
y,
|
|
4262
|
+
clickCount: nearby.length,
|
|
4263
|
+
duration_ms: ts - nearby[0].ts
|
|
4264
|
+
}
|
|
4265
|
+
});
|
|
4266
|
+
this.clicks = [];
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
};
|
|
4270
|
+
|
|
4271
|
+
// ../event-processor/dist/detectors/scroll-thrash.js
|
|
4272
|
+
var ScrollThrashDetector = class {
|
|
4273
|
+
constructor(config, emit2) {
|
|
4274
|
+
this.config = config;
|
|
4275
|
+
this.emit = emit2;
|
|
4276
|
+
this.lastY = null;
|
|
4277
|
+
this.lastDirection = null;
|
|
4278
|
+
this.reversals = [];
|
|
4279
|
+
}
|
|
4280
|
+
ingest(raw) {
|
|
4281
|
+
var _a2;
|
|
4282
|
+
if (raw.type !== 3 || raw.data.source !== RRWebSource.Scroll)
|
|
4283
|
+
return;
|
|
4284
|
+
const y = (_a2 = raw.data.y) != null ? _a2 : 0;
|
|
4285
|
+
const ts = raw.timestamp;
|
|
4286
|
+
if (this.lastY !== null) {
|
|
4287
|
+
const direction = y > this.lastY ? "down" : y < this.lastY ? "up" : this.lastDirection;
|
|
4288
|
+
if (direction && direction !== this.lastDirection) {
|
|
4289
|
+
const cutoff = ts - this.config.scrollThrashWindowMs;
|
|
4290
|
+
this.reversals = this.reversals.filter((t) => t > cutoff);
|
|
4291
|
+
this.reversals.push(ts);
|
|
4292
|
+
if (this.reversals.length >= this.config.scrollThrashReversals) {
|
|
4293
|
+
this.emit({
|
|
4294
|
+
ts,
|
|
4295
|
+
name: StandardEvents.UI_SCROLL_THRASH,
|
|
4296
|
+
source: "rrweb",
|
|
4297
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
4298
|
+
props: {
|
|
4299
|
+
reversals: this.reversals.length,
|
|
4300
|
+
duration_ms: ts - this.reversals[0]
|
|
4301
|
+
}
|
|
4302
|
+
});
|
|
4303
|
+
this.reversals = [];
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
this.lastDirection = direction;
|
|
4307
|
+
}
|
|
4308
|
+
this.lastY = y;
|
|
4309
|
+
}
|
|
4310
|
+
};
|
|
4311
|
+
|
|
4312
|
+
// ../event-processor/dist/processor.js
|
|
4313
|
+
function createEventProcessor(options) {
|
|
4314
|
+
const config = { ...DEFAULT_DETECTOR_CONFIG, ...options == null ? void 0 : options.config };
|
|
4315
|
+
const listeners = [];
|
|
4316
|
+
function emit2(event) {
|
|
4317
|
+
for (const cb of listeners)
|
|
4318
|
+
cb(event);
|
|
4319
|
+
}
|
|
4320
|
+
const hesitation = new HesitationDetector(config, emit2);
|
|
4321
|
+
const rageClick = new RageClickDetector(config, emit2);
|
|
4322
|
+
const scrollThrash = new ScrollThrashDetector(config, emit2);
|
|
4323
|
+
const focusBounce = new FocusBounceDetector(config, emit2);
|
|
4324
|
+
const idle = new IdleDetector(config, emit2);
|
|
4325
|
+
const hover = new HoverTracker(config, emit2, options == null ? void 0 : options.elementResolver);
|
|
4326
|
+
const clickAttrBuffer = [];
|
|
4327
|
+
return {
|
|
4328
|
+
ingest(raw) {
|
|
4329
|
+
if (raw.kind === "posthog") {
|
|
4330
|
+
const { kind: _, ...phEvent } = raw;
|
|
4331
|
+
if (shouldNormalizeEvent(phEvent)) {
|
|
4332
|
+
emit2(normalizePostHogEvent(phEvent));
|
|
4333
|
+
}
|
|
4334
|
+
} else if (raw.kind === "rrweb") {
|
|
4335
|
+
hesitation.ingest(raw);
|
|
4336
|
+
rageClick.ingest(raw);
|
|
4337
|
+
scrollThrash.ingest(raw);
|
|
4338
|
+
focusBounce.ingest(raw);
|
|
4339
|
+
idle.ingest(raw);
|
|
4340
|
+
hover.ingest(raw);
|
|
4341
|
+
}
|
|
4342
|
+
},
|
|
4343
|
+
onEvent(callback) {
|
|
4344
|
+
listeners.push(callback);
|
|
4345
|
+
},
|
|
4346
|
+
tick(timestamp) {
|
|
4347
|
+
hesitation.tick(timestamp);
|
|
4348
|
+
idle.tick(timestamp);
|
|
4349
|
+
hover.tick(timestamp);
|
|
4350
|
+
},
|
|
4351
|
+
enrichClickAttributes(timestamp, elements) {
|
|
4352
|
+
clickAttrBuffer.push({ ts: timestamp, elements });
|
|
4353
|
+
const cutoff = timestamp - 500;
|
|
4354
|
+
while (clickAttrBuffer.length > 0 && clickAttrBuffer[0].ts < cutoff) {
|
|
4355
|
+
clickAttrBuffer.shift();
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
};
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4361
|
+
// src/events/types.ts
|
|
4362
|
+
var StandardEvents2 = {
|
|
3818
4363
|
// UI events (from PostHog autocapture)
|
|
3819
4364
|
UI_CLICK: "ui.click",
|
|
3820
4365
|
UI_SCROLL: "ui.scroll",
|
|
@@ -3866,48 +4411,48 @@ function createCanvasEvent(name, props) {
|
|
|
3866
4411
|
};
|
|
3867
4412
|
}
|
|
3868
4413
|
function canvasOpened(surface) {
|
|
3869
|
-
return createCanvasEvent(
|
|
4414
|
+
return createCanvasEvent(StandardEvents2.CANVAS_OPENED, { surface });
|
|
3870
4415
|
}
|
|
3871
4416
|
function canvasClosed(surface) {
|
|
3872
|
-
return createCanvasEvent(
|
|
4417
|
+
return createCanvasEvent(StandardEvents2.CANVAS_CLOSED, { surface });
|
|
3873
4418
|
}
|
|
3874
4419
|
function tileViewed(tileId, surface) {
|
|
3875
|
-
return createCanvasEvent(
|
|
4420
|
+
return createCanvasEvent(StandardEvents2.TILE_VIEWED, { tileId, surface });
|
|
3876
4421
|
}
|
|
3877
4422
|
function tileExpanded(tileId, surface) {
|
|
3878
|
-
return createCanvasEvent(
|
|
4423
|
+
return createCanvasEvent(StandardEvents2.TILE_EXPANDED, { tileId, surface });
|
|
3879
4424
|
}
|
|
3880
4425
|
function tileCollapsed(tileId, surface) {
|
|
3881
|
-
return createCanvasEvent(
|
|
4426
|
+
return createCanvasEvent(StandardEvents2.TILE_COLLAPSED, { tileId, surface });
|
|
3882
4427
|
}
|
|
3883
4428
|
function tileAction(tileId, actionId, surface) {
|
|
3884
|
-
return createCanvasEvent(
|
|
4429
|
+
return createCanvasEvent(StandardEvents2.TILE_ACTION, {
|
|
3885
4430
|
tileId,
|
|
3886
4431
|
actionId,
|
|
3887
4432
|
surface
|
|
3888
4433
|
});
|
|
3889
4434
|
}
|
|
3890
4435
|
function overlayStarted(recipeId, recipeName) {
|
|
3891
|
-
return createCanvasEvent(
|
|
4436
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_STARTED, {
|
|
3892
4437
|
recipeId,
|
|
3893
4438
|
recipeName
|
|
3894
4439
|
});
|
|
3895
4440
|
}
|
|
3896
4441
|
function overlayCompleted(recipeId, recipeName) {
|
|
3897
|
-
return createCanvasEvent(
|
|
4442
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_COMPLETED, {
|
|
3898
4443
|
recipeId,
|
|
3899
4444
|
recipeName
|
|
3900
4445
|
});
|
|
3901
4446
|
}
|
|
3902
4447
|
function overlayDismissed(recipeId, recipeName, stepIndex) {
|
|
3903
|
-
return createCanvasEvent(
|
|
4448
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_DISMISSED, {
|
|
3904
4449
|
recipeId,
|
|
3905
4450
|
recipeName,
|
|
3906
4451
|
stepIndex
|
|
3907
4452
|
});
|
|
3908
4453
|
}
|
|
3909
4454
|
function overlayStepViewed(recipeId, stepIndex, stepTitle) {
|
|
3910
|
-
return createCanvasEvent(
|
|
4455
|
+
return createCanvasEvent(StandardEvents2.OVERLAY_STEP_VIEWED, {
|
|
3911
4456
|
recipeId,
|
|
3912
4457
|
stepIndex,
|
|
3913
4458
|
stepTitle
|
|
@@ -4233,7 +4778,7 @@ function useNotifications(eventBus, tiles) {
|
|
|
4233
4778
|
const timerIds = useRef2(/* @__PURE__ */ new Map());
|
|
4234
4779
|
const publishDismissed = useCallback2(
|
|
4235
4780
|
(notif) => {
|
|
4236
|
-
eventBus == null ? void 0 : eventBus.publish(
|
|
4781
|
+
eventBus == null ? void 0 : eventBus.publish(StandardEvents2.NOTIFICATION_DISMISSED, {
|
|
4237
4782
|
notificationId: notif.id,
|
|
4238
4783
|
tileId: notif.tileId,
|
|
4239
4784
|
itemId: notif.itemId
|
|
@@ -4298,7 +4843,7 @@ function useNotifications(eventBus, tiles) {
|
|
|
4298
4843
|
}
|
|
4299
4844
|
return next;
|
|
4300
4845
|
});
|
|
4301
|
-
eventBus.publish(
|
|
4846
|
+
eventBus.publish(StandardEvents2.NOTIFICATION_SHOWN, {
|
|
4302
4847
|
notificationId: matched.id,
|
|
4303
4848
|
tileId: matched.tileId,
|
|
4304
4849
|
itemId: matched.itemId,
|
|
@@ -4511,7 +5056,7 @@ function WidgetMount({ widgetId, props }) {
|
|
|
4511
5056
|
prevPropsJsonRef.current = propsJson;
|
|
4512
5057
|
(_a3 = handleRef.current) == null ? void 0 : _a3.update(propsRef.current);
|
|
4513
5058
|
}, [propsJson]);
|
|
4514
|
-
if (!registry
|
|
5059
|
+
if (!(registry == null ? void 0 : registry.has(widgetId))) {
|
|
4515
5060
|
return /* @__PURE__ */ jsxs2(
|
|
4516
5061
|
"div",
|
|
4517
5062
|
{
|
|
@@ -5132,7 +5677,7 @@ function ShadowCanvasOverlay({
|
|
|
5132
5677
|
const handleNotificationClick = useCallback4(
|
|
5133
5678
|
(notif) => {
|
|
5134
5679
|
if (runtime3) {
|
|
5135
|
-
runtime3.events.publish(
|
|
5680
|
+
runtime3.events.publish(StandardEvents2.NOTIFICATION_CLICKED, {
|
|
5136
5681
|
notificationId: notif.id,
|
|
5137
5682
|
tileId: notif.tileId,
|
|
5138
5683
|
itemId: notif.itemId
|
|
@@ -5142,7 +5687,7 @@ function ShadowCanvasOverlay({
|
|
|
5142
5687
|
onToggle();
|
|
5143
5688
|
}
|
|
5144
5689
|
if (runtime3 && notif.tileId) {
|
|
5145
|
-
runtime3.events.publish(
|
|
5690
|
+
runtime3.events.publish(StandardEvents2.NOTIFICATION_DEEP_LINK, {
|
|
5146
5691
|
tileId: notif.tileId,
|
|
5147
5692
|
itemId: notif.itemId
|
|
5148
5693
|
});
|
|
@@ -5215,6 +5760,17 @@ function ShadowCanvasOverlay({
|
|
|
5215
5760
|
}
|
|
5216
5761
|
onToggle();
|
|
5217
5762
|
}, [isOpen, telemetry, runtime3, onToggle]);
|
|
5763
|
+
useEffect7(() => {
|
|
5764
|
+
if (!isOpen) return;
|
|
5765
|
+
const handleOutsideClick = (e) => {
|
|
5766
|
+
const path = e.composedPath();
|
|
5767
|
+
if (containerRef.current && !path.includes(containerRef.current) && launcherRef.current && !path.includes(launcherRef.current)) {
|
|
5768
|
+
toggle2();
|
|
5769
|
+
}
|
|
5770
|
+
};
|
|
5771
|
+
document.addEventListener("mousedown", handleOutsideClick);
|
|
5772
|
+
return () => document.removeEventListener("mousedown", handleOutsideClick);
|
|
5773
|
+
}, [isOpen, toggle2]);
|
|
5218
5774
|
const onLauncherPointerDown = useCallback4((e) => {
|
|
5219
5775
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
5220
5776
|
dragRef.current = {
|
|
@@ -5253,6 +5809,7 @@ function ShadowCanvasOverlay({
|
|
|
5253
5809
|
const isPush = config.canvas.layout === "push";
|
|
5254
5810
|
const canvasBorder = (_b = config.canvas.border) != null ? _b : "none";
|
|
5255
5811
|
const containerRef = useRef5(null);
|
|
5812
|
+
const launcherRef = useRef5(null);
|
|
5256
5813
|
const zIndex = 2147483600;
|
|
5257
5814
|
useEffect7(() => {
|
|
5258
5815
|
var _a3, _b2, _c2, _d2;
|
|
@@ -5340,7 +5897,7 @@ function ShadowCanvasOverlay({
|
|
|
5340
5897
|
style: {
|
|
5341
5898
|
position: "fixed",
|
|
5342
5899
|
inset: 0,
|
|
5343
|
-
pointerEvents:
|
|
5900
|
+
pointerEvents: "none",
|
|
5344
5901
|
zIndex
|
|
5345
5902
|
},
|
|
5346
5903
|
children: /* @__PURE__ */ jsxs3("div", { style: wrapperStyle, children: [
|
|
@@ -5413,17 +5970,7 @@ function ShadowCanvasOverlay({
|
|
|
5413
5970
|
) }),
|
|
5414
5971
|
footerSlot
|
|
5415
5972
|
] }),
|
|
5416
|
-
/* @__PURE__ */ jsx8(
|
|
5417
|
-
"div",
|
|
5418
|
-
{
|
|
5419
|
-
onClick: toggle2,
|
|
5420
|
-
style: {
|
|
5421
|
-
flex: "1 1 auto",
|
|
5422
|
-
pointerEvents: isOpen ? "auto" : "none",
|
|
5423
|
-
cursor: "default"
|
|
5424
|
-
}
|
|
5425
|
-
}
|
|
5426
|
-
)
|
|
5973
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: "1 1 auto" } })
|
|
5427
5974
|
] })
|
|
5428
5975
|
}
|
|
5429
5976
|
);
|
|
@@ -5453,6 +6000,7 @@ function ShadowCanvasOverlay({
|
|
|
5453
6000
|
/* @__PURE__ */ jsxs3(
|
|
5454
6001
|
"button",
|
|
5455
6002
|
{
|
|
6003
|
+
ref: launcherRef,
|
|
5456
6004
|
type: "button",
|
|
5457
6005
|
"aria-label": "Toggle shadow canvas",
|
|
5458
6006
|
className: launcherAnimate && !isOpen ? "syntro-launcher-animate" : void 0,
|
|
@@ -5715,8 +6263,8 @@ function SmartCanvasApp({
|
|
|
5715
6263
|
controller,
|
|
5716
6264
|
fetcher,
|
|
5717
6265
|
configUri,
|
|
5718
|
-
configUriFeatureKey
|
|
5719
|
-
configFeatureKey
|
|
6266
|
+
configUriFeatureKey,
|
|
6267
|
+
configFeatureKey,
|
|
5720
6268
|
fetchCredentials = "include",
|
|
5721
6269
|
pollIntervalMs,
|
|
5722
6270
|
experiments,
|
|
@@ -5786,10 +6334,10 @@ function SmartCanvasAppInner({
|
|
|
5786
6334
|
controller,
|
|
5787
6335
|
fetcher,
|
|
5788
6336
|
configUri,
|
|
5789
|
-
configUriFeatureKey
|
|
5790
|
-
configFeatureKey
|
|
6337
|
+
configUriFeatureKey,
|
|
6338
|
+
configFeatureKey,
|
|
5791
6339
|
fetchCredentials = "include",
|
|
5792
|
-
pollIntervalMs,
|
|
6340
|
+
pollIntervalMs: _pollIntervalMs,
|
|
5793
6341
|
experiments,
|
|
5794
6342
|
telemetry,
|
|
5795
6343
|
runtime: runtime3,
|
|
@@ -7072,7 +7620,6 @@ var PostHogAdapter = class {
|
|
|
7072
7620
|
__publicField(this, "featureFlagsCallback");
|
|
7073
7621
|
__publicField(this, "captureCallback");
|
|
7074
7622
|
__publicField(this, "rrwebCallback");
|
|
7075
|
-
__publicField(this, "consentUnsub");
|
|
7076
7623
|
this.client = options.client;
|
|
7077
7624
|
this.featureFlagsCallback = options.onFeatureFlagsLoaded;
|
|
7078
7625
|
this.captureCallback = options.onCapture;
|
|
@@ -7083,7 +7630,7 @@ var PostHogAdapter = class {
|
|
|
7083
7630
|
if (currentStatus === "granted") {
|
|
7084
7631
|
this.initPostHog();
|
|
7085
7632
|
}
|
|
7086
|
-
|
|
7633
|
+
consent.subscribe((status) => {
|
|
7087
7634
|
if (status === "granted") {
|
|
7088
7635
|
if (!this.client) {
|
|
7089
7636
|
this.initPostHog();
|
|
@@ -7110,71 +7657,67 @@ var PostHogAdapter = class {
|
|
|
7110
7657
|
if (!options.apiKey) return;
|
|
7111
7658
|
const enableFeatureFlags = (_a2 = options.enableFeatureFlags) != null ? _a2 : true;
|
|
7112
7659
|
const instanceName = `syntro_${options.apiKey.slice(-6) || "sdk"}`;
|
|
7113
|
-
|
|
7114
|
-
options.
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
if (allFlags && this.featureFlagsCallback) {
|
|
7144
|
-
this.featureFlagsCallback(allFlags);
|
|
7145
|
-
}
|
|
7146
|
-
});
|
|
7147
|
-
const existingFlags = this.getAllFeatureFlags();
|
|
7148
|
-
if (existingFlags && Object.keys(existingFlags).length > 0) {
|
|
7149
|
-
this.featureFlagsCallback(existingFlags);
|
|
7660
|
+
const initOptions = {
|
|
7661
|
+
api_host: (_b = options.apiHost) != null ? _b : "https://telemetry.syntrologie.com",
|
|
7662
|
+
// Feature flags for segment membership (in_segment_* flags)
|
|
7663
|
+
// When enabled, /decide is called to get segment flags
|
|
7664
|
+
advanced_disable_feature_flags: !enableFeatureFlags,
|
|
7665
|
+
advanced_disable_feature_flags_on_first_load: !enableFeatureFlags,
|
|
7666
|
+
// Full-page tracking - all ON by default
|
|
7667
|
+
autocapture: (_c = options.autocapture) != null ? _c : true,
|
|
7668
|
+
capture_pageview: (_d = options.capturePageview) != null ? _d : "history_change",
|
|
7669
|
+
capture_pageleave: (_e = options.capturePageleave) != null ? _e : true,
|
|
7670
|
+
disable_session_recording: !((_f = options.sessionRecording) != null ? _f : true),
|
|
7671
|
+
// CRITICAL: Disable user agent filtering to allow headless Chrome
|
|
7672
|
+
// PostHog blocks "HeadlessChrome" user agents by default as bot detection
|
|
7673
|
+
// This enables session recording in Playwright/crawler sessions
|
|
7674
|
+
opt_out_useragent_filter: true,
|
|
7675
|
+
// Cross-domain iframe recording for embeds
|
|
7676
|
+
session_recording: {
|
|
7677
|
+
recordCrossDomainIFrames: true
|
|
7678
|
+
},
|
|
7679
|
+
// Capture performance metrics
|
|
7680
|
+
capture_performance: true,
|
|
7681
|
+
// Enable web vitals
|
|
7682
|
+
enable_recording_console_log: true,
|
|
7683
|
+
// Bootstrap callback for when flags are loaded
|
|
7684
|
+
loaded: (ph) => {
|
|
7685
|
+
if (enableFeatureFlags && this.featureFlagsCallback) {
|
|
7686
|
+
ph.onFeatureFlags(() => {
|
|
7687
|
+
const allFlags = this.getAllFeatureFlags();
|
|
7688
|
+
if (allFlags && this.featureFlagsCallback) {
|
|
7689
|
+
this.featureFlagsCallback(allFlags);
|
|
7150
7690
|
}
|
|
7151
|
-
}
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
const eventName = typeof data === "string" ? data : data == null ? void 0 : data.event;
|
|
7156
|
-
const properties = typeof data === "string" ? void 0 : data == null ? void 0 : data.properties;
|
|
7157
|
-
if (typeof eventName === "string") {
|
|
7158
|
-
(_a3 = this.captureCallback) == null ? void 0 : _a3.call(this, eventName, properties);
|
|
7159
|
-
}
|
|
7160
|
-
});
|
|
7691
|
+
});
|
|
7692
|
+
const existingFlags = this.getAllFeatureFlags();
|
|
7693
|
+
if (existingFlags && Object.keys(existingFlags).length > 0) {
|
|
7694
|
+
this.featureFlagsCallback(existingFlags);
|
|
7161
7695
|
}
|
|
7162
7696
|
}
|
|
7163
|
-
|
|
7697
|
+
if (this.captureCallback) {
|
|
7698
|
+
ph.on("eventCaptured", (...args) => {
|
|
7699
|
+
var _a3;
|
|
7700
|
+
const data = args[0];
|
|
7701
|
+
const eventName = typeof data === "string" ? data : data == null ? void 0 : data.event;
|
|
7702
|
+
const properties = typeof data === "string" ? void 0 : data == null ? void 0 : data.properties;
|
|
7703
|
+
if (typeof eventName === "string") {
|
|
7704
|
+
(_a3 = this.captureCallback) == null ? void 0 : _a3.call(this, eventName, properties);
|
|
7705
|
+
}
|
|
7706
|
+
});
|
|
7707
|
+
}
|
|
7708
|
+
}
|
|
7709
|
+
};
|
|
7710
|
+
const result = posthog.init(
|
|
7711
|
+
options.apiKey,
|
|
7712
|
+
initOptions,
|
|
7164
7713
|
instanceName
|
|
7165
7714
|
);
|
|
7715
|
+
if (result) {
|
|
7716
|
+
this.client = result;
|
|
7717
|
+
}
|
|
7166
7718
|
if (this.rrwebCallback && this.client) {
|
|
7167
7719
|
this.setupRRWebIntercept();
|
|
7168
7720
|
}
|
|
7169
|
-
if (options.replayMirrorEndpoint && this.client) {
|
|
7170
|
-
import("./replayMirror-QZ3GQ527.js").then(({ setupReplayMirror }) => {
|
|
7171
|
-
var _a3;
|
|
7172
|
-
setupReplayMirror({
|
|
7173
|
-
posthogHost: (_a3 = options.apiHost) != null ? _a3 : "https://telemetry.syntrologie.com",
|
|
7174
|
-
mirrorEndpoint: options.replayMirrorEndpoint
|
|
7175
|
-
});
|
|
7176
|
-
});
|
|
7177
|
-
}
|
|
7178
7721
|
}
|
|
7179
7722
|
/**
|
|
7180
7723
|
* Set up rrweb event interception on PostHog's session recording.
|
|
@@ -7197,8 +7740,9 @@ var PostHogAdapter = class {
|
|
|
7197
7740
|
return;
|
|
7198
7741
|
}
|
|
7199
7742
|
let recorder = null;
|
|
7200
|
-
|
|
7201
|
-
|
|
7743
|
+
const srRecord = sr;
|
|
7744
|
+
for (const key of Object.getOwnPropertyNames(srRecord)) {
|
|
7745
|
+
const val = srRecord[key];
|
|
7202
7746
|
if (val && typeof val === "object" && typeof val.onRRwebEmit === "function" && typeof val.start === "function" && val !== sr) {
|
|
7203
7747
|
recorder = val;
|
|
7204
7748
|
break;
|
|
@@ -7225,9 +7769,8 @@ var PostHogAdapter = class {
|
|
|
7225
7769
|
* Used to extract segment membership flags (in_segment_*).
|
|
7226
7770
|
*/
|
|
7227
7771
|
getAllFeatureFlags() {
|
|
7228
|
-
var _a2, _b
|
|
7229
|
-
|
|
7230
|
-
return flags;
|
|
7772
|
+
var _a2, _b;
|
|
7773
|
+
return (_b = (_a2 = this.client) == null ? void 0 : _a2.featureFlags) == null ? void 0 : _b.getFlagVariants();
|
|
7231
7774
|
}
|
|
7232
7775
|
/**
|
|
7233
7776
|
* Get segment membership flags (in_segment_*) from PostHog.
|
|
@@ -7578,187 +8121,36 @@ function hasExecutor(kind) {
|
|
|
7578
8121
|
return executorRegistry.has(kind);
|
|
7579
8122
|
}
|
|
7580
8123
|
|
|
7581
|
-
// src/actions/validation.ts
|
|
7582
|
-
|
|
7583
|
-
"
|
|
7584
|
-
"onerror",
|
|
7585
|
-
"onload",
|
|
7586
|
-
"onmouseover",
|
|
7587
|
-
"onfocus",
|
|
7588
|
-
"onblur",
|
|
7589
|
-
"onchange",
|
|
7590
|
-
"onsubmit",
|
|
7591
|
-
"onkeydown",
|
|
7592
|
-
"onkeyup",
|
|
7593
|
-
"onkeypress"
|
|
7594
|
-
]);
|
|
7595
|
-
var MAX_HTML_LENGTH = 5e4;
|
|
7596
|
-
var MAX_STYLE_COUNT = 50;
|
|
7597
|
-
function validateAction(action) {
|
|
7598
|
-
const errors = [];
|
|
7599
|
-
const warnings = [];
|
|
7600
|
-
if (!action || typeof action !== "object") {
|
|
8124
|
+
// src/actions/validation-rules.ts
|
|
8125
|
+
function validateBadgeAction(action, errors, warnings) {
|
|
8126
|
+
if (!action.content || typeof action.content !== "string") {
|
|
7601
8127
|
errors.push({
|
|
7602
|
-
code: "
|
|
7603
|
-
message: "
|
|
8128
|
+
code: "MISSING_CONTENT",
|
|
8129
|
+
message: "Badge action requires 'content' property",
|
|
8130
|
+
field: "content"
|
|
8131
|
+
});
|
|
8132
|
+
} else if (action.content.length > 100) {
|
|
8133
|
+
warnings.push({
|
|
8134
|
+
code: "LONG_BADGE_CONTENT",
|
|
8135
|
+
message: "Badge content is quite long",
|
|
8136
|
+
suggestion: "Keep badge content short (under 100 characters)"
|
|
7604
8137
|
});
|
|
7605
|
-
return { valid: false, errors, warnings };
|
|
7606
8138
|
}
|
|
7607
|
-
|
|
7608
|
-
|
|
8139
|
+
}
|
|
8140
|
+
function validateTooltipAction(action, errors, _warnings) {
|
|
8141
|
+
if (!action.content || typeof action.content !== "object") {
|
|
7609
8142
|
errors.push({
|
|
7610
|
-
code: "
|
|
7611
|
-
message: "
|
|
8143
|
+
code: "MISSING_CONTENT",
|
|
8144
|
+
message: "Tooltip action requires 'content' object",
|
|
8145
|
+
field: "content"
|
|
7612
8146
|
});
|
|
7613
|
-
return
|
|
8147
|
+
return;
|
|
7614
8148
|
}
|
|
7615
|
-
if (!
|
|
7616
|
-
const registered = executorRegistry.list();
|
|
7617
|
-
console.error(
|
|
7618
|
-
`[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.`
|
|
7619
|
-
);
|
|
8149
|
+
if (!action.content.body || typeof action.content.body !== "string") {
|
|
7620
8150
|
errors.push({
|
|
7621
|
-
code: "
|
|
7622
|
-
message:
|
|
7623
|
-
field: "
|
|
7624
|
-
});
|
|
7625
|
-
return { valid: false, errors, warnings };
|
|
7626
|
-
}
|
|
7627
|
-
switch (kind) {
|
|
7628
|
-
case "overlays:highlight":
|
|
7629
|
-
case "overlays:pulse":
|
|
7630
|
-
case "navigation:scrollTo":
|
|
7631
|
-
validateAnchorAction(action, errors, warnings);
|
|
7632
|
-
break;
|
|
7633
|
-
case "overlays:badge":
|
|
7634
|
-
validateAnchorAction(action, errors, warnings);
|
|
7635
|
-
validateBadgeAction(action, errors, warnings);
|
|
7636
|
-
break;
|
|
7637
|
-
case "overlays:tooltip":
|
|
7638
|
-
validateAnchorAction(action, errors, warnings);
|
|
7639
|
-
validateTooltipAction(action, errors, warnings);
|
|
7640
|
-
break;
|
|
7641
|
-
case "overlays:modal":
|
|
7642
|
-
validateModalAction(action, errors, warnings);
|
|
7643
|
-
break;
|
|
7644
|
-
case "content:insertHtml":
|
|
7645
|
-
validateAnchorAction(action, errors, warnings);
|
|
7646
|
-
validateInsertHtmlAction(action, errors, warnings);
|
|
7647
|
-
break;
|
|
7648
|
-
case "content:setText":
|
|
7649
|
-
validateAnchorAction(action, errors, warnings);
|
|
7650
|
-
validateSetTextAction(action, errors, warnings);
|
|
7651
|
-
break;
|
|
7652
|
-
case "content:setAttr":
|
|
7653
|
-
validateAnchorAction(action, errors, warnings);
|
|
7654
|
-
validateSetAttrAction(action, errors, warnings);
|
|
7655
|
-
break;
|
|
7656
|
-
case "content:addClass":
|
|
7657
|
-
case "content:removeClass":
|
|
7658
|
-
validateAnchorAction(action, errors, warnings);
|
|
7659
|
-
validateClassAction(action, errors, warnings);
|
|
7660
|
-
break;
|
|
7661
|
-
case "content:setStyle":
|
|
7662
|
-
validateAnchorAction(action, errors, warnings);
|
|
7663
|
-
validateSetStyleAction(action, errors, warnings);
|
|
7664
|
-
break;
|
|
7665
|
-
case "core:mountWidget":
|
|
7666
|
-
validateMountWidgetAction(action, errors, warnings);
|
|
7667
|
-
break;
|
|
7668
|
-
case "core:wait":
|
|
7669
|
-
validateWaitAction(action, errors, warnings);
|
|
7670
|
-
break;
|
|
7671
|
-
case "core:sequence":
|
|
7672
|
-
validateSequenceAction(action, errors, warnings);
|
|
7673
|
-
break;
|
|
7674
|
-
case "core:parallel":
|
|
7675
|
-
validateParallelAction(action, errors, warnings);
|
|
7676
|
-
break;
|
|
7677
|
-
case "core:tour":
|
|
7678
|
-
validateTourAction(action, errors, warnings);
|
|
7679
|
-
break;
|
|
7680
|
-
case "navigation:navigate":
|
|
7681
|
-
validateNavigateAction(action, errors, warnings);
|
|
7682
|
-
break;
|
|
7683
|
-
}
|
|
7684
|
-
return {
|
|
7685
|
-
valid: errors.length === 0,
|
|
7686
|
-
errors,
|
|
7687
|
-
warnings
|
|
7688
|
-
};
|
|
7689
|
-
}
|
|
7690
|
-
function validateAnchorAction(action, errors, warnings) {
|
|
7691
|
-
const anchorId = action.anchorId;
|
|
7692
|
-
if (!anchorId || typeof anchorId !== "object") {
|
|
7693
|
-
errors.push({
|
|
7694
|
-
code: "MISSING_ANCHOR_ID",
|
|
7695
|
-
message: "Action requires an 'anchorId' object with a 'selector' string",
|
|
7696
|
-
field: "anchorId"
|
|
7697
|
-
});
|
|
7698
|
-
return;
|
|
7699
|
-
}
|
|
7700
|
-
if (!anchorId.selector || typeof anchorId.selector !== "string") {
|
|
7701
|
-
errors.push({
|
|
7702
|
-
code: "MISSING_ANCHOR_SELECTOR",
|
|
7703
|
-
message: "anchorId requires a 'selector' string",
|
|
7704
|
-
field: "anchorId.selector"
|
|
7705
|
-
});
|
|
7706
|
-
} else if (anchorId.selector.length > 200) {
|
|
7707
|
-
warnings.push({
|
|
7708
|
-
code: "LONG_ANCHOR_ID",
|
|
7709
|
-
message: "Anchor selector is unusually long",
|
|
7710
|
-
suggestion: "Consider using a shorter, more descriptive selector"
|
|
7711
|
-
});
|
|
7712
|
-
}
|
|
7713
|
-
if (anchorId.route === void 0 || anchorId.route === null) {
|
|
7714
|
-
errors.push({
|
|
7715
|
-
code: "MISSING_ANCHOR_ROUTE",
|
|
7716
|
-
message: `anchorId requires a 'route' (string or array of strings). Use "**" for all routes.`,
|
|
7717
|
-
field: "anchorId.route"
|
|
7718
|
-
});
|
|
7719
|
-
} else {
|
|
7720
|
-
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
7721
|
-
for (const route of routes) {
|
|
7722
|
-
if (typeof route !== "string") {
|
|
7723
|
-
errors.push({
|
|
7724
|
-
code: "INVALID_ANCHOR_ROUTE",
|
|
7725
|
-
message: "anchorId.route must be a string or array of strings",
|
|
7726
|
-
field: "anchorId.route"
|
|
7727
|
-
});
|
|
7728
|
-
break;
|
|
7729
|
-
}
|
|
7730
|
-
}
|
|
7731
|
-
}
|
|
7732
|
-
}
|
|
7733
|
-
function validateBadgeAction(action, errors, warnings) {
|
|
7734
|
-
if (!action.content || typeof action.content !== "string") {
|
|
7735
|
-
errors.push({
|
|
7736
|
-
code: "MISSING_CONTENT",
|
|
7737
|
-
message: "Badge action requires 'content' property",
|
|
7738
|
-
field: "content"
|
|
7739
|
-
});
|
|
7740
|
-
} else if (action.content.length > 100) {
|
|
7741
|
-
warnings.push({
|
|
7742
|
-
code: "LONG_BADGE_CONTENT",
|
|
7743
|
-
message: "Badge content is quite long",
|
|
7744
|
-
suggestion: "Keep badge content short (under 100 characters)"
|
|
7745
|
-
});
|
|
7746
|
-
}
|
|
7747
|
-
}
|
|
7748
|
-
function validateTooltipAction(action, errors, _warnings) {
|
|
7749
|
-
if (!action.content || typeof action.content !== "object") {
|
|
7750
|
-
errors.push({
|
|
7751
|
-
code: "MISSING_CONTENT",
|
|
7752
|
-
message: "Tooltip action requires 'content' object",
|
|
7753
|
-
field: "content"
|
|
7754
|
-
});
|
|
7755
|
-
return;
|
|
7756
|
-
}
|
|
7757
|
-
if (!action.content.body || typeof action.content.body !== "string") {
|
|
7758
|
-
errors.push({
|
|
7759
|
-
code: "MISSING_BODY",
|
|
7760
|
-
message: "Tooltip content requires 'body' property",
|
|
7761
|
-
field: "content.body"
|
|
8151
|
+
code: "MISSING_BODY",
|
|
8152
|
+
message: "Tooltip content requires 'body' property",
|
|
8153
|
+
field: "content.body"
|
|
7762
8154
|
});
|
|
7763
8155
|
}
|
|
7764
8156
|
}
|
|
@@ -8116,6 +8508,159 @@ function validateTourAction(action, errors, warnings) {
|
|
|
8116
8508
|
}
|
|
8117
8509
|
}
|
|
8118
8510
|
}
|
|
8511
|
+
|
|
8512
|
+
// src/actions/validation-core.ts
|
|
8513
|
+
var DANGEROUS_ATTRS = /* @__PURE__ */ new Set([
|
|
8514
|
+
"onclick",
|
|
8515
|
+
"onerror",
|
|
8516
|
+
"onload",
|
|
8517
|
+
"onmouseover",
|
|
8518
|
+
"onfocus",
|
|
8519
|
+
"onblur",
|
|
8520
|
+
"onchange",
|
|
8521
|
+
"onsubmit",
|
|
8522
|
+
"onkeydown",
|
|
8523
|
+
"onkeyup",
|
|
8524
|
+
"onkeypress"
|
|
8525
|
+
]);
|
|
8526
|
+
var MAX_HTML_LENGTH = 5e4;
|
|
8527
|
+
var MAX_STYLE_COUNT = 50;
|
|
8528
|
+
function validateAction(action) {
|
|
8529
|
+
const errors = [];
|
|
8530
|
+
const warnings = [];
|
|
8531
|
+
if (!action || typeof action !== "object") {
|
|
8532
|
+
errors.push({
|
|
8533
|
+
code: "INVALID_ACTION",
|
|
8534
|
+
message: "Action must be an object"
|
|
8535
|
+
});
|
|
8536
|
+
return { valid: false, errors, warnings };
|
|
8537
|
+
}
|
|
8538
|
+
const { kind } = action;
|
|
8539
|
+
if (!kind || typeof kind !== "string") {
|
|
8540
|
+
errors.push({
|
|
8541
|
+
code: "MISSING_KIND",
|
|
8542
|
+
message: "Action must have a 'kind' property"
|
|
8543
|
+
});
|
|
8544
|
+
return { valid: false, errors, warnings };
|
|
8545
|
+
}
|
|
8546
|
+
if (!hasExecutor(kind) && kind !== "core:mountWidget") {
|
|
8547
|
+
const registered = executorRegistry.list();
|
|
8548
|
+
console.error(
|
|
8549
|
+
`[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.`
|
|
8550
|
+
);
|
|
8551
|
+
errors.push({
|
|
8552
|
+
code: "UNKNOWN_KIND",
|
|
8553
|
+
message: `Unknown action kind: ${kind}`,
|
|
8554
|
+
field: "kind"
|
|
8555
|
+
});
|
|
8556
|
+
return { valid: false, errors, warnings };
|
|
8557
|
+
}
|
|
8558
|
+
switch (kind) {
|
|
8559
|
+
case "overlays:highlight":
|
|
8560
|
+
case "overlays:pulse":
|
|
8561
|
+
case "navigation:scrollTo":
|
|
8562
|
+
validateAnchorAction(action, errors, warnings);
|
|
8563
|
+
break;
|
|
8564
|
+
case "overlays:badge":
|
|
8565
|
+
validateAnchorAction(action, errors, warnings);
|
|
8566
|
+
validateBadgeAction(action, errors, warnings);
|
|
8567
|
+
break;
|
|
8568
|
+
case "overlays:tooltip":
|
|
8569
|
+
validateAnchorAction(action, errors, warnings);
|
|
8570
|
+
validateTooltipAction(action, errors, warnings);
|
|
8571
|
+
break;
|
|
8572
|
+
case "overlays:modal":
|
|
8573
|
+
validateModalAction(action, errors, warnings);
|
|
8574
|
+
break;
|
|
8575
|
+
case "content:insertHtml":
|
|
8576
|
+
validateAnchorAction(action, errors, warnings);
|
|
8577
|
+
validateInsertHtmlAction(action, errors, warnings);
|
|
8578
|
+
break;
|
|
8579
|
+
case "content:setText":
|
|
8580
|
+
validateAnchorAction(action, errors, warnings);
|
|
8581
|
+
validateSetTextAction(action, errors, warnings);
|
|
8582
|
+
break;
|
|
8583
|
+
case "content:setAttr":
|
|
8584
|
+
validateAnchorAction(action, errors, warnings);
|
|
8585
|
+
validateSetAttrAction(action, errors, warnings);
|
|
8586
|
+
break;
|
|
8587
|
+
case "content:addClass":
|
|
8588
|
+
case "content:removeClass":
|
|
8589
|
+
validateAnchorAction(action, errors, warnings);
|
|
8590
|
+
validateClassAction(action, errors, warnings);
|
|
8591
|
+
break;
|
|
8592
|
+
case "content:setStyle":
|
|
8593
|
+
validateAnchorAction(action, errors, warnings);
|
|
8594
|
+
validateSetStyleAction(action, errors, warnings);
|
|
8595
|
+
break;
|
|
8596
|
+
case "core:mountWidget":
|
|
8597
|
+
validateMountWidgetAction(action, errors, warnings);
|
|
8598
|
+
break;
|
|
8599
|
+
case "core:wait":
|
|
8600
|
+
validateWaitAction(action, errors, warnings);
|
|
8601
|
+
break;
|
|
8602
|
+
case "core:sequence":
|
|
8603
|
+
validateSequenceAction(action, errors, warnings);
|
|
8604
|
+
break;
|
|
8605
|
+
case "core:parallel":
|
|
8606
|
+
validateParallelAction(action, errors, warnings);
|
|
8607
|
+
break;
|
|
8608
|
+
case "overlays:tour":
|
|
8609
|
+
validateTourAction(action, errors, warnings);
|
|
8610
|
+
break;
|
|
8611
|
+
case "navigation:navigate":
|
|
8612
|
+
validateNavigateAction(action, errors, warnings);
|
|
8613
|
+
break;
|
|
8614
|
+
}
|
|
8615
|
+
return {
|
|
8616
|
+
valid: errors.length === 0,
|
|
8617
|
+
errors,
|
|
8618
|
+
warnings
|
|
8619
|
+
};
|
|
8620
|
+
}
|
|
8621
|
+
function validateAnchorAction(action, errors, warnings) {
|
|
8622
|
+
const anchorId = action.anchorId;
|
|
8623
|
+
if (!anchorId || typeof anchorId !== "object") {
|
|
8624
|
+
errors.push({
|
|
8625
|
+
code: "MISSING_ANCHOR_ID",
|
|
8626
|
+
message: "Action requires an 'anchorId' object with a 'selector' string",
|
|
8627
|
+
field: "anchorId"
|
|
8628
|
+
});
|
|
8629
|
+
return;
|
|
8630
|
+
}
|
|
8631
|
+
if (!anchorId.selector || typeof anchorId.selector !== "string") {
|
|
8632
|
+
errors.push({
|
|
8633
|
+
code: "MISSING_ANCHOR_SELECTOR",
|
|
8634
|
+
message: "anchorId requires a 'selector' string",
|
|
8635
|
+
field: "anchorId.selector"
|
|
8636
|
+
});
|
|
8637
|
+
} else if (anchorId.selector.length > 200) {
|
|
8638
|
+
warnings.push({
|
|
8639
|
+
code: "LONG_ANCHOR_ID",
|
|
8640
|
+
message: "Anchor selector is unusually long",
|
|
8641
|
+
suggestion: "Consider using a shorter, more descriptive selector"
|
|
8642
|
+
});
|
|
8643
|
+
}
|
|
8644
|
+
if (anchorId.route === void 0 || anchorId.route === null) {
|
|
8645
|
+
errors.push({
|
|
8646
|
+
code: "MISSING_ANCHOR_ROUTE",
|
|
8647
|
+
message: `anchorId requires a 'route' (string or array of strings). Use "**" for all routes.`,
|
|
8648
|
+
field: "anchorId.route"
|
|
8649
|
+
});
|
|
8650
|
+
} else {
|
|
8651
|
+
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
8652
|
+
for (const route of routes) {
|
|
8653
|
+
if (typeof route !== "string") {
|
|
8654
|
+
errors.push({
|
|
8655
|
+
code: "INVALID_ANCHOR_ROUTE",
|
|
8656
|
+
message: "anchorId.route must be a string or array of strings",
|
|
8657
|
+
field: "anchorId.route"
|
|
8658
|
+
});
|
|
8659
|
+
break;
|
|
8660
|
+
}
|
|
8661
|
+
}
|
|
8662
|
+
}
|
|
8663
|
+
}
|
|
8119
8664
|
function validateActions(actions) {
|
|
8120
8665
|
var _a2;
|
|
8121
8666
|
const errors = [];
|
|
@@ -8262,7 +8807,7 @@ function createActionEngine(options) {
|
|
|
8262
8807
|
}
|
|
8263
8808
|
return executor(action, context);
|
|
8264
8809
|
}
|
|
8265
|
-
function subscribeForReeval(id, action, triggerWhen,
|
|
8810
|
+
function subscribeForReeval(id, action, triggerWhen, _handle) {
|
|
8266
8811
|
if (!runtime3) return;
|
|
8267
8812
|
const unsubs = [];
|
|
8268
8813
|
const onReeval = async () => {
|
|
@@ -9232,6 +9777,66 @@ function createEventAccumulator(options) {
|
|
|
9232
9777
|
};
|
|
9233
9778
|
}
|
|
9234
9779
|
|
|
9780
|
+
// src/events/validation.ts
|
|
9781
|
+
var APP_PREFIX = "app:";
|
|
9782
|
+
var RESERVED_PREFIX = "syntro:";
|
|
9783
|
+
var SEGMENT_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
9784
|
+
function validateEventName(name) {
|
|
9785
|
+
if (!name) {
|
|
9786
|
+
return { valid: false, reason: "Event name cannot be empty" };
|
|
9787
|
+
}
|
|
9788
|
+
if (name.startsWith(RESERVED_PREFIX)) {
|
|
9789
|
+
return { valid: false, reason: '"syntro:" prefix is reserved for internal SDK events' };
|
|
9790
|
+
}
|
|
9791
|
+
if (!name.startsWith(APP_PREFIX)) {
|
|
9792
|
+
return { valid: false, reason: `Custom events must start with "app:" prefix. Got: "${name}"` };
|
|
9793
|
+
}
|
|
9794
|
+
const segments = name.slice(APP_PREFIX.length).split(":");
|
|
9795
|
+
if (segments.length < 2) {
|
|
9796
|
+
return {
|
|
9797
|
+
valid: false,
|
|
9798
|
+
reason: `Event name must have at least 2 segments after "app:" (app:{category}:{action}). Got: "${name}"`
|
|
9799
|
+
};
|
|
9800
|
+
}
|
|
9801
|
+
for (const segment of segments) {
|
|
9802
|
+
if (!SEGMENT_PATTERN.test(segment)) {
|
|
9803
|
+
return {
|
|
9804
|
+
valid: false,
|
|
9805
|
+
reason: `Segment "${segment}" must be lowercase alphanumeric + underscores. Got: "${name}"`
|
|
9806
|
+
};
|
|
9807
|
+
}
|
|
9808
|
+
}
|
|
9809
|
+
return { valid: true };
|
|
9810
|
+
}
|
|
9811
|
+
function isSerializable(value) {
|
|
9812
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null;
|
|
9813
|
+
}
|
|
9814
|
+
function checkDepth(obj, maxDepth, current = 0) {
|
|
9815
|
+
if (current >= maxDepth) return false;
|
|
9816
|
+
for (const value of Object.values(obj)) {
|
|
9817
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
9818
|
+
if (!checkDepth(value, maxDepth, current + 1)) return false;
|
|
9819
|
+
}
|
|
9820
|
+
}
|
|
9821
|
+
return true;
|
|
9822
|
+
}
|
|
9823
|
+
function validateProps(props) {
|
|
9824
|
+
if (props === void 0) return { valid: true };
|
|
9825
|
+
if (props === null || typeof props !== "object" || Array.isArray(props)) {
|
|
9826
|
+
return { valid: false, reason: "Props must be a plain object" };
|
|
9827
|
+
}
|
|
9828
|
+
if (!checkDepth(props, 2)) {
|
|
9829
|
+
return { valid: false, reason: "Props nesting depth exceeds 2 levels" };
|
|
9830
|
+
}
|
|
9831
|
+
const stripped = [];
|
|
9832
|
+
for (const [key, value] of Object.entries(props)) {
|
|
9833
|
+
if (value !== null && typeof value === "object") continue;
|
|
9834
|
+
if (!isSerializable(value)) stripped.push(key);
|
|
9835
|
+
}
|
|
9836
|
+
if (stripped.length > 0) return { valid: true, stripped };
|
|
9837
|
+
return { valid: true };
|
|
9838
|
+
}
|
|
9839
|
+
|
|
9235
9840
|
// src/events/EventBus.ts
|
|
9236
9841
|
function matchesFilter(event, filter) {
|
|
9237
9842
|
if (!filter) return true;
|
|
@@ -9263,8 +9868,16 @@ var EventBus = class {
|
|
|
9263
9868
|
__publicField(this, "subscriptions", /* @__PURE__ */ new Set());
|
|
9264
9869
|
__publicField(this, "history", []);
|
|
9265
9870
|
__publicField(this, "maxHistorySize");
|
|
9266
|
-
|
|
9871
|
+
__publicField(this, "debug");
|
|
9872
|
+
__publicField(this, "emitHistory");
|
|
9873
|
+
__publicField(this, "posthogCapture");
|
|
9874
|
+
__publicField(this, "testMode");
|
|
9875
|
+
var _a2, _b, _c, _d, _e;
|
|
9267
9876
|
this.maxHistorySize = (_a2 = options.maxHistorySize) != null ? _a2 : 100;
|
|
9877
|
+
this.debug = (_b = options.debug) != null ? _b : false;
|
|
9878
|
+
this.emitHistory = (_c = options.history) != null ? _c : null;
|
|
9879
|
+
this.posthogCapture = (_d = options.posthogCapture) != null ? _d : null;
|
|
9880
|
+
this.testMode = (_e = options.testMode) != null ? _e : false;
|
|
9268
9881
|
}
|
|
9269
9882
|
/**
|
|
9270
9883
|
* Subscribe to events matching an optional filter.
|
|
@@ -9287,35 +9900,112 @@ var EventBus = class {
|
|
|
9287
9900
|
};
|
|
9288
9901
|
}
|
|
9289
9902
|
/**
|
|
9290
|
-
* Publish an event to all matching subscribers.
|
|
9903
|
+
* Publish an event to all matching subscribers.
|
|
9904
|
+
*/
|
|
9905
|
+
publish(name, props, source = "canvas") {
|
|
9906
|
+
const event = {
|
|
9907
|
+
ts: Date.now(),
|
|
9908
|
+
name,
|
|
9909
|
+
source,
|
|
9910
|
+
props,
|
|
9911
|
+
schemaVersion: EVENT_SCHEMA_VERSION
|
|
9912
|
+
};
|
|
9913
|
+
this.publishEvent(event);
|
|
9914
|
+
}
|
|
9915
|
+
/**
|
|
9916
|
+
* Publish a pre-constructed NormalizedEvent.
|
|
9917
|
+
*/
|
|
9918
|
+
publishEvent(event) {
|
|
9919
|
+
this.history.push(event);
|
|
9920
|
+
if (this.history.length > this.maxHistorySize) {
|
|
9921
|
+
this.history.shift();
|
|
9922
|
+
}
|
|
9923
|
+
for (const subscription of this.subscriptions) {
|
|
9924
|
+
if (matchesFilter(event, subscription.filter)) {
|
|
9925
|
+
try {
|
|
9926
|
+
subscription.callback(event);
|
|
9927
|
+
} catch (err) {
|
|
9928
|
+
console.error("[EventBus] Subscriber error:", err);
|
|
9929
|
+
}
|
|
9930
|
+
}
|
|
9931
|
+
}
|
|
9932
|
+
}
|
|
9933
|
+
/**
|
|
9934
|
+
* Emit a validated custom event from the host application.
|
|
9935
|
+
*
|
|
9936
|
+
* Custom events must use the `app:` prefix (e.g. `app:cart:abandoned`).
|
|
9937
|
+
* In debug mode, returns an EmitResult with delivery details.
|
|
9938
|
+
* In production mode, returns undefined.
|
|
9291
9939
|
*/
|
|
9292
|
-
|
|
9940
|
+
emit(name, props) {
|
|
9941
|
+
const nameResult = validateEventName(name);
|
|
9942
|
+
if (!nameResult.valid) {
|
|
9943
|
+
console.warn(`[EventBus] emit() rejected: ${nameResult.reason}`);
|
|
9944
|
+
return this.debug ? { delivered: false, matchedRules: [], posthogCaptured: false, listenersNotified: 0 } : void 0;
|
|
9945
|
+
}
|
|
9946
|
+
const propsResult = validateProps(props);
|
|
9947
|
+
if (!propsResult.valid) {
|
|
9948
|
+
console.warn(`[EventBus] emit() rejected props: ${propsResult.reason}`);
|
|
9949
|
+
return this.debug ? { delivered: false, matchedRules: [], posthogCaptured: false, listenersNotified: 0 } : void 0;
|
|
9950
|
+
}
|
|
9293
9951
|
const event = {
|
|
9294
9952
|
ts: Date.now(),
|
|
9295
9953
|
name,
|
|
9296
|
-
source,
|
|
9954
|
+
source: "custom",
|
|
9297
9955
|
props,
|
|
9298
9956
|
schemaVersion: EVENT_SCHEMA_VERSION
|
|
9299
9957
|
};
|
|
9300
|
-
this.publishEvent(event);
|
|
9301
|
-
}
|
|
9302
|
-
/**
|
|
9303
|
-
* Publish a pre-constructed NormalizedEvent.
|
|
9304
|
-
*/
|
|
9305
|
-
publishEvent(event) {
|
|
9306
9958
|
this.history.push(event);
|
|
9307
9959
|
if (this.history.length > this.maxHistorySize) {
|
|
9308
9960
|
this.history.shift();
|
|
9309
9961
|
}
|
|
9962
|
+
let listenersNotified = 0;
|
|
9310
9963
|
for (const subscription of this.subscriptions) {
|
|
9311
9964
|
if (matchesFilter(event, subscription.filter)) {
|
|
9312
9965
|
try {
|
|
9313
9966
|
subscription.callback(event);
|
|
9967
|
+
listenersNotified++;
|
|
9314
9968
|
} catch (err) {
|
|
9315
9969
|
console.error("[EventBus] Subscriber error:", err);
|
|
9970
|
+
listenersNotified++;
|
|
9316
9971
|
}
|
|
9317
9972
|
}
|
|
9318
9973
|
}
|
|
9974
|
+
let posthogCaptured = false;
|
|
9975
|
+
if (this.posthogCapture && !this.testMode) {
|
|
9976
|
+
try {
|
|
9977
|
+
this.posthogCapture(name, props);
|
|
9978
|
+
posthogCaptured = true;
|
|
9979
|
+
} catch (err) {
|
|
9980
|
+
console.error("[EventBus] PostHog capture error:", err);
|
|
9981
|
+
}
|
|
9982
|
+
}
|
|
9983
|
+
if (this.emitHistory) {
|
|
9984
|
+
this.emitHistory.record({
|
|
9985
|
+
name,
|
|
9986
|
+
props,
|
|
9987
|
+
source: "custom",
|
|
9988
|
+
timestamp: event.ts,
|
|
9989
|
+
matchedRules: []
|
|
9990
|
+
});
|
|
9991
|
+
}
|
|
9992
|
+
if (this.debug) {
|
|
9993
|
+
console.debug("[EventBus] emit()", { name, props, listenersNotified, posthogCaptured });
|
|
9994
|
+
return {
|
|
9995
|
+
delivered: true,
|
|
9996
|
+
matchedRules: [],
|
|
9997
|
+
posthogCaptured,
|
|
9998
|
+
listenersNotified
|
|
9999
|
+
};
|
|
10000
|
+
}
|
|
10001
|
+
return void 0;
|
|
10002
|
+
}
|
|
10003
|
+
/**
|
|
10004
|
+
* Set the PostHog capture function after construction.
|
|
10005
|
+
* Used by bootstrap to wire PostHog after the EventBus is created.
|
|
10006
|
+
*/
|
|
10007
|
+
setPosthogCapture(fn) {
|
|
10008
|
+
this.posthogCapture = fn;
|
|
9319
10009
|
}
|
|
9320
10010
|
/**
|
|
9321
10011
|
* Get recent events matching an optional filter.
|
|
@@ -9367,6 +10057,27 @@ function createEventBus(options = {}) {
|
|
|
9367
10057
|
return new EventBus(options);
|
|
9368
10058
|
}
|
|
9369
10059
|
|
|
10060
|
+
// src/events/history.ts
|
|
10061
|
+
var EventHistory = class {
|
|
10062
|
+
constructor(maxSize = 100) {
|
|
10063
|
+
__publicField(this, "entries", []);
|
|
10064
|
+
__publicField(this, "maxSize");
|
|
10065
|
+
this.maxSize = maxSize;
|
|
10066
|
+
}
|
|
10067
|
+
record(entry) {
|
|
10068
|
+
this.entries.push(entry);
|
|
10069
|
+
if (this.maxSize > 0 && this.entries.length > this.maxSize) {
|
|
10070
|
+
this.entries.shift();
|
|
10071
|
+
}
|
|
10072
|
+
}
|
|
10073
|
+
getAll() {
|
|
10074
|
+
return [...this.entries];
|
|
10075
|
+
}
|
|
10076
|
+
clear() {
|
|
10077
|
+
this.entries = [];
|
|
10078
|
+
}
|
|
10079
|
+
};
|
|
10080
|
+
|
|
9370
10081
|
// src/navigation/NavigationMonitor.ts
|
|
9371
10082
|
var NavigationMonitor = class {
|
|
9372
10083
|
constructor() {
|
|
@@ -10478,7 +11189,16 @@ function matchesAnchorRoute(anchorId) {
|
|
|
10478
11189
|
const pathname = typeof window !== "undefined" ? window.location.pathname : "/";
|
|
10479
11190
|
const normalizedPath = pathname.replace(/\/$/, "") || "/";
|
|
10480
11191
|
const routes = Array.isArray(anchorId.route) ? anchorId.route : [anchorId.route];
|
|
10481
|
-
return routes.some((pattern) =>
|
|
11192
|
+
return routes.some((pattern) => {
|
|
11193
|
+
let normalized = pattern;
|
|
11194
|
+
if (/^https?:\/\//.test(normalized)) {
|
|
11195
|
+
try {
|
|
11196
|
+
normalized = new URL(normalized).pathname;
|
|
11197
|
+
} catch {
|
|
11198
|
+
}
|
|
11199
|
+
}
|
|
11200
|
+
return matchRoutePattern(normalizedPath, normalized);
|
|
11201
|
+
});
|
|
10482
11202
|
}
|
|
10483
11203
|
function createSmartCanvasRuntime(options = {}) {
|
|
10484
11204
|
var _a2, _b, _c, _d;
|
|
@@ -10650,8 +11370,141 @@ function encodeToken(payload) {
|
|
|
10650
11370
|
return TOKEN_PREFIX + base64;
|
|
10651
11371
|
}
|
|
10652
11372
|
|
|
10653
|
-
// src/bootstrap.ts
|
|
10654
|
-
|
|
11373
|
+
// src/bootstrap-init.ts
|
|
11374
|
+
function getEnvVar(name) {
|
|
11375
|
+
if (typeof process !== "undefined" && process.env) {
|
|
11376
|
+
return process.env[name];
|
|
11377
|
+
}
|
|
11378
|
+
try {
|
|
11379
|
+
const meta = (0, eval)("import.meta");
|
|
11380
|
+
if (meta == null ? void 0 : meta.env) {
|
|
11381
|
+
return meta.env[name];
|
|
11382
|
+
}
|
|
11383
|
+
} catch {
|
|
11384
|
+
}
|
|
11385
|
+
return void 0;
|
|
11386
|
+
}
|
|
11387
|
+
var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
|
|
11388
|
+
function loadCachedSegmentAttributes() {
|
|
11389
|
+
if (typeof window === "undefined") return {};
|
|
11390
|
+
try {
|
|
11391
|
+
const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
|
|
11392
|
+
if (cached) {
|
|
11393
|
+
const attrs = JSON.parse(cached);
|
|
11394
|
+
debug("Syntro Bootstrap", "Loaded cached segment attributes:", attrs);
|
|
11395
|
+
return attrs;
|
|
11396
|
+
}
|
|
11397
|
+
} catch (err) {
|
|
11398
|
+
warn("Syntro Bootstrap", "Failed to load cached segment attributes:", err);
|
|
11399
|
+
}
|
|
11400
|
+
return {};
|
|
11401
|
+
}
|
|
11402
|
+
function cacheSegmentAttributes(attrs) {
|
|
11403
|
+
if (typeof window === "undefined") return;
|
|
11404
|
+
try {
|
|
11405
|
+
localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
|
|
11406
|
+
debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
|
|
11407
|
+
} catch (err) {
|
|
11408
|
+
warn("Syntro Bootstrap", "Failed to cache segment attributes:", err);
|
|
11409
|
+
}
|
|
11410
|
+
}
|
|
11411
|
+
function extractSegmentFlags(allFlags) {
|
|
11412
|
+
if (!allFlags) return {};
|
|
11413
|
+
const segmentFlags = {};
|
|
11414
|
+
for (const [key, value] of Object.entries(allFlags)) {
|
|
11415
|
+
if (key.startsWith("in_segment_")) {
|
|
11416
|
+
segmentFlags[key] = value === true;
|
|
11417
|
+
}
|
|
11418
|
+
}
|
|
11419
|
+
return segmentFlags;
|
|
11420
|
+
}
|
|
11421
|
+
function collectBrowserMetadata() {
|
|
11422
|
+
var _a2;
|
|
11423
|
+
if (typeof window === "undefined") return {};
|
|
11424
|
+
const attrs = {};
|
|
11425
|
+
try {
|
|
11426
|
+
const params = new URLSearchParams(window.location.search);
|
|
11427
|
+
for (const key of ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]) {
|
|
11428
|
+
const val = params.get(key);
|
|
11429
|
+
if (val) attrs[key] = val;
|
|
11430
|
+
}
|
|
11431
|
+
} catch {
|
|
11432
|
+
}
|
|
11433
|
+
try {
|
|
11434
|
+
if (navigator.language) attrs.browser_language = navigator.language;
|
|
11435
|
+
if ((_a2 = navigator.languages) == null ? void 0 : _a2.length) attrs.browser_languages = [...navigator.languages];
|
|
11436
|
+
} catch {
|
|
11437
|
+
}
|
|
11438
|
+
try {
|
|
11439
|
+
const w = window.innerWidth;
|
|
11440
|
+
attrs.device_type = w < 768 ? "mobile" : w < 1024 ? "tablet" : "desktop";
|
|
11441
|
+
} catch {
|
|
11442
|
+
}
|
|
11443
|
+
try {
|
|
11444
|
+
if (document.referrer) {
|
|
11445
|
+
attrs.referrer = document.referrer;
|
|
11446
|
+
try {
|
|
11447
|
+
attrs.referrer_hostname = new URL(document.referrer).hostname;
|
|
11448
|
+
} catch {
|
|
11449
|
+
}
|
|
11450
|
+
}
|
|
11451
|
+
} catch {
|
|
11452
|
+
}
|
|
11453
|
+
try {
|
|
11454
|
+
const ua = navigator.userAgent;
|
|
11455
|
+
if (ua.includes("Edg/")) attrs.browser = "Edge";
|
|
11456
|
+
else if (ua.includes("OPR/") || ua.includes("Opera")) attrs.browser = "Opera";
|
|
11457
|
+
else if (ua.includes("Chrome/") && !ua.includes("Chromium")) attrs.browser = "Chrome";
|
|
11458
|
+
else if (ua.includes("Safari/") && !ua.includes("Chrome")) attrs.browser = "Safari";
|
|
11459
|
+
else if (ua.includes("Firefox/")) attrs.browser = "Firefox";
|
|
11460
|
+
if (ua.includes("Windows")) attrs.os = "Windows";
|
|
11461
|
+
else if (ua.includes("iPhone") || ua.includes("iPad")) attrs.os = "iOS";
|
|
11462
|
+
else if (ua.includes("Mac OS X") || ua.includes("Macintosh")) attrs.os = "macOS";
|
|
11463
|
+
else if (ua.includes("Android")) attrs.os = "Android";
|
|
11464
|
+
else if (ua.includes("Linux")) attrs.os = "Linux";
|
|
11465
|
+
} catch {
|
|
11466
|
+
}
|
|
11467
|
+
try {
|
|
11468
|
+
attrs.page_url = window.location.href;
|
|
11469
|
+
attrs.page_path = window.location.pathname;
|
|
11470
|
+
attrs.page_host = window.location.hostname;
|
|
11471
|
+
if (window.location.search) attrs.page_query = window.location.search;
|
|
11472
|
+
} catch {
|
|
11473
|
+
}
|
|
11474
|
+
return attrs;
|
|
11475
|
+
}
|
|
11476
|
+
var GEO_CACHE_KEY = "syntro_geo";
|
|
11477
|
+
var GEO_DEFAULT_HOST = "https://geo.syntrologie.com";
|
|
11478
|
+
async function fetchGeo(geoHost) {
|
|
11479
|
+
if (typeof window === "undefined") return {};
|
|
11480
|
+
try {
|
|
11481
|
+
const cached = localStorage.getItem(GEO_CACHE_KEY);
|
|
11482
|
+
if (cached) {
|
|
11483
|
+
const parsed = JSON.parse(cached);
|
|
11484
|
+
debug("Syntro Bootstrap", "Geo: using cached data:", parsed);
|
|
11485
|
+
return parsed;
|
|
11486
|
+
}
|
|
11487
|
+
} catch {
|
|
11488
|
+
}
|
|
11489
|
+
try {
|
|
11490
|
+
const res = await fetch(geoHost, { signal: AbortSignal.timeout(2e3) });
|
|
11491
|
+
if (res.ok) {
|
|
11492
|
+
const geo = await res.json();
|
|
11493
|
+
const cleaned = {};
|
|
11494
|
+
for (const [k, v] of Object.entries(geo)) {
|
|
11495
|
+
if (typeof v === "string" && v) cleaned[k] = v;
|
|
11496
|
+
}
|
|
11497
|
+
try {
|
|
11498
|
+
localStorage.setItem(GEO_CACHE_KEY, JSON.stringify(cleaned));
|
|
11499
|
+
} catch {
|
|
11500
|
+
}
|
|
11501
|
+
debug("Syntro Bootstrap", "Geo: fetched from worker:", cleaned);
|
|
11502
|
+
return cleaned;
|
|
11503
|
+
}
|
|
11504
|
+
} catch {
|
|
11505
|
+
}
|
|
11506
|
+
return {};
|
|
11507
|
+
}
|
|
10655
11508
|
|
|
10656
11509
|
// src/experiments/registry.ts
|
|
10657
11510
|
var adapters = {
|
|
@@ -10790,6 +11643,11 @@ var ExperimentsFetcher = class {
|
|
|
10790
11643
|
};
|
|
10791
11644
|
}
|
|
10792
11645
|
}
|
|
11646
|
+
if (!this.featureKey) {
|
|
11647
|
+
throw new Error(
|
|
11648
|
+
"[SmartCanvas] No featureKey configured and no variant flags found. Ensure at least one config feature flag exists in your experiment platform."
|
|
11649
|
+
);
|
|
11650
|
+
}
|
|
10793
11651
|
const config = (_b = (_a2 = this.client).getFeatureValue) == null ? void 0 : _b.call(_a2, this.featureKey, null);
|
|
10794
11652
|
if (!config || typeof config !== "object") {
|
|
10795
11653
|
throw new Error(
|
|
@@ -10901,95 +11759,9 @@ function createTelemetryClient(provider, config) {
|
|
|
10901
11759
|
return factory(config);
|
|
10902
11760
|
}
|
|
10903
11761
|
|
|
10904
|
-
// src/bootstrap.ts
|
|
10905
|
-
function
|
|
10906
|
-
|
|
10907
|
-
return process.env[name];
|
|
10908
|
-
}
|
|
10909
|
-
try {
|
|
10910
|
-
const meta = (0, eval)("import.meta");
|
|
10911
|
-
if (meta == null ? void 0 : meta.env) {
|
|
10912
|
-
return meta.env[name];
|
|
10913
|
-
}
|
|
10914
|
-
} catch {
|
|
10915
|
-
}
|
|
10916
|
-
return void 0;
|
|
10917
|
-
}
|
|
10918
|
-
var SEGMENT_CACHE_KEY = "syntro_segment_attributes";
|
|
10919
|
-
function loadCachedSegmentAttributes() {
|
|
10920
|
-
if (typeof window === "undefined") return {};
|
|
10921
|
-
try {
|
|
10922
|
-
const cached = localStorage.getItem(SEGMENT_CACHE_KEY);
|
|
10923
|
-
if (cached) {
|
|
10924
|
-
const attrs = JSON.parse(cached);
|
|
10925
|
-
debug("Syntro Bootstrap", "Loaded cached segment attributes:", attrs);
|
|
10926
|
-
return attrs;
|
|
10927
|
-
}
|
|
10928
|
-
} catch (err) {
|
|
10929
|
-
warn("Syntro Bootstrap", "Failed to load cached segment attributes:", err);
|
|
10930
|
-
}
|
|
10931
|
-
return {};
|
|
10932
|
-
}
|
|
10933
|
-
function cacheSegmentAttributes(attrs) {
|
|
10934
|
-
if (typeof window === "undefined") return;
|
|
10935
|
-
try {
|
|
10936
|
-
localStorage.setItem(SEGMENT_CACHE_KEY, JSON.stringify(attrs));
|
|
10937
|
-
debug("Syntro Bootstrap", "Cached segment attributes:", attrs);
|
|
10938
|
-
} catch (err) {
|
|
10939
|
-
warn("Syntro Bootstrap", "Failed to cache segment attributes:", err);
|
|
10940
|
-
}
|
|
10941
|
-
}
|
|
10942
|
-
function extractSegmentFlags(allFlags) {
|
|
10943
|
-
if (!allFlags) return {};
|
|
10944
|
-
const segmentFlags = {};
|
|
10945
|
-
for (const [key, value] of Object.entries(allFlags)) {
|
|
10946
|
-
if (key.startsWith("in_segment_")) {
|
|
10947
|
-
segmentFlags[key] = value === true;
|
|
10948
|
-
}
|
|
10949
|
-
}
|
|
10950
|
-
return segmentFlags;
|
|
10951
|
-
}
|
|
10952
|
-
function collectBrowserMetadata() {
|
|
10953
|
-
var _a2;
|
|
10954
|
-
if (typeof window === "undefined") return {};
|
|
10955
|
-
const attrs = {};
|
|
10956
|
-
try {
|
|
10957
|
-
const params = new URLSearchParams(window.location.search);
|
|
10958
|
-
for (const key of ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]) {
|
|
10959
|
-
const val = params.get(key);
|
|
10960
|
-
if (val) attrs[key] = val;
|
|
10961
|
-
}
|
|
10962
|
-
} catch {
|
|
10963
|
-
}
|
|
10964
|
-
try {
|
|
10965
|
-
if (navigator.language) attrs.browser_language = navigator.language;
|
|
10966
|
-
if ((_a2 = navigator.languages) == null ? void 0 : _a2.length) attrs.browser_languages = [...navigator.languages];
|
|
10967
|
-
} catch {
|
|
10968
|
-
}
|
|
10969
|
-
try {
|
|
10970
|
-
const w = window.innerWidth;
|
|
10971
|
-
attrs.device_type = w < 768 ? "mobile" : w < 1024 ? "tablet" : "desktop";
|
|
10972
|
-
} catch {
|
|
10973
|
-
}
|
|
10974
|
-
try {
|
|
10975
|
-
if (document.referrer) {
|
|
10976
|
-
attrs.referrer = document.referrer;
|
|
10977
|
-
try {
|
|
10978
|
-
attrs.referrer_hostname = new URL(document.referrer).hostname;
|
|
10979
|
-
} catch {
|
|
10980
|
-
}
|
|
10981
|
-
}
|
|
10982
|
-
} catch {
|
|
10983
|
-
}
|
|
10984
|
-
try {
|
|
10985
|
-
attrs.page_url = window.location.href;
|
|
10986
|
-
attrs.page_path = window.location.pathname;
|
|
10987
|
-
} catch {
|
|
10988
|
-
}
|
|
10989
|
-
return attrs;
|
|
10990
|
-
}
|
|
10991
|
-
async function init(options) {
|
|
10992
|
-
var _a2, _b, _c, _d, _e, _f;
|
|
11762
|
+
// src/bootstrap-runtime.ts
|
|
11763
|
+
async function _initCore(options) {
|
|
11764
|
+
var _a2, _b, _c, _d, _e, _f, _g;
|
|
10993
11765
|
initLogger();
|
|
10994
11766
|
debug("Syntro Bootstrap", "====== INIT ======");
|
|
10995
11767
|
debug("Syntro Bootstrap", "Options:", {
|
|
@@ -11054,13 +11826,20 @@ async function init(options) {
|
|
|
11054
11826
|
const experimentHost = getEnvVar("NEXT_PUBLIC_SYNTRO_EXPERIMENT_HOST") || getEnvVar("VITE_SYNTRO_EXPERIMENT_HOST") || (payload == null ? void 0 : payload.eh);
|
|
11055
11827
|
const telemetryHost = getEnvVar("NEXT_PUBLIC_SYNTRO_TELEMETRY_HOST") || getEnvVar("VITE_SYNTRO_TELEMETRY_HOST") || (payload == null ? void 0 : payload.th);
|
|
11056
11828
|
const editorUrl = getEnvVar("NEXT_PUBLIC_SYNTRO_EDITOR_URL") || getEnvVar("VITE_SYNTRO_EDITOR_URL") || ((_b = options.canvas) == null ? void 0 : _b.editorUrl);
|
|
11829
|
+
const geoHost = (payload == null ? void 0 : payload.g) || getEnvVar("NEXT_PUBLIC_SYNTRO_GEO_HOST") || getEnvVar("VITE_SYNTRO_GEO_HOST") || GEO_DEFAULT_HOST;
|
|
11057
11830
|
const cachedSegmentAttrs = loadCachedSegmentAttributes();
|
|
11058
11831
|
const browserMetadata = collectBrowserMetadata();
|
|
11059
11832
|
const phaseOneAttrs = { ...browserMetadata, ...cachedSegmentAttrs };
|
|
11060
11833
|
debug("Syntro Bootstrap", "Phase 1: Browser metadata:", browserMetadata);
|
|
11061
11834
|
debug("Syntro Bootstrap", "Phase 1: Cached segment attributes:", cachedSegmentAttrs);
|
|
11835
|
+
const geoPromise = fetchGeo(geoHost);
|
|
11062
11836
|
let experiments;
|
|
11063
|
-
const
|
|
11837
|
+
const isDebugOrTest = options.debug || options.testMode;
|
|
11838
|
+
const events = createEventBus({
|
|
11839
|
+
debug: options.debug,
|
|
11840
|
+
history: isDebugOrTest ? new EventHistory(options.testMode ? 0 : 100) : void 0,
|
|
11841
|
+
testMode: options.testMode
|
|
11842
|
+
});
|
|
11064
11843
|
console.log("[Syntro Bootstrap] EventBus created");
|
|
11065
11844
|
const processor = createEventProcessor({
|
|
11066
11845
|
elementResolver: typeof window !== "undefined" ? (x, y) => {
|
|
@@ -11122,6 +11901,9 @@ async function init(options) {
|
|
|
11122
11901
|
// undefined falls back to adapter default
|
|
11123
11902
|
// Enable PostHog feature flags for segment membership
|
|
11124
11903
|
enableFeatureFlags: true,
|
|
11904
|
+
// Disable session recording in debug/dev mode (mock telemetry doesn't
|
|
11905
|
+
// support the PostHog recorder extension, causing console errors)
|
|
11906
|
+
sessionRecording: !payload.d,
|
|
11125
11907
|
// Wire up callback for when flags are loaded (Phase 2)
|
|
11126
11908
|
onFeatureFlagsLoaded,
|
|
11127
11909
|
// Wire up event capture to feed into event processor
|
|
@@ -11134,6 +11916,11 @@ async function init(options) {
|
|
|
11134
11916
|
}
|
|
11135
11917
|
});
|
|
11136
11918
|
console.log(`[Syntro Bootstrap] Telemetry client created (${provider}) with EventBus wiring`);
|
|
11919
|
+
const telemetryForCapture = telemetry;
|
|
11920
|
+
events.setPosthogCapture((name, props) => {
|
|
11921
|
+
var _a3;
|
|
11922
|
+
(_a3 = telemetryForCapture.track) == null ? void 0 : _a3.call(telemetryForCapture, name, props);
|
|
11923
|
+
});
|
|
11137
11924
|
}
|
|
11138
11925
|
let sessionMetrics;
|
|
11139
11926
|
if (payload == null ? void 0 : payload.e) {
|
|
@@ -11226,11 +12013,17 @@ async function init(options) {
|
|
|
11226
12013
|
warn("Syntro Bootstrap", "Failed to load GrowthBook features:", err);
|
|
11227
12014
|
}
|
|
11228
12015
|
}
|
|
12016
|
+
const geoData = await geoPromise;
|
|
12017
|
+
if (experiments && Object.keys(geoData).length > 0) {
|
|
12018
|
+
const mergedAttrs = { ...browserMetadata, ...geoData };
|
|
12019
|
+
debug("Syntro Bootstrap", "Merging geo data into GrowthBook attributes:", geoData);
|
|
12020
|
+
(_f = experiments.setAttributes) == null ? void 0 : _f.call(experiments, mergedAttrs);
|
|
12021
|
+
}
|
|
11229
12022
|
let baseFetcher;
|
|
11230
12023
|
if (options.fetcher) {
|
|
11231
12024
|
baseFetcher = options.fetcher;
|
|
11232
12025
|
} else if (payload == null ? void 0 : payload.f) {
|
|
11233
|
-
const configFetcher = createConfigFetcher(payload.f, (
|
|
12026
|
+
const configFetcher = createConfigFetcher(payload.f, (_g = payload.o) != null ? _g : {});
|
|
11234
12027
|
baseFetcher = async () => {
|
|
11235
12028
|
var _a3;
|
|
11236
12029
|
const result = await configFetcher.fetch();
|
|
@@ -11244,7 +12037,7 @@ async function init(options) {
|
|
|
11244
12037
|
}
|
|
11245
12038
|
const warnedAppFailures = /* @__PURE__ */ new Set();
|
|
11246
12039
|
const appLoadingFetcher = baseFetcher ? async () => {
|
|
11247
|
-
var _a3, _b2, _c2, _d2, _e2, _f2,
|
|
12040
|
+
var _a3, _b2, _c2, _d2, _e2, _f2, _g2;
|
|
11248
12041
|
const config = await baseFetcher();
|
|
11249
12042
|
console.log(
|
|
11250
12043
|
"[Syntro Bootstrap] Config fetched:",
|
|
@@ -11252,7 +12045,7 @@ async function init(options) {
|
|
|
11252
12045
|
`actions=${(_d2 = (_c2 = config.actions) == null ? void 0 : _c2.length) != null ? _d2 : 0},`,
|
|
11253
12046
|
`theme=${(_f2 = (_e2 = config.theme) == null ? void 0 : _e2.name) != null ? _f2 : "none"}`
|
|
11254
12047
|
);
|
|
11255
|
-
if (((
|
|
12048
|
+
if (((_g2 = config.actions) == null ? void 0 : _g2.length) > 0) {
|
|
11256
12049
|
console.log(
|
|
11257
12050
|
"[Syntro Bootstrap] Actions in config:",
|
|
11258
12051
|
config.actions.map(
|
|
@@ -11315,10 +12108,33 @@ async function init(options) {
|
|
|
11315
12108
|
});
|
|
11316
12109
|
return { canvas, runtime: runtime3, experiments, telemetry, sessionMetrics, appLoader };
|
|
11317
12110
|
}
|
|
12111
|
+
|
|
12112
|
+
// src/bootstrap.ts
|
|
12113
|
+
async function init(options) {
|
|
12114
|
+
var _a2;
|
|
12115
|
+
try {
|
|
12116
|
+
return await _initCore(options);
|
|
12117
|
+
} catch (err) {
|
|
12118
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12119
|
+
console.warn("[Syntrologie] SDK initialization failed:", message);
|
|
12120
|
+
if (typeof document !== "undefined") {
|
|
12121
|
+
(_a2 = document.getElementById("syntrologie-anti-flicker")) == null ? void 0 : _a2.remove();
|
|
12122
|
+
}
|
|
12123
|
+
return void 0;
|
|
12124
|
+
}
|
|
12125
|
+
}
|
|
12126
|
+
function emit(eventName, props = {}) {
|
|
12127
|
+
var _a2, _b;
|
|
12128
|
+
if (typeof window === "undefined") return;
|
|
12129
|
+
const runtime3 = (_a2 = window.SynOS) == null ? void 0 : _a2.runtime;
|
|
12130
|
+
if (!((_b = runtime3 == null ? void 0 : runtime3.events) == null ? void 0 : _b.publish)) return;
|
|
12131
|
+
runtime3.events.publish({ name: eventName, source: "custom", props });
|
|
12132
|
+
}
|
|
11318
12133
|
var Syntro = {
|
|
11319
12134
|
init,
|
|
11320
12135
|
encodeToken,
|
|
11321
|
-
decodeToken
|
|
12136
|
+
decodeToken,
|
|
12137
|
+
events: { emit }
|
|
11322
12138
|
};
|
|
11323
12139
|
if (typeof window !== "undefined") {
|
|
11324
12140
|
window.Syntro = Syntro;
|
|
@@ -11349,8 +12165,11 @@ export {
|
|
|
11349
12165
|
createSmartCanvasController,
|
|
11350
12166
|
ShadowRootProvider,
|
|
11351
12167
|
useShadowRoot,
|
|
11352
|
-
StandardEvents,
|
|
11353
12168
|
EVENT_SCHEMA_VERSION,
|
|
12169
|
+
normalizePostHogEvent,
|
|
12170
|
+
shouldNormalizeEvent,
|
|
12171
|
+
createPostHogNormalizer,
|
|
12172
|
+
StandardEvents2 as StandardEvents,
|
|
11354
12173
|
CanvasEvents,
|
|
11355
12174
|
NotificationToastStack,
|
|
11356
12175
|
MAX_VISIBLE_TOASTS,
|
|
@@ -11399,8 +12218,11 @@ export {
|
|
|
11399
12218
|
evaluateSync,
|
|
11400
12219
|
createDecisionEngine,
|
|
11401
12220
|
createEventAccumulator,
|
|
12221
|
+
validateEventName,
|
|
12222
|
+
validateProps,
|
|
11402
12223
|
EventBus,
|
|
11403
12224
|
createEventBus,
|
|
12225
|
+
EventHistory,
|
|
11404
12226
|
NavigationMonitor,
|
|
11405
12227
|
StateStore,
|
|
11406
12228
|
createStateStore,
|
|
@@ -11424,4 +12246,4 @@ export {
|
|
|
11424
12246
|
encodeToken,
|
|
11425
12247
|
Syntro
|
|
11426
12248
|
};
|
|
11427
|
-
//# sourceMappingURL=chunk-
|
|
12249
|
+
//# sourceMappingURL=chunk-J2LGX2PV.js.map
|