@agent-native/core 0.90.11 → 0.91.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +34 -0
- package/corpus/core/docs/content/toolkit-settings.mdx +56 -3
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/agent/run-ownership.ts +29 -1
- package/corpus/core/src/changelog/parse.ts +78 -0
- package/corpus/core/src/chat-threads/schema.ts +43 -0
- package/corpus/core/src/chat-threads/store.ts +144 -12
- package/corpus/core/src/cli/design-connect.ts +53 -9
- package/corpus/core/src/cli/workspace-dev.ts +25 -5
- package/corpus/core/src/client/AgentPanel.tsx +79 -14
- package/corpus/core/src/client/AssistantChat.tsx +359 -425
- package/corpus/core/src/client/analytics-session.ts +70 -0
- package/corpus/core/src/client/analytics.ts +175 -49
- package/corpus/core/src/client/chat/message-components.tsx +22 -2
- package/corpus/core/src/client/components/ui/message-scroller.tsx +131 -0
- package/corpus/core/src/client/conversation/AgentConversation.tsx +63 -41
- package/corpus/core/src/client/error-capture.ts +616 -0
- package/corpus/core/src/client/index.ts +12 -0
- package/corpus/core/src/client/session-replay.ts +57 -7
- package/corpus/core/src/client/settings/SettingsPanel.tsx +123 -1
- package/corpus/core/src/client/settings/SettingsTabsPage.tsx +292 -45
- package/corpus/core/src/client/settings/index.ts +1 -0
- package/corpus/core/src/client/sharing/ShareButton.tsx +14 -11
- package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -10
- package/corpus/core/src/mcp/builtin-tools.ts +29 -2
- package/corpus/core/src/server/agent-chat-plugin.ts +174 -79
- package/corpus/core/src/server/onboarding-html.ts +28 -16
- package/corpus/core/src/sharing/actions/list-resource-shares.ts +45 -1
- package/corpus/core/src/sharing/actions/share-resource.ts +9 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
- package/corpus/core/src/vite/client.ts +217 -35
- package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +8 -7
- package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +14 -10
- package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +15 -15
- package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -22
- package/corpus/templates/analytics/.agents/skills/data-programs/SKILL.md +114 -61
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +7 -7
- package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +1 -1
- package/corpus/templates/analytics/.builder/skills/bigquery/SKILL.md +17 -17
- package/corpus/templates/analytics/.builder/skills/gcloud/SKILL.md +5 -5
- package/corpus/templates/analytics/.builder/skills/github/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/gong/SKILL.md +12 -12
- package/corpus/templates/analytics/.builder/skills/grafana/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/sentry/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/slack/SKILL.md +6 -6
- package/corpus/templates/analytics/.builder/skills/stripe/SKILL.md +7 -7
- package/corpus/templates/analytics/AGENTS.md +47 -2
- package/corpus/templates/analytics/actions/add-status-page-monitor.ts +36 -0
- package/corpus/templates/analytics/actions/capture-test-error.ts +33 -0
- package/corpus/templates/analytics/actions/delete-monitor.ts +24 -0
- package/corpus/templates/analytics/actions/delete-status-page.ts +23 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +36 -0
- package/corpus/templates/analytics/actions/get-monitor-stats.ts +55 -0
- package/corpus/templates/analytics/actions/get-monitor.ts +27 -0
- package/corpus/templates/analytics/actions/get-public-status-page.ts +41 -0
- package/corpus/templates/analytics/actions/get-status-page.ts +29 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +40 -0
- package/corpus/templates/analytics/actions/list-monitors.ts +21 -0
- package/corpus/templates/analytics/actions/list-status-pages.ts +21 -0
- package/corpus/templates/analytics/actions/match-error-issues.ts +51 -0
- package/corpus/templates/analytics/actions/navigate.ts +58 -4
- package/corpus/templates/analytics/actions/remove-status-page-monitor.ts +22 -0
- package/corpus/templates/analytics/actions/reorder-status-page-monitors.ts +25 -0
- package/corpus/templates/analytics/actions/resolve-error-issue.ts +38 -0
- package/corpus/templates/analytics/actions/run-monitor-check.ts +23 -0
- package/corpus/templates/analytics/actions/save-analysis.ts +1 -0
- package/corpus/templates/analytics/actions/save-monitor.ts +145 -0
- package/corpus/templates/analytics/actions/save-status-page.ts +47 -0
- package/corpus/templates/analytics/actions/view-screen.ts +212 -0
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +10 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +134 -39
- package/corpus/templates/analytics/app/components/monitoring/PublicStatusView.tsx +351 -0
- package/corpus/templates/analytics/app/components/monitoring/ResponseTimeChart.tsx +174 -0
- package/corpus/templates/analytics/app/components/monitoring/UptimeStatCards.tsx +85 -0
- package/corpus/templates/analytics/app/components/monitoring/UptimeTimelineBars.tsx +106 -0
- package/corpus/templates/analytics/app/components/monitoring/chart-utils.ts +101 -0
- package/corpus/templates/analytics/app/components/monitoring/index.ts +28 -0
- package/corpus/templates/analytics/app/components/monitoring/types.ts +42 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +34 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -0
- package/corpus/templates/analytics/app/i18n-data.ts +33 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +77 -9
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +7 -0
- package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +205 -0
- package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +100 -0
- package/corpus/templates/analytics/app/pages/monitoring/UptimePanel.tsx +475 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +372 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +360 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/Sparkline.tsx +55 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +106 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +75 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/utils.ts +132 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +535 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +1026 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorList.tsx +311 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +235 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPageEditor.tsx +661 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPagesView.tsx +355 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/i18n.ts +106 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/slug.ts +24 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/types.ts +20 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-summary.ts +87 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +161 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/utils.ts +210 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +76 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +74 -9
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +197 -20
- package/corpus/templates/analytics/app/root.tsx +33 -1
- package/corpus/templates/analytics/app/routes/monitoring._index.tsx +10 -0
- package/corpus/templates/analytics/app/routes/status.$slug.tsx +118 -0
- package/corpus/templates/analytics/changelog/2026-07-08-add-uptime-monitors-that-ping-your-urls-and-alert-you-when-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-analytics-chats-keep-large-data-dictionaries-compact-so-prov.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-create-public-status-pages-that-share-the-live-health-of-cho.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-extension-panels-use-clearer-open-copy.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-error-capture.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-fixed-single-panel-dashboard-drags-so-they-no-longer-rewrite.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-jump-straight-from-an-error-in-a-session-recording-to-its-fu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-monitor-detail-and-list-now-show-colorful-uptime-timelines-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-pinned-ask-chats-now-show-a-pin-icon-in-the-sidebar.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-publish-a-public-uptime-status-page-with-colorful-uptime-tim.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sessions-now-hide-visitor-emails-in-demo-mode-and-show-clean.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-the-uptime-monitor-list-now-has-a-current-status-overview-wi.md +6 -0
- package/corpus/templates/analytics/docs/error-capture.md +172 -0
- package/corpus/templates/analytics/docs/uptime-monitoring.md +150 -0
- package/corpus/templates/analytics/server/db/schema-errors.ts +150 -0
- package/corpus/templates/analytics/server/db/schema-monitoring.ts +177 -0
- package/corpus/templates/analytics/server/db/schema.ts +6 -0
- package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +123 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +41 -0
- package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +55 -12
- package/corpus/templates/analytics/server/lib/error-capture.ts +1331 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +47 -1
- package/corpus/templates/analytics/server/lib/monitor-stats.ts +494 -0
- package/corpus/templates/analytics/server/lib/status-pages.ts +798 -0
- package/corpus/templates/analytics/server/lib/uptime-monitors.ts +1665 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -37
- package/corpus/templates/analytics/server/plugins/auth.ts +11 -1
- package/corpus/templates/analytics/server/plugins/db.ts +408 -0
- package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +63 -0
- package/corpus/templates/assets/app/routes/_index.tsx +1 -1
- package/corpus/templates/assets/app/routes/settings.tsx +22 -1
- package/corpus/templates/assets/changelog/2026-07-08-recent-drafts-keep-comfortable-side-padding.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/brain/app/routes/settings.tsx +43 -5
- package/corpus/templates/brain/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +44 -6
- package/corpus/templates/calendar/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/chat/app/routes/settings.tsx +16 -1
- package/corpus/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +79 -37
- package/corpus/templates/clips/app/components/player/player-controls.tsx +35 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +162 -18
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +63 -6
- package/corpus/templates/clips/app/routes/record.tsx +18 -1
- package/corpus/templates/clips/changelog/2026-07-07-shared-clips-start-playback-reliably-from-the-first-play-click.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-camera-and-microphone-menus-now-show-which-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-copies-new-clip-links-after-saving.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-recordings-now-continue-after-granting-came.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-mobile-shared-clips-now-have-loom-style-tap-and-skip-controls.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-recordings-and-uploads-copy-links-after-saving.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-settings-are-cleaner-searchable-and-collapse-s3-with-builder.md +5 -0
- package/corpus/templates/clips/changelog/2026-07-08-transcripts-are-more-reliable-for-longer-desktop-recordings-.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +162 -13
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +14 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +36 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +99 -25
- package/corpus/templates/clips/chrome-extension/src/permission.ts +63 -14
- package/corpus/templates/clips/chrome-extension/src/popup.ts +123 -23
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +47 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +33 -4
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +214 -29
- package/corpus/templates/content/actions/attach-content-database-source.ts +3 -0
- package/corpus/templates/content/actions/change-content-database-source-role.ts +1 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +42 -32
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +352 -81
- package/corpus/templates/content/app/components/editor/database/settings.tsx +49 -24
- package/corpus/templates/content/app/routes/_app.settings.tsx +19 -1
- package/corpus/templates/content/changelog/2026-07-07-builder-source-tag-fields-now-import-as-multi-select.md +6 -0
- package/corpus/templates/content/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/content/shared/api.ts +3 -0
- package/corpus/templates/content/shared/properties.ts +42 -0
- package/corpus/templates/design/AGENTS.md +9 -0
- package/corpus/templates/design/actions/generate-design.ts +3 -0
- package/corpus/templates/design/actions/get-design-system.ts +147 -1
- package/corpus/templates/design/actions/request-localhost-write-consent.ts +141 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +13 -19
- package/corpus/templates/design/app/routes/settings.tsx +16 -1
- package/corpus/templates/design/changelog/2026-07-08-design-generation-now-follows-hydrated-builder-design-system.md +6 -0
- package/corpus/templates/design/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/design/server/lib/verify-write-grant.ts +4 -2
- package/corpus/templates/dispatch/app/routes/settings.tsx +23 -2
- package/corpus/templates/dispatch/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/forms/app/routes/_app.settings.tsx +16 -1
- package/corpus/templates/forms/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/macros/app/routes/settings.tsx +16 -1
- package/corpus/templates/macros/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/mail/app/components/settings/GmailFiltersSection.tsx +1 -1
- package/corpus/templates/mail/app/components/settings/SnippetsSection.tsx +1 -1
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +123 -105
- package/corpus/templates/mail/changelog/2026-07-08-settings-redesigned-with-a-consistent-searchable-layout.md +5 -0
- package/corpus/templates/plan/app/routes/settings.tsx +23 -2
- package/corpus/templates/plan/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/slides/actions/add-slide.ts +1 -0
- package/corpus/templates/slides/actions/get-design-system.ts +147 -1
- package/corpus/templates/slides/app/pages/Index.tsx +46 -1
- package/corpus/templates/slides/app/routes/settings.tsx +16 -1
- package/corpus/templates/slides/changelog/2026-07-08-deck-generation-now-follows-hydrated-builder-design-system-g.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/dist/agent/run-ownership.d.ts +6 -0
- package/dist/agent/run-ownership.d.ts.map +1 -1
- package/dist/agent/run-ownership.js +11 -1
- package/dist/agent/run-ownership.js.map +1 -1
- package/dist/changelog/parse.d.ts +7 -0
- package/dist/changelog/parse.d.ts.map +1 -1
- package/dist/changelog/parse.js +64 -0
- package/dist/changelog/parse.js.map +1 -1
- package/dist/chat-threads/schema.d.ts +445 -0
- package/dist/chat-threads/schema.d.ts.map +1 -0
- package/dist/chat-threads/schema.js +39 -0
- package/dist/chat-threads/schema.js.map +1 -0
- package/dist/chat-threads/store.d.ts +12 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +99 -10
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +40 -10
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts.map +1 -1
- package/dist/cli/workspace-dev.js +20 -5
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +35 -7
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +105 -183
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/analytics-session.d.ts +3 -0
- package/dist/client/analytics-session.d.ts.map +1 -0
- package/dist/client/analytics-session.js +66 -0
- package/dist/client/analytics-session.js.map +1 -0
- package/dist/client/analytics.d.ts +32 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +116 -46
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +2 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +16 -6
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/components/ui/message-scroller.d.ts +16 -0
- package/dist/client/components/ui/message-scroller.d.ts.map +1 -0
- package/dist/client/components/ui/message-scroller.js +25 -0
- package/dist/client/components/ui/message-scroller.js.map +1 -0
- package/dist/client/conversation/AgentConversation.d.ts +1 -1
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/client/conversation/AgentConversation.js +3 -8
- package/dist/client/conversation/AgentConversation.js.map +1 -1
- package/dist/client/error-capture.d.ts +99 -0
- package/dist/client/error-capture.d.ts.map +1 -0
- package/dist/client/error-capture.js +437 -0
- package/dist/client/error-capture.js.map +1 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +22 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +45 -4
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +100 -5
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/SettingsTabsPage.d.ts +49 -1
- package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
- package/dist/client/settings/SettingsTabsPage.js +131 -19
- package/dist/client/settings/SettingsTabsPage.js.map +1 -1
- package/dist/client/settings/index.d.ts +1 -1
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +13 -8
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/client/sharing/ShareDialog.js +12 -7
- package/dist/client/sharing/ShareDialog.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +21 -2
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/org/schema.d.ts +15 -15
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +109 -73
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +28 -16
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.js +30 -1
- package/dist/sharing/actions/list-resource-shares.js.map +1 -1
- package/dist/sharing/actions/share-resource.js +6 -0
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +192 -30
- package/dist/vite/client.js.map +1 -1
- package/docs/content/toolkit-settings.mdx +56 -3
- package/package.json +2 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export type ExceptionLevel = "fatal" | "error" | "warning" | "info" | "debug";
|
|
2
|
+
/** Extra Sentry-style context accepted by `captureException`. */
|
|
3
|
+
export interface CaptureExceptionContext {
|
|
4
|
+
/** Low-cardinality searchable tags. Values are coerced to strings. */
|
|
5
|
+
tags?: Record<string, string | number | boolean | null | undefined>;
|
|
6
|
+
/** Structured, higher-cardinality detail shown on the event. */
|
|
7
|
+
extra?: Record<string, unknown>;
|
|
8
|
+
/** Severity; defaults to "error". */
|
|
9
|
+
level?: ExceptionLevel;
|
|
10
|
+
}
|
|
11
|
+
export interface ExceptionBreadcrumb {
|
|
12
|
+
timestamp: string;
|
|
13
|
+
category: string;
|
|
14
|
+
message: string;
|
|
15
|
+
level?: ExceptionLevel;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Compact exception payload emitted to transport. Field names are the wire
|
|
19
|
+
* contract the analytics server ingest reads — keep them stable.
|
|
20
|
+
*/
|
|
21
|
+
export interface CapturedExceptionEvent {
|
|
22
|
+
/** Error class/name, e.g. "TypeError". "Message" for `captureMessage`. */
|
|
23
|
+
type: string;
|
|
24
|
+
message: string;
|
|
25
|
+
/** Raw (bounded, redacted) stack string; server parses it into frames. */
|
|
26
|
+
stack?: string;
|
|
27
|
+
/** False for uncaught/global errors, true for manually handled ones. */
|
|
28
|
+
handled: boolean;
|
|
29
|
+
level: ExceptionLevel;
|
|
30
|
+
/** ISO timestamp of the occurrence. */
|
|
31
|
+
occurredAt: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
release?: string;
|
|
34
|
+
environment?: string;
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
/** Client session replay id (localStorage) for replay linkage. */
|
|
37
|
+
sessionReplayId?: string;
|
|
38
|
+
anonymousId?: string;
|
|
39
|
+
breadcrumbs: ExceptionBreadcrumb[];
|
|
40
|
+
tags?: Record<string, string>;
|
|
41
|
+
extra?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
export interface InstallErrorCaptureOptions {
|
|
44
|
+
/** Transport for a captured exception. Must not throw. */
|
|
45
|
+
send: (event: CapturedExceptionEvent) => void;
|
|
46
|
+
/** Resolve current analytics/session-replay identifiers at capture time. */
|
|
47
|
+
getSessionContext?: () => {
|
|
48
|
+
sessionId?: string;
|
|
49
|
+
anonymousId?: string;
|
|
50
|
+
replayId?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Optional hook to also surface a manual capture on the session replay
|
|
54
|
+
* timeline. Only invoked for manual `captureException`/`captureMessage`;
|
|
55
|
+
* auto-captured global errors are already recorded by the replay recorder.
|
|
56
|
+
*/
|
|
57
|
+
emitReplayEvent?: (event: CapturedExceptionEvent) => void;
|
|
58
|
+
release?: string;
|
|
59
|
+
environment?: string;
|
|
60
|
+
/** Auto-capture `window.onerror`. Defaults to true. */
|
|
61
|
+
captureGlobalErrors?: boolean;
|
|
62
|
+
/** Auto-capture `unhandledrejection`. Defaults to true. */
|
|
63
|
+
captureUnhandledRejections?: boolean;
|
|
64
|
+
/** Breadcrumb ring buffer size. Defaults to 20. */
|
|
65
|
+
maxBreadcrumbs?: number;
|
|
66
|
+
/** Dedupe window (ms) for identical signatures. Defaults to 3000. */
|
|
67
|
+
dedupeWindowMs?: number;
|
|
68
|
+
}
|
|
69
|
+
/** Normalize any thrown value into a stable `{ type, message, stack }`. */
|
|
70
|
+
export declare function normalizeCapturedError(error: unknown): {
|
|
71
|
+
type: string;
|
|
72
|
+
message: string;
|
|
73
|
+
stack?: string;
|
|
74
|
+
};
|
|
75
|
+
/** Append a privacy-safe breadcrumb to the bounded ring buffer. */
|
|
76
|
+
export declare function addErrorBreadcrumb(breadcrumb: {
|
|
77
|
+
category: string;
|
|
78
|
+
message: string;
|
|
79
|
+
level?: ExceptionLevel;
|
|
80
|
+
}): void;
|
|
81
|
+
/**
|
|
82
|
+
* Capture a handled exception. Mirrors Sentry's `captureException(err, ctx)`.
|
|
83
|
+
* Safe to call before `configureTracking` has run — it simply no-ops if no
|
|
84
|
+
* transport is installed yet.
|
|
85
|
+
*/
|
|
86
|
+
export declare function captureException(error: unknown, context?: CaptureExceptionContext): void;
|
|
87
|
+
/**
|
|
88
|
+
* Capture a message string as an exception-like event. Mirrors Sentry's
|
|
89
|
+
* `captureMessage(message, level?)`.
|
|
90
|
+
*/
|
|
91
|
+
export declare function captureMessage(message: string, level?: ExceptionLevel): void;
|
|
92
|
+
/**
|
|
93
|
+
* Install auto-capture + wire the transport. Idempotent: re-invoking updates
|
|
94
|
+
* the config (and (re)installs global handlers) without duplicating listeners.
|
|
95
|
+
* Returns a disposer that removes the global handlers.
|
|
96
|
+
*/
|
|
97
|
+
export declare function installErrorCapture(options: InstallErrorCaptureOptions): () => void;
|
|
98
|
+
export declare function isErrorCaptureInstalled(): boolean;
|
|
99
|
+
//# sourceMappingURL=error-capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-capture.d.ts","sourceRoot":"","sources":["../../src/client/error-capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-party, Sentry-style browser error capture for the Agent Native
|
|
3
|
+
* analytics SDK.
|
|
4
|
+
*
|
|
5
|
+
* Two responsibilities:
|
|
6
|
+
* 1. Automatic capture of uncaught exceptions (`window.onerror`) and
|
|
7
|
+
* unhandled promise rejections (`unhandledrejection`).
|
|
8
|
+
* 2. A documented manual API — `captureException(error, context?)` and
|
|
9
|
+
* `captureMessage(message, level?)` — mirroring Sentry's ergonomics.
|
|
10
|
+
*
|
|
11
|
+
* Captured exceptions are handed to a `send` callback (wired by
|
|
12
|
+
* `configureTracking` to the first-party analytics `/track` ingest as a
|
|
13
|
+
* dedicated `$exception` event) and are tagged with the current analytics
|
|
14
|
+
* session id + session replay id so each error links back to the recording it
|
|
15
|
+
* happened in. Everything here is defensive: capture must never throw back into
|
|
16
|
+
* the host app, so every path is wrapped and failures are swallowed.
|
|
17
|
+
*
|
|
18
|
+
* Stack parsing and fingerprinting are intentionally done authoritatively on
|
|
19
|
+
* the server (see the analytics template's `server/lib/error-capture.ts`); the
|
|
20
|
+
* client sends a compact, bounded payload (type/message/raw stack/context) and
|
|
21
|
+
* the server normalizes + groups it. That keeps one tested source of truth for
|
|
22
|
+
* grouping instead of duplicating parser logic across the wire.
|
|
23
|
+
*/
|
|
24
|
+
import { scrubUrl } from "./url-scrub.js";
|
|
25
|
+
const MAX_MESSAGE_LENGTH = 1000;
|
|
26
|
+
const MAX_STACK_LENGTH = 8000;
|
|
27
|
+
const MAX_TAGS = 30;
|
|
28
|
+
const MAX_EXTRA_KEYS = 50;
|
|
29
|
+
const MAX_EXTRA_DEPTH = 4;
|
|
30
|
+
const MAX_EXTRA_OBJECT_KEYS = 20;
|
|
31
|
+
const MAX_EXTRA_ARRAY_ITEMS = 20;
|
|
32
|
+
const MAX_EXTRA_STRING_LENGTH = 2000;
|
|
33
|
+
const ERROR_CAPTURE_STATE_KEY = Symbol.for("agent-native.client.errorCapture");
|
|
34
|
+
// Reuse the same credential-looking redaction the replay capture uses so a
|
|
35
|
+
// stack/message that echoes a token never leaves the browser in the clear.
|
|
36
|
+
const SECRET_KEY_FRAGMENT = "(?:authorization|cookie|set[-_]?cookie|token|secret|password|passwd|pwd|api[-_]?key|apikey|session|credential)";
|
|
37
|
+
const BEARER_RE = /\b(bearer|basic)\s+[a-z0-9._~+/-]+=*/gi;
|
|
38
|
+
const UNQUOTED_SECRET_RE = new RegExp(`(["']?)([A-Za-z0-9_$.-]*${SECRET_KEY_FRAGMENT}[A-Za-z0-9_$.-]*)\\1(\\s*[:=]\\s*)([^"',\\s;}\\]]+)`, "gi");
|
|
39
|
+
const SECRET_KEY_RE = new RegExp(SECRET_KEY_FRAGMENT, "i");
|
|
40
|
+
function redactSecrets(value) {
|
|
41
|
+
return value
|
|
42
|
+
.replace(BEARER_RE, "$1 <redacted>")
|
|
43
|
+
.replace(UNQUOTED_SECRET_RE, "$1$2$1$3<redacted>");
|
|
44
|
+
}
|
|
45
|
+
function getRuntime() {
|
|
46
|
+
const g = globalThis;
|
|
47
|
+
if (!g[ERROR_CAPTURE_STATE_KEY]) {
|
|
48
|
+
g[ERROR_CAPTURE_STATE_KEY] = {
|
|
49
|
+
installed: false,
|
|
50
|
+
config: {
|
|
51
|
+
send: () => { },
|
|
52
|
+
captureGlobalErrors: true,
|
|
53
|
+
captureUnhandledRejections: true,
|
|
54
|
+
maxBreadcrumbs: 20,
|
|
55
|
+
dedupeWindowMs: 3000,
|
|
56
|
+
},
|
|
57
|
+
breadcrumbs: [],
|
|
58
|
+
recentSignatures: new Map(),
|
|
59
|
+
removeHandlers: null,
|
|
60
|
+
navigationInstalled: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return g[ERROR_CAPTURE_STATE_KEY];
|
|
64
|
+
}
|
|
65
|
+
function nowIso() {
|
|
66
|
+
return new Date().toISOString();
|
|
67
|
+
}
|
|
68
|
+
function truncate(value, max) {
|
|
69
|
+
return value.length > max ? value.slice(0, max) : value;
|
|
70
|
+
}
|
|
71
|
+
function currentUrl() {
|
|
72
|
+
try {
|
|
73
|
+
return scrubUrl(window.location.href);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Normalize any thrown value into a stable `{ type, message, stack }`. */
|
|
80
|
+
export function normalizeCapturedError(error) {
|
|
81
|
+
if (error instanceof Error) {
|
|
82
|
+
return {
|
|
83
|
+
type: error.name || "Error",
|
|
84
|
+
message: error.message || String(error),
|
|
85
|
+
stack: typeof error.stack === "string" ? error.stack : undefined,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (typeof error === "string") {
|
|
89
|
+
return { type: "Error", message: error };
|
|
90
|
+
}
|
|
91
|
+
if (error && typeof error === "object") {
|
|
92
|
+
const record = error;
|
|
93
|
+
const name = typeof record.name === "string" ? record.name : undefined;
|
|
94
|
+
const message = typeof record.message === "string" ? record.message : undefined;
|
|
95
|
+
const stack = typeof record.stack === "string" ? record.stack : undefined;
|
|
96
|
+
if (name || message || stack) {
|
|
97
|
+
return {
|
|
98
|
+
type: name || "Error",
|
|
99
|
+
message: message || safeStringify(error),
|
|
100
|
+
stack,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return { type: "Error", message: safeStringify(error) };
|
|
104
|
+
}
|
|
105
|
+
return { type: "Error", message: String(error) };
|
|
106
|
+
}
|
|
107
|
+
function safeStringify(value) {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.stringify(value) ?? String(value);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return String(value);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function coerceTags(tags) {
|
|
116
|
+
if (!tags)
|
|
117
|
+
return undefined;
|
|
118
|
+
const out = {};
|
|
119
|
+
let count = 0;
|
|
120
|
+
for (const [key, value] of Object.entries(tags)) {
|
|
121
|
+
if (count >= MAX_TAGS)
|
|
122
|
+
break;
|
|
123
|
+
if (value === undefined || value === null)
|
|
124
|
+
continue;
|
|
125
|
+
out[key] = truncate(redactSecrets(String(value)), 200);
|
|
126
|
+
count += 1;
|
|
127
|
+
}
|
|
128
|
+
return Object.keys(out).length ? out : undefined;
|
|
129
|
+
}
|
|
130
|
+
function coerceExtra(extra) {
|
|
131
|
+
if (!extra || typeof extra !== "object")
|
|
132
|
+
return undefined;
|
|
133
|
+
const out = {};
|
|
134
|
+
let count = 0;
|
|
135
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
136
|
+
if (count >= MAX_EXTRA_KEYS)
|
|
137
|
+
break;
|
|
138
|
+
const safeKey = truncate(redactSecrets(key), 100);
|
|
139
|
+
out[safeKey] = SECRET_KEY_RE.test(safeKey)
|
|
140
|
+
? "<redacted>"
|
|
141
|
+
: coerceExtraValue(value, MAX_EXTRA_DEPTH);
|
|
142
|
+
count += 1;
|
|
143
|
+
}
|
|
144
|
+
return Object.keys(out).length ? out : undefined;
|
|
145
|
+
}
|
|
146
|
+
function coerceExtraValue(value, depth) {
|
|
147
|
+
if (value == null ||
|
|
148
|
+
typeof value === "boolean" ||
|
|
149
|
+
typeof value === "number") {
|
|
150
|
+
return value;
|
|
151
|
+
}
|
|
152
|
+
if (typeof value === "string") {
|
|
153
|
+
return truncate(redactSecrets(value), MAX_EXTRA_STRING_LENGTH);
|
|
154
|
+
}
|
|
155
|
+
if (typeof value === "bigint") {
|
|
156
|
+
return truncate(redactSecrets(value.toString()), MAX_EXTRA_STRING_LENGTH);
|
|
157
|
+
}
|
|
158
|
+
if (depth <= 0) {
|
|
159
|
+
return truncate(redactSecrets(safeStringify(value)), MAX_EXTRA_STRING_LENGTH);
|
|
160
|
+
}
|
|
161
|
+
if (Array.isArray(value)) {
|
|
162
|
+
return value
|
|
163
|
+
.slice(0, MAX_EXTRA_ARRAY_ITEMS)
|
|
164
|
+
.map((item) => coerceExtraValue(item, depth - 1));
|
|
165
|
+
}
|
|
166
|
+
if (typeof value === "object") {
|
|
167
|
+
const out = {};
|
|
168
|
+
let count = 0;
|
|
169
|
+
for (const [rawKey, child] of Object.entries(value)) {
|
|
170
|
+
if (count >= MAX_EXTRA_OBJECT_KEYS)
|
|
171
|
+
break;
|
|
172
|
+
const key = truncate(redactSecrets(rawKey), 100);
|
|
173
|
+
out[key] = SECRET_KEY_RE.test(key)
|
|
174
|
+
? "<redacted>"
|
|
175
|
+
: coerceExtraValue(child, depth - 1);
|
|
176
|
+
count += 1;
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
return truncate(redactSecrets(String(value)), MAX_EXTRA_STRING_LENGTH);
|
|
181
|
+
}
|
|
182
|
+
function firstStackLine(stack) {
|
|
183
|
+
if (!stack)
|
|
184
|
+
return "";
|
|
185
|
+
const lines = stack.split("\n").map((line) => line.trim());
|
|
186
|
+
return (lines.find((line) => line.startsWith("at ") || /:\d+:\d+/.test(line)) ??
|
|
187
|
+
lines[1] ??
|
|
188
|
+
"");
|
|
189
|
+
}
|
|
190
|
+
/** Cheap client-side signature used only for local dedupe. */
|
|
191
|
+
function signatureOf(type, message, stack) {
|
|
192
|
+
return `${type}|${message}|${firstStackLine(stack)}`;
|
|
193
|
+
}
|
|
194
|
+
function shouldDedupe(runtime, signature) {
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
const windowMs = runtime.config.dedupeWindowMs;
|
|
197
|
+
// Opportunistic cleanup so the map can't grow without bound.
|
|
198
|
+
if (runtime.recentSignatures.size > 200) {
|
|
199
|
+
for (const [key, ts] of runtime.recentSignatures) {
|
|
200
|
+
if (now - ts > windowMs)
|
|
201
|
+
runtime.recentSignatures.delete(key);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const last = runtime.recentSignatures.get(signature);
|
|
205
|
+
runtime.recentSignatures.set(signature, now);
|
|
206
|
+
return last !== undefined && now - last < windowMs;
|
|
207
|
+
}
|
|
208
|
+
/** Append a privacy-safe breadcrumb to the bounded ring buffer. */
|
|
209
|
+
export function addErrorBreadcrumb(breadcrumb) {
|
|
210
|
+
try {
|
|
211
|
+
const runtime = getRuntime();
|
|
212
|
+
runtime.breadcrumbs.push({
|
|
213
|
+
timestamp: nowIso(),
|
|
214
|
+
category: truncate(breadcrumb.category, 60),
|
|
215
|
+
message: truncate(redactSecrets(breadcrumb.message), 300),
|
|
216
|
+
...(breadcrumb.level ? { level: breadcrumb.level } : {}),
|
|
217
|
+
});
|
|
218
|
+
const max = runtime.config.maxBreadcrumbs;
|
|
219
|
+
if (runtime.breadcrumbs.length > max) {
|
|
220
|
+
runtime.breadcrumbs.splice(0, runtime.breadcrumbs.length - max);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// breadcrumbs are best-effort
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function snapshotBreadcrumbs(runtime) {
|
|
228
|
+
return runtime.breadcrumbs.slice(-runtime.config.maxBreadcrumbs);
|
|
229
|
+
}
|
|
230
|
+
function installNavigationBreadcrumbs(runtime) {
|
|
231
|
+
if (runtime.navigationInstalled || typeof window === "undefined")
|
|
232
|
+
return;
|
|
233
|
+
runtime.navigationInstalled = true;
|
|
234
|
+
const record = (navType) => {
|
|
235
|
+
try {
|
|
236
|
+
addErrorBreadcrumb({
|
|
237
|
+
category: "navigation",
|
|
238
|
+
message: `${navType} ${scrubUrl(window.location.href) ?? window.location.pathname}`,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// ignore
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
try {
|
|
246
|
+
const originalPush = window.history.pushState;
|
|
247
|
+
const originalReplace = window.history.replaceState;
|
|
248
|
+
window.history.pushState = function pushState(...args) {
|
|
249
|
+
const result = originalPush.apply(this, args);
|
|
250
|
+
record("navigate");
|
|
251
|
+
return result;
|
|
252
|
+
};
|
|
253
|
+
window.history.replaceState = function replaceState(...args) {
|
|
254
|
+
const result = originalReplace.apply(this, args);
|
|
255
|
+
record("replace");
|
|
256
|
+
return result;
|
|
257
|
+
};
|
|
258
|
+
window.addEventListener("popstate", () => record("popstate"));
|
|
259
|
+
// Seed the trail with the initial location.
|
|
260
|
+
record("load");
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
// navigation breadcrumbs are best-effort
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function buildEvent(runtime, normalized, options) {
|
|
267
|
+
const context = runtime.config.getSessionContext?.() ?? {};
|
|
268
|
+
const stack = normalized.stack
|
|
269
|
+
? truncate(redactSecrets(normalized.stack), MAX_STACK_LENGTH)
|
|
270
|
+
: undefined;
|
|
271
|
+
return {
|
|
272
|
+
type: truncate(normalized.type || "Error", 200),
|
|
273
|
+
message: truncate(redactSecrets(normalized.message || ""), MAX_MESSAGE_LENGTH),
|
|
274
|
+
...(stack ? { stack } : {}),
|
|
275
|
+
handled: options.handled,
|
|
276
|
+
level: options.level,
|
|
277
|
+
occurredAt: nowIso(),
|
|
278
|
+
...(currentUrl() ? { url: currentUrl() } : {}),
|
|
279
|
+
...(runtime.config.release ? { release: runtime.config.release } : {}),
|
|
280
|
+
...(runtime.config.environment
|
|
281
|
+
? { environment: runtime.config.environment }
|
|
282
|
+
: {}),
|
|
283
|
+
...(context.sessionId ? { sessionId: context.sessionId } : {}),
|
|
284
|
+
...(context.replayId ? { sessionReplayId: context.replayId } : {}),
|
|
285
|
+
...(context.anonymousId ? { anonymousId: context.anonymousId } : {}),
|
|
286
|
+
breadcrumbs: snapshotBreadcrumbs(runtime),
|
|
287
|
+
...(options.tags ? { tags: options.tags } : {}),
|
|
288
|
+
...(options.extra ? { extra: options.extra } : {}),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function dispatch(runtime, event, emitToReplay) {
|
|
292
|
+
const signature = signatureOf(event.type, event.message, event.stack);
|
|
293
|
+
if (shouldDedupe(runtime, signature))
|
|
294
|
+
return;
|
|
295
|
+
try {
|
|
296
|
+
runtime.config.send(event);
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
// transport must never throw into the host app
|
|
300
|
+
}
|
|
301
|
+
if (emitToReplay) {
|
|
302
|
+
try {
|
|
303
|
+
runtime.config.emitReplayEvent?.(event);
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// replay timeline emission is best-effort
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// Record the exception itself as a breadcrumb so a following error carries
|
|
310
|
+
// the prior failure in its trail.
|
|
311
|
+
addErrorBreadcrumb({
|
|
312
|
+
category: "exception",
|
|
313
|
+
message: `${event.type}: ${event.message}`,
|
|
314
|
+
level: event.level,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Capture a handled exception. Mirrors Sentry's `captureException(err, ctx)`.
|
|
319
|
+
* Safe to call before `configureTracking` has run — it simply no-ops if no
|
|
320
|
+
* transport is installed yet.
|
|
321
|
+
*/
|
|
322
|
+
export function captureException(error, context = {}) {
|
|
323
|
+
try {
|
|
324
|
+
const runtime = getRuntime();
|
|
325
|
+
const normalized = normalizeCapturedError(error);
|
|
326
|
+
const event = buildEvent(runtime, normalized, {
|
|
327
|
+
handled: true,
|
|
328
|
+
level: context.level ?? "error",
|
|
329
|
+
tags: coerceTags(context.tags),
|
|
330
|
+
extra: coerceExtra(context.extra),
|
|
331
|
+
});
|
|
332
|
+
dispatch(runtime, event, true);
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
// never throw from capture
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Capture a message string as an exception-like event. Mirrors Sentry's
|
|
340
|
+
* `captureMessage(message, level?)`.
|
|
341
|
+
*/
|
|
342
|
+
export function captureMessage(message, level = "info") {
|
|
343
|
+
try {
|
|
344
|
+
const runtime = getRuntime();
|
|
345
|
+
const event = buildEvent(runtime, { type: "Message", message: String(message ?? "") }, { handled: true, level });
|
|
346
|
+
dispatch(runtime, event, true);
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
// never throw from capture
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Install auto-capture + wire the transport. Idempotent: re-invoking updates
|
|
354
|
+
* the config (and (re)installs global handlers) without duplicating listeners.
|
|
355
|
+
* Returns a disposer that removes the global handlers.
|
|
356
|
+
*/
|
|
357
|
+
export function installErrorCapture(options) {
|
|
358
|
+
const runtime = getRuntime();
|
|
359
|
+
runtime.config = {
|
|
360
|
+
...runtime.config,
|
|
361
|
+
...options,
|
|
362
|
+
captureGlobalErrors: options.captureGlobalErrors ?? true,
|
|
363
|
+
captureUnhandledRejections: options.captureUnhandledRejections ?? true,
|
|
364
|
+
maxBreadcrumbs: options.maxBreadcrumbs ?? runtime.config.maxBreadcrumbs,
|
|
365
|
+
dedupeWindowMs: options.dedupeWindowMs ?? runtime.config.dedupeWindowMs,
|
|
366
|
+
};
|
|
367
|
+
if (typeof window === "undefined")
|
|
368
|
+
return () => { };
|
|
369
|
+
installNavigationBreadcrumbs(runtime);
|
|
370
|
+
// Tear down any previously-installed handlers before reinstalling so a second
|
|
371
|
+
// configureTracking call doesn't double-report.
|
|
372
|
+
runtime.removeHandlers?.();
|
|
373
|
+
runtime.removeHandlers = null;
|
|
374
|
+
const removers = [];
|
|
375
|
+
if (runtime.config.captureGlobalErrors) {
|
|
376
|
+
const onError = (event) => {
|
|
377
|
+
try {
|
|
378
|
+
const error = event?.error;
|
|
379
|
+
const normalized = error
|
|
380
|
+
? normalizeCapturedError(error)
|
|
381
|
+
: {
|
|
382
|
+
type: "Error",
|
|
383
|
+
message: String(event?.message ?? "Uncaught error"),
|
|
384
|
+
};
|
|
385
|
+
// Global errors are already logged by the session replay recorder, so
|
|
386
|
+
// don't re-emit them onto the replay timeline (avoid double-counting).
|
|
387
|
+
dispatch(runtime, buildEvent(runtime, normalized, {
|
|
388
|
+
handled: false,
|
|
389
|
+
level: "error",
|
|
390
|
+
}), false);
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
// never throw from the listener
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
window.addEventListener("error", onError);
|
|
397
|
+
removers.push(() => window.removeEventListener("error", onError));
|
|
398
|
+
}
|
|
399
|
+
if (runtime.config.captureUnhandledRejections) {
|
|
400
|
+
const onRejection = (event) => {
|
|
401
|
+
try {
|
|
402
|
+
const reason = event?.reason;
|
|
403
|
+
const normalized = normalizeCapturedError(reason);
|
|
404
|
+
if (!normalized.type || normalized.type === "Error") {
|
|
405
|
+
normalized.type = "UnhandledRejection";
|
|
406
|
+
}
|
|
407
|
+
dispatch(runtime, buildEvent(runtime, normalized, {
|
|
408
|
+
handled: false,
|
|
409
|
+
level: "error",
|
|
410
|
+
}), false);
|
|
411
|
+
}
|
|
412
|
+
catch {
|
|
413
|
+
// never throw from the listener
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
window.addEventListener("unhandledrejection", onRejection);
|
|
417
|
+
removers.push(() => window.removeEventListener("unhandledrejection", onRejection));
|
|
418
|
+
}
|
|
419
|
+
runtime.installed = true;
|
|
420
|
+
runtime.removeHandlers = () => {
|
|
421
|
+
for (const remove of removers) {
|
|
422
|
+
try {
|
|
423
|
+
remove();
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
// best-effort teardown
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
runtime.removeHandlers = null;
|
|
430
|
+
runtime.installed = false;
|
|
431
|
+
};
|
|
432
|
+
return runtime.removeHandlers;
|
|
433
|
+
}
|
|
434
|
+
export function isErrorCaptureInstalled() {
|
|
435
|
+
return getRuntime().installed;
|
|
436
|
+
}
|
|
437
|
+
//# sourceMappingURL=error-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-capture.js","sourceRoot":"","sources":["../../src/client/error-capture.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * First-party, Sentry-style browser error capture for the Agent Native\n * analytics SDK.\n *\n * Two responsibilities:\n * 1. Automatic capture of uncaught exceptions (`window.onerror`) and\n * unhandled promise rejections (`unhandledrejection`).\n * 2. A documented manual API — `captureException(error, context?)` and\n * `captureMessage(message, level?)` — mirroring Sentry's ergonomics.\n *\n * Captured exceptions are handed to a `send` callback (wired by\n * `configureTracking` to the first-party analytics `/track` ingest as a\n * dedicated `$exception` event) and are tagged with the current analytics\n * session id + session replay id so each error links back to the recording it\n * happened in. Everything here is defensive: capture must never throw back into\n * the host app, so every path is wrapped and failures are swallowed.\n *\n * Stack parsing and fingerprinting are intentionally done authoritatively on\n * the server (see the analytics template's `server/lib/error-capture.ts`); the\n * client sends a compact, bounded payload (type/message/raw stack/context) and\n * the server normalizes + groups it. That keeps one tested source of truth for\n * grouping instead of duplicating parser logic across the wire.\n */\nimport { scrubUrl } from \"./url-scrub.js\";\n\nexport type ExceptionLevel = \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n\n/** Extra Sentry-style context accepted by `captureException`. */\nexport interface CaptureExceptionContext {\n /** Low-cardinality searchable tags. Values are coerced to strings. */\n tags?: Record<string, string | number | boolean | null | undefined>;\n /** Structured, higher-cardinality detail shown on the event. */\n extra?: Record<string, unknown>;\n /** Severity; defaults to \"error\". */\n level?: ExceptionLevel;\n}\n\nexport interface ExceptionBreadcrumb {\n timestamp: string;\n category: string;\n message: string;\n level?: ExceptionLevel;\n}\n\n/**\n * Compact exception payload emitted to transport. Field names are the wire\n * contract the analytics server ingest reads — keep them stable.\n */\nexport interface CapturedExceptionEvent {\n /** Error class/name, e.g. \"TypeError\". \"Message\" for `captureMessage`. */\n type: string;\n message: string;\n /** Raw (bounded, redacted) stack string; server parses it into frames. */\n stack?: string;\n /** False for uncaught/global errors, true for manually handled ones. */\n handled: boolean;\n level: ExceptionLevel;\n /** ISO timestamp of the occurrence. */\n occurredAt: string;\n url?: string;\n release?: string;\n environment?: string;\n sessionId?: string;\n /** Client session replay id (localStorage) for replay linkage. */\n sessionReplayId?: string;\n anonymousId?: string;\n breadcrumbs: ExceptionBreadcrumb[];\n tags?: Record<string, string>;\n extra?: Record<string, unknown>;\n}\n\nexport interface InstallErrorCaptureOptions {\n /** Transport for a captured exception. Must not throw. */\n send: (event: CapturedExceptionEvent) => void;\n /** Resolve current analytics/session-replay identifiers at capture time. */\n getSessionContext?: () => {\n sessionId?: string;\n anonymousId?: string;\n replayId?: string;\n };\n /**\n * Optional hook to also surface a manual capture on the session replay\n * timeline. Only invoked for manual `captureException`/`captureMessage`;\n * auto-captured global errors are already recorded by the replay recorder.\n */\n emitReplayEvent?: (event: CapturedExceptionEvent) => void;\n release?: string;\n environment?: string;\n /** Auto-capture `window.onerror`. Defaults to true. */\n captureGlobalErrors?: boolean;\n /** Auto-capture `unhandledrejection`. Defaults to true. */\n captureUnhandledRejections?: boolean;\n /** Breadcrumb ring buffer size. Defaults to 20. */\n maxBreadcrumbs?: number;\n /** Dedupe window (ms) for identical signatures. Defaults to 3000. */\n dedupeWindowMs?: number;\n}\n\ninterface ErrorCaptureRuntime {\n installed: boolean;\n config: Required<\n Pick<\n InstallErrorCaptureOptions,\n | \"captureGlobalErrors\"\n | \"captureUnhandledRejections\"\n | \"maxBreadcrumbs\"\n | \"dedupeWindowMs\"\n >\n > &\n Omit<\n InstallErrorCaptureOptions,\n | \"captureGlobalErrors\"\n | \"captureUnhandledRejections\"\n | \"maxBreadcrumbs\"\n | \"dedupeWindowMs\"\n >;\n breadcrumbs: ExceptionBreadcrumb[];\n recentSignatures: Map<string, number>;\n removeHandlers: (() => void) | null;\n navigationInstalled: boolean;\n}\n\nconst MAX_MESSAGE_LENGTH = 1000;\nconst MAX_STACK_LENGTH = 8000;\nconst MAX_TAGS = 30;\nconst MAX_EXTRA_KEYS = 50;\nconst MAX_EXTRA_DEPTH = 4;\nconst MAX_EXTRA_OBJECT_KEYS = 20;\nconst MAX_EXTRA_ARRAY_ITEMS = 20;\nconst MAX_EXTRA_STRING_LENGTH = 2000;\n\nconst ERROR_CAPTURE_STATE_KEY = Symbol.for(\"agent-native.client.errorCapture\");\n\n// Reuse the same credential-looking redaction the replay capture uses so a\n// stack/message that echoes a token never leaves the browser in the clear.\nconst SECRET_KEY_FRAGMENT =\n \"(?:authorization|cookie|set[-_]?cookie|token|secret|password|passwd|pwd|api[-_]?key|apikey|session|credential)\";\nconst BEARER_RE = /\\b(bearer|basic)\\s+[a-z0-9._~+/-]+=*/gi;\nconst UNQUOTED_SECRET_RE = new RegExp(\n `([\"']?)([A-Za-z0-9_$.-]*${SECRET_KEY_FRAGMENT}[A-Za-z0-9_$.-]*)\\\\1(\\\\s*[:=]\\\\s*)([^\"',\\\\s;}\\\\]]+)`,\n \"gi\",\n);\nconst SECRET_KEY_RE = new RegExp(SECRET_KEY_FRAGMENT, \"i\");\n\nfunction redactSecrets(value: string): string {\n return value\n .replace(BEARER_RE, \"$1 <redacted>\")\n .replace(UNQUOTED_SECRET_RE, \"$1$2$1$3<redacted>\");\n}\n\nfunction getRuntime(): ErrorCaptureRuntime {\n const g = globalThis as typeof globalThis & {\n [ERROR_CAPTURE_STATE_KEY]?: ErrorCaptureRuntime;\n };\n if (!g[ERROR_CAPTURE_STATE_KEY]) {\n g[ERROR_CAPTURE_STATE_KEY] = {\n installed: false,\n config: {\n send: () => {},\n captureGlobalErrors: true,\n captureUnhandledRejections: true,\n maxBreadcrumbs: 20,\n dedupeWindowMs: 3000,\n },\n breadcrumbs: [],\n recentSignatures: new Map(),\n removeHandlers: null,\n navigationInstalled: false,\n };\n }\n return g[ERROR_CAPTURE_STATE_KEY]!;\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nfunction truncate(value: string, max: number): string {\n return value.length > max ? value.slice(0, max) : value;\n}\n\nfunction currentUrl(): string | undefined {\n try {\n return scrubUrl(window.location.href);\n } catch {\n return undefined;\n }\n}\n\n/** Normalize any thrown value into a stable `{ type, message, stack }`. */\nexport function normalizeCapturedError(error: unknown): {\n type: string;\n message: string;\n stack?: string;\n} {\n if (error instanceof Error) {\n return {\n type: error.name || \"Error\",\n message: error.message || String(error),\n stack: typeof error.stack === \"string\" ? error.stack : undefined,\n };\n }\n if (typeof error === \"string\") {\n return { type: \"Error\", message: error };\n }\n if (error && typeof error === \"object\") {\n const record = error as Record<string, unknown>;\n const name = typeof record.name === \"string\" ? record.name : undefined;\n const message =\n typeof record.message === \"string\" ? record.message : undefined;\n const stack = typeof record.stack === \"string\" ? record.stack : undefined;\n if (name || message || stack) {\n return {\n type: name || \"Error\",\n message: message || safeStringify(error),\n stack,\n };\n }\n return { type: \"Error\", message: safeStringify(error) };\n }\n return { type: \"Error\", message: String(error) };\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\nfunction coerceTags(\n tags: CaptureExceptionContext[\"tags\"],\n): Record<string, string> | undefined {\n if (!tags) return undefined;\n const out: Record<string, string> = {};\n let count = 0;\n for (const [key, value] of Object.entries(tags)) {\n if (count >= MAX_TAGS) break;\n if (value === undefined || value === null) continue;\n out[key] = truncate(redactSecrets(String(value)), 200);\n count += 1;\n }\n return Object.keys(out).length ? out : undefined;\n}\n\nfunction coerceExtra(\n extra: CaptureExceptionContext[\"extra\"],\n): Record<string, unknown> | undefined {\n if (!extra || typeof extra !== \"object\") return undefined;\n const out: Record<string, unknown> = {};\n let count = 0;\n for (const [key, value] of Object.entries(extra)) {\n if (count >= MAX_EXTRA_KEYS) break;\n const safeKey = truncate(redactSecrets(key), 100);\n out[safeKey] = SECRET_KEY_RE.test(safeKey)\n ? \"<redacted>\"\n : coerceExtraValue(value, MAX_EXTRA_DEPTH);\n count += 1;\n }\n return Object.keys(out).length ? out : undefined;\n}\n\nfunction coerceExtraValue(value: unknown, depth: number): unknown {\n if (\n value == null ||\n typeof value === \"boolean\" ||\n typeof value === \"number\"\n ) {\n return value;\n }\n if (typeof value === \"string\") {\n return truncate(redactSecrets(value), MAX_EXTRA_STRING_LENGTH);\n }\n if (typeof value === \"bigint\") {\n return truncate(redactSecrets(value.toString()), MAX_EXTRA_STRING_LENGTH);\n }\n if (depth <= 0) {\n return truncate(\n redactSecrets(safeStringify(value)),\n MAX_EXTRA_STRING_LENGTH,\n );\n }\n if (Array.isArray(value)) {\n return value\n .slice(0, MAX_EXTRA_ARRAY_ITEMS)\n .map((item) => coerceExtraValue(item, depth - 1));\n }\n if (typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n let count = 0;\n for (const [rawKey, child] of Object.entries(value)) {\n if (count >= MAX_EXTRA_OBJECT_KEYS) break;\n const key = truncate(redactSecrets(rawKey), 100);\n out[key] = SECRET_KEY_RE.test(key)\n ? \"<redacted>\"\n : coerceExtraValue(child, depth - 1);\n count += 1;\n }\n return out;\n }\n return truncate(redactSecrets(String(value)), MAX_EXTRA_STRING_LENGTH);\n}\n\nfunction firstStackLine(stack: string | undefined): string {\n if (!stack) return \"\";\n const lines = stack.split(\"\\n\").map((line) => line.trim());\n return (\n lines.find((line) => line.startsWith(\"at \") || /:\\d+:\\d+/.test(line)) ??\n lines[1] ??\n \"\"\n );\n}\n\n/** Cheap client-side signature used only for local dedupe. */\nfunction signatureOf(type: string, message: string, stack?: string): string {\n return `${type}|${message}|${firstStackLine(stack)}`;\n}\n\nfunction shouldDedupe(\n runtime: ErrorCaptureRuntime,\n signature: string,\n): boolean {\n const now = Date.now();\n const windowMs = runtime.config.dedupeWindowMs;\n // Opportunistic cleanup so the map can't grow without bound.\n if (runtime.recentSignatures.size > 200) {\n for (const [key, ts] of runtime.recentSignatures) {\n if (now - ts > windowMs) runtime.recentSignatures.delete(key);\n }\n }\n const last = runtime.recentSignatures.get(signature);\n runtime.recentSignatures.set(signature, now);\n return last !== undefined && now - last < windowMs;\n}\n\n/** Append a privacy-safe breadcrumb to the bounded ring buffer. */\nexport function addErrorBreadcrumb(breadcrumb: {\n category: string;\n message: string;\n level?: ExceptionLevel;\n}): void {\n try {\n const runtime = getRuntime();\n runtime.breadcrumbs.push({\n timestamp: nowIso(),\n category: truncate(breadcrumb.category, 60),\n message: truncate(redactSecrets(breadcrumb.message), 300),\n ...(breadcrumb.level ? { level: breadcrumb.level } : {}),\n });\n const max = runtime.config.maxBreadcrumbs;\n if (runtime.breadcrumbs.length > max) {\n runtime.breadcrumbs.splice(0, runtime.breadcrumbs.length - max);\n }\n } catch {\n // breadcrumbs are best-effort\n }\n}\n\nfunction snapshotBreadcrumbs(\n runtime: ErrorCaptureRuntime,\n): ExceptionBreadcrumb[] {\n return runtime.breadcrumbs.slice(-runtime.config.maxBreadcrumbs);\n}\n\nfunction installNavigationBreadcrumbs(runtime: ErrorCaptureRuntime): void {\n if (runtime.navigationInstalled || typeof window === \"undefined\") return;\n runtime.navigationInstalled = true;\n const record = (navType: string) => {\n try {\n addErrorBreadcrumb({\n category: \"navigation\",\n message: `${navType} ${scrubUrl(window.location.href) ?? window.location.pathname}`,\n });\n } catch {\n // ignore\n }\n };\n try {\n const originalPush = window.history.pushState;\n const originalReplace = window.history.replaceState;\n window.history.pushState = function pushState(...args) {\n const result = originalPush.apply(this, args);\n record(\"navigate\");\n return result;\n };\n window.history.replaceState = function replaceState(...args) {\n const result = originalReplace.apply(this, args);\n record(\"replace\");\n return result;\n };\n window.addEventListener(\"popstate\", () => record(\"popstate\"));\n // Seed the trail with the initial location.\n record(\"load\");\n } catch {\n // navigation breadcrumbs are best-effort\n }\n}\n\nfunction buildEvent(\n runtime: ErrorCaptureRuntime,\n normalized: { type: string; message: string; stack?: string },\n options: {\n handled: boolean;\n level: ExceptionLevel;\n tags?: Record<string, string>;\n extra?: Record<string, unknown>;\n },\n): CapturedExceptionEvent {\n const context = runtime.config.getSessionContext?.() ?? {};\n const stack = normalized.stack\n ? truncate(redactSecrets(normalized.stack), MAX_STACK_LENGTH)\n : undefined;\n return {\n type: truncate(normalized.type || \"Error\", 200),\n message: truncate(\n redactSecrets(normalized.message || \"\"),\n MAX_MESSAGE_LENGTH,\n ),\n ...(stack ? { stack } : {}),\n handled: options.handled,\n level: options.level,\n occurredAt: nowIso(),\n ...(currentUrl() ? { url: currentUrl() } : {}),\n ...(runtime.config.release ? { release: runtime.config.release } : {}),\n ...(runtime.config.environment\n ? { environment: runtime.config.environment }\n : {}),\n ...(context.sessionId ? { sessionId: context.sessionId } : {}),\n ...(context.replayId ? { sessionReplayId: context.replayId } : {}),\n ...(context.anonymousId ? { anonymousId: context.anonymousId } : {}),\n breadcrumbs: snapshotBreadcrumbs(runtime),\n ...(options.tags ? { tags: options.tags } : {}),\n ...(options.extra ? { extra: options.extra } : {}),\n };\n}\n\nfunction dispatch(\n runtime: ErrorCaptureRuntime,\n event: CapturedExceptionEvent,\n emitToReplay: boolean,\n): void {\n const signature = signatureOf(event.type, event.message, event.stack);\n if (shouldDedupe(runtime, signature)) return;\n try {\n runtime.config.send(event);\n } catch {\n // transport must never throw into the host app\n }\n if (emitToReplay) {\n try {\n runtime.config.emitReplayEvent?.(event);\n } catch {\n // replay timeline emission is best-effort\n }\n }\n // Record the exception itself as a breadcrumb so a following error carries\n // the prior failure in its trail.\n addErrorBreadcrumb({\n category: \"exception\",\n message: `${event.type}: ${event.message}`,\n level: event.level,\n });\n}\n\n/**\n * Capture a handled exception. Mirrors Sentry's `captureException(err, ctx)`.\n * Safe to call before `configureTracking` has run — it simply no-ops if no\n * transport is installed yet.\n */\nexport function captureException(\n error: unknown,\n context: CaptureExceptionContext = {},\n): void {\n try {\n const runtime = getRuntime();\n const normalized = normalizeCapturedError(error);\n const event = buildEvent(runtime, normalized, {\n handled: true,\n level: context.level ?? \"error\",\n tags: coerceTags(context.tags),\n extra: coerceExtra(context.extra),\n });\n dispatch(runtime, event, true);\n } catch {\n // never throw from capture\n }\n}\n\n/**\n * Capture a message string as an exception-like event. Mirrors Sentry's\n * `captureMessage(message, level?)`.\n */\nexport function captureMessage(\n message: string,\n level: ExceptionLevel = \"info\",\n): void {\n try {\n const runtime = getRuntime();\n const event = buildEvent(\n runtime,\n { type: \"Message\", message: String(message ?? \"\") },\n { handled: true, level },\n );\n dispatch(runtime, event, true);\n } catch {\n // never throw from capture\n }\n}\n\n/**\n * Install auto-capture + wire the transport. Idempotent: re-invoking updates\n * the config (and (re)installs global handlers) without duplicating listeners.\n * Returns a disposer that removes the global handlers.\n */\nexport function installErrorCapture(\n options: InstallErrorCaptureOptions,\n): () => void {\n const runtime = getRuntime();\n runtime.config = {\n ...runtime.config,\n ...options,\n captureGlobalErrors: options.captureGlobalErrors ?? true,\n captureUnhandledRejections: options.captureUnhandledRejections ?? true,\n maxBreadcrumbs: options.maxBreadcrumbs ?? runtime.config.maxBreadcrumbs,\n dedupeWindowMs: options.dedupeWindowMs ?? runtime.config.dedupeWindowMs,\n };\n\n if (typeof window === \"undefined\") return () => {};\n\n installNavigationBreadcrumbs(runtime);\n\n // Tear down any previously-installed handlers before reinstalling so a second\n // configureTracking call doesn't double-report.\n runtime.removeHandlers?.();\n runtime.removeHandlers = null;\n\n const removers: Array<() => void> = [];\n\n if (runtime.config.captureGlobalErrors) {\n const onError = (event: ErrorEvent) => {\n try {\n const error = event?.error;\n const normalized = error\n ? normalizeCapturedError(error)\n : {\n type: \"Error\",\n message: String(event?.message ?? \"Uncaught error\"),\n };\n // Global errors are already logged by the session replay recorder, so\n // don't re-emit them onto the replay timeline (avoid double-counting).\n dispatch(\n runtime,\n buildEvent(runtime, normalized, {\n handled: false,\n level: \"error\",\n }),\n false,\n );\n } catch {\n // never throw from the listener\n }\n };\n window.addEventListener(\"error\", onError as EventListener);\n removers.push(() =>\n window.removeEventListener(\"error\", onError as EventListener),\n );\n }\n\n if (runtime.config.captureUnhandledRejections) {\n const onRejection = (event: PromiseRejectionEvent) => {\n try {\n const reason = event?.reason;\n const normalized = normalizeCapturedError(reason);\n if (!normalized.type || normalized.type === \"Error\") {\n normalized.type = \"UnhandledRejection\";\n }\n dispatch(\n runtime,\n buildEvent(runtime, normalized, {\n handled: false,\n level: \"error\",\n }),\n false,\n );\n } catch {\n // never throw from the listener\n }\n };\n window.addEventListener(\"unhandledrejection\", onRejection as EventListener);\n removers.push(() =>\n window.removeEventListener(\n \"unhandledrejection\",\n onRejection as EventListener,\n ),\n );\n }\n\n runtime.installed = true;\n runtime.removeHandlers = () => {\n for (const remove of removers) {\n try {\n remove();\n } catch {\n // best-effort teardown\n }\n }\n runtime.removeHandlers = null;\n runtime.installed = false;\n };\n return runtime.removeHandlers;\n}\n\nexport function isErrorCaptureInstalled(): boolean {\n return getRuntime().installed;\n}\n"]}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -66,7 +66,7 @@ export * from "./chat/runtime.js";
|
|
|
66
66
|
export { ACTION_CHAT_UI_DATA_CHART_RENDERER, ACTION_CHAT_UI_DATA_INSIGHTS_RENDERER, ACTION_CHAT_UI_DATA_TABLE_RENDERER, ACTION_CHAT_UI_DATA_WIDGET_RENDERER, ACTION_CHAT_UI_INLINE_EXTENSION_RENDERER, type ActionChatUIConfig, } from "../action-ui.js";
|
|
67
67
|
export { DATA_CHART_WIDGET, DATA_INSIGHTS_WIDGET, DATA_TABLE_WIDGET, createDataChartWidgetResult, createDataInsightsWidgetResult, createDataTableWidgetResult, dataChartWidgetResultSchema, dataChartWidgetSchema, dataInsightsWidgetResultSchema, dataTableWidgetResultSchema, dataTableWidgetSchema, dataWidgetResultSchema, isDataChartWidget, isDataTableWidget, isDataWidgetResult, normalizeDataWidgetKind, normalizeDataWidgetResult, type DataChartSeriesDefinition, type DataChartWidget, type DataChartWidgetResult, type DataChartWidgetResultInput, type DataInsightsWidgetResult, type DataInsightsWidgetResultInput, type DataTableColumn, type DataTableWidget, type DataTableWidgetResult, type DataTableWidgetResultInput, type DataWidgetDisplay, type DataWidgetKind, type DataWidgetResult, type DataWidgetResultMetadata, } from "./chat/widgets/data-widget-types.js";
|
|
68
68
|
export { AgentNativeIcon } from "./components/icons/AgentNativeIcon.js";
|
|
69
|
-
export { SettingsPanel, SettingsTabsPage, SecretsSection, openBuilderConnectPopup, useAgentSettingsTabs, useBuilderConnectFlow, useBuilderStatus, withBuilderConnectTrackingParams, type BuilderConnectFlow, type BuilderConnectFlowOptions, type BuilderConnectStartOptions, type BuilderStatus, type OpenBuilderConnectPopupOptions, type SecretsSectionProps, type SettingsPanelProps, type SettingsTabItem, type SettingsTabsPageProps, } from "./settings/index.js";
|
|
69
|
+
export { SettingsPanel, SettingsTabsPage, SecretsSection, openBuilderConnectPopup, useAgentSettingsTabs, useBuilderConnectFlow, useBuilderStatus, withBuilderConnectTrackingParams, type BuilderConnectFlow, type BuilderConnectFlowOptions, type BuilderConnectStartOptions, type BuilderStatus, type OpenBuilderConnectPopupOptions, type SecretsSectionProps, type SettingsPanelProps, type SettingsSearchEntry, type SettingsTabItem, type SettingsTabsPageProps, } from "./settings/index.js";
|
|
70
70
|
export { ProductionAgentPanel, type ProductionAgentPanelProps, } from "./ProductionAgentPanel.js";
|
|
71
71
|
export { useProductionAgent, type ProductionAgentMessage, type UseProductionAgentOptions, type UseProductionAgentResult, } from "./useProductionAgent.js";
|
|
72
72
|
export { Turnstile, type TurnstileProps } from "./Turnstile.js";
|
|
@@ -86,7 +86,7 @@ export { getThemeInitScript, themeInitScript, type ThemePreference, } from "./th
|
|
|
86
86
|
export { APPEARANCE_PRESETS, applyAppearance, getStoredAppearance, useAppearance, useAppearanceSync, type AppearancePresetId, } from "./appearance.js";
|
|
87
87
|
export { AppearancePicker, type AppearancePickerProps, } from "./AppearancePicker.js";
|
|
88
88
|
export { AgentTerminal, type AgentTerminalProps } from "./terminal/index.js";
|
|
89
|
-
export { trackEvent, trackSessionStatus, configureTracking, maybeStartSessionReplay, startSessionReplay, stopSessionReplay, getAnalyticsAnonymousId, getAnalyticsSessionId, getFirstTouchAttribution, setSentryUser, captureError, captureClientException, type ClientCaptureContext, type ConfigureTrackingOptions, type FirstTouchAttribution, type SessionReplayOptions, type SessionReplayStartResult, type SessionReplayUrlMatcher, } from "./analytics.js";
|
|
89
|
+
export { trackEvent, trackSessionStatus, configureTracking, maybeStartSessionReplay, startSessionReplay, stopSessionReplay, getAnalyticsAnonymousId, getAnalyticsSessionId, getFirstTouchAttribution, setSentryUser, captureError, captureClientException, AGENT_NATIVE_EXCEPTION_EVENT_NAME, addErrorBreadcrumb, captureException, captureMessage, isErrorCaptureInstalled, type CaptureExceptionContext, type CapturedExceptionEvent, type ClientCaptureContext, type ConfigureTrackingOptions, type ErrorCaptureConfigOptions, type ExceptionBreadcrumb, type ExceptionLevel, type FirstTouchAttribution, type SessionReplayOptions, type SessionReplayStartResult, type SessionReplayUrlMatcher, } from "./analytics.js";
|
|
90
90
|
export { track } from "./track.js";
|
|
91
91
|
export { useCollaborativeDoc, isReconcileLeadClient, emailToColor, emailToName, dedupeCollabUsersByEmail, type UseCollaborativeDocOptions, type UseCollaborativeDocResult, type CollabUser, } from "../collab/client.js";
|
|
92
92
|
export { AGENT_CLIENT_ID } from "../collab/agent-identity.js";
|