@agent-native/core 0.98.3 → 0.98.5
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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +29 -0
- package/corpus/core/docs/content/durable-background-runs.mdx +37 -0
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +4 -2
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
- package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +2 -0
- package/corpus/core/docs/content/tracking.mdx +2 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/durable-background.ts +16 -16
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +25 -8
- package/corpus/core/src/agent/engine/anthropic-engine.ts +17 -3
- package/corpus/core/src/agent/engine/output-tokens.ts +6 -6
- package/corpus/core/src/agent/production-agent.ts +200 -27
- package/corpus/core/src/agent/run-manager.ts +81 -1
- package/corpus/core/src/agent/run-store.ts +301 -41
- package/corpus/core/src/client/AgentPanel.tsx +6 -2
- package/corpus/core/src/client/AssistantChat.tsx +364 -69
- package/corpus/core/src/client/agent-chat-adapter.ts +169 -1
- package/corpus/core/src/client/analytics.ts +12 -0
- package/corpus/core/src/client/chat/message-components.tsx +3 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +20 -36
- package/corpus/core/src/client/conversation/use-near-bottom-autoscroll.ts +7 -0
- package/corpus/core/src/client/extensions/AgentNativeExtensionFrame.tsx +2 -0
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +2 -0
- package/corpus/core/src/client/extensions/ExtensionEditor.tsx +9 -2
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +2 -0
- package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +2 -0
- package/corpus/core/src/client/extensions/portable-extension.ts +2 -0
- package/corpus/core/src/client/session-replay.ts +971 -53
- package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -3
- package/corpus/core/src/client/sse-event-processor.ts +43 -1
- package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
- package/corpus/core/src/demo/config.ts +6 -6
- package/corpus/core/src/demo/fetch-interceptor.ts +34 -2
- package/corpus/core/src/demo/redact.ts +71 -158
- package/corpus/core/src/extensions/html-shell.ts +3 -0
- package/corpus/core/src/extensions/session-replay-iframe.ts +131 -0
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +1 -20
- package/corpus/core/src/session-replay-iframe-protocol.ts +58 -0
- package/corpus/core/src/shared/reasoning-effort.ts +35 -0
- package/corpus/core/src/styles/agent-conversation.css +26 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +67 -16
- package/corpus/templates/analytics/AGENTS.md +12 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-events.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +1 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +1 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -1
- package/corpus/templates/analytics/app/global.css +6 -64
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +41 -4
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +143 -121
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +34 -12
- package/corpus/templates/analytics/changelog/2026-07-12-analytics-chat-retries-before-showing-a-generic-no-data-mess.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-analytics-sessions-search-no-longer-loses-fast-keystrokes-an.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-chart-selection-respects-chat-state.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-anonymizes-error-reporting-emails.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-fixed-session-replays-that-appeared-ultra-wide-hid-recorded-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-session-replays-load-faster-in-demo-mode-while-visitor-email.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-session-replays-show-iframe-content.md +6 -0
- package/corpus/templates/analytics/netlify.toml +0 -3
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +14 -0
- package/corpus/templates/analytics/server/lib/error-capture.ts +59 -2
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +24 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +2 -9
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +39 -6
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/brain/app/global.css +2 -2
- package/corpus/templates/brain/changelog/2026-07-12-fix-long-response-progress.md +6 -0
- package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +11 -2
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +14 -2
- package/corpus/templates/calendar/changelog/2026-07-12-calendar-responses-can-now-be-saved-with-command-enter-or-ct.md +6 -0
- package/corpus/templates/forms/app/components/CloudUpgrade.tsx +1 -1
- package/corpus/templates/forms/app/components/ThemeToggle.tsx +22 -6
- package/corpus/templates/forms/app/components/builder/FieldPropertiesPanel.tsx +5 -5
- package/corpus/templates/forms/app/components/builder/FieldRenderer.tsx +3 -3
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +16 -16
- package/corpus/templates/forms/app/global.css +110 -5
- package/corpus/templates/forms/app/pages/AskPage.tsx +3 -3
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +134 -52
- package/corpus/templates/forms/app/pages/FormFillPage.tsx +44 -11
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +42 -24
- package/corpus/templates/forms/app/pages/ResponseInsightsPage.tsx +28 -15
- package/corpus/templates/forms/app/pages/ResponsesPage.tsx +38 -15
- package/corpus/templates/forms/app/routes/_app.settings.tsx +1 -1
- package/corpus/templates/forms/changelog/2026-07-12-form-builder-surfaces-are-calmer-fields-stay-stable-on-hover.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-12-smoother-more-tactile-controls-throughout-animated-icon-and-.md +6 -0
- package/corpus/templates/mail/app/components/email/EmailThread.tsx +21 -13
- package/corpus/templates/mail/app/components/email/email-iframe-document.ts +18 -0
- package/dist/agent/durable-background.d.ts +10 -10
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +16 -16
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +19 -8
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/anthropic-engine.js +11 -3
- package/dist/agent/engine/anthropic-engine.js.map +1 -1
- package/dist/agent/engine/output-tokens.js +6 -6
- package/dist/agent/engine/output-tokens.js.map +1 -1
- package/dist/agent/production-agent.d.ts +52 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +154 -26
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +9 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +71 -1
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +9 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +243 -48
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +6 -2
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +21 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +298 -67
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +146 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +11 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +2 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +3 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +13 -37
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts +1 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
- package/dist/client/conversation/use-near-bottom-autoscroll.js +6 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.d.ts.map +1 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.js +2 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +2 -1
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionEditor.js +5 -2
- package/dist/client/extensions/ExtensionEditor.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +2 -1
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.js +2 -1
- package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
- package/dist/client/extensions/portable-extension.d.ts.map +1 -1
- package/dist/client/extensions/portable-extension.js +2 -0
- package/dist/client/extensions/portable-extension.js.map +1 -1
- package/dist/client/session-replay.d.ts +12 -3
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +793 -49
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/DemoModeSection.js +1 -1
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +5 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +37 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/demo/actions/toggle-demo-mode.js +2 -2
- package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
- package/dist/demo/config.js +6 -6
- package/dist/demo/config.js.map +1 -1
- package/dist/demo/fetch-interceptor.d.ts +1 -0
- package/dist/demo/fetch-interceptor.d.ts.map +1 -1
- package/dist/demo/fetch-interceptor.js +28 -2
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/demo/redact.d.ts +14 -7
- package/dist/demo/redact.d.ts.map +1 -1
- package/dist/demo/redact.js +27 -155
- package/dist/demo/redact.js.map +1 -1
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +2 -0
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/session-replay-iframe.d.ts +10 -0
- package/dist/extensions/session-replay-iframe.d.ts.map +1 -0
- package/dist/extensions/session-replay-iframe.js +121 -0
- package/dist/extensions/session-replay-iframe.js.map +1 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +1 -19
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/session-replay-iframe-protocol.d.ts +36 -0
- package/dist/session-replay-iframe-protocol.d.ts.map +1 -0
- package/dist/session-replay-iframe-protocol.js +24 -0
- package/dist/session-replay-iframe-protocol.js.map +1 -0
- package/dist/shared/reasoning-effort.d.ts +11 -0
- package/dist/shared/reasoning-effort.d.ts.map +1 -1
- package/dist/shared/reasoning-effort.js +36 -0
- package/dist/shared/reasoning-effort.js.map +1 -1
- package/dist/styles/agent-conversation.css +26 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/docs/content/durable-background-runs.mdx +37 -0
- package/docs/content/locales/ar-SA/tracking.mdx +2 -0
- package/docs/content/locales/de-DE/tracking.mdx +2 -0
- package/docs/content/locales/es-ES/tracking.mdx +2 -0
- package/docs/content/locales/fr-FR/tracking.mdx +4 -2
- package/docs/content/locales/hi-IN/tracking.mdx +2 -0
- package/docs/content/locales/ja-JP/tracking.mdx +2 -0
- package/docs/content/locales/ko-KR/tracking.mdx +2 -0
- package/docs/content/locales/pt-BR/tracking.mdx +2 -0
- package/docs/content/locales/zh-CN/tracking.mdx +2 -0
- package/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
- package/docs/content/locales/zh-TW/tracking.mdx +2 -0
- package/docs/content/tracking.mdx +2 -0
- package/package.json +2 -2
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/corpus/core/src/observability/hosted-model-experiment.ts +0 -118
- package/dist/observability/hosted-model-experiment.d.ts +0 -39
- package/dist/observability/hosted-model-experiment.d.ts.map +0 -1
- package/dist/observability/hosted-model-experiment.js +0 -90
- package/dist/observability/hosted-model-experiment.js.map +0 -1
|
@@ -166,11 +166,6 @@ type ReplayViewportChange = ReplayViewportDimensions & {
|
|
|
166
166
|
|
|
167
167
|
const DEFAULT_PLAYER_WIDTH = 1024;
|
|
168
168
|
const DEFAULT_PLAYER_HEIGHT = 640;
|
|
169
|
-
const MALFORMED_REPLAY_MIN_WIDTH = 4000;
|
|
170
|
-
const MALFORMED_REPLAY_MIN_ASPECT_RATIO = 4;
|
|
171
|
-
const MIN_REPLAY_DISPLAY_DIMENSION = 240;
|
|
172
|
-
const RECOVERED_REPLAY_DISPLAY_ASPECT_RATIO =
|
|
173
|
-
DEFAULT_PLAYER_WIDTH / DEFAULT_PLAYER_HEIGHT;
|
|
174
169
|
const DEFAULT_SPEED = 2;
|
|
175
170
|
const SPEED_OPTIONS = [0.5, 1, 2, 4, 8];
|
|
176
171
|
const SKIP_STEP_MS = 5000;
|
|
@@ -186,10 +181,14 @@ const MIN_STAGE_HEIGHT_PX = 240;
|
|
|
186
181
|
const SCRUBBER_MARKER_LIMIT = 500;
|
|
187
182
|
const TIMELINE_MARKER_LIMIT = 300;
|
|
188
183
|
const TIMELINE_FOLLOW_PAUSE_MS = 4000;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
184
|
+
const REPLAY_CLOCK_UPDATE_INTERVAL_MS = 100;
|
|
185
|
+
/**
|
|
186
|
+
* Keep captured overlays intact. Toasts and snackbars are product feedback,
|
|
187
|
+
* not recorder chrome, and can be essential to understanding the session.
|
|
188
|
+
* The recorder does not inject notification UI into the recorded document, so
|
|
189
|
+
* blanket selectors (including Sonner's data attributes) are not justified.
|
|
190
|
+
*/
|
|
191
|
+
export const REPLAY_OVERLAY_STYLE_RULES: string[] = [];
|
|
193
192
|
type ReplayConsoleDiagnostics = ReturnType<
|
|
194
193
|
typeof extractReplayDiagnostics
|
|
195
194
|
>["console"];
|
|
@@ -235,11 +234,13 @@ const RRWEB_EVENT_TYPE = {
|
|
|
235
234
|
|
|
236
235
|
const INCREMENTAL_SOURCE = {
|
|
237
236
|
Mutation: 0,
|
|
237
|
+
MouseMove: 1,
|
|
238
238
|
MouseInteraction: 2,
|
|
239
239
|
Scroll: 3,
|
|
240
240
|
ViewportResize: 4,
|
|
241
241
|
Input: 5,
|
|
242
242
|
TouchMove: 6,
|
|
243
|
+
Drag: 12,
|
|
243
244
|
} as const;
|
|
244
245
|
|
|
245
246
|
const MOUSE_INTERACTION = {
|
|
@@ -480,6 +481,7 @@ function ReplayPlayer({
|
|
|
480
481
|
const stageRootRef = useRef<HTMLDivElement>(null);
|
|
481
482
|
const replayerRef = useRef<any>(null);
|
|
482
483
|
const rafRef = useRef<number | null>(null);
|
|
484
|
+
const lastClockUpdateAtRef = useRef<number | null>(null);
|
|
483
485
|
const [status, setStatus] = useState<ReplayPlayerStatus>("idle");
|
|
484
486
|
const [error, setError] = useState<string | null>(null);
|
|
485
487
|
const [playing, setPlaying] = useState(false);
|
|
@@ -497,7 +499,7 @@ function ReplayPlayer({
|
|
|
497
499
|
} | null>(null);
|
|
498
500
|
const [fitScale, setFitScale] = useState(1);
|
|
499
501
|
const initialDims = useMemo(
|
|
500
|
-
() =>
|
|
502
|
+
() => replayInitialViewportDimensions(events),
|
|
501
503
|
[events],
|
|
502
504
|
);
|
|
503
505
|
const viewportTimeline = useMemo(
|
|
@@ -519,16 +521,14 @@ function ReplayPlayer({
|
|
|
519
521
|
const scrubbingRef = useRef(false);
|
|
520
522
|
const scrubResumePlayingRef = useRef(false);
|
|
521
523
|
|
|
522
|
-
//
|
|
523
|
-
//
|
|
524
|
-
//
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
const
|
|
530
|
-
const playerWidth = displayDims?.width ?? DEFAULT_PLAYER_WIDTH;
|
|
531
|
-
const playerHeight = displayDims?.height ?? DEFAULT_PLAYER_HEIGHT;
|
|
524
|
+
// Fall back to the default player size only when the viewport is unknown;
|
|
525
|
+
// otherwise render the raw recorded dimensions untouched. See the Replayer
|
|
526
|
+
// construction below for why "recovery" heuristics were removed here.
|
|
527
|
+
const displayDims = resolveReplayDisplayDimensions(
|
|
528
|
+
streamedDims ?? initialDims,
|
|
529
|
+
);
|
|
530
|
+
const playerWidth = displayDims.width;
|
|
531
|
+
const playerHeight = displayDims.height;
|
|
532
532
|
const skipRanges = useMemo(() => buildIdleSkipRanges(events), [events]);
|
|
533
533
|
const skipRangesRef = useLiveRef(skipRanges);
|
|
534
534
|
const skipInactiveRef = useLiveRef(skipInactive);
|
|
@@ -624,10 +624,16 @@ function ReplayPlayer({
|
|
|
624
624
|
|
|
625
625
|
const updateTime = useCallback(
|
|
626
626
|
(next: number) => {
|
|
627
|
+
if (!Number.isFinite(next) || next === currentTimeRef.current) return;
|
|
628
|
+
// Keep the live value in sync before React commits. The animation clock
|
|
629
|
+
// can run again while React is still processing the previous render;
|
|
630
|
+
// relying on useLiveRef's effect here republishes the same value and can
|
|
631
|
+
// create a nested update loop in development.
|
|
632
|
+
currentTimeRef.current = next;
|
|
627
633
|
setCurrentTime(next);
|
|
628
634
|
onTimeUpdate(next);
|
|
629
635
|
},
|
|
630
|
-
[onTimeUpdate],
|
|
636
|
+
[currentTimeRef, onTimeUpdate],
|
|
631
637
|
);
|
|
632
638
|
|
|
633
639
|
const seek = useCallback(
|
|
@@ -652,18 +658,16 @@ function ReplayPlayer({
|
|
|
652
658
|
clamped,
|
|
653
659
|
);
|
|
654
660
|
if (seekDims) {
|
|
655
|
-
// rrweb 2.1 does not reliably re-emit
|
|
656
|
-
//
|
|
657
|
-
//
|
|
658
|
-
const correctedSeekDims = clampReplayDisplayDimensions(seekDims);
|
|
661
|
+
// rrweb 2.1 does not reliably re-emit its resize event when seeking
|
|
662
|
+
// backwards, so mirror the raw viewport-timeline lookup onto both
|
|
663
|
+
// rrweb's iframe and the outer stage state to keep them in sync.
|
|
659
664
|
const currentDims = streamedDimsRef.current;
|
|
660
665
|
if (
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
currentDims?.height !== correctedSeekDims.height)
|
|
666
|
+
currentDims?.width !== seekDims.width ||
|
|
667
|
+
currentDims?.height !== seekDims.height
|
|
664
668
|
) {
|
|
665
|
-
replayer.handleResize?.(
|
|
666
|
-
setStreamedDims(
|
|
669
|
+
replayer.handleResize?.(seekDims);
|
|
670
|
+
setStreamedDims(seekDims);
|
|
667
671
|
}
|
|
668
672
|
}
|
|
669
673
|
updateTime(clamped);
|
|
@@ -709,27 +713,17 @@ function ReplayPlayer({
|
|
|
709
713
|
let localReplayer: any = null;
|
|
710
714
|
|
|
711
715
|
async function loadReplay() {
|
|
712
|
-
// Wait for the full recording before creating the Replayer. Progressive
|
|
713
|
-
// chunk publishes used to rebuild the player on every append, which
|
|
714
|
-
// reset the clock, disabled the scrubber, and desynced the playhead.
|
|
715
716
|
const replayEvents = eventsRef.current;
|
|
717
|
+
// Replayer construction remains all-or-nothing. Progressive response
|
|
718
|
+
// publishes update loading progress only; rebuilding during download
|
|
719
|
+
// rewinds the player and can desync the scrubber/playhead.
|
|
716
720
|
if (!response.isComplete) {
|
|
717
721
|
setStatus("loading");
|
|
718
722
|
setError(null);
|
|
719
723
|
setPlaying(false);
|
|
720
724
|
return;
|
|
721
725
|
}
|
|
722
|
-
if (replayEvents.length < 2) {
|
|
723
|
-
throw new Error(t("sessions.noReplayEvents"));
|
|
724
|
-
}
|
|
725
|
-
if (
|
|
726
|
-
!replayEvents.some(
|
|
727
|
-
(event) => event.type === RRWEB_EVENT_TYPE.FullSnapshot,
|
|
728
|
-
)
|
|
729
|
-
) {
|
|
730
|
-
throw new Error(t("sessions.noReplayEvents"));
|
|
731
|
-
}
|
|
732
|
-
if (!hasPlayableReplayEvents(replayEvents)) {
|
|
726
|
+
if (replayEvents.length < 2 || !hasPlayableReplayEvents(replayEvents)) {
|
|
733
727
|
throw new Error(t("sessions.noReplayEvents"));
|
|
734
728
|
}
|
|
735
729
|
setStatus("loading");
|
|
@@ -739,35 +733,30 @@ function ReplayPlayer({
|
|
|
739
733
|
if (cancelled || !stageRootRef.current) return;
|
|
740
734
|
|
|
741
735
|
stageRootRef.current.innerHTML = "";
|
|
742
|
-
//
|
|
743
|
-
//
|
|
744
|
-
//
|
|
745
|
-
//
|
|
746
|
-
//
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
736
|
+
// Viewport and pointer events must pass through to rrweb untouched.
|
|
737
|
+
// The 2026-07 "ultra-wide replay" bugs (e.g. a stored 1,152px-wide
|
|
738
|
+
// recording rendering as a 4,491px Meta width) were caused by demo
|
|
739
|
+
// mode's fetch redaction faking numbers >= 1000 in raw replay JSON at
|
|
740
|
+
// view time, not by malformed stored geometry — fixed in
|
|
741
|
+
// packages/core/src/demo/fetch-interceptor.ts. Stored recordings were
|
|
742
|
+
// always sane, so never add viewport "recovery" heuristics here; they
|
|
743
|
+
// can only corrupt genuine recordings (e.g. a real ultrawide window).
|
|
744
|
+
setStreamedDims(replayInitialViewportDimensions(replayEvents));
|
|
745
|
+
// Keep this loosely typed: our internal AnyReplayEvent shape doesn't
|
|
746
|
+
// exactly match rrweb's declared eventWithTime type.
|
|
750
747
|
localReplayer = new Replayer(replayEvents as any[], {
|
|
751
748
|
root: stageRootRef.current,
|
|
752
749
|
speed: speedRef.current,
|
|
753
750
|
skipInactive: false,
|
|
754
751
|
showWarning: false,
|
|
755
752
|
showDebug: false,
|
|
756
|
-
triggerFocus: false,
|
|
757
753
|
mouseTail: false,
|
|
758
|
-
|
|
754
|
+
// Match stock rrweb/builder-internal focus replay. Disabling focus
|
|
755
|
+
// drops recorded focus-visible state and can leave menus/forms looking
|
|
756
|
+
// unlike the source page even when the snapshot CSS is correct.
|
|
757
|
+
triggerFocus: true,
|
|
758
|
+
insertStyleRules: REPLAY_OVERLAY_STYLE_RULES,
|
|
759
759
|
});
|
|
760
|
-
// IMPORTANT: rrweb constructs its iframe from the raw initial Meta event.
|
|
761
|
-
// When that legacy Meta width is malformed, correcting only streamedDims
|
|
762
|
-
// fixes the outer stage but leaves CSS breakpoints and clicks ultra-wide.
|
|
763
|
-
// Apply the same correction to rrweb immediately, before first playback.
|
|
764
|
-
if (
|
|
765
|
-
correctedInitialDims &&
|
|
766
|
-
(rawInitialDims?.width !== correctedInitialDims.width ||
|
|
767
|
-
rawInitialDims?.height !== correctedInitialDims.height)
|
|
768
|
-
) {
|
|
769
|
-
localReplayer.handleResize?.(correctedInitialDims);
|
|
770
|
-
}
|
|
771
760
|
// rrweb already sandboxes the replay document without script execution.
|
|
772
761
|
// Do not mutate recorded URLs/CSS; suppress viewer-page referrer leakage
|
|
773
762
|
// at the iframe boundary while retaining historical visual resources.
|
|
@@ -800,25 +789,17 @@ function ReplayPlayer({
|
|
|
800
789
|
width: Math.round(dims.width),
|
|
801
790
|
height: Math.round(dims.height),
|
|
802
791
|
};
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
//
|
|
806
|
-
// impossible legacy geometry so its iframe and our stage stay equal.
|
|
807
|
-
// DO NOT clamp just one layer; that breaks responsive CSS and clicks.
|
|
792
|
+
// rrweb owns its iframe geometry from raw Meta/ViewportResize
|
|
793
|
+
// events. Only mirror the raw dims into React state here, for the
|
|
794
|
+
// outer stage's fit-to-container scaling.
|
|
808
795
|
const currentDims = streamedDimsRef.current;
|
|
809
796
|
if (
|
|
810
|
-
currentDims?.width ===
|
|
811
|
-
currentDims?.height ===
|
|
797
|
+
currentDims?.width === rawDims.width &&
|
|
798
|
+
currentDims?.height === rawDims.height
|
|
812
799
|
) {
|
|
813
800
|
return;
|
|
814
801
|
}
|
|
815
|
-
|
|
816
|
-
correctedDims.width !== rawDims.width ||
|
|
817
|
-
correctedDims.height !== rawDims.height
|
|
818
|
-
) {
|
|
819
|
-
localReplayer.handleResize?.(correctedDims);
|
|
820
|
-
}
|
|
821
|
-
setStreamedDims(correctedDims);
|
|
802
|
+
setStreamedDims(rawDims);
|
|
822
803
|
}
|
|
823
804
|
});
|
|
824
805
|
updateTime(startAt);
|
|
@@ -851,6 +832,7 @@ function ReplayPlayer({
|
|
|
851
832
|
try {
|
|
852
833
|
localReplayer?.pause?.();
|
|
853
834
|
localReplayer?.destroy?.();
|
|
835
|
+
replayerRef.current?.pause?.();
|
|
854
836
|
replayerRef.current?.destroy?.();
|
|
855
837
|
} catch {
|
|
856
838
|
// rrweb cleanup is best-effort across versions.
|
|
@@ -858,9 +840,6 @@ function ReplayPlayer({
|
|
|
858
840
|
replayerRef.current = null;
|
|
859
841
|
if (stageRootRef.current) stageRootRef.current.innerHTML = "";
|
|
860
842
|
};
|
|
861
|
-
// Key only on isComplete + a stable events identity. Including the events
|
|
862
|
-
// array reference would rebuild the Replayer when the final publish()
|
|
863
|
-
// replaces the chunks object even though the event set is unchanged.
|
|
864
843
|
}, [
|
|
865
844
|
currentTimeRef,
|
|
866
845
|
eventsIdentity,
|
|
@@ -875,10 +854,11 @@ function ReplayPlayer({
|
|
|
875
854
|
if (!playing || status !== "ready") {
|
|
876
855
|
if (rafRef.current != null) cancelAnimationFrame(rafRef.current);
|
|
877
856
|
rafRef.current = null;
|
|
857
|
+
lastClockUpdateAtRef.current = null;
|
|
878
858
|
return;
|
|
879
859
|
}
|
|
880
860
|
|
|
881
|
-
const tick = () => {
|
|
861
|
+
const tick = (frameTime: number) => {
|
|
882
862
|
const replayer = replayerRef.current;
|
|
883
863
|
if (replayer && !scrubbingRef.current) {
|
|
884
864
|
let nextTime = Number(
|
|
@@ -901,7 +881,17 @@ function ReplayPlayer({
|
|
|
901
881
|
}
|
|
902
882
|
}
|
|
903
883
|
}
|
|
904
|
-
if (
|
|
884
|
+
if (
|
|
885
|
+
shouldPublishReplayClockUpdate(
|
|
886
|
+
lastClockUpdateAtRef.current,
|
|
887
|
+
frameTime,
|
|
888
|
+
currentTimeRef.current,
|
|
889
|
+
nextTime,
|
|
890
|
+
)
|
|
891
|
+
) {
|
|
892
|
+
lastClockUpdateAtRef.current = frameTime;
|
|
893
|
+
updateTime(nextTime);
|
|
894
|
+
}
|
|
905
895
|
}
|
|
906
896
|
rafRef.current = requestAnimationFrame(tick);
|
|
907
897
|
};
|
|
@@ -910,6 +900,7 @@ function ReplayPlayer({
|
|
|
910
900
|
return () => {
|
|
911
901
|
if (rafRef.current != null) cancelAnimationFrame(rafRef.current);
|
|
912
902
|
rafRef.current = null;
|
|
903
|
+
lastClockUpdateAtRef.current = null;
|
|
913
904
|
};
|
|
914
905
|
}, [
|
|
915
906
|
currentTimeRef,
|
|
@@ -995,6 +986,10 @@ function ReplayPlayer({
|
|
|
995
986
|
/>
|
|
996
987
|
<button
|
|
997
988
|
type="button"
|
|
989
|
+
// IMPORTANT: Keep the viewer's real OS pointer visible while
|
|
990
|
+
// the synthetic rrweb pointer replays underneath it. Hiding
|
|
991
|
+
// this during playback makes the page feel broken whenever
|
|
992
|
+
// the viewer moves their mouse over the full-stage control.
|
|
998
993
|
className="absolute inset-0 z-20 cursor-pointer rounded-[inherit] border-0 bg-transparent p-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-default"
|
|
999
994
|
disabled={disabled}
|
|
1000
995
|
aria-label={
|
|
@@ -2169,9 +2164,7 @@ export function buildIdleSkipRanges(events: AnyReplayEvent[]): SkipRange[] {
|
|
|
2169
2164
|
const timestamp = Number(event.timestamp ?? 0);
|
|
2170
2165
|
if (!Number.isFinite(timestamp) || timestamp <= 0) continue;
|
|
2171
2166
|
lastTimestamp = Math.max(lastTimestamp, timestamp);
|
|
2172
|
-
|
|
2173
|
-
interactions.push(timestamp);
|
|
2174
|
-
}
|
|
2167
|
+
interactions.push(...replayActivityTimestamps(event, timestamp));
|
|
2175
2168
|
}
|
|
2176
2169
|
interactions.sort((a, b) => a - b);
|
|
2177
2170
|
const ranges: SkipRange[] = [];
|
|
@@ -2194,22 +2187,42 @@ export function buildIdleSkipRanges(events: AnyReplayEvent[]): SkipRange[] {
|
|
|
2194
2187
|
return ranges;
|
|
2195
2188
|
}
|
|
2196
2189
|
|
|
2197
|
-
function
|
|
2198
|
-
|
|
2199
|
-
|
|
2190
|
+
function replayActivityTimestamps(
|
|
2191
|
+
event: AnyReplayEvent,
|
|
2192
|
+
timestamp: number,
|
|
2193
|
+
): number[] {
|
|
2194
|
+
if (event.type === RRWEB_EVENT_TYPE.Meta) return [timestamp];
|
|
2195
|
+
if (event.type !== RRWEB_EVENT_TYPE.IncrementalSnapshot) return [];
|
|
2200
2196
|
|
|
2201
2197
|
const source = event.data?.source;
|
|
2198
|
+
if (
|
|
2199
|
+
source === INCREMENTAL_SOURCE.MouseMove ||
|
|
2200
|
+
source === INCREMENTAL_SOURCE.TouchMove ||
|
|
2201
|
+
source === INCREMENTAL_SOURCE.Drag
|
|
2202
|
+
) {
|
|
2203
|
+
const positions = Array.isArray(event.data?.positions)
|
|
2204
|
+
? event.data.positions
|
|
2205
|
+
: [];
|
|
2206
|
+
// IMPORTANT: rrweb batches pointer positions and schedules each one at
|
|
2207
|
+
// event.timestamp + timeOffset. Treat those exact moments as activity.
|
|
2208
|
+
// Ignoring the batch made Skip inactivity jump across visible movement,
|
|
2209
|
+
// which looked like a frozen cursor even though the recording was intact.
|
|
2210
|
+
return positions.flatMap((position: unknown) => {
|
|
2211
|
+
if (!isRecord(position)) return [];
|
|
2212
|
+
const timeOffset = Number(position.timeOffset ?? 0);
|
|
2213
|
+
return [timestamp + (Number.isFinite(timeOffset) ? timeOffset : 0)];
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2202
2216
|
if (
|
|
2203
2217
|
source === INCREMENTAL_SOURCE.Input ||
|
|
2204
|
-
source === INCREMENTAL_SOURCE.Scroll
|
|
2205
|
-
source === INCREMENTAL_SOURCE.TouchMove
|
|
2218
|
+
source === INCREMENTAL_SOURCE.Scroll
|
|
2206
2219
|
) {
|
|
2207
|
-
return
|
|
2220
|
+
return [timestamp];
|
|
2208
2221
|
}
|
|
2209
|
-
if (source !== INCREMENTAL_SOURCE.MouseInteraction) return
|
|
2222
|
+
if (source !== INCREMENTAL_SOURCE.MouseInteraction) return [];
|
|
2210
2223
|
|
|
2211
2224
|
const interactionType = event.data?.type;
|
|
2212
|
-
return
|
|
2225
|
+
return [
|
|
2213
2226
|
interactionType === MOUSE_INTERACTION.MouseUp ||
|
|
2214
2227
|
interactionType === MOUSE_INTERACTION.MouseDown ||
|
|
2215
2228
|
interactionType === MOUSE_INTERACTION.Click ||
|
|
@@ -2218,7 +2231,9 @@ function isReplayActivityEvent(event: AnyReplayEvent): boolean {
|
|
|
2218
2231
|
interactionType === MOUSE_INTERACTION.Focus ||
|
|
2219
2232
|
interactionType === MOUSE_INTERACTION.TouchStart ||
|
|
2220
2233
|
interactionType === MOUSE_INTERACTION.TouchEnd
|
|
2221
|
-
|
|
2234
|
+
? timestamp
|
|
2235
|
+
: null,
|
|
2236
|
+
].filter((value): value is number => value !== null);
|
|
2222
2237
|
}
|
|
2223
2238
|
|
|
2224
2239
|
function pushIdleRange(
|
|
@@ -2291,14 +2306,6 @@ export function replayInitialViewportDimensions(
|
|
|
2291
2306
|
return null;
|
|
2292
2307
|
}
|
|
2293
2308
|
|
|
2294
|
-
export function replayInitialDisplayDimensions(
|
|
2295
|
-
events: AnyReplayEvent[],
|
|
2296
|
-
): ReplayViewportDimensions | null {
|
|
2297
|
-
// Keep the initial outer stage and rrweb iframe on one corrected camera.
|
|
2298
|
-
// DO NOT use the raw initial Meta dimensions for only one of those layers.
|
|
2299
|
-
return clampReplayDisplayDimensions(replayInitialViewportDimensions(events));
|
|
2300
|
-
}
|
|
2301
|
-
|
|
2302
2309
|
export function buildReplayViewportTimeline(
|
|
2303
2310
|
events: AnyReplayEvent[],
|
|
2304
2311
|
): ReplayViewportChange[] {
|
|
@@ -2384,27 +2391,28 @@ export function normalizeReplayDimensions(
|
|
|
2384
2391
|
};
|
|
2385
2392
|
}
|
|
2386
2393
|
|
|
2387
|
-
|
|
2394
|
+
/**
|
|
2395
|
+
* Fall back to the default player size only when the viewport is entirely
|
|
2396
|
+
* unknown (no Meta/ViewportResize event yet). This is not a "recovery"
|
|
2397
|
+
* heuristic for real recorded geometry — it never rewrites valid dims, no
|
|
2398
|
+
* matter how wide, narrow, or unusual the aspect ratio. See the Replayer
|
|
2399
|
+
* construction in ReplayPlayer for why viewport "correction" was removed:
|
|
2400
|
+
* the 2026-07 ultra-wide replay bugs were caused by demo mode's fetch
|
|
2401
|
+
* redaction faking numbers at view time, not by malformed stored geometry.
|
|
2402
|
+
*/
|
|
2403
|
+
export function resolveReplayDisplayDimensions(
|
|
2388
2404
|
dims: ReplayViewportDimensions | null,
|
|
2389
|
-
): ReplayViewportDimensions
|
|
2390
|
-
if (!dims) return null;
|
|
2405
|
+
): ReplayViewportDimensions {
|
|
2391
2406
|
if (
|
|
2392
|
-
dims
|
|
2393
|
-
dims.
|
|
2407
|
+
dims &&
|
|
2408
|
+
Number.isFinite(dims.width) &&
|
|
2409
|
+
Number.isFinite(dims.height) &&
|
|
2410
|
+
dims.width > 0 &&
|
|
2411
|
+
dims.height > 0
|
|
2394
2412
|
) {
|
|
2395
|
-
return
|
|
2413
|
+
return dims;
|
|
2396
2414
|
}
|
|
2397
|
-
|
|
2398
|
-
if (
|
|
2399
|
-
dims.width >= MALFORMED_REPLAY_MIN_WIDTH &&
|
|
2400
|
-
aspect > MALFORMED_REPLAY_MIN_ASPECT_RATIO
|
|
2401
|
-
) {
|
|
2402
|
-
return {
|
|
2403
|
-
width: Math.round(dims.height * RECOVERED_REPLAY_DISPLAY_ASPECT_RATIO),
|
|
2404
|
-
height: dims.height,
|
|
2405
|
-
};
|
|
2406
|
-
}
|
|
2407
|
-
return dims;
|
|
2415
|
+
return { width: DEFAULT_PLAYER_WIDTH, height: DEFAULT_PLAYER_HEIGHT };
|
|
2408
2416
|
}
|
|
2409
2417
|
|
|
2410
2418
|
export function filterReplayMarkers(
|
|
@@ -2563,6 +2571,20 @@ function clamp(value: number, min: number, max: number): number {
|
|
|
2563
2571
|
return Math.min(max, Math.max(min, value));
|
|
2564
2572
|
}
|
|
2565
2573
|
|
|
2574
|
+
export function shouldPublishReplayClockUpdate(
|
|
2575
|
+
lastUpdateAt: number | null,
|
|
2576
|
+
frameTime: number,
|
|
2577
|
+
currentTime: number,
|
|
2578
|
+
nextTime: number,
|
|
2579
|
+
): boolean {
|
|
2580
|
+
if (!Number.isFinite(frameTime) || !Number.isFinite(nextTime)) return false;
|
|
2581
|
+
if (nextTime === currentTime) return false;
|
|
2582
|
+
return (
|
|
2583
|
+
lastUpdateAt == null ||
|
|
2584
|
+
frameTime - lastUpdateAt >= REPLAY_CLOCK_UPDATE_INTERVAL_MS
|
|
2585
|
+
);
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2566
2588
|
function isRecord(value: unknown): value is AnyRecord {
|
|
2567
2589
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2568
2590
|
}
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
IconSettings,
|
|
22
22
|
} from "@tabler/icons-react";
|
|
23
23
|
import { useQuery } from "@tanstack/react-query";
|
|
24
|
-
import { useMemo, useState } from "react";
|
|
24
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
25
25
|
import { Link, useNavigate, useSearchParams } from "react-router";
|
|
26
26
|
import { toast } from "sonner";
|
|
27
27
|
|
|
@@ -167,6 +167,7 @@ type SessionRecordingIdentity = Pick<
|
|
|
167
167
|
type SessionRecordingDevice = Pick<SessionRecordingSummary, "metadata">;
|
|
168
168
|
|
|
169
169
|
const RANGE_OPTIONS: ReplayRange[] = ["24h", "7d", "30d", "90d", "all"];
|
|
170
|
+
const SESSION_QUERY_DEBOUNCE_MS = 250;
|
|
170
171
|
|
|
171
172
|
export default function SessionsPage() {
|
|
172
173
|
const t = useT();
|
|
@@ -175,8 +176,38 @@ export default function SessionsPage() {
|
|
|
175
176
|
const range = readRange(searchParams.get("range"));
|
|
176
177
|
const app = searchParams.get("app") ?? "";
|
|
177
178
|
const query = searchParams.get("q") ?? "";
|
|
179
|
+
const [queryInput, setQueryInput] = useState(query);
|
|
178
180
|
const from = useMemo(() => rangeToFrom(range), [range]);
|
|
179
181
|
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
setQueryInput(query);
|
|
184
|
+
}, [query]);
|
|
185
|
+
|
|
186
|
+
const updateFilter = useCallback(
|
|
187
|
+
(key: string, value: string) => {
|
|
188
|
+
setSearchParams(
|
|
189
|
+
(current) => {
|
|
190
|
+
const next = new URLSearchParams(current);
|
|
191
|
+
const emptyDefault =
|
|
192
|
+
(key === "range" && value === "30d") || value.trim() === "";
|
|
193
|
+
if (emptyDefault) next.delete(key);
|
|
194
|
+
else next.set(key, value);
|
|
195
|
+
return next;
|
|
196
|
+
},
|
|
197
|
+
{ replace: true },
|
|
198
|
+
);
|
|
199
|
+
},
|
|
200
|
+
[setSearchParams],
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
if (queryInput === query) return;
|
|
205
|
+
const timeout = window.setTimeout(() => {
|
|
206
|
+
updateFilter("q", queryInput);
|
|
207
|
+
}, SESSION_QUERY_DEBOUNCE_MS);
|
|
208
|
+
return () => window.clearTimeout(timeout);
|
|
209
|
+
}, [query, queryInput, updateFilter]);
|
|
210
|
+
|
|
180
211
|
const { data, isLoading, isFetching, refetch, error } = useActionQuery<
|
|
181
212
|
SessionRecordingSummary[]
|
|
182
213
|
>(
|
|
@@ -192,15 +223,6 @@ export default function SessionsPage() {
|
|
|
192
223
|
|
|
193
224
|
const recordings = data ?? [];
|
|
194
225
|
|
|
195
|
-
function updateFilter(key: string, value: string) {
|
|
196
|
-
const next = new URLSearchParams(searchParams);
|
|
197
|
-
const emptyDefault =
|
|
198
|
-
(key === "range" && value === "30d") || value.trim() === "";
|
|
199
|
-
if (emptyDefault) next.delete(key);
|
|
200
|
-
else next.set(key, value);
|
|
201
|
-
setSearchParams(next, { replace: true });
|
|
202
|
-
}
|
|
203
|
-
|
|
204
226
|
return (
|
|
205
227
|
<div className="analytics-sessions-page mx-auto flex w-full max-w-7xl flex-col gap-4 px-4 py-5">
|
|
206
228
|
<Card>
|
|
@@ -213,8 +235,8 @@ export default function SessionsPage() {
|
|
|
213
235
|
<div className="analytics-sessions-filter-search relative min-w-0">
|
|
214
236
|
<IconSearch className="pointer-events-none absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
|
215
237
|
<Input
|
|
216
|
-
value={
|
|
217
|
-
onChange={(event) =>
|
|
238
|
+
value={queryInput}
|
|
239
|
+
onChange={(event) => setQueryInput(event.target.value)}
|
|
218
240
|
placeholder={t("sessions.searchPlaceholder")}
|
|
219
241
|
className="h-9 ps-9"
|
|
220
242
|
/>
|
|
@@ -9,14 +9,11 @@ GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
|
|
|
9
9
|
NITRO_PRESET = "netlify"
|
|
10
10
|
NPM_CONFIG_PRODUCTION = "false"
|
|
11
11
|
AGENT_PROD_CODE_EXECUTION = "sandboxed"
|
|
12
|
-
AGENT_CHAT_DURABLE_BACKGROUND = "true"
|
|
13
12
|
|
|
14
13
|
# A2A delegation calls run a full agent loop (LLM + tool calls + DB queries).
|
|
15
14
|
# Hosted agent chat uses a soft timeout before this function timeout so the
|
|
16
15
|
# hidden auto-continuation path can hand off before Netlify kills the function.
|
|
17
16
|
# If AGENT_RUN_SOFT_TIMEOUT_MS is customized, keep it below this timeout.
|
|
18
|
-
# Agent chat runs are dispatched to the emitted Netlify background function;
|
|
19
|
-
# the normal server timeout still protects non-background HTTP handlers.
|
|
20
17
|
[functions."*"]
|
|
21
18
|
timeout = 75
|
|
22
19
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deliberately small authenticated MCP surface for Analytics.
|
|
3
|
+
*
|
|
4
|
+
* Keep this list read-only and incident-focused. In particular, do not add
|
|
5
|
+
* replay-event/blob actions or dashboard/data mutation actions here.
|
|
6
|
+
*/
|
|
7
|
+
export const ANALYTICS_CONNECTOR_CATALOG = [
|
|
8
|
+
"list-session-recordings",
|
|
9
|
+
"get-session-replay-summary",
|
|
10
|
+
"get-session-replay-events",
|
|
11
|
+
"query-agent-native-analytics",
|
|
12
|
+
"list-error-issues",
|
|
13
|
+
"get-error-issue",
|
|
14
|
+
] as const;
|