@interfere/react 0.1.0-alpha.5 → 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/error-boundary.d.mts +27 -0
- package/dist/error-boundary.d.mts.map +1 -0
- package/dist/error-boundary.mjs +42 -0
- package/dist/error-boundary.mjs.map +1 -0
- package/dist/internal/client.d.mts +13 -0
- package/dist/internal/client.d.mts.map +1 -0
- package/dist/internal/client.mjs +80 -0
- package/dist/internal/client.mjs.map +1 -0
- package/dist/internal/config.d.mts +9 -0
- package/dist/internal/config.d.mts.map +1 -0
- package/dist/internal/config.mjs +27 -0
- package/dist/internal/config.mjs.map +1 -0
- package/dist/internal/context.d.mts +6 -0
- package/dist/internal/context.d.mts.map +1 -0
- package/dist/internal/context.mjs +32 -0
- package/dist/internal/context.mjs.map +1 -0
- package/dist/internal/envelope.d.mts +14 -0
- package/dist/internal/envelope.d.mts.map +1 -0
- package/dist/internal/envelope.mjs +20 -0
- package/dist/internal/envelope.mjs.map +1 -0
- package/dist/internal/errors.d.mts +4 -0
- package/dist/internal/errors.d.mts.map +1 -0
- package/dist/internal/errors.mjs +4 -0
- package/dist/internal/errors.mjs.map +1 -0
- package/dist/internal/sw.d.mts +4 -0
- package/dist/internal/sw.d.mts.map +1 -0
- package/dist/internal/sw.mjs +10 -0
- package/dist/internal/sw.mjs.map +1 -0
- package/dist/plugins/errors.d.mts +6 -0
- package/dist/plugins/errors.d.mts.map +1 -0
- package/dist/plugins/errors.mjs +59 -0
- package/dist/plugins/errors.mjs.map +1 -0
- package/dist/plugins/lib/loader.d.mts +9 -0
- package/dist/plugins/lib/loader.d.mts.map +1 -0
- package/dist/plugins/lib/loader.mjs +47 -0
- package/dist/plugins/lib/loader.mjs.map +1 -0
- package/dist/plugins/lib/types.d.mts +14 -0
- package/dist/plugins/lib/types.d.mts.map +1 -0
- package/dist/plugins/lib/types.mjs +1 -0
- package/dist/plugins/pages.d.mts +6 -0
- package/dist/plugins/pages.d.mts.map +1 -0
- package/dist/plugins/pages.mjs +102 -0
- package/dist/plugins/pages.mjs.map +1 -0
- package/dist/plugins/rage-clicks.d.mts +6 -0
- package/dist/plugins/rage-clicks.d.mts.map +1 -0
- package/dist/plugins/rage-clicks.mjs +53 -0
- package/dist/plugins/rage-clicks.mjs.map +1 -0
- package/dist/plugins/replay.d.mts +6 -0
- package/dist/plugins/replay.d.mts.map +1 -0
- package/dist/plugins/replay.mjs +62 -0
- package/dist/plugins/replay.mjs.map +1 -0
- package/dist/provider.d.mts +17 -11
- package/dist/provider.d.mts.map +1 -1
- package/dist/provider.mjs +18 -17
- package/dist/provider.mjs.map +1 -1
- package/dist/tracking/api.d.mts +22 -0
- package/dist/tracking/api.d.mts.map +1 -0
- package/dist/tracking/api.mjs +88 -0
- package/dist/tracking/api.mjs.map +1 -0
- package/dist/tracking/session.d.mts +19 -0
- package/dist/tracking/session.d.mts.map +1 -0
- package/dist/tracking/session.mjs +92 -0
- package/dist/tracking/session.mjs.map +1 -0
- package/dist/tracking/visitor.d.mts +6 -0
- package/dist/tracking/visitor.d.mts.map +1 -0
- package/dist/tracking/visitor.mjs +35 -0
- package/dist/tracking/visitor.mjs.map +1 -0
- package/dist/transport/http.d.mts +15 -0
- package/dist/transport/http.d.mts.map +1 -0
- package/dist/transport/http.mjs +56 -0
- package/dist/transport/http.mjs.map +1 -0
- package/dist/transport/queue.d.mts +25 -0
- package/dist/transport/queue.d.mts.map +1 -0
- package/dist/transport/queue.mjs +60 -0
- package/dist/transport/queue.mjs.map +1 -0
- package/dist/util/log.d.mts +13 -0
- package/dist/util/log.d.mts.map +1 -0
- package/dist/util/log.mjs +37 -0
- package/dist/util/log.mjs.map +1 -0
- package/package.json +43 -66
- package/dist/client.d.mts +0 -15
- package/dist/client.d.mts.map +0 -1
- package/dist/client.mjs +0 -75
- package/dist/client.mjs.map +0 -1
- package/dist/core/events/event-registry.d.mts +0 -23
- package/dist/core/events/event-registry.d.mts.map +0 -1
- package/dist/core/events/event-registry.mjs +0 -32
- package/dist/core/events/event-registry.mjs.map +0 -1
- package/dist/core/events/plugin-event-types.d.mts +0 -92
- package/dist/core/events/plugin-event-types.d.mts.map +0 -1
- package/dist/core/events/plugin-event-types.mjs +0 -25
- package/dist/core/events/plugin-event-types.mjs.map +0 -1
- package/dist/core/plugins/dom-utils.d.mts +0 -9
- package/dist/core/plugins/dom-utils.d.mts.map +0 -1
- package/dist/core/plugins/dom-utils.mjs +0 -25
- package/dist/core/plugins/dom-utils.mjs.map +0 -1
- package/dist/core/plugins/impl/ai-summary.d.mts +0 -6
- package/dist/core/plugins/impl/ai-summary.d.mts.map +0 -1
- package/dist/core/plugins/impl/ai-summary.mjs +0 -122
- package/dist/core/plugins/impl/ai-summary.mjs.map +0 -1
- package/dist/core/plugins/impl/errors.d.mts +0 -9
- package/dist/core/plugins/impl/errors.d.mts.map +0 -1
- package/dist/core/plugins/impl/errors.mjs +0 -160
- package/dist/core/plugins/impl/errors.mjs.map +0 -1
- package/dist/core/plugins/impl/page-events.d.mts +0 -15
- package/dist/core/plugins/impl/page-events.d.mts.map +0 -1
- package/dist/core/plugins/impl/page-events.mjs +0 -131
- package/dist/core/plugins/impl/page-events.mjs.map +0 -1
- package/dist/core/plugins/impl/rage-click.d.mts +0 -6
- package/dist/core/plugins/impl/rage-click.d.mts.map +0 -1
- package/dist/core/plugins/impl/rage-click.mjs +0 -53
- package/dist/core/plugins/impl/rage-click.mjs.map +0 -1
- package/dist/core/plugins/impl/replay.d.mts +0 -9
- package/dist/core/plugins/impl/replay.d.mts.map +0 -1
- package/dist/core/plugins/impl/replay.mjs +0 -144
- package/dist/core/plugins/impl/replay.mjs.map +0 -1
- package/dist/core/plugins/impl/server-tracing.d.mts +0 -7
- package/dist/core/plugins/impl/server-tracing.d.mts.map +0 -1
- package/dist/core/plugins/impl/server-tracing.mjs +0 -160
- package/dist/core/plugins/impl/server-tracing.mjs.map +0 -1
- package/dist/core/plugins/plugin-event-system.d.mts +0 -47
- package/dist/core/plugins/plugin-event-system.d.mts.map +0 -1
- package/dist/core/plugins/plugin-event-system.mjs +0 -75
- package/dist/core/plugins/plugin-event-system.mjs.map +0 -1
- package/dist/core/plugins/plugin-loader.d.mts +0 -22
- package/dist/core/plugins/plugin-loader.d.mts.map +0 -1
- package/dist/core/plugins/plugin-loader.mjs +0 -142
- package/dist/core/plugins/plugin-loader.mjs.map +0 -1
- package/dist/core/runtime/config.d.mts +0 -14
- package/dist/core/runtime/config.d.mts.map +0 -1
- package/dist/core/runtime/config.mjs +0 -39
- package/dist/core/runtime/config.mjs.map +0 -1
- package/dist/core/runtime/context.d.mts +0 -25
- package/dist/core/runtime/context.d.mts.map +0 -1
- package/dist/core/runtime/context.mjs +0 -48
- package/dist/core/runtime/context.mjs.map +0 -1
- package/dist/core/runtime/ingest-target.d.mts +0 -10
- package/dist/core/runtime/ingest-target.d.mts.map +0 -1
- package/dist/core/runtime/ingest-target.mjs +0 -15
- package/dist/core/runtime/ingest-target.mjs.map +0 -1
- package/dist/core/runtime/native-fetch.d.mts +0 -32
- package/dist/core/runtime/native-fetch.d.mts.map +0 -1
- package/dist/core/runtime/native-fetch.mjs +0 -49
- package/dist/core/runtime/native-fetch.mjs.map +0 -1
- package/dist/core/schemas.d.mts +0 -85
- package/dist/core/schemas.d.mts.map +0 -1
- package/dist/core/schemas.mjs +0 -1
- package/dist/effect/build-envelope.d.mts +0 -9
- package/dist/effect/build-envelope.d.mts.map +0 -1
- package/dist/effect/build-envelope.mjs +0 -29
- package/dist/effect/build-envelope.mjs.map +0 -1
- package/dist/effect/errors.d.mts +0 -36
- package/dist/effect/errors.d.mts.map +0 -1
- package/dist/effect/errors.mjs +0 -10
- package/dist/effect/errors.mjs.map +0 -1
- package/dist/effect/layers/config.layer.d.mts +0 -13
- package/dist/effect/layers/config.layer.d.mts.map +0 -1
- package/dist/effect/layers/config.layer.mjs +0 -21
- package/dist/effect/layers/config.layer.mjs.map +0 -1
- package/dist/effect/layers/context.layer.d.mts +0 -12
- package/dist/effect/layers/context.layer.d.mts.map +0 -1
- package/dist/effect/layers/context.layer.mjs +0 -14
- package/dist/effect/layers/context.layer.mjs.map +0 -1
- package/dist/effect/layers/http.layer.d.mts +0 -21
- package/dist/effect/layers/http.layer.d.mts.map +0 -1
- package/dist/effect/layers/http.layer.mjs +0 -114
- package/dist/effect/layers/http.layer.mjs.map +0 -1
- package/dist/effect/layers/queue.layer.d.mts +0 -30
- package/dist/effect/layers/queue.layer.d.mts.map +0 -1
- package/dist/effect/layers/queue.layer.mjs +0 -258
- package/dist/effect/layers/queue.layer.mjs.map +0 -1
- package/dist/effect/layers/session.layer.d.mts +0 -26
- package/dist/effect/layers/session.layer.d.mts.map +0 -1
- package/dist/effect/layers/session.layer.mjs +0 -126
- package/dist/effect/layers/session.layer.mjs.map +0 -1
- package/dist/effect/layers/storage.layer.d.mts +0 -50
- package/dist/effect/layers/storage.layer.d.mts.map +0 -1
- package/dist/effect/layers/storage.layer.mjs +0 -180
- package/dist/effect/layers/storage.layer.mjs.map +0 -1
- package/dist/effect/layers/tracer.layer.d.mts +0 -9
- package/dist/effect/layers/tracer.layer.d.mts.map +0 -1
- package/dist/effect/layers/tracer.layer.mjs +0 -11
- package/dist/effect/layers/tracer.layer.mjs.map +0 -1
- package/dist/effect/runtime-services.d.mts +0 -22
- package/dist/effect/runtime-services.d.mts.map +0 -1
- package/dist/effect/runtime-services.mjs +0 -76
- package/dist/effect/runtime-services.mjs.map +0 -1
- package/dist/effect/tags.d.mts +0 -58
- package/dist/effect/tags.d.mts.map +0 -1
- package/dist/effect/tags.mjs +0 -7
- package/dist/effect/tags.mjs.map +0 -1
- package/dist/hooks/use-runtime-and-plugins.d.mts +0 -7
- package/dist/hooks/use-runtime-and-plugins.d.mts.map +0 -1
- package/dist/hooks/use-runtime-and-plugins.mjs +0 -153
- package/dist/hooks/use-runtime-and-plugins.mjs.map +0 -1
- package/dist/hooks/use-session.d.mts +0 -40
- package/dist/hooks/use-session.d.mts.map +0 -1
- package/dist/hooks/use-session.mjs +0 -96
- package/dist/hooks/use-session.mjs.map +0 -1
- package/dist/package.mjs +0 -100
- package/dist/package.mjs.map +0 -1
- package/dist/server/auth.d.mts +0 -11
- package/dist/server/auth.d.mts.map +0 -1
- package/dist/server/auth.mjs +0 -36
- package/dist/server/auth.mjs.map +0 -1
- package/dist/server/capture.d.mts +0 -18
- package/dist/server/capture.d.mts.map +0 -1
- package/dist/server/capture.mjs +0 -105
- package/dist/server/capture.mjs.map +0 -1
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { getElementSelector, getElementText } from "../dom-utils.mjs";
|
|
2
|
-
import { createEffectPlugin, defineEvent } from "../plugin-event-system.mjs";
|
|
3
|
-
import { Effect } from "effect";
|
|
4
|
-
|
|
5
|
-
//#region src/core/plugins/impl/page-events.ts
|
|
6
|
-
/**
|
|
7
|
-
* Page Events Plugin
|
|
8
|
-
*
|
|
9
|
-
* Handles tracking of page navigation and UI interaction events:
|
|
10
|
-
* - pageview: When a user views a page
|
|
11
|
-
* - pageleave: When a user leaves a page
|
|
12
|
-
* - ui_event: General UI interaction events (clicks, form submits, etc.)
|
|
13
|
-
*/
|
|
14
|
-
var page_events_default = createEffectPlugin("pageEvents", {
|
|
15
|
-
name: "page-events",
|
|
16
|
-
events: [
|
|
17
|
-
defineEvent("pageview").value(),
|
|
18
|
-
defineEvent("pageleave").value(),
|
|
19
|
-
defineEvent("ui_event").value()
|
|
20
|
-
],
|
|
21
|
-
setup: (ctx) => Effect.gen(function* () {
|
|
22
|
-
if (typeof window === "undefined") {
|
|
23
|
-
ctx.log.debug("page-events: SSR - skipping setup");
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
let lastKey = null;
|
|
27
|
-
const shouldSkip = (key) => lastKey === key;
|
|
28
|
-
const remember = (key) => {
|
|
29
|
-
lastKey = key;
|
|
30
|
-
};
|
|
31
|
-
const handlePageView = () => {
|
|
32
|
-
const url = window.location.href;
|
|
33
|
-
const title = document.title;
|
|
34
|
-
ctx.log.trace("Page view", {
|
|
35
|
-
url,
|
|
36
|
-
title
|
|
37
|
-
});
|
|
38
|
-
const key = `pageview:${url}`;
|
|
39
|
-
if (shouldSkip(key)) return;
|
|
40
|
-
remember(key);
|
|
41
|
-
ctx.run(ctx.capture("pageview", {
|
|
42
|
-
url,
|
|
43
|
-
title
|
|
44
|
-
}).pipe(Effect.catchAll((error) => Effect.gen(function* () {
|
|
45
|
-
yield* Effect.logError("Failed to capture pageview", {
|
|
46
|
-
error: String(error),
|
|
47
|
-
url,
|
|
48
|
-
title
|
|
49
|
-
});
|
|
50
|
-
}))));
|
|
51
|
-
};
|
|
52
|
-
const handlePageLeave = () => {
|
|
53
|
-
const url = window.location.href;
|
|
54
|
-
const duration = performance.now();
|
|
55
|
-
ctx.log.trace("Page leave", {
|
|
56
|
-
url,
|
|
57
|
-
duration
|
|
58
|
-
});
|
|
59
|
-
const key = `pageleave:${url}`;
|
|
60
|
-
if (shouldSkip(key)) return;
|
|
61
|
-
remember(key);
|
|
62
|
-
ctx.captureNow("pageleave", {
|
|
63
|
-
url,
|
|
64
|
-
durationMs: Math.round(duration)
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
const handleUIEvent = (event) => {
|
|
68
|
-
const target = event.target;
|
|
69
|
-
if (!isInteractiveElement(target)) return;
|
|
70
|
-
const selector = getElementSelector(target);
|
|
71
|
-
const text = getElementText(target);
|
|
72
|
-
const TRUNCATE_LENGTH = 100;
|
|
73
|
-
const key = `ui_event:${selector}:${text}`;
|
|
74
|
-
if (shouldSkip(key)) return;
|
|
75
|
-
remember(key);
|
|
76
|
-
ctx.captureNow("ui_event", { event: {
|
|
77
|
-
type: "click",
|
|
78
|
-
selector,
|
|
79
|
-
text: text ? text.substring(0, TRUNCATE_LENGTH) : void 0,
|
|
80
|
-
url: window.location.href,
|
|
81
|
-
timestamp: Date.now()
|
|
82
|
-
} });
|
|
83
|
-
};
|
|
84
|
-
function isInteractiveElement(element) {
|
|
85
|
-
const isInteractiveTag = [
|
|
86
|
-
"BUTTON",
|
|
87
|
-
"A",
|
|
88
|
-
"INPUT",
|
|
89
|
-
"SELECT",
|
|
90
|
-
"TEXTAREA"
|
|
91
|
-
].includes(element.tagName);
|
|
92
|
-
const hasClickHandler = element.onclick !== null;
|
|
93
|
-
const hasRole = element.getAttribute("role") === "button";
|
|
94
|
-
return isInteractiveTag || hasClickHandler || hasRole;
|
|
95
|
-
}
|
|
96
|
-
handlePageView();
|
|
97
|
-
const originalPushState = history.pushState;
|
|
98
|
-
const originalReplaceState = history.replaceState;
|
|
99
|
-
history.pushState = (...args) => {
|
|
100
|
-
const result = originalPushState.apply(history, args);
|
|
101
|
-
handlePageView();
|
|
102
|
-
return result;
|
|
103
|
-
};
|
|
104
|
-
history.replaceState = (...args) => {
|
|
105
|
-
const result = originalReplaceState.apply(history, args);
|
|
106
|
-
handlePageView();
|
|
107
|
-
return result;
|
|
108
|
-
};
|
|
109
|
-
window.addEventListener("popstate", handlePageView);
|
|
110
|
-
window.addEventListener("beforeunload", handlePageLeave);
|
|
111
|
-
const onVisibility = () => {
|
|
112
|
-
if (document.visibilityState === "hidden") handlePageLeave();
|
|
113
|
-
};
|
|
114
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
115
|
-
document.addEventListener("click", handleUIEvent, true);
|
|
116
|
-
return {
|
|
117
|
-
key: "pageEvents",
|
|
118
|
-
cleanup: () => {
|
|
119
|
-
history.pushState = originalPushState;
|
|
120
|
-
history.replaceState = originalReplaceState;
|
|
121
|
-
window.removeEventListener("popstate", handlePageView);
|
|
122
|
-
window.removeEventListener("beforeunload", handlePageLeave);
|
|
123
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
124
|
-
document.removeEventListener("click", handleUIEvent, true);
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
})
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
//#endregion
|
|
131
|
-
export { page_events_default as default };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page-events.mjs","names":["lastKey: string | null"],"sources":["../../../../src/core/plugins/impl/page-events.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport { getElementSelector, getElementText } from \"../dom-utils.js\";\nimport { createEffectPlugin, defineEvent } from \"../plugin-event-system.js\";\n\n/**\n * Page Events Plugin\n *\n * Handles tracking of page navigation and UI interaction events:\n * - pageview: When a user views a page\n * - pageleave: When a user leaves a page\n * - ui_event: General UI interaction events (clicks, form submits, etc.)\n */\nexport default createEffectPlugin(\"pageEvents\", {\n name: \"page-events\",\n events: [\n defineEvent(\"pageview\").value(),\n defineEvent(\"pageleave\").value(),\n defineEvent(\"ui_event\").value(),\n ],\n setup: (ctx) =>\n Effect.gen(function* () {\n if (typeof window === \"undefined\") {\n ctx.log.debug(\"page-events: SSR - skipping setup\");\n return;\n }\n\n // Deduplicate consecutive identical events (best-effort, last-in-queue proxy)\n let lastKey: string | null = null;\n\n const shouldSkip = (key: string) => lastKey === key;\n\n const remember = (key: string) => {\n lastKey = key;\n };\n\n // Track page views on navigation\n const handlePageView = () => {\n const url = window.location.href;\n const title = document.title;\n\n ctx.log.trace(\"Page view\", { url, title });\n\n const key = `pageview:${url}`;\n\n if (shouldSkip(key)) {\n return;\n }\n\n remember(key);\n\n ctx.run(\n ctx.capture(\"pageview\", { url, title }).pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logError(\"Failed to capture pageview\", {\n error: String(error),\n url,\n title,\n });\n })\n )\n )\n );\n };\n\n // Track page leaves\n const handlePageLeave = () => {\n const url = window.location.href;\n const duration = performance.now();\n\n ctx.log.trace(\"Page leave\", { url, duration });\n\n const key = `pageleave:${url}`;\n\n if (shouldSkip(key)) {\n return;\n }\n\n remember(key);\n\n ctx.captureNow(\"pageleave\", {\n url,\n durationMs: Math.round(duration),\n });\n };\n\n // Track UI events (example: clicks on interactive elements)\n const handleUIEvent = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n\n // Only track clicks on interactive elements\n if (!isInteractiveElement(target)) {\n return;\n }\n\n const selector = getElementSelector(target);\n const text = getElementText(target);\n const TRUNCATE_LENGTH = 100;\n\n const key = `ui_event:${selector}:${text}`;\n\n if (shouldSkip(key)) {\n return;\n }\n\n remember(key);\n\n ctx.captureNow(\"ui_event\", {\n event: {\n type: \"click\",\n selector,\n text: text ? text.substring(0, TRUNCATE_LENGTH) : undefined,\n url: window.location.href,\n timestamp: Date.now(),\n },\n });\n };\n\n // Helper to determine if element is interactive\n function isInteractiveElement(element: HTMLElement): boolean {\n const interactiveTags = [\"BUTTON\", \"A\", \"INPUT\", \"SELECT\", \"TEXTAREA\"];\n const isInteractiveTag = interactiveTags.includes(element.tagName);\n const hasClickHandler = element.onclick !== null;\n const hasRole = element.getAttribute(\"role\") === \"button\";\n\n return isInteractiveTag || hasClickHandler || hasRole;\n }\n\n // Selector and text helpers are imported from dom-utils\n\n // Set up event listeners\n // Initial page view\n handlePageView();\n\n // Listen for navigation changes (for SPAs)\n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n\n history.pushState = (...args) => {\n const result = originalPushState.apply(history, args);\n handlePageView();\n return result;\n };\n\n history.replaceState = (...args) => {\n const result = originalReplaceState.apply(history, args);\n handlePageView();\n return result;\n };\n\n window.addEventListener(\"popstate\", handlePageView);\n\n // Page leave events\n window.addEventListener(\"beforeunload\", handlePageLeave);\n\n const onVisibility = () => {\n if (document.visibilityState === \"hidden\") {\n handlePageLeave();\n }\n };\n document.addEventListener(\"visibilitychange\", onVisibility);\n\n // UI interaction events\n document.addEventListener(\"click\", handleUIEvent, true);\n\n return {\n key: \"pageEvents\",\n cleanup: () => {\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n window.removeEventListener(\"popstate\", handlePageView);\n window.removeEventListener(\"beforeunload\", handlePageLeave);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n document.removeEventListener(\"click\", handleUIEvent, true);\n },\n };\n }),\n});\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rage-click.d.mts","names":[],"sources":["../../../../src/core/plugins/impl/rage-click.ts"],"sourcesContent":[],"mappings":""}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { getElementSelector } from "../dom-utils.mjs";
|
|
2
|
-
import { createEffectPlugin, defineEvent } from "../plugin-event-system.mjs";
|
|
3
|
-
import { Effect } from "effect";
|
|
4
|
-
|
|
5
|
-
//#region src/core/plugins/impl/rage-click.ts
|
|
6
|
-
var rage_click_default = createEffectPlugin("rageClick", {
|
|
7
|
-
name: "rage-click",
|
|
8
|
-
events: [defineEvent("rage_click").value()],
|
|
9
|
-
config: {
|
|
10
|
-
timeWindow: 1e3,
|
|
11
|
-
threshold: 3
|
|
12
|
-
},
|
|
13
|
-
setup: (ctx, config) => Effect.gen(function* () {
|
|
14
|
-
if (typeof window === "undefined") {
|
|
15
|
-
ctx.log.debug("rage-click: SSR - skipping setup");
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
let clickTimestamps = [];
|
|
19
|
-
function handleClick(event) {
|
|
20
|
-
const now = Date.now();
|
|
21
|
-
clickTimestamps = clickTimestamps.filter((ts) => now - ts < config.timeWindow);
|
|
22
|
-
clickTimestamps.push(now);
|
|
23
|
-
if (clickTimestamps.length >= config.threshold) {
|
|
24
|
-
const target = event.target;
|
|
25
|
-
const TRUNCATE_LENGTH = 100;
|
|
26
|
-
ctx.log.debug("Rage click detected", {
|
|
27
|
-
count: clickTimestamps.length,
|
|
28
|
-
selector: target ? getElementSelector(target) : "unknown"
|
|
29
|
-
});
|
|
30
|
-
ctx.span("plugin.rage_click", ctx.capture("rage_click", {
|
|
31
|
-
count: clickTimestamps.length,
|
|
32
|
-
timeWindow: config.timeWindow,
|
|
33
|
-
selector: target ? getElementSelector(target) : "unknown",
|
|
34
|
-
text: target?.textContent?.substring(0, TRUNCATE_LENGTH) || "",
|
|
35
|
-
x: event.clientX,
|
|
36
|
-
y: event.clientY,
|
|
37
|
-
timestamp: now
|
|
38
|
-
}));
|
|
39
|
-
clickTimestamps = [];
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
window.addEventListener("click", handleClick, true);
|
|
43
|
-
return {
|
|
44
|
-
key: "rageClick",
|
|
45
|
-
cleanup: () => {
|
|
46
|
-
window.removeEventListener("click", handleClick, true);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
})
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
//#endregion
|
|
53
|
-
export { rage_click_default as default };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rage-click.mjs","names":["clickTimestamps: number[]"],"sources":["../../../../src/core/plugins/impl/rage-click.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport type { PluginContext } from \"../../schemas.js\";\nimport { getElementSelector } from \"../dom-utils.js\";\nimport { createEffectPlugin, defineEvent } from \"../plugin-event-system.js\";\n\nexport default createEffectPlugin(\"rageClick\", {\n name: \"rage-click\",\n events: [defineEvent(\"rage_click\").value()],\n config: {\n timeWindow: 1000,\n threshold: 3,\n },\n setup: (\n ctx: PluginContext,\n config: { timeWindow: number; threshold: number }\n ) =>\n Effect.gen(function* () {\n if (typeof window === \"undefined\") {\n ctx.log.debug(\"rage-click: SSR - skipping setup\");\n return;\n }\n\n let clickTimestamps: number[] = [];\n\n function handleClick(event: MouseEvent) {\n const now = Date.now();\n clickTimestamps = clickTimestamps.filter(\n (ts) => now - ts < config.timeWindow\n );\n clickTimestamps.push(now);\n\n if (clickTimestamps.length >= config.threshold) {\n const target = event.target as Element;\n const TRUNCATE_LENGTH = 100;\n\n ctx.log.debug(\"Rage click detected\", {\n count: clickTimestamps.length,\n selector: target ? getElementSelector(target) : \"unknown\",\n });\n\n ctx.span(\n \"plugin.rage_click\",\n ctx.capture(\"rage_click\", {\n count: clickTimestamps.length,\n timeWindow: config.timeWindow,\n selector: target ? getElementSelector(target) : \"unknown\",\n text: target?.textContent?.substring(0, TRUNCATE_LENGTH) || \"\",\n x: event.clientX,\n y: event.clientY,\n timestamp: now,\n })\n );\n\n clickTimestamps = [];\n }\n }\n\n window.addEventListener(\"click\", handleClick, true);\n\n return {\n key: \"rageClick\",\n cleanup: () => {\n window.removeEventListener(\"click\", handleClick, true);\n },\n };\n }),\n});\n"],"mappings":";;;;;AAMA,yBAAe,mBAAmB,aAAa;CAC7C,MAAM;CACN,QAAQ,CAAC,YAAY,aAAa,CAAC,OAAO,CAAC;CAC3C,QAAQ;EACN,YAAY;EACZ,WAAW;EACZ;CACD,QACE,KACA,WAEA,OAAO,IAAI,aAAa;AACtB,MAAI,OAAO,WAAW,aAAa;AACjC,OAAI,IAAI,MAAM,mCAAmC;AACjD;;EAGF,IAAIA,kBAA4B,EAAE;EAElC,SAAS,YAAY,OAAmB;GACtC,MAAM,MAAM,KAAK,KAAK;AACtB,qBAAkB,gBAAgB,QAC/B,OAAO,MAAM,KAAK,OAAO,WAC3B;AACD,mBAAgB,KAAK,IAAI;AAEzB,OAAI,gBAAgB,UAAU,OAAO,WAAW;IAC9C,MAAM,SAAS,MAAM;IACrB,MAAM,kBAAkB;AAExB,QAAI,IAAI,MAAM,uBAAuB;KACnC,OAAO,gBAAgB;KACvB,UAAU,SAAS,mBAAmB,OAAO,GAAG;KACjD,CAAC;AAEF,QAAI,KACF,qBACA,IAAI,QAAQ,cAAc;KACxB,OAAO,gBAAgB;KACvB,YAAY,OAAO;KACnB,UAAU,SAAS,mBAAmB,OAAO,GAAG;KAChD,MAAM,QAAQ,aAAa,UAAU,GAAG,gBAAgB,IAAI;KAC5D,GAAG,MAAM;KACT,GAAG,MAAM;KACT,WAAW;KACZ,CAAC,CACH;AAED,sBAAkB,EAAE;;;AAIxB,SAAO,iBAAiB,SAAS,aAAa,KAAK;AAEnD,SAAO;GACL,KAAK;GACL,eAAe;AACb,WAAO,oBAAoB,SAAS,aAAa,KAAK;;GAEzD;GACD;CACL,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"replay.d.mts","names":[],"sources":["../../../../src/core/plugins/impl/replay.ts"],"sourcesContent":[],"mappings":";;;UAYiB,SAAA;;;AAAjB,cAEC,QAFyB,EAEzB,MAFyB,CAAA,QAAA,EAAA,OAAA,CAAA"}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { createEffectPlugin } from "../plugin-event-system.mjs";
|
|
2
|
-
import { Effect } from "effect";
|
|
3
|
-
import { v7 } from "uuid";
|
|
4
|
-
|
|
5
|
-
//#region src/core/plugins/impl/replay.ts
|
|
6
|
-
let replayStarted = false;
|
|
7
|
-
let replayStopFn = null;
|
|
8
|
-
var replay_default = createEffectPlugin("replay", {
|
|
9
|
-
name: "replay",
|
|
10
|
-
setup: (ctx) => Effect.gen(function* () {
|
|
11
|
-
if (typeof window === "undefined" || replayStarted || ctx.config.features.replay !== true) {
|
|
12
|
-
ctx.log.trace("Skipping replay setup in a non-browser environment");
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const startRecording = async () => {
|
|
16
|
-
ctx.log.trace("Starting replay recording");
|
|
17
|
-
const chunk = [];
|
|
18
|
-
let sessionId = v7();
|
|
19
|
-
const sendChunk = () => {
|
|
20
|
-
if (chunk.length === 0) return;
|
|
21
|
-
ctx.log.trace("Sending replay chunk", {
|
|
22
|
-
sessionId,
|
|
23
|
-
count: chunk.length
|
|
24
|
-
});
|
|
25
|
-
ctx.span("plugin.replay.send_chunk", ctx.capture("replay_chunk", {
|
|
26
|
-
ts: Date.now(),
|
|
27
|
-
count: chunk.length,
|
|
28
|
-
events: chunk.map((e) => JSON.stringify(e))
|
|
29
|
-
}));
|
|
30
|
-
chunk.length = 0;
|
|
31
|
-
};
|
|
32
|
-
const flushNow = () => {
|
|
33
|
-
try {
|
|
34
|
-
sendChunk();
|
|
35
|
-
} catch (error) {
|
|
36
|
-
ctx.log.error("Failed to flush replay chunk", { error });
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
const beforeUnload = () => flushNow();
|
|
40
|
-
const visibility = () => {
|
|
41
|
-
if (document.visibilityState === "hidden") flushNow();
|
|
42
|
-
};
|
|
43
|
-
const detach = () => {
|
|
44
|
-
try {
|
|
45
|
-
window.removeEventListener("beforeunload", beforeUnload);
|
|
46
|
-
document.removeEventListener("visibilitychange", visibility);
|
|
47
|
-
} catch (error) {
|
|
48
|
-
ctx.log.debug("Failed to remove listeners after flushing replay chunk", { error });
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
window.addEventListener("beforeunload", beforeUnload);
|
|
52
|
-
document.addEventListener("visibilitychange", visibility);
|
|
53
|
-
const rrweb = await import("rrweb");
|
|
54
|
-
if (typeof rrweb.record !== "function") return () => {
|
|
55
|
-
ctx.log.error("Failed to start recording", { error: "rrweb is not a function" });
|
|
56
|
-
};
|
|
57
|
-
const MAX_CHUNK_AGE_MS = 6e4;
|
|
58
|
-
const MAX_CHUNK_EVENTS = 100;
|
|
59
|
-
const MAX_CHUNK_SIZE_BYTES = 1e6;
|
|
60
|
-
const stopRecord = rrweb.record({
|
|
61
|
-
emit: (event) => {
|
|
62
|
-
if (chunk.length > 0) {
|
|
63
|
-
const first = chunk.at(0);
|
|
64
|
-
if (first && event.timestamp - first.timestamp > MAX_CHUNK_AGE_MS) {
|
|
65
|
-
sendChunk();
|
|
66
|
-
sessionId = v7();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
chunk.push(event);
|
|
70
|
-
const estimatedSize = JSON.stringify(chunk).length;
|
|
71
|
-
if (chunk.length >= MAX_CHUNK_EVENTS || estimatedSize > MAX_CHUNK_SIZE_BYTES) sendChunk();
|
|
72
|
-
},
|
|
73
|
-
sampling: {
|
|
74
|
-
mousemove: 50,
|
|
75
|
-
mouseInteraction: true,
|
|
76
|
-
scroll: 150,
|
|
77
|
-
media: 800,
|
|
78
|
-
input: "last"
|
|
79
|
-
},
|
|
80
|
-
slimDOMOptions: "all",
|
|
81
|
-
inlineStylesheet: false,
|
|
82
|
-
collectFonts: false,
|
|
83
|
-
recordCanvas: false
|
|
84
|
-
});
|
|
85
|
-
const intervalId = window.setInterval(() => {
|
|
86
|
-
try {
|
|
87
|
-
sendChunk();
|
|
88
|
-
} catch (error) {
|
|
89
|
-
ctx.log.warn("Failed to send replay chunk after recording event", {
|
|
90
|
-
error,
|
|
91
|
-
chunk
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}, 1e4);
|
|
95
|
-
return () => {
|
|
96
|
-
try {
|
|
97
|
-
if (typeof stopRecord === "function") stopRecord();
|
|
98
|
-
} catch (error) {
|
|
99
|
-
ctx.log.debug("Failed to stop recording on cleanup", {
|
|
100
|
-
error,
|
|
101
|
-
stopRecord,
|
|
102
|
-
intervalId
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
window.clearInterval(intervalId);
|
|
107
|
-
} catch (error) {
|
|
108
|
-
ctx.log.debug("Failed to clear interval on cleanup", {
|
|
109
|
-
error,
|
|
110
|
-
intervalId
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
detach();
|
|
114
|
-
};
|
|
115
|
-
};
|
|
116
|
-
try {
|
|
117
|
-
replayStopFn = yield* Effect.promise(() => startRecording());
|
|
118
|
-
replayStarted = true;
|
|
119
|
-
} catch (error) {
|
|
120
|
-
ctx.log.error("Failed to start session replay recording", { error });
|
|
121
|
-
replayStarted = false;
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
key: "replay",
|
|
125
|
-
api: { stop: () => {
|
|
126
|
-
if (replayStopFn) {
|
|
127
|
-
replayStopFn();
|
|
128
|
-
replayStopFn = null;
|
|
129
|
-
replayStarted = false;
|
|
130
|
-
}
|
|
131
|
-
} },
|
|
132
|
-
cleanup: () => {
|
|
133
|
-
if (replayStopFn) {
|
|
134
|
-
replayStopFn();
|
|
135
|
-
replayStopFn = null;
|
|
136
|
-
replayStarted = false;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
})
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
//#endregion
|
|
144
|
-
export { replay_default as default };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"replay.mjs","names":["replayStopFn: (() => void) | null","chunk: eventWithTime[]","uuidv7"],"sources":["../../../../src/core/plugins/impl/replay.ts"],"sourcesContent":["import type { eventWithTime } from \"@rrweb/types\";\nimport { Effect } from \"effect\";\nimport type { recordOptions } from \"rrweb\";\nimport { v7 as uuidv7 } from \"uuid\";\n\nimport type { PluginExpose } from \"../../schemas.js\";\nimport { createEffectPlugin } from \"../plugin-event-system.js\";\n\n// Ensure recording starts only once across multiple setup() calls\nlet replayStarted = false;\nlet replayStopFn: (() => void) | null = null;\n\nexport interface ReplayAPI {\n stop: () => void;\n}\n\nexport default createEffectPlugin(\"replay\", {\n name: \"replay\",\n setup: (ctx) =>\n Effect.gen(function* () {\n // Respect config.features.replay; schema should default based on env\n if (\n typeof window === \"undefined\" ||\n replayStarted ||\n ctx.config.features.replay !== true\n ) {\n ctx.log.trace(\"Skipping replay setup in a non-browser environment\");\n\n return;\n }\n\n const startRecording = async () => {\n ctx.log.trace(\"Starting replay recording\");\n\n const chunk: eventWithTime[] = [];\n let sessionId = uuidv7();\n\n const sendChunk = () => {\n if (chunk.length === 0) {\n return;\n }\n\n ctx.log.trace(\"Sending replay chunk\", {\n sessionId,\n count: chunk.length,\n });\n\n ctx.span(\n \"plugin.replay.send_chunk\",\n ctx.capture(\"replay_chunk\", {\n ts: Date.now(),\n count: chunk.length,\n events: chunk.map((e) => JSON.stringify(e)),\n })\n );\n\n chunk.length = 0;\n };\n\n const flushNow = () => {\n try {\n sendChunk();\n } catch (error) {\n ctx.log.error(\"Failed to flush replay chunk\", { error });\n }\n };\n\n const beforeUnload = () => flushNow();\n const visibility = () => {\n if (document.visibilityState === \"hidden\") {\n flushNow();\n }\n };\n\n const detach = () => {\n try {\n window.removeEventListener(\"beforeunload\", beforeUnload);\n document.removeEventListener(\"visibilitychange\", visibility);\n } catch (error) {\n ctx.log.debug(\n \"Failed to remove listeners after flushing replay chunk\",\n { error }\n );\n }\n };\n\n window.addEventListener(\"beforeunload\", beforeUnload);\n document.addEventListener(\"visibilitychange\", visibility);\n\n // Dynamically import rrweb to reduce initial bundle size\n const rrweb = await import(\"rrweb\");\n\n if (typeof rrweb.record !== \"function\") {\n return () => {\n ctx.log.error(\"Failed to start recording\", {\n error: \"rrweb is not a function\",\n });\n };\n }\n\n const MAX_CHUNK_AGE_MS = 60_000;\n const MAX_CHUNK_EVENTS = 100;\n const MAX_CHUNK_SIZE_BYTES = 1_000_000;\n\n const options: recordOptions<eventWithTime> = {\n emit: (event) => {\n // Start a new session if the chunk is too old\n if (chunk.length > 0) {\n const first = chunk.at(0);\n if (\n first &&\n event.timestamp - first.timestamp > MAX_CHUNK_AGE_MS\n ) {\n sendChunk();\n sessionId = uuidv7();\n }\n }\n\n chunk.push(event);\n\n // Send chunk if it's getting large\n const estimatedSize = JSON.stringify(chunk).length;\n if (\n chunk.length >= MAX_CHUNK_EVENTS ||\n estimatedSize > MAX_CHUNK_SIZE_BYTES\n ) {\n sendChunk();\n }\n },\n sampling: {\n mousemove: 50,\n mouseInteraction: true,\n scroll: 150,\n media: 800,\n input: \"last\",\n },\n slimDOMOptions: \"all\",\n inlineStylesheet: false,\n collectFonts: false,\n recordCanvas: false,\n };\n\n const stopRecord = rrweb.record(options);\n\n const FLUSH_INTERVAL_MS = 10_000;\n const intervalId = window.setInterval(() => {\n try {\n sendChunk();\n } catch (error) {\n ctx.log.warn(\"Failed to send replay chunk after recording event\", {\n error,\n chunk,\n });\n }\n }, FLUSH_INTERVAL_MS);\n\n return () => {\n try {\n if (typeof stopRecord === \"function\") {\n stopRecord();\n }\n } catch (error) {\n ctx.log.debug(\"Failed to stop recording on cleanup\", {\n error,\n stopRecord,\n intervalId,\n });\n }\n try {\n window.clearInterval(intervalId);\n } catch (error) {\n ctx.log.debug(\"Failed to clear interval on cleanup\", {\n error,\n intervalId,\n });\n }\n detach();\n };\n };\n\n try {\n replayStopFn = yield* Effect.promise(() => startRecording());\n replayStarted = true;\n } catch (error) {\n ctx.log.error(\"Failed to start session replay recording\", { error });\n\n replayStarted = false;\n }\n\n const expose: PluginExpose<\"replay\", ReplayAPI> = {\n key: \"replay\",\n api: {\n stop: () => {\n if (replayStopFn) {\n replayStopFn();\n replayStopFn = null;\n replayStarted = false;\n }\n },\n },\n cleanup: () => {\n if (replayStopFn) {\n replayStopFn();\n replayStopFn = null;\n replayStarted = false;\n }\n },\n };\n\n return expose;\n }),\n});\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server-tracing.d.mts","names":[],"sources":["../../../../src/core/plugins/impl/server-tracing.ts"],"sourcesContent":[],"mappings":";;;KAqGY,gBAAA;cAAwB,UAAA"}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { createEffectPlugin } from "../plugin-event-system.mjs";
|
|
2
|
-
import { Effect } from "effect";
|
|
3
|
-
import { nanoid } from "nanoid";
|
|
4
|
-
|
|
5
|
-
//#region src/core/plugins/impl/server-tracing.ts
|
|
6
|
-
const X_INTERFERE_REQUEST_HEADER = "x-interfere-request";
|
|
7
|
-
/**
|
|
8
|
-
* Generate a unique request ID
|
|
9
|
-
*/
|
|
10
|
-
function generateRequestId() {
|
|
11
|
-
return nanoid();
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Check if a URL matches any of the tracing origins
|
|
15
|
-
*/
|
|
16
|
-
function shouldTraceUrl(url, tracingOrigins) {
|
|
17
|
-
if (!tracingOrigins) return false;
|
|
18
|
-
if (tracingOrigins === true) try {
|
|
19
|
-
const currentOrigin = window.location.origin;
|
|
20
|
-
return new URL(url, window.location.href).origin === currentOrigin;
|
|
21
|
-
} catch {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
for (const pattern of tracingOrigins) if (typeof pattern === "string" && url.includes(pattern) || pattern instanceof RegExp && pattern.test(url)) return true;
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Get session ID synchronously from localStorage.
|
|
29
|
-
*
|
|
30
|
-
* NOTE: Unlike other plugins that use `ctx.capture()` (which automatically
|
|
31
|
-
* gets session ID via `buildEnvelopeEffect()` -> `SessionServiceTag`),
|
|
32
|
-
* this plugin needs synchronous access because:
|
|
33
|
-
* 1. We're patching network requests (fetch/XHR) synchronously
|
|
34
|
-
* 2. Headers must be set synchronously before requests are sent
|
|
35
|
-
*
|
|
36
|
-
* The session service stores the session ID in localStorage (see session.layer.ts),
|
|
37
|
-
* so reading directly is safe and matches the storage location used by the service.
|
|
38
|
-
*/
|
|
39
|
-
function getSessionIdSync() {
|
|
40
|
-
if (typeof window === "undefined") return null;
|
|
41
|
-
try {
|
|
42
|
-
const storage = window.localStorage;
|
|
43
|
-
if (!storage) return null;
|
|
44
|
-
return storage.getItem("__interfere_session_id__");
|
|
45
|
-
} catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Get session ID asynchronously (for fetch API compatibility).
|
|
51
|
-
* Uses synchronous read since session ID is stored in localStorage.
|
|
52
|
-
*/
|
|
53
|
-
function getSessionIdAsync() {
|
|
54
|
-
return Promise.resolve(getSessionIdSync());
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Create the x-interfere-request header value
|
|
58
|
-
*/
|
|
59
|
-
function createRequestHeader(sessionId, requestId) {
|
|
60
|
-
return `${sessionId ?? ""}/${requestId}`;
|
|
61
|
-
}
|
|
62
|
-
var server_tracing_default = createEffectPlugin("serverTracing", {
|
|
63
|
-
name: "serverTracing",
|
|
64
|
-
setup: (ctx) => Effect.gen(function* () {
|
|
65
|
-
if (typeof window === "undefined") {
|
|
66
|
-
ctx.log.debug("serverTracing: SSR - skipping setup");
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
const tracingOrigins = true;
|
|
70
|
-
ctx.log.debug("serverTracing: patching fetch and XMLHttpRequest", { tracingOrigins });
|
|
71
|
-
const originalFetch = window.fetch.bind(window);
|
|
72
|
-
const extractUrl = (input) => {
|
|
73
|
-
if (typeof input === "string") try {
|
|
74
|
-
return new URL(input, window.location.href).href;
|
|
75
|
-
} catch {
|
|
76
|
-
return input;
|
|
77
|
-
}
|
|
78
|
-
if (input instanceof URL) return input.href;
|
|
79
|
-
try {
|
|
80
|
-
return new URL(input.url, window.location.href).href;
|
|
81
|
-
} catch {
|
|
82
|
-
return input.url;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
const mergeHeaders = (init, request) => {
|
|
86
|
-
const headers = new Headers(init?.headers);
|
|
87
|
-
if (request) {
|
|
88
|
-
for (const [key, value] of request.headers.entries()) if (!headers.has(key)) headers.set(key, value);
|
|
89
|
-
}
|
|
90
|
-
return headers;
|
|
91
|
-
};
|
|
92
|
-
const patchedFetch = async (input, init) => {
|
|
93
|
-
const url = extractUrl(input);
|
|
94
|
-
if (!(url && shouldTraceUrl(url, tracingOrigins))) {
|
|
95
|
-
ctx.log.debug("serverTracing: skipping URL", {
|
|
96
|
-
url,
|
|
97
|
-
tracingOrigins
|
|
98
|
-
});
|
|
99
|
-
return originalFetch(input, init);
|
|
100
|
-
}
|
|
101
|
-
const sessionId = await getSessionIdAsync();
|
|
102
|
-
const requestId = generateRequestId();
|
|
103
|
-
const headerValue = createRequestHeader(sessionId, requestId);
|
|
104
|
-
ctx.log.debug("serverTracing: injecting header", {
|
|
105
|
-
url,
|
|
106
|
-
sessionId,
|
|
107
|
-
requestId,
|
|
108
|
-
headerValue
|
|
109
|
-
});
|
|
110
|
-
const headers = mergeHeaders(init, input instanceof Request ? input : void 0);
|
|
111
|
-
headers.set(X_INTERFERE_REQUEST_HEADER, headerValue);
|
|
112
|
-
if (input instanceof Request) return originalFetch(new Request(input, { headers }));
|
|
113
|
-
return originalFetch(input, {
|
|
114
|
-
...init,
|
|
115
|
-
headers
|
|
116
|
-
});
|
|
117
|
-
};
|
|
118
|
-
window.fetch = patchedFetch;
|
|
119
|
-
const originalXHROpen = XMLHttpRequest.prototype.open;
|
|
120
|
-
const originalXHRSend = XMLHttpRequest.prototype.send;
|
|
121
|
-
const originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
122
|
-
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
|
|
123
|
-
this._interfereUrl = typeof url === "string" ? url : url.href;
|
|
124
|
-
return originalXHROpen.call(this, method, url, ...rest);
|
|
125
|
-
};
|
|
126
|
-
XMLHttpRequest.prototype.setRequestHeader = function(name, value) {
|
|
127
|
-
const url = this._interfereUrl;
|
|
128
|
-
if (url && shouldTraceUrl(url, tracingOrigins)) {
|
|
129
|
-
const headerValue = createRequestHeader(getSessionIdSync(), generateRequestId());
|
|
130
|
-
if (!this._interfereHeaderSet) {
|
|
131
|
-
originalSetRequestHeader.call(this, X_INTERFERE_REQUEST_HEADER, headerValue);
|
|
132
|
-
this._interfereHeaderSet = true;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return originalSetRequestHeader.call(this, name, value);
|
|
136
|
-
};
|
|
137
|
-
XMLHttpRequest.prototype.send = function(body) {
|
|
138
|
-
const url = this._interfereUrl;
|
|
139
|
-
if (url && shouldTraceUrl(url, tracingOrigins) && !this._interfereHeaderSet) {
|
|
140
|
-
const headerValue = createRequestHeader(getSessionIdSync(), generateRequestId());
|
|
141
|
-
originalSetRequestHeader.call(this, X_INTERFERE_REQUEST_HEADER, headerValue);
|
|
142
|
-
this._interfereHeaderSet = true;
|
|
143
|
-
}
|
|
144
|
-
return originalXHRSend.call(this, body);
|
|
145
|
-
};
|
|
146
|
-
return {
|
|
147
|
-
key: "serverTracing",
|
|
148
|
-
cleanup: () => {
|
|
149
|
-
ctx.log.debug("serverTracing: removing patches");
|
|
150
|
-
window.fetch = originalFetch;
|
|
151
|
-
XMLHttpRequest.prototype.open = originalXHROpen;
|
|
152
|
-
XMLHttpRequest.prototype.send = originalXHRSend;
|
|
153
|
-
XMLHttpRequest.prototype.setRequestHeader = originalSetRequestHeader;
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
})
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
//#endregion
|
|
160
|
-
export { server_tracing_default as default };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server-tracing.mjs","names":["originalFetch: typeof window.fetch","patchedFetch: typeof window.fetch"],"sources":["../../../../src/core/plugins/impl/server-tracing.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { nanoid } from \"nanoid\";\n\nimport { createEffectPlugin } from \"../plugin-event-system.js\";\n\nconst X_INTERFERE_REQUEST_HEADER = \"x-interfere-request\";\n\n/**\n * Generate a unique request ID\n */\nfunction generateRequestId(): string {\n return nanoid();\n}\n\n/**\n * Check if a URL matches any of the tracing origins\n */\nfunction shouldTraceUrl(\n url: string,\n tracingOrigins?: boolean | (string | RegExp)[]\n): boolean {\n if (!tracingOrigins) {\n return false;\n }\n\n if (tracingOrigins === true) {\n // If true, match all URLs on the same origin\n try {\n const currentOrigin = window.location.origin;\n const urlObj = new URL(url, window.location.href);\n return urlObj.origin === currentOrigin;\n } catch {\n // If URL parsing fails, default to false\n return false;\n }\n }\n\n // Check against array of patterns\n for (const pattern of tracingOrigins) {\n if (\n (typeof pattern === \"string\" && url.includes(pattern)) ||\n (pattern instanceof RegExp && pattern.test(url))\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Get session ID synchronously from localStorage.\n *\n * NOTE: Unlike other plugins that use `ctx.capture()` (which automatically\n * gets session ID via `buildEnvelopeEffect()` -> `SessionServiceTag`),\n * this plugin needs synchronous access because:\n * 1. We're patching network requests (fetch/XHR) synchronously\n * 2. Headers must be set synchronously before requests are sent\n *\n * The session service stores the session ID in localStorage (see session.layer.ts),\n * so reading directly is safe and matches the storage location used by the service.\n */\nfunction getSessionIdSync(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n const storage = window.localStorage;\n if (!storage) {\n return null;\n }\n\n const stored = storage.getItem(\"__interfere_session_id__\");\n return stored;\n } catch {\n // Storage might be blocked or unavailable\n return null;\n }\n}\n\n/**\n * Get session ID asynchronously (for fetch API compatibility).\n * Uses synchronous read since session ID is stored in localStorage.\n */\nfunction getSessionIdAsync(): Promise<string | null> {\n return Promise.resolve(getSessionIdSync());\n}\n\n/**\n * Create the x-interfere-request header value\n */\nfunction createRequestHeader(\n sessionId: string | null,\n requestId: string\n): string {\n // Format: {sessionId}/{requestId}\n // If no session ID yet, use empty string as placeholder\n return `${sessionId ?? \"\"}/${requestId}`;\n}\n\nexport type ServerTracingAPI = null;\n\nexport default createEffectPlugin(\"serverTracing\", {\n name: \"serverTracing\",\n setup: (ctx) =>\n Effect.gen(function* () {\n if (typeof window === \"undefined\") {\n ctx.log.debug(\"serverTracing: SSR - skipping setup\");\n return;\n }\n\n // Default to true - trace all same-origin requests\n // This is plugin-specific config, not part of base SDK config\n const tracingOrigins = true;\n\n ctx.log.debug(\"serverTracing: patching fetch and XMLHttpRequest\", {\n tracingOrigins,\n });\n\n // Patch fetch API\n const originalFetch: typeof window.fetch = window.fetch.bind(window);\n\n const extractUrl = (input: RequestInfo | URL): string => {\n if (typeof input === \"string\") {\n // If it's a relative URL, convert to absolute\n try {\n return new URL(input, window.location.href).href;\n } catch {\n return input;\n }\n }\n if (input instanceof URL) {\n return input.href;\n }\n // Request.url might be relative, convert to absolute\n try {\n return new URL(input.url, window.location.href).href;\n } catch {\n return input.url;\n }\n };\n\n const mergeHeaders = (init?: RequestInit, request?: Request): Headers => {\n const headers = new Headers(init?.headers);\n\n if (request) {\n for (const [key, value] of request.headers.entries()) {\n if (!headers.has(key)) {\n headers.set(key, value);\n }\n }\n }\n\n return headers;\n };\n\n const patchedFetch: typeof window.fetch = async (\n input: RequestInfo | URL,\n init?: RequestInit\n ) => {\n const url = extractUrl(input);\n\n // Check if we should trace this request\n const shouldTrace = url && shouldTraceUrl(url, tracingOrigins);\n if (!shouldTrace) {\n ctx.log.debug(\"serverTracing: skipping URL\", { url, tracingOrigins });\n return originalFetch(input, init);\n }\n\n const sessionId = await getSessionIdAsync();\n const requestId = generateRequestId();\n const headerValue = createRequestHeader(sessionId, requestId);\n\n ctx.log.debug(\"serverTracing: injecting header\", {\n url,\n sessionId,\n requestId,\n headerValue,\n });\n\n // Merge headers\n const headers = mergeHeaders(\n init,\n input instanceof Request ? input : undefined\n );\n\n // Set x-interfere-request header\n headers.set(X_INTERFERE_REQUEST_HEADER, headerValue);\n\n // If input is a Request object, create a new Request\n if (input instanceof Request) {\n return originalFetch(\n new Request(input, {\n headers,\n })\n );\n }\n\n // Create new init object with merged headers\n const newInit: RequestInit = {\n ...init,\n headers,\n };\n\n return originalFetch(input, newInit);\n };\n\n window.fetch = patchedFetch;\n\n // Patch XMLHttpRequest\n // We need to patch setRequestHeader to inject the header when needed\n const originalXHROpen = XMLHttpRequest.prototype.open;\n const originalXHRSend = XMLHttpRequest.prototype.send;\n const originalSetRequestHeader =\n XMLHttpRequest.prototype.setRequestHeader;\n\n XMLHttpRequest.prototype.open = function (\n method: string,\n url: string | URL,\n ...rest: unknown[]\n ) {\n // Store the URL for use later\n const urlString = typeof url === \"string\" ? url : url.href;\n (this as XMLHttpRequest & { _interfereUrl?: string })._interfereUrl =\n urlString;\n\n // Call original - XMLHttpRequest.open accepts 2-5 parameters\n // biome-ignore lint/suspicious/noExplicitAny: XMLHttpRequest.open has variable arity\n return (originalXHROpen as any).call(this, method, url, ...rest);\n };\n\n XMLHttpRequest.prototype.setRequestHeader = function (\n name: string,\n value: string\n ) {\n const url = (this as XMLHttpRequest & { _interfereUrl?: string })\n ._interfereUrl;\n\n // If this is a traced URL, inject our header\n if (url && shouldTraceUrl(url, tracingOrigins)) {\n // Get session ID synchronously for XHR\n const sessionId = getSessionIdSync();\n const requestId = generateRequestId();\n const headerValue = createRequestHeader(sessionId, requestId);\n\n // Set our header first if it hasn't been set\n if (\n !(this as XMLHttpRequest & { _interfereHeaderSet?: boolean })\n ._interfereHeaderSet\n ) {\n originalSetRequestHeader.call(\n this,\n X_INTERFERE_REQUEST_HEADER,\n headerValue\n );\n (\n this as XMLHttpRequest & { _interfereHeaderSet?: boolean }\n )._interfereHeaderSet = true;\n }\n }\n\n return originalSetRequestHeader.call(this, name, value);\n };\n\n XMLHttpRequest.prototype.send = function (\n body?: Document | XMLHttpRequestBodyInit | null\n ) {\n const url = (this as XMLHttpRequest & { _interfereUrl?: string })\n ._interfereUrl;\n\n // Ensure header is set if needed (fallback in case setRequestHeader wasn't called)\n if (\n url &&\n shouldTraceUrl(url, tracingOrigins) &&\n !(this as XMLHttpRequest & { _interfereHeaderSet?: boolean })\n ._interfereHeaderSet\n ) {\n const sessionId = getSessionIdSync();\n const requestId = generateRequestId();\n const headerValue = createRequestHeader(sessionId, requestId);\n originalSetRequestHeader.call(\n this,\n X_INTERFERE_REQUEST_HEADER,\n headerValue\n );\n (\n this as XMLHttpRequest & { _interfereHeaderSet?: boolean }\n )._interfereHeaderSet = true;\n }\n\n return originalXHRSend.call(this, body);\n };\n\n return {\n key: \"serverTracing\",\n cleanup: () => {\n ctx.log.debug(\"serverTracing: removing patches\");\n\n window.fetch = originalFetch;\n XMLHttpRequest.prototype.open = originalXHROpen;\n XMLHttpRequest.prototype.send = originalXHRSend;\n XMLHttpRequest.prototype.setRequestHeader = originalSetRequestHeader;\n },\n };\n }),\n});\n"],"mappings":"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"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { AnyEventDefinition, EventDefinitionFor, EventSchemas, EventsForPlugin } from "../events/plugin-event-types.mjs";
|
|
2
|
-
import { Plugin, PluginContext } from "../schemas.mjs";
|
|
3
|
-
import { Effect } from "effect";
|
|
4
|
-
import { PluginKey } from "@interfere/types/sdk/plugins/lib/types";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
|
|
7
|
-
//#region src/core/plugins/plugin-event-system.d.ts
|
|
8
|
-
type SetupResult = {
|
|
9
|
-
api?: object;
|
|
10
|
-
cleanup?: () => void;
|
|
11
|
-
} | undefined;
|
|
12
|
-
declare function createPlugin<TKey extends PluginKey>(key: TKey, config: {
|
|
13
|
-
name: string;
|
|
14
|
-
events?: readonly Extract<AnyEventDefinition, {
|
|
15
|
-
type: EventsForPlugin<TKey>;
|
|
16
|
-
}>[];
|
|
17
|
-
setup: (ctx: PluginContext) => SetupResult | Promise<SetupResult>;
|
|
18
|
-
}): Plugin<TKey, unknown>;
|
|
19
|
-
declare function createEffectPlugin<TKey extends PluginKey>(key: TKey, config: {
|
|
20
|
-
name: string;
|
|
21
|
-
events?: readonly Extract<AnyEventDefinition, {
|
|
22
|
-
type: EventsForPlugin<TKey>;
|
|
23
|
-
}>[];
|
|
24
|
-
setup: (ctx: PluginContext) => Effect.Effect<{
|
|
25
|
-
api?: object;
|
|
26
|
-
cleanup?: () => void;
|
|
27
|
-
} | undefined, never>;
|
|
28
|
-
}): Plugin<TKey, unknown>;
|
|
29
|
-
declare function createEffectPlugin<TKey extends PluginKey, TConfig>(key: TKey, config: {
|
|
30
|
-
name: string;
|
|
31
|
-
events?: readonly Extract<AnyEventDefinition, {
|
|
32
|
-
type: EventsForPlugin<TKey>;
|
|
33
|
-
}>[];
|
|
34
|
-
config: TConfig;
|
|
35
|
-
setup: (ctx: PluginContext, config: TConfig) => Effect.Effect<{
|
|
36
|
-
api?: object;
|
|
37
|
-
cleanup?: () => void;
|
|
38
|
-
} | undefined, never>;
|
|
39
|
-
}): Plugin<TKey, unknown>;
|
|
40
|
-
type FinalEventDefinition<T extends keyof EventSchemas> = EventDefinitionFor<T>;
|
|
41
|
-
declare function defineEvent<T extends keyof EventSchemas>(type: T): {
|
|
42
|
-
enrich: (v?: boolean) => EventDefinitionFor<T>;
|
|
43
|
-
transform: <TOut>(fn: (input: z.infer<EventSchemas[T]>) => TOut) => EventDefinitionFor<T>;
|
|
44
|
-
value: () => EventDefinitionFor<T>;
|
|
45
|
-
};
|
|
46
|
-
//#endregion
|
|
47
|
-
export { FinalEventDefinition, createEffectPlugin, createPlugin, defineEvent };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-event-system.d.mts","names":[],"sources":["../../../src/core/plugins/plugin-event-system.ts"],"sourcesContent":[],"mappings":";;;;;;;KAiBK,WAAA;;EAAA,OAAA,CAAA,EAAA,GAAA,GAAW,IAAA;AAOhB,CAAA,GAAgB,SAAA;AAA0B,iBAA1B,YAA0B,CAAA,aAAA,SAAA,CAAA,CAAA,GAAA,EACnC,IADmC,EAAA,MAAA,EAAA;EACnC,IAAA,EAAA,MAAA;EAID,MAAA,CAAA,EAAA,SADgB,OAChB,CAAA,kBAAA,EAAA;IACwB,IAAA,EAAhB,eAAgB,CAAA,IAAA,CAAA;EAAhB,CAAA,CAAA,EAAA;EAFQ,KAAA,EAAA,CAAA,GAAA,EAIL,aAJK,EAAA,GAIa,WAJb,GAI2B,OAJ3B,CAImC,WAJnC,CAAA;CAIL,CAAA,EAEd,MAFc,CAEP,IAFO,EAAA,OAAA,CAAA;AAAkB,iBA8BnB,kBA9BmB,CAAA,aA8Ba,SA9Bb,CAAA,CAAA,GAAA,EA+B5B,IA/B4B,EAAA,MAAA,EAAA;EAAsB,IAAA,EAAA,MAAA;EAAR,MAAA,CAAA,EAAA,SAkC3B,OAlC2B,CAmC3C,kBAnC2C,EAAA;IAEvC,IAAA,EAkCI,eAlCJ,CAkCoB,IAlCpB,CAAA;EAAP,CAAA,CAAA,EAAA;EAAM,KAAA,EAAA,CAAA,GAAA,EAoCQ,aApCR,EAAA,GAoC0B,MAAA,CAAW,MApCrC,CAAA;IA4BO,GAAA,CAAA,EAAA,MAAA;IAAgC,OAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EACzC,CAAA,GAAA,SAAA,EAAA,KAAA,CAAA;CAID,CAAA,EAYH,MAZG,CAYI,IAZJ,EAAA,OAAA,CAAA;AACwB,iBAad,kBAbc,CAAA,aAakB,SAblB,EAAA,OAAA,CAAA,CAAA,GAAA,EAcvB,IAduB,EAAA,MAAA,EAAA;EAAhB,IAAA,EAAA,MAAA;EAFQ,MAAA,CAAA,EAAA,SAmBA,OAnBA,CAoBhB,kBApBgB,EAAA;IAIL,IAAA,EAiBH,eAjBG,CAiBa,IAjBb,CAAA;EAAkB,CAAA,CAAA,EAAW;EASpC,MAAA,EAUE,OAVF;EAAP,KAAA,EAAA,CAAA,GAAA,EAYQ,aAZR,EAAA,MAAA,EAaW,OAbX,EAAA,GAcM,MAAA,CAAW,MAdjB,CAAA;IAAM,GAAA,CAAA,EAAA,MAAA;IAEO,OAAA,CAAA,EAAA,GAAA,GAAA,IAAkB;EAAc,CAAA,GAAA,SAAA,EAAA,KAAA,CAAA;CACzC,CAAA,EAoBJ,MApBI,CAoBG,IApBH,EAAA,OAAA,CAAA;AAID,KA2DM,oBA3DN,CAAA,UAAA,MA2D2C,YA3D3C,CAAA,GA4DJ,kBA5DI,CA4De,CA5Df,CAAA;AACwB,iBA0Fd,WA1Fc,CAAA,UAAA,MA0Fc,YA1Fd,CAAA,CAAA,IAAA,EA0FkC,CA1FlC,CAAA,EAAA;EAAhB,MAAA,EAAA,CAAA,CAAA,CAAA,EAAA,OAAA,EAAA,GA8FU,kBA9FV,CA8FU,CA9FV,CAAA;EAFQ,SAAA,EAAA,CAAA,IAAA,CAAA,CAAA,EAAA,EAAA,CAAA,KAAA,EAiGY,CAAA,CAAE,KAjGd,CAiGoB,YAjGpB,CAiGiC,CAjGjC,CAAA,CAAA,EAAA,GAiGyC,IAjGzC,EAAA,GAiG6C,kBAjG7C,CAiG6C,CAjG7C,CAAA;EAIV,KAAA,EAAA,GAAA,qBAAA,EAAA,CAAA;CAED"}
|