@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
|
@@ -2,6 +2,11 @@ import { getDbExec } from "@agent-native/core/db";
|
|
|
2
2
|
import { and, eq, isNull, or } from "drizzle-orm";
|
|
3
3
|
|
|
4
4
|
import { getDb, schema } from "../db/index.js";
|
|
5
|
+
import {
|
|
6
|
+
EXCEPTION_EVENT_NAME,
|
|
7
|
+
ingestAnalyticsExceptionEvents,
|
|
8
|
+
type DerivedExceptionFields,
|
|
9
|
+
} from "./error-capture.js";
|
|
5
10
|
|
|
6
11
|
export interface AnalyticsScope {
|
|
7
12
|
userEmail: string;
|
|
@@ -351,6 +356,10 @@ export async function recordAnalyticsEvents(
|
|
|
351
356
|
}
|
|
352
357
|
|
|
353
358
|
const receivedAt = nowIso();
|
|
359
|
+
const exceptionSources: Array<{
|
|
360
|
+
properties: Record<string, unknown>;
|
|
361
|
+
derived: DerivedExceptionFields;
|
|
362
|
+
}> = [];
|
|
354
363
|
const rows = events.map((event) => {
|
|
355
364
|
const properties = event.properties ?? {};
|
|
356
365
|
const context = event.context ?? {};
|
|
@@ -380,6 +389,24 @@ export async function recordAnalyticsEvents(
|
|
|
380
389
|
asString((properties as any).distinctId);
|
|
381
390
|
const userKey = userId || anonymousId;
|
|
382
391
|
const timestamp = normalizeAnalyticsTimestamp(event.timestamp, receivedAt);
|
|
392
|
+
const sessionId =
|
|
393
|
+
event.sessionId ?? asString((properties as any).sessionId);
|
|
394
|
+
|
|
395
|
+
if (event.event === EXCEPTION_EVENT_NAME) {
|
|
396
|
+
exceptionSources.push({
|
|
397
|
+
properties,
|
|
398
|
+
derived: {
|
|
399
|
+
app,
|
|
400
|
+
template,
|
|
401
|
+
url: parts.url,
|
|
402
|
+
userId,
|
|
403
|
+
anonymousId,
|
|
404
|
+
userKey,
|
|
405
|
+
sessionId,
|
|
406
|
+
timestamp,
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
}
|
|
383
410
|
|
|
384
411
|
return {
|
|
385
412
|
id: id("evt"),
|
|
@@ -388,7 +415,7 @@ export async function recordAnalyticsEvents(
|
|
|
388
415
|
userId,
|
|
389
416
|
anonymousId,
|
|
390
417
|
userKey,
|
|
391
|
-
sessionId
|
|
418
|
+
sessionId,
|
|
392
419
|
timestamp,
|
|
393
420
|
eventDate: eventDateFromTimestamp(timestamp),
|
|
394
421
|
receivedAt,
|
|
@@ -415,6 +442,25 @@ export async function recordAnalyticsEvents(
|
|
|
415
442
|
.where(eq(schema.analyticsPublicKeys.id, key.id));
|
|
416
443
|
}
|
|
417
444
|
|
|
445
|
+
// Fork captured exceptions into the dedicated error-capture tables. This is
|
|
446
|
+
// best-effort: a malformed `$exception` payload must never reject the whole
|
|
447
|
+
// analytics ingest (the event is still recorded in analytics_events above,
|
|
448
|
+
// which keeps alerting working).
|
|
449
|
+
if (exceptionSources.length) {
|
|
450
|
+
try {
|
|
451
|
+
await ingestAnalyticsExceptionEvents(
|
|
452
|
+
{
|
|
453
|
+
ownerEmail: key.ownerEmail,
|
|
454
|
+
orgId: key.orgId ?? null,
|
|
455
|
+
publicKeyId: key.id,
|
|
456
|
+
},
|
|
457
|
+
exceptionSources,
|
|
458
|
+
);
|
|
459
|
+
} catch (error) {
|
|
460
|
+
console.warn("[first-party-analytics] Exception ingest failed:", error);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
418
464
|
return { accepted: rows.length, keyId: key.id };
|
|
419
465
|
}
|
|
420
466
|
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aggregated uptime statistics for the monitoring feature.
|
|
3
|
+
*
|
|
4
|
+
* This module turns the raw `monitor_check_results` / `monitor_incidents`
|
|
5
|
+
* history into the numbers a status dashboard needs: current status, uptime %
|
|
6
|
+
* over 24h / 7d / 30d / 90d, a bucketed uptime timeline (green/amber/red/no
|
|
7
|
+
* data), a downsampled response-time series, incident count, and MTBF.
|
|
8
|
+
*
|
|
9
|
+
* Design notes (see the `performance` skill):
|
|
10
|
+
* - Reads are done as a small fixed set of GROUPED, column-projected queries
|
|
11
|
+
* (one per shape), never one query per monitor — no N+1. All aggregation
|
|
12
|
+
* (uptime %, daily buckets, hourly response averages) happens IN SQL so we
|
|
13
|
+
* never pull the full result history across the wire.
|
|
14
|
+
* - Every query is scoped by owner_email + org_id, mirroring
|
|
15
|
+
* server/lib/uptime-monitors.ts. The in-app stats action passes the request
|
|
16
|
+
* user; the public status page passes the PAGE OWNER's scope.
|
|
17
|
+
* - The math (`computeUptimePercents`, `assembleDailyTimeline`, `computeMtbf`,
|
|
18
|
+
* `bucketStatusFromCounts`) is pure and unit-tested (monitor-stats.spec.ts).
|
|
19
|
+
*/
|
|
20
|
+
import { and, eq, gte, inArray, isNull, sql } from "drizzle-orm";
|
|
21
|
+
|
|
22
|
+
import { getDb, schema } from "../db/index.js";
|
|
23
|
+
import type { AccessCtx, MonitorStatus } from "./uptime-monitors.js";
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Types
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/** Coarse health of a single timeline bucket. */
|
|
30
|
+
export type BucketStatus = "up" | "down" | "degraded" | "no-data";
|
|
31
|
+
|
|
32
|
+
export interface UptimeWindows {
|
|
33
|
+
uptime24h: number | null;
|
|
34
|
+
uptime7d: number | null;
|
|
35
|
+
uptime30d: number | null;
|
|
36
|
+
uptime90d: number | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface UptimeBucket {
|
|
40
|
+
/** ISO timestamp for the inclusive start of the bucket. */
|
|
41
|
+
start: string;
|
|
42
|
+
/** ISO timestamp for the exclusive end of the bucket. */
|
|
43
|
+
end: string;
|
|
44
|
+
status: BucketStatus;
|
|
45
|
+
/** Uptime percentage in the bucket (null when there were no checks). */
|
|
46
|
+
uptimePct: number | null;
|
|
47
|
+
total: number;
|
|
48
|
+
downCount: number;
|
|
49
|
+
degradedCount: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ResponseTimePoint {
|
|
53
|
+
/** ISO timestamp for the start of the bucket. */
|
|
54
|
+
bucketStart: string;
|
|
55
|
+
avg: number | null;
|
|
56
|
+
min: number | null;
|
|
57
|
+
max: number | null;
|
|
58
|
+
count: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface MonitorStats {
|
|
62
|
+
monitorId: string;
|
|
63
|
+
/** Current status from the monitor row (up/down/degraded/…), null if never run. */
|
|
64
|
+
status: MonitorStatus | null;
|
|
65
|
+
lastCheckedAt: string | null;
|
|
66
|
+
lastLatencyMs: number | null;
|
|
67
|
+
windows: UptimeWindows;
|
|
68
|
+
/** Bucketed uptime timeline, oldest → newest (default: 90 daily buckets). */
|
|
69
|
+
timeline: UptimeBucket[];
|
|
70
|
+
/** Downsampled recent response-time series, oldest → newest. */
|
|
71
|
+
responseSeries: ResponseTimePoint[];
|
|
72
|
+
/** Count-weighted average response time across `responseSeries`. */
|
|
73
|
+
avgResponseMs: number | null;
|
|
74
|
+
incidentCount: number;
|
|
75
|
+
/** Mean time between failures over the 90d window, in ms (null if <1 failure). */
|
|
76
|
+
mtbfMs: number | null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface MonitorStatsOptions {
|
|
80
|
+
now?: Date;
|
|
81
|
+
/** How many trailing daily buckets to include in `timeline`. Default 90. */
|
|
82
|
+
timelineDays?: number;
|
|
83
|
+
/** Trailing window (hours) for the hourly `responseSeries`. Default 24. */
|
|
84
|
+
responseWindowHours?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Constants
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
92
|
+
const HOUR_MS = 60 * 60 * 1000;
|
|
93
|
+
const DEFAULT_TIMELINE_DAYS = 90;
|
|
94
|
+
const DEFAULT_RESPONSE_WINDOW_HOURS = 24;
|
|
95
|
+
const MAX_TIMELINE_DAYS = 365;
|
|
96
|
+
const MAX_RESPONSE_WINDOW_HOURS = 24 * 90;
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Pure math (unit-tested)
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
export interface UptimeWindowAggregate {
|
|
103
|
+
total24h: number;
|
|
104
|
+
ok24h: number;
|
|
105
|
+
total7d: number;
|
|
106
|
+
ok7d: number;
|
|
107
|
+
total30d: number;
|
|
108
|
+
ok30d: number;
|
|
109
|
+
total90d: number;
|
|
110
|
+
ok90d: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function pct(ok: number, total: number): number | null {
|
|
114
|
+
return total > 0 ? (ok / total) * 100 : null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function computeUptimePercents(
|
|
118
|
+
agg: UptimeWindowAggregate,
|
|
119
|
+
): UptimeWindows {
|
|
120
|
+
return {
|
|
121
|
+
uptime24h: pct(agg.ok24h, agg.total24h),
|
|
122
|
+
uptime7d: pct(agg.ok7d, agg.total7d),
|
|
123
|
+
uptime30d: pct(agg.ok30d, agg.total30d),
|
|
124
|
+
uptime90d: pct(agg.ok90d, agg.total90d),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Daily aggregate for a single monitor+day, as produced by the DB reader. */
|
|
129
|
+
export interface DailyBucketRow {
|
|
130
|
+
/** UTC calendar day key, `YYYY-MM-DD`. */
|
|
131
|
+
day: string;
|
|
132
|
+
total: number;
|
|
133
|
+
ok: number;
|
|
134
|
+
down: number;
|
|
135
|
+
degraded: number;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function bucketStatusFromCounts(
|
|
139
|
+
total: number,
|
|
140
|
+
down: number,
|
|
141
|
+
degraded: number,
|
|
142
|
+
): BucketStatus {
|
|
143
|
+
if (total <= 0) return "no-data";
|
|
144
|
+
if (down > 0) return "down";
|
|
145
|
+
if (degraded > 0) return "degraded";
|
|
146
|
+
return "up";
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function utcDayKey(ms: number): string {
|
|
150
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Expand per-day aggregates into a dense, gap-filled trailing timeline of
|
|
155
|
+
* `days` calendar-day buckets (oldest → newest). Days with no checks become
|
|
156
|
+
* `no-data` buckets so the rendered strip stays a fixed width.
|
|
157
|
+
*/
|
|
158
|
+
export function assembleDailyTimeline(
|
|
159
|
+
rows: DailyBucketRow[],
|
|
160
|
+
opts: { now?: Date; days?: number } = {},
|
|
161
|
+
): UptimeBucket[] {
|
|
162
|
+
const now = opts.now ?? new Date();
|
|
163
|
+
const days = Math.max(
|
|
164
|
+
1,
|
|
165
|
+
Math.min(opts.days ?? DEFAULT_TIMELINE_DAYS, MAX_TIMELINE_DAYS),
|
|
166
|
+
);
|
|
167
|
+
const byDay = new Map<string, DailyBucketRow>();
|
|
168
|
+
for (const row of rows) byDay.set(row.day, row);
|
|
169
|
+
|
|
170
|
+
const nowMs = now.getTime();
|
|
171
|
+
const buckets: UptimeBucket[] = [];
|
|
172
|
+
for (let i = days - 1; i >= 0; i--) {
|
|
173
|
+
const dayMs = nowMs - i * DAY_MS;
|
|
174
|
+
const dayKey = utcDayKey(dayMs);
|
|
175
|
+
const startMs = Date.parse(`${dayKey}T00:00:00.000Z`);
|
|
176
|
+
const nextDayStartMs = startMs + DAY_MS;
|
|
177
|
+
// The most recent bucket ends "now", not at the end of the calendar day.
|
|
178
|
+
const endMs = i === 0 ? Math.max(nowMs, startMs) : nextDayStartMs;
|
|
179
|
+
const row = byDay.get(dayKey);
|
|
180
|
+
const total = row?.total ?? 0;
|
|
181
|
+
const down = row?.down ?? 0;
|
|
182
|
+
const degraded = row?.degraded ?? 0;
|
|
183
|
+
const ok = row?.ok ?? 0;
|
|
184
|
+
buckets.push({
|
|
185
|
+
start: new Date(startMs).toISOString(),
|
|
186
|
+
end: new Date(endMs).toISOString(),
|
|
187
|
+
status: bucketStatusFromCounts(total, down, degraded),
|
|
188
|
+
uptimePct: pct(ok, total),
|
|
189
|
+
total,
|
|
190
|
+
downCount: down,
|
|
191
|
+
degradedCount: degraded,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return buckets;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface IncidentWindowRow {
|
|
198
|
+
startedAt: string;
|
|
199
|
+
resolvedAt: string | null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Mean time between failures over a window, in ms. Defined as operational time
|
|
204
|
+
* (window length minus clamped downtime) divided by the number of failures.
|
|
205
|
+
* Returns null when there were no failures in the window.
|
|
206
|
+
*/
|
|
207
|
+
export function computeMtbf(
|
|
208
|
+
incidents: IncidentWindowRow[],
|
|
209
|
+
opts: { windowStartMs: number; nowMs: number },
|
|
210
|
+
): number | null {
|
|
211
|
+
const failures = incidents.length;
|
|
212
|
+
if (failures === 0) return null;
|
|
213
|
+
const { windowStartMs, nowMs } = opts;
|
|
214
|
+
const windowMs = Math.max(0, nowMs - windowStartMs);
|
|
215
|
+
let downtime = 0;
|
|
216
|
+
for (const incident of incidents) {
|
|
217
|
+
const startedMs = Date.parse(incident.startedAt);
|
|
218
|
+
if (!Number.isFinite(startedMs)) continue;
|
|
219
|
+
const resolvedMs = incident.resolvedAt
|
|
220
|
+
? Date.parse(incident.resolvedAt)
|
|
221
|
+
: nowMs;
|
|
222
|
+
const start = Math.max(startedMs, windowStartMs);
|
|
223
|
+
const end = Math.min(
|
|
224
|
+
Number.isFinite(resolvedMs) ? resolvedMs : nowMs,
|
|
225
|
+
nowMs,
|
|
226
|
+
);
|
|
227
|
+
if (end > start) downtime += end - start;
|
|
228
|
+
}
|
|
229
|
+
const operational = Math.max(0, windowMs - downtime);
|
|
230
|
+
return operational / failures;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function averageResponse(series: ResponseTimePoint[]): number | null {
|
|
234
|
+
let weighted = 0;
|
|
235
|
+
let count = 0;
|
|
236
|
+
for (const point of series) {
|
|
237
|
+
if (point.avg == null || point.count <= 0) continue;
|
|
238
|
+
weighted += point.avg * point.count;
|
|
239
|
+
count += point.count;
|
|
240
|
+
}
|
|
241
|
+
return count > 0 ? weighted / count : null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
// Owner scoping (mirrors uptime-monitors.ts)
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
|
|
248
|
+
function ownerScope(table: { ownerEmail: any; orgId: any }, ctx: AccessCtx) {
|
|
249
|
+
return and(
|
|
250
|
+
sql`lower(${table.ownerEmail}) = ${ctx.email.toLowerCase()}`,
|
|
251
|
+
ctx.orgId ? eq(table.orgId, ctx.orgId) : isNull(table.orgId),
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** All monitor ids owned by `ctx` (used when a caller wants stats for "all"). */
|
|
256
|
+
export async function listOwnedMonitorIds(ctx: AccessCtx): Promise<string[]> {
|
|
257
|
+
const db = getDb() as any;
|
|
258
|
+
const rows = await db
|
|
259
|
+
.select({ id: schema.monitors.id })
|
|
260
|
+
.from(schema.monitors)
|
|
261
|
+
.where(ownerScope(schema.monitors, ctx));
|
|
262
|
+
return rows.map((row: any) => row.id as string);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
// DB reader
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Compute aggregated stats for the given monitor ids, scoped to `ctx`. Returns
|
|
271
|
+
* a Map keyed by monitor id. Ids the caller doesn't own are simply absent.
|
|
272
|
+
*/
|
|
273
|
+
export async function getMonitorStats(
|
|
274
|
+
ctx: AccessCtx,
|
|
275
|
+
monitorIds: string[],
|
|
276
|
+
opts: MonitorStatsOptions = {},
|
|
277
|
+
): Promise<Map<string, MonitorStats>> {
|
|
278
|
+
const result = new Map<string, MonitorStats>();
|
|
279
|
+
const ids = Array.from(new Set(monitorIds.filter(Boolean)));
|
|
280
|
+
if (ids.length === 0) return result;
|
|
281
|
+
|
|
282
|
+
const db = getDb() as any;
|
|
283
|
+
const now = opts.now ?? new Date();
|
|
284
|
+
const nowMs = now.getTime();
|
|
285
|
+
const timelineDays = Math.max(
|
|
286
|
+
1,
|
|
287
|
+
Math.min(opts.timelineDays ?? DEFAULT_TIMELINE_DAYS, MAX_TIMELINE_DAYS),
|
|
288
|
+
);
|
|
289
|
+
const responseWindowHours = Math.max(
|
|
290
|
+
1,
|
|
291
|
+
Math.min(
|
|
292
|
+
opts.responseWindowHours ?? DEFAULT_RESPONSE_WINDOW_HOURS,
|
|
293
|
+
MAX_RESPONSE_WINDOW_HOURS,
|
|
294
|
+
),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const since24h = new Date(nowMs - 24 * HOUR_MS).toISOString();
|
|
298
|
+
const since7d = new Date(nowMs - 7 * DAY_MS).toISOString();
|
|
299
|
+
const since30d = new Date(nowMs - 30 * DAY_MS).toISOString();
|
|
300
|
+
const since90d = new Date(nowMs - 90 * DAY_MS).toISOString();
|
|
301
|
+
const sinceTimeline = new Date(
|
|
302
|
+
nowMs - (timelineDays - 1) * DAY_MS - DAY_MS,
|
|
303
|
+
).toISOString();
|
|
304
|
+
const sinceResponse = new Date(
|
|
305
|
+
nowMs - responseWindowHours * HOUR_MS,
|
|
306
|
+
).toISOString();
|
|
307
|
+
|
|
308
|
+
const monitorsTable = schema.monitors;
|
|
309
|
+
const resultsTable = schema.monitorCheckResults;
|
|
310
|
+
const incidentsTable = schema.monitorIncidents;
|
|
311
|
+
|
|
312
|
+
const [monitorRows, windowRows, dailyRows, responseRows, incidentRows] =
|
|
313
|
+
await Promise.all([
|
|
314
|
+
db
|
|
315
|
+
.select({
|
|
316
|
+
id: monitorsTable.id,
|
|
317
|
+
lastStatus: monitorsTable.lastStatus,
|
|
318
|
+
lastCheckedAt: monitorsTable.lastCheckedAt,
|
|
319
|
+
lastLatencyMs: monitorsTable.lastLatencyMs,
|
|
320
|
+
})
|
|
321
|
+
.from(monitorsTable)
|
|
322
|
+
.where(
|
|
323
|
+
and(ownerScope(monitorsTable, ctx), inArray(monitorsTable.id, ids)),
|
|
324
|
+
),
|
|
325
|
+
db
|
|
326
|
+
.select({
|
|
327
|
+
monitorId: resultsTable.monitorId,
|
|
328
|
+
total24h: sql<number>`sum(case when ${resultsTable.checkedAt} >= ${since24h} then 1 else 0 end)`,
|
|
329
|
+
ok24h: sql<number>`sum(case when ${resultsTable.checkedAt} >= ${since24h} and ${resultsTable.ok} then 1 else 0 end)`,
|
|
330
|
+
total7d: sql<number>`sum(case when ${resultsTable.checkedAt} >= ${since7d} then 1 else 0 end)`,
|
|
331
|
+
ok7d: sql<number>`sum(case when ${resultsTable.checkedAt} >= ${since7d} and ${resultsTable.ok} then 1 else 0 end)`,
|
|
332
|
+
total30d: sql<number>`sum(case when ${resultsTable.checkedAt} >= ${since30d} then 1 else 0 end)`,
|
|
333
|
+
ok30d: sql<number>`sum(case when ${resultsTable.checkedAt} >= ${since30d} and ${resultsTable.ok} then 1 else 0 end)`,
|
|
334
|
+
total90d: sql<number>`sum(case when ${resultsTable.checkedAt} >= ${since90d} then 1 else 0 end)`,
|
|
335
|
+
ok90d: sql<number>`sum(case when ${resultsTable.checkedAt} >= ${since90d} and ${resultsTable.ok} then 1 else 0 end)`,
|
|
336
|
+
})
|
|
337
|
+
.from(resultsTable)
|
|
338
|
+
.where(
|
|
339
|
+
and(
|
|
340
|
+
ownerScope(resultsTable, ctx),
|
|
341
|
+
inArray(resultsTable.monitorId, ids),
|
|
342
|
+
gte(resultsTable.checkedAt, since90d),
|
|
343
|
+
),
|
|
344
|
+
)
|
|
345
|
+
.groupBy(resultsTable.monitorId),
|
|
346
|
+
db
|
|
347
|
+
.select({
|
|
348
|
+
monitorId: resultsTable.monitorId,
|
|
349
|
+
day: sql<string>`substr(${resultsTable.checkedAt}, 1, 10)`,
|
|
350
|
+
total: sql<number>`count(*)`,
|
|
351
|
+
ok: sql<number>`sum(case when ${resultsTable.ok} then 1 else 0 end)`,
|
|
352
|
+
down: sql<number>`sum(case when ${resultsTable.status} in ('down','error') then 1 else 0 end)`,
|
|
353
|
+
degraded: sql<number>`sum(case when ${resultsTable.status} = 'degraded' then 1 else 0 end)`,
|
|
354
|
+
})
|
|
355
|
+
.from(resultsTable)
|
|
356
|
+
.where(
|
|
357
|
+
and(
|
|
358
|
+
ownerScope(resultsTable, ctx),
|
|
359
|
+
inArray(resultsTable.monitorId, ids),
|
|
360
|
+
gte(resultsTable.checkedAt, sinceTimeline),
|
|
361
|
+
),
|
|
362
|
+
)
|
|
363
|
+
.groupBy(
|
|
364
|
+
resultsTable.monitorId,
|
|
365
|
+
sql`substr(${resultsTable.checkedAt}, 1, 10)`,
|
|
366
|
+
),
|
|
367
|
+
db
|
|
368
|
+
.select({
|
|
369
|
+
monitorId: resultsTable.monitorId,
|
|
370
|
+
hour: sql<string>`substr(${resultsTable.checkedAt}, 1, 13)`,
|
|
371
|
+
avg: sql<number>`avg(${resultsTable.latencyMs})`,
|
|
372
|
+
min: sql<number>`min(${resultsTable.latencyMs})`,
|
|
373
|
+
max: sql<number>`max(${resultsTable.latencyMs})`,
|
|
374
|
+
count: sql<number>`count(${resultsTable.latencyMs})`,
|
|
375
|
+
})
|
|
376
|
+
.from(resultsTable)
|
|
377
|
+
.where(
|
|
378
|
+
and(
|
|
379
|
+
ownerScope(resultsTable, ctx),
|
|
380
|
+
inArray(resultsTable.monitorId, ids),
|
|
381
|
+
gte(resultsTable.checkedAt, sinceResponse),
|
|
382
|
+
sql`${resultsTable.latencyMs} is not null`,
|
|
383
|
+
),
|
|
384
|
+
)
|
|
385
|
+
.groupBy(
|
|
386
|
+
resultsTable.monitorId,
|
|
387
|
+
sql`substr(${resultsTable.checkedAt}, 1, 13)`,
|
|
388
|
+
),
|
|
389
|
+
db
|
|
390
|
+
.select({
|
|
391
|
+
monitorId: incidentsTable.monitorId,
|
|
392
|
+
startedAt: incidentsTable.startedAt,
|
|
393
|
+
resolvedAt: incidentsTable.resolvedAt,
|
|
394
|
+
})
|
|
395
|
+
.from(incidentsTable)
|
|
396
|
+
.where(
|
|
397
|
+
and(
|
|
398
|
+
ownerScope(incidentsTable, ctx),
|
|
399
|
+
inArray(incidentsTable.monitorId, ids),
|
|
400
|
+
gte(incidentsTable.startedAt, since90d),
|
|
401
|
+
),
|
|
402
|
+
),
|
|
403
|
+
]);
|
|
404
|
+
|
|
405
|
+
const windowById = new Map<string, UptimeWindowAggregate>();
|
|
406
|
+
for (const row of windowRows) {
|
|
407
|
+
windowById.set(row.monitorId, {
|
|
408
|
+
total24h: Number(row.total24h ?? 0),
|
|
409
|
+
ok24h: Number(row.ok24h ?? 0),
|
|
410
|
+
total7d: Number(row.total7d ?? 0),
|
|
411
|
+
ok7d: Number(row.ok7d ?? 0),
|
|
412
|
+
total30d: Number(row.total30d ?? 0),
|
|
413
|
+
ok30d: Number(row.ok30d ?? 0),
|
|
414
|
+
total90d: Number(row.total90d ?? 0),
|
|
415
|
+
ok90d: Number(row.ok90d ?? 0),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const dailyById = new Map<string, DailyBucketRow[]>();
|
|
420
|
+
for (const row of dailyRows) {
|
|
421
|
+
const list = dailyById.get(row.monitorId) ?? [];
|
|
422
|
+
list.push({
|
|
423
|
+
day: String(row.day),
|
|
424
|
+
total: Number(row.total ?? 0),
|
|
425
|
+
ok: Number(row.ok ?? 0),
|
|
426
|
+
down: Number(row.down ?? 0),
|
|
427
|
+
degraded: Number(row.degraded ?? 0),
|
|
428
|
+
});
|
|
429
|
+
dailyById.set(row.monitorId, list);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const responseById = new Map<string, ResponseTimePoint[]>();
|
|
433
|
+
for (const row of responseRows) {
|
|
434
|
+
const list = responseById.get(row.monitorId) ?? [];
|
|
435
|
+
const hourKey = String(row.hour);
|
|
436
|
+
list.push({
|
|
437
|
+
bucketStart: new Date(`${hourKey}:00:00.000Z`).toISOString(),
|
|
438
|
+
avg: row.avg == null ? null : Number(row.avg),
|
|
439
|
+
min: row.min == null ? null : Number(row.min),
|
|
440
|
+
max: row.max == null ? null : Number(row.max),
|
|
441
|
+
count: Number(row.count ?? 0),
|
|
442
|
+
});
|
|
443
|
+
responseById.set(row.monitorId, list);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const incidentsById = new Map<string, IncidentWindowRow[]>();
|
|
447
|
+
for (const row of incidentRows) {
|
|
448
|
+
const list = incidentsById.get(row.monitorId) ?? [];
|
|
449
|
+
list.push({ startedAt: row.startedAt, resolvedAt: row.resolvedAt ?? null });
|
|
450
|
+
incidentsById.set(row.monitorId, list);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const since90dMs = nowMs - 90 * DAY_MS;
|
|
454
|
+
|
|
455
|
+
for (const monitor of monitorRows) {
|
|
456
|
+
const id = monitor.id as string;
|
|
457
|
+
const windowAgg = windowById.get(id) ?? {
|
|
458
|
+
total24h: 0,
|
|
459
|
+
ok24h: 0,
|
|
460
|
+
total7d: 0,
|
|
461
|
+
ok7d: 0,
|
|
462
|
+
total30d: 0,
|
|
463
|
+
ok30d: 0,
|
|
464
|
+
total90d: 0,
|
|
465
|
+
ok90d: 0,
|
|
466
|
+
};
|
|
467
|
+
const timeline = assembleDailyTimeline(dailyById.get(id) ?? [], {
|
|
468
|
+
now,
|
|
469
|
+
days: timelineDays,
|
|
470
|
+
});
|
|
471
|
+
const responseSeries = (responseById.get(id) ?? []).sort((a, b) =>
|
|
472
|
+
a.bucketStart < b.bucketStart
|
|
473
|
+
? -1
|
|
474
|
+
: a.bucketStart > b.bucketStart
|
|
475
|
+
? 1
|
|
476
|
+
: 0,
|
|
477
|
+
);
|
|
478
|
+
const incidents = incidentsById.get(id) ?? [];
|
|
479
|
+
result.set(id, {
|
|
480
|
+
monitorId: id,
|
|
481
|
+
status: (monitor.lastStatus ?? null) as MonitorStatus | null,
|
|
482
|
+
lastCheckedAt: monitor.lastCheckedAt ?? null,
|
|
483
|
+
lastLatencyMs: monitor.lastLatencyMs ?? null,
|
|
484
|
+
windows: computeUptimePercents(windowAgg),
|
|
485
|
+
timeline,
|
|
486
|
+
responseSeries,
|
|
487
|
+
avgResponseMs: averageResponse(responseSeries),
|
|
488
|
+
incidentCount: incidents.length,
|
|
489
|
+
mtbfMs: computeMtbf(incidents, { windowStartMs: since90dMs, nowMs }),
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return result;
|
|
494
|
+
}
|