@agent-native/core 0.115.4 → 0.117.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +1 -0
- package/corpus/README.md +3 -3
- package/corpus/core/CHANGELOG.md +43 -0
- package/corpus/core/agent-native.eject.json +1 -0
- package/corpus/core/docs/AGENTS.md +1 -1
- package/corpus/core/docs/content/agent-mentions.mdx +2 -2
- package/corpus/core/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
- package/corpus/core/docs/content/agent-teams.mdx +4 -4
- package/corpus/core/docs/content/dispatch.mdx +10 -10
- package/corpus/core/docs/content/drop-in-agent.mdx +4 -4
- package/corpus/core/docs/content/external-agents.mdx +1 -1
- package/corpus/core/docs/content/frames.mdx +1 -1
- package/corpus/core/docs/content/integrations.mdx +13 -2
- package/corpus/core/docs/content/key-concepts.mdx +2 -2
- package/corpus/core/docs/content/mcp-clients.mdx +7 -1
- package/corpus/core/docs/content/multi-app-workspace.mdx +3 -3
- package/corpus/core/docs/content/real-time-collaboration.mdx +33 -15
- package/corpus/core/docs/content/recurring-jobs.mdx +7 -7
- package/corpus/core/docs/content/skills-guide.mdx +4 -4
- package/corpus/core/docs/content/template-brain.mdx +1 -1
- package/corpus/core/docs/content/toolkit-collaboration.mdx +1 -1
- package/corpus/core/docs/content/using-your-agent.mdx +1 -1
- package/corpus/core/docs/content/what-is-agent-native.mdx +4 -4
- package/corpus/core/docs/content/workspace-management.mdx +4 -4
- package/corpus/core/package.json +4 -1
- package/corpus/core/src/agent/production-agent.ts +13 -3
- package/corpus/core/src/cli/doctor.ts +6 -1
- package/corpus/core/src/client/AgentPanel.tsx +79 -41
- package/corpus/core/src/client/AssistantChat.tsx +71 -25
- package/corpus/core/src/client/FeedbackButton.tsx +33 -7
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +6 -8
- package/corpus/core/src/client/agent-chat-adapter.ts +11 -2
- package/corpus/core/src/client/agent-page/AgentTabFrame.tsx +22 -3
- package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +34 -19
- package/corpus/core/src/client/analytics.ts +7 -0
- package/corpus/core/src/client/chat/message-components.tsx +43 -16
- package/corpus/core/src/client/chat/tool-call-display.tsx +30 -18
- package/corpus/core/src/client/chat/tool-render-registry.tsx +2 -0
- package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +19 -2
- package/corpus/core/src/client/resources/ResourceTree.tsx +7 -10
- package/corpus/core/src/client/resources/ResourcesPanel.tsx +33 -70
- package/corpus/core/src/client/resources/mcp-connection-resume.ts +107 -0
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +65 -12
- package/corpus/core/src/client/resources/mcp-integration-logos.ts +4 -0
- package/corpus/core/src/client/sse-event-processor.ts +50 -14
- package/corpus/core/src/client/use-db-sync.ts +370 -21
- package/corpus/core/src/collab/client.ts +26 -2
- package/corpus/core/src/connections/catalog.ts +7 -1
- package/corpus/core/src/db/ddl-guard.ts +49 -10
- package/corpus/core/src/deploy/build.ts +25 -2
- package/corpus/core/src/eject/remote-mcp-presets.ts +37 -5
- package/corpus/core/src/guards/explicit-collab-access.ts +229 -0
- package/corpus/core/src/guards/index.ts +1 -0
- package/corpus/core/src/localization/default-messages.ts +54 -5
- package/corpus/core/src/mcp/connect-route.ts +34 -51
- package/corpus/core/src/provider-api/index.ts +1 -1
- package/corpus/core/src/realtime-protocol.ts +92 -0
- package/corpus/core/src/server/collab-plugin.ts +137 -18
- package/corpus/core/src/server/core-routes-plugin.ts +7 -0
- package/corpus/core/src/server/index.ts +2 -0
- package/corpus/core/src/server/poll-events.ts +29 -8
- package/corpus/core/src/server/poll.ts +1123 -865
- package/corpus/core/src/server/realtime-token.ts +106 -0
- package/corpus/core/src/server/sentry-config.ts +40 -0
- package/corpus/core/src/server/short-lived-token.ts +156 -0
- package/corpus/core/src/server/sse.ts +15 -0
- package/corpus/core/src/server/ssr-handler.ts +9 -3
- package/corpus/core/src/styles/agent-native.css +40 -0
- package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/analytics/AGENTS.md +7 -2
- package/corpus/templates/analytics/actions/export-dashboard-panel-to-google-sheet.ts +144 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -88
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +34 -37
- package/corpus/templates/analytics/app/global.css +0 -4
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -7
- package/corpus/templates/analytics/app/i18n-data.ts +107 -0
- package/corpus/templates/analytics/app/lib/data-source-status.ts +9 -0
- package/corpus/templates/analytics/app/lib/sql-query.ts +1 -2
- package/corpus/templates/analytics/app/pages/Ask.tsx +2 -7
- package/corpus/templates/analytics/app/pages/DataSources.tsx +48 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +59 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +3 -1
- package/corpus/templates/analytics/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-daily-dashboard-email-query-batches.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-export-table-panels-directly-to-google-sheets.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-recent-chats-can-expand-in-the-sidebar.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +8 -8
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +31 -0
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +3 -5
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +12 -0
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +3 -5
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +150 -21
- package/corpus/templates/analytics/server/lib/google-sheets-export.ts +188 -0
- package/corpus/templates/analytics/server/lib/provider-api.ts +7 -2
- package/corpus/templates/analytics/server/plugins/collab.ts +6 -3
- package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +54 -62
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -6
- package/corpus/templates/assets/app/routes/_index.tsx +8 -5
- package/corpus/templates/assets/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-22-recent-chats-expand-from-a-compact-list.md +6 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/brain/actions/rotate-source-ingest-token.ts +77 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -51
- package/corpus/templates/brain/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/brain/app/i18n-data.ts +120 -0
- package/corpus/templates/brain/app/routes/sources.tsx +156 -5
- package/corpus/templates/brain/changelog/2026-07-22-chat-runs-always-end-with-an-answer.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-long-chat-titles-stay-inside-the-sidebar.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-new-clips-and-webhook-sources-now-show-their-secure-connecti.md +6 -0
- package/corpus/templates/brain/jobs/emit-netlify-brain-queue-cron.ts +125 -0
- package/corpus/templates/brain/netlify.toml +5 -1
- package/corpus/templates/brain/scripts/configure-prod-clips-source.ts +50 -0
- package/corpus/templates/brain/server/lib/capture-sanitization.ts +64 -6
- package/corpus/templates/brain/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/brain/server/plugins/brain-jobs.ts +1 -0
- package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +55 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/corpus/templates/chat/app/routes/_index.tsx +8 -5
- package/corpus/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/clips/AGENTS.md +9 -1
- package/corpus/templates/clips/actions/export-to-brain.ts +82 -6
- package/corpus/templates/clips/actions/request-transcript.ts +25 -14
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +12 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/changelog/2026-07-22-clips-transcripts-now-retry-brain-export.md +5 -0
- package/corpus/templates/clips/changelog/2026-07-22-german-umlauts-and-other-non-ascii-characters-now-paste-corr.md +6 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +26 -3
- package/corpus/templates/clips/jobs/emit-netlify-brain-export-cron.ts +118 -0
- package/corpus/templates/clips/netlify.toml +4 -1
- package/corpus/templates/clips/scripts/configure-prod-brain-export.ts +92 -0
- package/corpus/templates/clips/server/jobs/brain-export.ts +182 -0
- package/corpus/templates/clips/server/lib/brain-export-state.ts +42 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +5 -1
- package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
- package/corpus/templates/clips/server/register-secrets.ts +42 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +10 -1
- package/corpus/templates/clips/server/routes/api/clips/brain-export/run.post.ts +45 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +566 -299
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +14 -0
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -1
- package/corpus/templates/content/app/i18n-data.ts +90 -0
- package/corpus/templates/content/server/plugins/collab.ts +1 -1
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/crm/actions/_crm-data-program-actions.ts +15 -0
- package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +2 -0
- package/corpus/templates/crm/actions/run.ts +2 -6
- package/corpus/templates/crm/actions/update-crm-record.ts +4 -2
- package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-crm-field-validation-now-explains-which-fields-cannot-be-edi.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-fixed-hubspot-contact-syncs-missing-records-updated-after-th.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-fixed-pipeline-dashboard-panels-so-their-opportunity-data-lo.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/crm/server/crm/hubspot-adapter.ts +4 -1
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/design/server/plugins/collab.ts +11 -8
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/forms/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/forms/app/root.tsx +1 -6
- package/corpus/templates/forms/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/plan/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +57 -72
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/plan/app/lib/create-plan-routing.ts +2 -2
- package/corpus/templates/plan/app/pages/PlanChatPage.tsx +0 -1
- package/corpus/templates/plan/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-22-recent-chats-and-sidebar-controls-are-more-compact.md +6 -0
- package/corpus/templates/plan/server/plugins/collab.ts +5 -2
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/slides/server/plugins/collab.ts +11 -8
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +5 -22
- package/corpus/templates/tasks/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +7 -0
- package/corpus/toolkit/README.md +12 -3
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/chat-history/ChatHistoryRail.tsx +89 -0
- package/corpus/toolkit/src/chat-history/index.ts +5 -0
- package/corpus/toolkit/src/chat-history.css +59 -0
- package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +106 -36
- package/corpus/toolkit/src/composer/VoiceButton.tsx +49 -0
- package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +2 -1
- package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +5 -3
- package/corpus/toolkit/src/styles.css +35 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +13 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +5 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +1 -0
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +38 -18
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +55 -20
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/FeedbackButton.d.ts +4 -2
- package/dist/client/FeedbackButton.d.ts.map +1 -1
- package/dist/client/FeedbackButton.js +18 -2
- package/dist/client/FeedbackButton.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +2 -3
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +11 -3
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-page/AgentTabFrame.d.ts +3 -1
- package/dist/client/agent-page/AgentTabFrame.d.ts.map +1 -1
- package/dist/client/agent-page/AgentTabFrame.js +3 -2
- package/dist/client/agent-page/AgentTabFrame.js.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.d.ts +2 -0
- package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.js +26 -15
- package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
- package/dist/client/analytics.d.ts +10 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +6 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +17 -11
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +11 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +16 -17
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/tool-render-registry.d.ts +2 -0
- package/dist/client/chat/tool-render-registry.d.ts.map +1 -1
- package/dist/client/chat/tool-render-registry.js.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.js +15 -1
- package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
- package/dist/client/resources/ResourceTree.d.ts.map +1 -1
- package/dist/client/resources/ResourceTree.js +3 -3
- package/dist/client/resources/ResourceTree.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts +1 -0
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +34 -20
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/resources/mcp-connection-resume.d.ts +11 -0
- package/dist/client/resources/mcp-connection-resume.d.ts.map +1 -0
- package/dist/client/resources/mcp-connection-resume.js +95 -0
- package/dist/client/resources/mcp-connection-resume.js.map +1 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +63 -8
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/resources/mcp-integration-logos.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-logos.js +4 -0
- package/dist/client/resources/mcp-integration-logos.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +5 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +39 -13
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -3
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +332 -21
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +26 -2
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +1 -1
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +7 -1
- package/dist/connections/catalog.js.map +1 -1
- package/dist/db/ddl-guard.d.ts +7 -2
- package/dist/db/ddl-guard.d.ts.map +1 -1
- package/dist/db/ddl-guard.js +21 -9
- package/dist/db/ddl-guard.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +25 -2
- package/dist/deploy/build.js.map +1 -1
- package/dist/eject/remote-mcp-presets.d.ts.map +1 -1
- package/dist/eject/remote-mcp-presets.js +33 -3
- package/dist/eject/remote-mcp-presets.js.map +1 -1
- package/dist/guards/explicit-collab-access.d.ts +8 -0
- package/dist/guards/explicit-collab-access.d.ts.map +1 -0
- package/dist/guards/explicit-collab-access.js +214 -0
- package/dist/guards/explicit-collab-access.js.map +1 -0
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.d.ts.map +1 -1
- package/dist/guards/index.js +1 -0
- package/dist/guards/index.js.map +1 -1
- package/dist/localization/default-messages.d.ts +43 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +48 -5
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +34 -48
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.js +1 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/realtime-protocol.d.ts +40 -0
- package/dist/realtime-protocol.d.ts.map +1 -0
- package/dist/realtime-protocol.js +69 -0
- package/dist/realtime-protocol.js.map +1 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/collab-plugin.d.ts +34 -3
- package/dist/server/collab-plugin.d.ts.map +1 -1
- package/dist/server/collab-plugin.js +65 -12
- package/dist/server/collab-plugin.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +3 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/poll-events.d.ts +7 -1
- package/dist/server/poll-events.d.ts.map +1 -1
- package/dist/server/poll-events.js +24 -7
- package/dist/server/poll-events.js.map +1 -1
- package/dist/server/poll.d.ts +223 -42
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +849 -737
- package/dist/server/poll.js.map +1 -1
- package/dist/server/realtime-token.d.ts +34 -0
- package/dist/server/realtime-token.d.ts.map +1 -0
- package/dist/server/realtime-token.js +85 -0
- package/dist/server/realtime-token.js.map +1 -0
- package/dist/server/sentry-config.d.ts +12 -0
- package/dist/server/sentry-config.d.ts.map +1 -1
- package/dist/server/sentry-config.js +34 -0
- package/dist/server/sentry-config.js.map +1 -1
- package/dist/server/short-lived-token.d.ts +46 -0
- package/dist/server/short-lived-token.d.ts.map +1 -1
- package/dist/server/short-lived-token.js +104 -0
- package/dist/server/short-lived-token.js.map +1 -1
- package/dist/server/sse.d.ts +1 -1
- package/dist/server/sse.d.ts.map +1 -1
- package/dist/server/sse.js +4 -0
- package/dist/server/sse.js.map +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +5 -3
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-native.css +40 -0
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/dist/templates/chat/app/routes/_index.tsx +8 -5
- package/dist/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/dist/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/dist/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
- package/docs/AGENTS.md +1 -1
- package/docs/content/agent-mentions.mdx +2 -2
- package/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
- package/docs/content/agent-teams.mdx +4 -4
- package/docs/content/dispatch.mdx +10 -10
- package/docs/content/drop-in-agent.mdx +4 -4
- package/docs/content/external-agents.mdx +1 -1
- package/docs/content/frames.mdx +1 -1
- package/docs/content/integrations.mdx +13 -2
- package/docs/content/key-concepts.mdx +2 -2
- package/docs/content/mcp-clients.mdx +7 -1
- package/docs/content/multi-app-workspace.mdx +3 -3
- package/docs/content/real-time-collaboration.mdx +33 -15
- package/docs/content/recurring-jobs.mdx +7 -7
- package/docs/content/skills-guide.mdx +4 -4
- package/docs/content/template-brain.mdx +1 -1
- package/docs/content/toolkit-collaboration.mdx +1 -1
- package/docs/content/using-your-agent.mdx +1 -1
- package/docs/content/what-is-agent-native.mdx +4 -4
- package/docs/content/workspace-management.mdx +4 -4
- package/package.json +6 -3
- package/src/agent/production-agent.ts +13 -3
- package/src/cli/doctor.ts +6 -1
- package/src/client/AgentPanel.tsx +79 -41
- package/src/client/AssistantChat.tsx +71 -25
- package/src/client/FeedbackButton.tsx +33 -7
- package/src/client/MultiTabAssistantChat.tsx +6 -8
- package/src/client/agent-chat-adapter.ts +11 -2
- package/src/client/agent-page/AgentTabFrame.tsx +22 -3
- package/src/client/agent-page/AgentTabsPage.tsx +34 -19
- package/src/client/analytics.ts +7 -0
- package/src/client/chat/message-components.tsx +43 -16
- package/src/client/chat/tool-call-display.tsx +30 -18
- package/src/client/chat/tool-render-registry.tsx +2 -0
- package/src/client/resources/McpConnectionSuggestion.tsx +19 -2
- package/src/client/resources/ResourceTree.tsx +7 -10
- package/src/client/resources/ResourcesPanel.tsx +33 -70
- package/src/client/resources/mcp-connection-resume.ts +107 -0
- package/src/client/resources/mcp-integration-catalog.ts +65 -12
- package/src/client/resources/mcp-integration-logos.ts +4 -0
- package/src/client/sse-event-processor.ts +50 -14
- package/src/client/use-db-sync.ts +370 -21
- package/src/collab/client.ts +26 -2
- package/src/connections/catalog.ts +7 -1
- package/src/db/ddl-guard.ts +49 -10
- package/src/deploy/build.ts +25 -2
- package/src/eject/remote-mcp-presets.ts +37 -5
- package/src/guards/explicit-collab-access.ts +229 -0
- package/src/guards/index.ts +1 -0
- package/src/localization/default-messages.ts +54 -5
- package/src/mcp/connect-route.ts +34 -51
- package/src/provider-api/index.ts +1 -1
- package/src/realtime-protocol.ts +92 -0
- package/src/server/collab-plugin.ts +137 -18
- package/src/server/core-routes-plugin.ts +7 -0
- package/src/server/index.ts +2 -0
- package/src/server/poll-events.ts +29 -8
- package/src/server/poll.ts +1123 -865
- package/src/server/realtime-token.ts +106 -0
- package/src/server/sentry-config.ts +40 -0
- package/src/server/short-lived-token.ts +156 -0
- package/src/server/sse.ts +15 -0
- package/src/server/ssr-handler.ts +9 -3
- package/src/styles/agent-native.css +40 -0
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/src/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/src/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/src/templates/chat/app/routes/_index.tsx +8 -5
- package/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-db-sync.d.ts","sourceRoot":"","sources":["../../src/client/use-db-sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-db-sync.d.ts","sourceRoot":"","sources":["../../src/client/use-db-sync.ts"],"names":[],"mappings":"AAkBA,UAAU,KAAK;IACb,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;CAC9B;AAED,UAAU,WAAW;IACnB,iBAAiB,CACf,IAAI,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;KACvC,EACD,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GACpC,OAAO,CAAC;IACX,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE;QACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;KACvC,GAAG,MAAM,CAAC;CACZ;AA2BD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AA4HF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAUxE;AA0sBD,gBAAgB;AAChB,wBAAgB,mCAAmC,IAAI,IAAI,CAE1D;AAED,MAAM,WAAW,0BAA0B;IACzC,gEAAgE;IAChE,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACrE,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,CACjB,SAAS,EAAE,OAAO,EAClB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,KAC7B,IAAI,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,0BAA0B,GAClC,MAAM,IAAI,CAuBZ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,SAAS,CACvB,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACxB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yBAAyB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;IACtD,6BAA6B,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC,GACL,IAAI,CAwTN;AAED,wCAAwC;AACxC,eAAO,MAAM,cAAc,kBAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;CACtB,GACL,MAAM,CAqER"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
2
|
import { ensureDemoModeFetchInterceptor } from "../demo/fetch-interceptor.js";
|
|
3
|
+
import { parseHandshakeFrame, parseTokenFrame, REALTIME_PROTOCOL_VERSION, REALTIME_SSE_HANDSHAKE_EVENT, REALTIME_SSE_TOKEN_EVENT, } from "../realtime-protocol.js";
|
|
3
4
|
import { agentNativePath } from "./api-path.js";
|
|
4
5
|
import { getBrowserTabId } from "./browser-tab-id.js";
|
|
5
6
|
import { ensureEmbedAuthFetchInterceptor, isEmbedAuthActive, } from "./embed-auth.js";
|
|
@@ -10,6 +11,7 @@ const POLL_ABORT_MIN_MS = 10_000;
|
|
|
10
11
|
// four times per minute forever. Focus and active agent work still poll now.
|
|
11
12
|
const SSE_FALLBACK_INTERVAL_MS = 60_000;
|
|
12
13
|
const IDLE_POLL_INTERVAL_MS = 60_000;
|
|
14
|
+
const HIDDEN_POLL_INTERVAL_MS = 10_000;
|
|
13
15
|
const POLL_AUTH_FAILURE_COOLDOWN_MS = 60_000;
|
|
14
16
|
/**
|
|
15
17
|
* Max cadence for SSE/poll-driven query invalidation in `useDbSync`. Events
|
|
@@ -38,6 +40,51 @@ function resolveSseUrl(sseUrl) {
|
|
|
38
40
|
return false;
|
|
39
41
|
return agentNativePath(sseUrl ?? "/_agent-native/events");
|
|
40
42
|
}
|
|
43
|
+
// --- Hosted Realtime Gateway binding ----------------------------------------
|
|
44
|
+
//
|
|
45
|
+
// When the app is configured for the hosted gateway, the transport connects to
|
|
46
|
+
// the gateway (cross-origin) instead of the Netlify app, carrying a short-lived
|
|
47
|
+
// subscribe token minted from the app's own same-origin endpoint. All of this
|
|
48
|
+
// is gated on a non-null binding — apps without hosted config keep the exact
|
|
49
|
+
// local behavior below.
|
|
50
|
+
const REALTIME_GATEWAY_SSE_PATH = "/stream";
|
|
51
|
+
const REALTIME_GATEWAY_POLL_PATH = "/poll";
|
|
52
|
+
const REALTIME_TOKEN_MINT_PATH = "/_agent-native/realtime-token";
|
|
53
|
+
/** Consecutive gateway failures before health-gating back to the local app. */
|
|
54
|
+
const HOSTED_UNHEALTHY_THRESHOLD = 3;
|
|
55
|
+
function getRealtimeConfig() {
|
|
56
|
+
if (typeof window === "undefined")
|
|
57
|
+
return undefined;
|
|
58
|
+
return window.__AGENT_NATIVE_CONFIG__?.realtime;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve the hosted-gateway binding, or null to stay on the local app. Gated
|
|
62
|
+
* on: SSE enabled (the gateway is push-first), not embed auth (needs the
|
|
63
|
+
* same-origin session to mint), and `transport: "hosted"` with a base URL in
|
|
64
|
+
* the impersonal SSR config.
|
|
65
|
+
*/
|
|
66
|
+
function resolveGatewayBinding(localSseUrl) {
|
|
67
|
+
if (localSseUrl === false)
|
|
68
|
+
return null;
|
|
69
|
+
if (isEmbedAuthActive())
|
|
70
|
+
return null;
|
|
71
|
+
const config = getRealtimeConfig();
|
|
72
|
+
if (config?.transport !== "hosted")
|
|
73
|
+
return null;
|
|
74
|
+
const base = config.gatewayBaseUrl?.replace(/\/+$/, "");
|
|
75
|
+
if (!base)
|
|
76
|
+
return null;
|
|
77
|
+
return {
|
|
78
|
+
sseUrl: `${base}${REALTIME_GATEWAY_SSE_PATH}`,
|
|
79
|
+
pollUrl: `${base}${REALTIME_GATEWAY_POLL_PATH}`,
|
|
80
|
+
tokenMintUrl: agentNativePath(REALTIME_TOKEN_MINT_PATH),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** ±20% jitter so gateway timeout/deploy-driven reconnects don't stampede. */
|
|
84
|
+
function applyReconnectJitter(delay) {
|
|
85
|
+
const jitter = delay * 0.2 * (Math.random() * 2 - 1);
|
|
86
|
+
return Math.max(0, Math.round(delay + jitter));
|
|
87
|
+
}
|
|
41
88
|
function normalizeEventPayload(payload) {
|
|
42
89
|
if (!payload || typeof payload !== "object")
|
|
43
90
|
return [];
|
|
@@ -90,13 +137,19 @@ export function isInteractionCriticalSyncEvent(event) {
|
|
|
90
137
|
INTERACTION_CRITICAL_APP_STATE_KEYS.some((key) => event.key === key ||
|
|
91
138
|
(typeof event.key === "string" && event.key.startsWith(`${key}:`)))));
|
|
92
139
|
}
|
|
93
|
-
async function fetchPollJson(pollUrl, since, interval) {
|
|
140
|
+
async function fetchPollJson(pollUrl, since, interval, token) {
|
|
94
141
|
const controller = typeof AbortController === "undefined" ? null : new AbortController();
|
|
95
142
|
const timeout = controller
|
|
96
143
|
? setTimeout(() => controller.abort(), getPollAbortMs(interval))
|
|
97
144
|
: null;
|
|
145
|
+
// Local path stays exactly `?since=N`; the hosted gateway also carries the
|
|
146
|
+
// subscribe token on the query string (a cross-origin fetch can't set the
|
|
147
|
+
// Authorization header for the SSE sibling either, so both use the query).
|
|
148
|
+
const url = token
|
|
149
|
+
? `${pollUrl}${pollUrl.includes("?") ? "&" : "?"}since=${since}&token=${encodeURIComponent(token)}`
|
|
150
|
+
: `${pollUrl}?since=${since}`;
|
|
98
151
|
try {
|
|
99
|
-
const res = await fetch(
|
|
152
|
+
const res = await fetch(url, controller ? { signal: controller.signal } : undefined);
|
|
100
153
|
if (!res.ok)
|
|
101
154
|
throw new HttpStatusError(res.status);
|
|
102
155
|
// Await the json before the finally so a body-stream abort doesn't
|
|
@@ -111,6 +164,7 @@ async function fetchPollJson(pollUrl, since, interval) {
|
|
|
111
164
|
class SyncTransport {
|
|
112
165
|
pollUrl;
|
|
113
166
|
sseUrl;
|
|
167
|
+
gateway;
|
|
114
168
|
subscribers = new Map();
|
|
115
169
|
versionRef = 0;
|
|
116
170
|
timer = null;
|
|
@@ -121,9 +175,145 @@ class SyncTransport {
|
|
|
121
175
|
authFailureUntil = 0;
|
|
122
176
|
consecutiveFailures = 0;
|
|
123
177
|
activeChatIds = new Set();
|
|
124
|
-
|
|
178
|
+
// Hosted-gateway state. `mode` starts "hosted" when a binding is present and
|
|
179
|
+
// flips to "local" on health-gate revert; `token` is the current subscribe
|
|
180
|
+
// token (minted from the app, rotated over the stream), never part of any
|
|
181
|
+
// registry key.
|
|
182
|
+
mode;
|
|
183
|
+
token = null;
|
|
184
|
+
tokenMintInFlight = null;
|
|
185
|
+
gatewayReconnectTimer = null;
|
|
186
|
+
capabilities = [];
|
|
187
|
+
constructor(pollUrl, sseUrl, gateway = null) {
|
|
125
188
|
this.pollUrl = pollUrl;
|
|
126
189
|
this.sseUrl = sseUrl;
|
|
190
|
+
this.gateway = gateway;
|
|
191
|
+
this.mode = gateway ? "hosted" : "local";
|
|
192
|
+
}
|
|
193
|
+
/** Capabilities advertised by the gateway handshake (e.g. `no-awareness`). */
|
|
194
|
+
getCapabilities() {
|
|
195
|
+
return this.capabilities;
|
|
196
|
+
}
|
|
197
|
+
get activeSseUrl() {
|
|
198
|
+
if (this.mode === "hosted" && this.gateway) {
|
|
199
|
+
return this.token
|
|
200
|
+
? `${this.gateway.sseUrl}?token=${encodeURIComponent(this.token)}`
|
|
201
|
+
: this.gateway.sseUrl;
|
|
202
|
+
}
|
|
203
|
+
return this.sseUrl;
|
|
204
|
+
}
|
|
205
|
+
get activePollUrl() {
|
|
206
|
+
return this.mode === "hosted" && this.gateway
|
|
207
|
+
? this.gateway.pollUrl
|
|
208
|
+
: this.pollUrl;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Mint a subscribe token from the app's same-origin endpoint.
|
|
212
|
+
*
|
|
213
|
+
* Only TERMINAL outcomes health-gate to local: 404 (gateway not provisioned)
|
|
214
|
+
* and 401/403 (not authorized) — retrying those for this tab is pointless.
|
|
215
|
+
* TRANSIENT failures (5xx/429 from a cold Netlify function, network errors)
|
|
216
|
+
* keep the hosted intent and ride the jittered reconnect + unhealthy-threshold
|
|
217
|
+
* path, so a deploy / scale-to-zero blip doesn't permanently abandon the
|
|
218
|
+
* gateway for the tab.
|
|
219
|
+
*/
|
|
220
|
+
mintToken() {
|
|
221
|
+
if (!this.gateway || this.mode !== "hosted")
|
|
222
|
+
return Promise.resolve(false);
|
|
223
|
+
if (this.tokenMintInFlight)
|
|
224
|
+
return this.tokenMintInFlight;
|
|
225
|
+
const mintUrl = this.gateway.tokenMintUrl;
|
|
226
|
+
this.tokenMintInFlight = (async () => {
|
|
227
|
+
// Bound the mint like fetchPollJson bounds polls: a black-holed request
|
|
228
|
+
// must resolve as a transient failure, not hang tokenMintInFlight forever
|
|
229
|
+
// (poll() awaits this while holding inFlight, so a hung mint would stall
|
|
230
|
+
// the whole transport with no timer pending).
|
|
231
|
+
const controller = typeof AbortController === "undefined" ? null : new AbortController();
|
|
232
|
+
const timeout = controller
|
|
233
|
+
? setTimeout(() => controller.abort(), POLL_ABORT_MIN_MS)
|
|
234
|
+
: null;
|
|
235
|
+
try {
|
|
236
|
+
const res = await fetch(mintUrl, {
|
|
237
|
+
credentials: "same-origin",
|
|
238
|
+
...(controller ? { signal: controller.signal } : {}),
|
|
239
|
+
});
|
|
240
|
+
if (res.ok) {
|
|
241
|
+
const data = (await res.json());
|
|
242
|
+
if (typeof data?.token === "string" && data.token) {
|
|
243
|
+
this.token = data.token;
|
|
244
|
+
// Deliberately NOT resetting consecutiveFailures here: minting
|
|
245
|
+
// succeeds via the app origin even when the GATEWAY is down, so a
|
|
246
|
+
// reset would let a mint-ok -> stream-fail loop run forever below
|
|
247
|
+
// the unhealthy threshold. Only real gateway connectivity (stream
|
|
248
|
+
// onopen / poll success) clears the count.
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
// 2xx without a token is a terminal misconfiguration.
|
|
252
|
+
this.revertToLocal();
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
if (res.status === 404 || res.status === 401 || res.status === 403) {
|
|
256
|
+
this.revertToLocal();
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
this.onGatewayTransientFailure();
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
this.onGatewayTransientFailure();
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
if (timeout)
|
|
268
|
+
clearTimeout(timeout);
|
|
269
|
+
this.tokenMintInFlight = null;
|
|
270
|
+
}
|
|
271
|
+
})();
|
|
272
|
+
return this.tokenMintInFlight;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* A transient gateway failure (mint 5xx/429, network). Keep hosted intent but
|
|
276
|
+
* count toward the unhealthy threshold; revert to local only once it trips.
|
|
277
|
+
*/
|
|
278
|
+
onGatewayTransientFailure() {
|
|
279
|
+
this.consecutiveFailures++;
|
|
280
|
+
if (this.consecutiveFailures >= HOSTED_UNHEALTHY_THRESHOLD) {
|
|
281
|
+
this.revertToLocal();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Health-gate back to the app's own /poll + /events with the cursor intact
|
|
286
|
+
* (versionRef is untouched), so delivery stays poll-equivalent — never a
|
|
287
|
+
* silent stall.
|
|
288
|
+
*/
|
|
289
|
+
revertToLocal() {
|
|
290
|
+
if (this.mode === "local")
|
|
291
|
+
return;
|
|
292
|
+
this.mode = "local";
|
|
293
|
+
this.token = null;
|
|
294
|
+
// The local in-process SSE path sends no handshake, so hosted capabilities
|
|
295
|
+
// (e.g. no-awareness) must not survive the fallback — stale caps would keep
|
|
296
|
+
// collab on its fast presence cadence against the local stream. Subscribers
|
|
297
|
+
// are re-notified via the close/connect cycle below.
|
|
298
|
+
this.capabilities = [];
|
|
299
|
+
if (this.gatewayReconnectTimer) {
|
|
300
|
+
clearTimeout(this.gatewayReconnectTimer);
|
|
301
|
+
this.gatewayReconnectTimer = null;
|
|
302
|
+
}
|
|
303
|
+
this.closeEvents();
|
|
304
|
+
if (!this.stopped) {
|
|
305
|
+
this.connectEvents();
|
|
306
|
+
this.schedulePoll();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
scheduleGatewayReconnect() {
|
|
310
|
+
if (this.stopped || this.gatewayReconnectTimer)
|
|
311
|
+
return;
|
|
312
|
+
this.gatewayReconnectTimer = setTimeout(() => {
|
|
313
|
+
this.gatewayReconnectTimer = null;
|
|
314
|
+
if (!this.stopped && !this.eventSource)
|
|
315
|
+
this.connectEvents();
|
|
316
|
+
}, applyReconnectJitter(1000));
|
|
127
317
|
}
|
|
128
318
|
// -------------------------------------------------------------------------
|
|
129
319
|
// Subscriber management
|
|
@@ -144,7 +334,7 @@ class SyncTransport {
|
|
|
144
334
|
else {
|
|
145
335
|
this.reschedule();
|
|
146
336
|
}
|
|
147
|
-
sub.onSseStateChange?.(this.sseConnected);
|
|
337
|
+
sub.onSseStateChange?.(this.sseConnected, this.capabilities);
|
|
148
338
|
}
|
|
149
339
|
remove(id) {
|
|
150
340
|
this.subscribers.delete(id);
|
|
@@ -207,8 +397,17 @@ class SyncTransport {
|
|
|
207
397
|
if (this.sseConnected === connected)
|
|
208
398
|
return;
|
|
209
399
|
this.sseConnected = connected;
|
|
400
|
+
this.notifySseState();
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Notify subscribers of the current SSE state AND the negotiated gateway
|
|
404
|
+
* capabilities. Called on connect/disconnect and again once the handshake
|
|
405
|
+
* arrives, so a consumer (e.g. collab) can decide — for instance — not to
|
|
406
|
+
* relax its presence cadence on a `no-awareness` hosted stream.
|
|
407
|
+
*/
|
|
408
|
+
notifySseState() {
|
|
210
409
|
for (const sub of this.subscribers.values()) {
|
|
211
|
-
sub.onSseStateChange?.(
|
|
410
|
+
sub.onSseStateChange?.(this.sseConnected, this.capabilities);
|
|
212
411
|
}
|
|
213
412
|
}
|
|
214
413
|
// -------------------------------------------------------------------------
|
|
@@ -232,18 +431,25 @@ class SyncTransport {
|
|
|
232
431
|
}, authDelay);
|
|
233
432
|
return;
|
|
234
433
|
}
|
|
235
|
-
const
|
|
434
|
+
const visibleBase = this.isActive
|
|
236
435
|
? this.effectiveInterval
|
|
237
436
|
: this.sseConnected
|
|
238
437
|
? this.effectiveFallbackInterval
|
|
239
438
|
: this.effectiveIdleInterval;
|
|
439
|
+
const base = isDocumentHidden()
|
|
440
|
+
? Math.max(visibleBase, HIDDEN_POLL_INTERVAL_MS)
|
|
441
|
+
: visibleBase;
|
|
240
442
|
// Exponential backoff while polls keep failing (500s during a deploy,
|
|
241
443
|
// DNS blips, a struggling DB). Auth failures have their own cooldown
|
|
242
444
|
// above; this covers everything else so a down server isn't hammered at
|
|
243
445
|
// full cadence. Resets on the first successful poll.
|
|
244
|
-
const
|
|
446
|
+
const backoff = this.consecutiveFailures > 0
|
|
245
447
|
? Math.min(base * 2 ** Math.min(this.consecutiveFailures, 5), 300_000)
|
|
246
448
|
: base;
|
|
449
|
+
// Jitter only for gateway-capable transports so reconnect/poll retries
|
|
450
|
+
// don't stampede a gateway deploy; apps with no gateway config keep the
|
|
451
|
+
// exact deterministic cadence.
|
|
452
|
+
const delay = this.gateway ? applyReconnectJitter(backoff) : backoff;
|
|
247
453
|
this.timer = setTimeout(() => {
|
|
248
454
|
this.timer = null;
|
|
249
455
|
void this.poll();
|
|
@@ -267,16 +473,44 @@ class SyncTransport {
|
|
|
267
473
|
}
|
|
268
474
|
connectEvents() {
|
|
269
475
|
if (this.stopped ||
|
|
270
|
-
!this.sseUrl ||
|
|
271
476
|
this.eventSource ||
|
|
272
477
|
typeof EventSource === "undefined" ||
|
|
273
478
|
(this.effectivePauseWhenHidden && isDocumentHidden())) {
|
|
274
479
|
return;
|
|
275
480
|
}
|
|
276
|
-
|
|
481
|
+
// Hosted gateway needs a subscribe token before the stream can open.
|
|
482
|
+
// EventSource can't set headers, so the token rides the connect query
|
|
483
|
+
// string (see activeSseUrl). Mint first, then connect.
|
|
484
|
+
if (this.mode === "hosted" && this.gateway && !this.token) {
|
|
485
|
+
void this.mintToken().then((ok) => {
|
|
486
|
+
if (this.stopped)
|
|
487
|
+
return;
|
|
488
|
+
if (ok && !this.eventSource) {
|
|
489
|
+
this.connectEvents();
|
|
490
|
+
}
|
|
491
|
+
else if (!ok && this.mode === "hosted") {
|
|
492
|
+
// Transient mint failure (terminal ones already reverted to local,
|
|
493
|
+
// flipping mode). Without a retry timer nothing would ever reopen
|
|
494
|
+
// SSE — connectEvents is only reachable from focus/visibility/run
|
|
495
|
+
// events — leaving the tab poll-only at the idle cadence.
|
|
496
|
+
this.scheduleGatewayReconnect();
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
const url = this.activeSseUrl;
|
|
502
|
+
if (!url)
|
|
503
|
+
return;
|
|
504
|
+
const source = new EventSource(url);
|
|
277
505
|
this.eventSource = source;
|
|
278
506
|
source.onopen = () => {
|
|
279
507
|
this.setSseConnected(true);
|
|
508
|
+
if (this.mode === "hosted") {
|
|
509
|
+
// A live gateway stream is the real health signal: clear failure
|
|
510
|
+
// counts accumulated by mint/stream retries. Local mode keeps main's
|
|
511
|
+
// semantics (only a successful poll resets the poll backoff).
|
|
512
|
+
this.consecutiveFailures = 0;
|
|
513
|
+
}
|
|
280
514
|
this.schedulePoll();
|
|
281
515
|
};
|
|
282
516
|
source.onerror = () => {
|
|
@@ -288,6 +522,20 @@ class SyncTransport {
|
|
|
288
522
|
// we'd be stuck on polling-only forever.
|
|
289
523
|
if (source.readyState === EventSource.CLOSED) {
|
|
290
524
|
this.eventSource = null;
|
|
525
|
+
if (this.mode === "hosted" && this.gateway) {
|
|
526
|
+
// A closed gateway stream is most likely an expired token or a
|
|
527
|
+
// request-timeout/deploy cycle. Re-mint and reconnect with jitter;
|
|
528
|
+
// this is NOT the poll-401 cooldown path. Each closed stream counts
|
|
529
|
+
// toward the unhealthy threshold so a hard-down gateway (or one
|
|
530
|
+
// rejecting our tokens) health-gates to local instead of looping
|
|
531
|
+
// mint+connect forever; a successful reconnect resets the count in
|
|
532
|
+
// onopen above.
|
|
533
|
+
this.token = null;
|
|
534
|
+
this.onGatewayTransientFailure();
|
|
535
|
+
if (this.mode === "hosted")
|
|
536
|
+
this.scheduleGatewayReconnect();
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
291
539
|
}
|
|
292
540
|
this.schedulePoll();
|
|
293
541
|
};
|
|
@@ -303,6 +551,37 @@ class SyncTransport {
|
|
|
303
551
|
// Ignore malformed SSE frames; polling is the safety net.
|
|
304
552
|
}
|
|
305
553
|
};
|
|
554
|
+
if (this.mode === "hosted" && this.gateway) {
|
|
555
|
+
// Control frames ride NAMED SSE events so they never reach onmessage /
|
|
556
|
+
// normalizeEventPayload as spurious data events.
|
|
557
|
+
source.addEventListener(REALTIME_SSE_HANDSHAKE_EVENT, (e) => {
|
|
558
|
+
const hs = parseHandshakeFrame(e.data);
|
|
559
|
+
if (!hs)
|
|
560
|
+
return;
|
|
561
|
+
if (hs.protocol !== REALTIME_PROTOCOL_VERSION) {
|
|
562
|
+
// Surface an unexpected protocol rather than silently adopting its
|
|
563
|
+
// capabilities; keep the conservative (no advertised capabilities)
|
|
564
|
+
// stance so downstream (collab) does not relax on assumptions.
|
|
565
|
+
console.warn(`[agent-native] unsupported realtime protocol ${hs.protocol} (expected ${REALTIME_PROTOCOL_VERSION})`);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
this.capabilities = hs.capabilities;
|
|
569
|
+
// Re-notify subscribers now that capabilities are known — the initial
|
|
570
|
+
// connected notification fired before the handshake arrived.
|
|
571
|
+
this.notifySseState();
|
|
572
|
+
});
|
|
573
|
+
source.addEventListener(REALTIME_SSE_TOKEN_EVENT, (e) => {
|
|
574
|
+
const frame = parseTokenFrame(e.data);
|
|
575
|
+
if (!frame?.token)
|
|
576
|
+
return;
|
|
577
|
+
this.token = frame.token;
|
|
578
|
+
// EventSource can't change a live stream's URL, and its auto-reconnect
|
|
579
|
+
// reuses the original (old-token) URL. Close and reconnect (jittered) so
|
|
580
|
+
// the rotated token is actually used on the next connect.
|
|
581
|
+
this.closeEvents();
|
|
582
|
+
this.scheduleGatewayReconnect();
|
|
583
|
+
});
|
|
584
|
+
}
|
|
306
585
|
}
|
|
307
586
|
/**
|
|
308
587
|
* Advance the transport's shared version cursor. Subscribers receive the
|
|
@@ -325,7 +604,14 @@ class SyncTransport {
|
|
|
325
604
|
return;
|
|
326
605
|
this.inFlight = true;
|
|
327
606
|
try {
|
|
328
|
-
|
|
607
|
+
if (this.mode === "hosted" && this.gateway && !this.token) {
|
|
608
|
+
// No token yet — mint before polling the gateway. A failed mint has
|
|
609
|
+
// already reverted us to local; a scheduled poll will pick it up.
|
|
610
|
+
const ok = await this.mintToken();
|
|
611
|
+
if (!ok || this.stopped)
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
const data = await fetchPollJson(this.activePollUrl, this.versionRef, this.effectiveInterval, this.mode === "hosted" ? (this.token ?? undefined) : undefined);
|
|
329
615
|
if (this.stopped)
|
|
330
616
|
return;
|
|
331
617
|
this.consecutiveFailures = 0;
|
|
@@ -337,7 +623,19 @@ class SyncTransport {
|
|
|
337
623
|
if (this.stopped)
|
|
338
624
|
return;
|
|
339
625
|
this.consecutiveFailures++;
|
|
340
|
-
if (
|
|
626
|
+
if (this.mode === "hosted" && this.gateway) {
|
|
627
|
+
// Gateway auth failure → re-mint (expired/rotated token), WITHOUT
|
|
628
|
+
// tripping the poll-401 cooldown. Persistent failures of any kind
|
|
629
|
+
// health-gate back to the local app.
|
|
630
|
+
if (isAuthFailure(err)) {
|
|
631
|
+
this.token = null;
|
|
632
|
+
void this.mintToken();
|
|
633
|
+
}
|
|
634
|
+
if (this.consecutiveFailures >= HOSTED_UNHEALTHY_THRESHOLD) {
|
|
635
|
+
this.revertToLocal();
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
else if (isAuthFailure(err)) {
|
|
341
639
|
this.authFailureUntil = Date.now() + POLL_AUTH_FAILURE_COOLDOWN_MS;
|
|
342
640
|
this.closeEvents();
|
|
343
641
|
}
|
|
@@ -374,6 +672,12 @@ class SyncTransport {
|
|
|
374
672
|
this.timer = null;
|
|
375
673
|
}
|
|
376
674
|
}
|
|
675
|
+
else {
|
|
676
|
+
// Keep push connected and the polling safety net alive in backgrounded
|
|
677
|
+
// tabs, but relax an active chat's cadence so hidden work stays current
|
|
678
|
+
// without polling as aggressively as the visible surface.
|
|
679
|
+
this.reschedule();
|
|
680
|
+
}
|
|
377
681
|
};
|
|
378
682
|
handleFocus = () => {
|
|
379
683
|
this.pollNow();
|
|
@@ -427,6 +731,10 @@ class SyncTransport {
|
|
|
427
731
|
clearTimeout(this.timer);
|
|
428
732
|
this.timer = null;
|
|
429
733
|
}
|
|
734
|
+
if (this.gatewayReconnectTimer) {
|
|
735
|
+
clearTimeout(this.gatewayReconnectTimer);
|
|
736
|
+
this.gatewayReconnectTimer = null;
|
|
737
|
+
}
|
|
430
738
|
window.removeEventListener("focus", this.handleFocus);
|
|
431
739
|
window.removeEventListener("agentNative.chatRunning", this.handleChatRunning);
|
|
432
740
|
document.removeEventListener("visibilitychange", this.handleVisibilityChange);
|
|
@@ -438,11 +746,13 @@ class SyncTransport {
|
|
|
438
746
|
* hook instances in the same browser tab.
|
|
439
747
|
*/
|
|
440
748
|
const transportRegistry = new Map();
|
|
441
|
-
function getOrCreateTransport(pollUrl, sseUrl) {
|
|
749
|
+
function getOrCreateTransport(pollUrl, sseUrl, gateway = null) {
|
|
750
|
+
// Key on the LOCAL urls only — a transport may flip hosted→local at runtime,
|
|
751
|
+
// and the token must never fragment the registry, so neither is in the key.
|
|
442
752
|
const key = `${pollUrl}\0${String(sseUrl)}`;
|
|
443
753
|
let transport = transportRegistry.get(key);
|
|
444
754
|
if (!transport) {
|
|
445
|
-
transport = new SyncTransport(pollUrl, sseUrl);
|
|
755
|
+
transport = new SyncTransport(pollUrl, sseUrl, gateway);
|
|
446
756
|
transportRegistry.set(key, transport);
|
|
447
757
|
}
|
|
448
758
|
return transport;
|
|
@@ -475,12 +785,12 @@ export function _resetSyncTransportRegistryForTests() {
|
|
|
475
785
|
export function subscribeSyncEvents(options) {
|
|
476
786
|
const pollUrl = agentNativePath(options.pollUrl ?? "/_agent-native/poll");
|
|
477
787
|
const sseUrl = resolveSseUrl(options.sseUrl);
|
|
478
|
-
const transport = getOrCreateTransport(pollUrl, sseUrl);
|
|
788
|
+
const transport = getOrCreateTransport(pollUrl, sseUrl, resolveGatewayBinding(sseUrl));
|
|
479
789
|
const id = Symbol("subscribeSyncEvents");
|
|
480
790
|
transport.add(id, {
|
|
481
791
|
onEvents: options.onEvents,
|
|
482
792
|
onSseStateChange: options.onSseStateChange,
|
|
483
|
-
pauseWhenHidden: options.pauseWhenHidden ??
|
|
793
|
+
pauseWhenHidden: options.pauseWhenHidden ?? false,
|
|
484
794
|
interval: options.interval ?? 60_000,
|
|
485
795
|
idleInterval: options.interval ?? 60_000,
|
|
486
796
|
fallbackInterval: options.fallbackInterval ?? 60_000,
|
|
@@ -513,8 +823,9 @@ export function subscribeSyncEvents(options) {
|
|
|
513
823
|
* @param options.interval - Poll interval in ms. Default: 2000
|
|
514
824
|
* @param options.fallbackInterval - Poll interval while SSE is connected.
|
|
515
825
|
* Default: 60000
|
|
516
|
-
* @param options.pauseWhenHidden - Pause
|
|
517
|
-
* Default:
|
|
826
|
+
* @param options.pauseWhenHidden - Pause sync while the tab is hidden.
|
|
827
|
+
* Default: false. Hidden tabs keep SSE connected and poll no faster than
|
|
828
|
+
* every 10 seconds while active; idle polling remains at 60 seconds.
|
|
518
829
|
* @param options.ignoreSource - Skip events whose `requestSource` matches this
|
|
519
830
|
* value. Use a per-tab ID so the UI ignores its own writes while still
|
|
520
831
|
* picking up changes from other tabs, agents, and scripts.
|
|
@@ -527,7 +838,7 @@ export function subscribeSyncEvents(options) {
|
|
|
527
838
|
* background actions that perform their own narrow client invalidation.
|
|
528
839
|
*/
|
|
529
840
|
export function useDbSync(options = {}) {
|
|
530
|
-
const { queryClient, pollUrl = agentNativePath(options.eventsUrl ?? "/_agent-native/poll"), sseUrl = resolveSseUrl(options.sseUrl), interval = 2000, fallbackInterval = Math.max(options.fallbackInterval ?? SSE_FALLBACK_INTERVAL_MS, interval), pauseWhenHidden =
|
|
841
|
+
const { queryClient, pollUrl = agentNativePath(options.eventsUrl ?? "/_agent-native/poll"), sseUrl = resolveSseUrl(options.sseUrl), interval = 2000, fallbackInterval = Math.max(options.fallbackInterval ?? SSE_FALLBACK_INTERVAL_MS, interval), pauseWhenHidden = false, } = options;
|
|
531
842
|
const idleInterval = options.interval === undefined ? IDLE_POLL_INTERVAL_MS : interval;
|
|
532
843
|
const onEventRef = useRef(options.onEvent);
|
|
533
844
|
onEventRef.current = options.onEvent;
|
|
@@ -730,7 +1041,7 @@ export function useDbSync(options = {}) {
|
|
|
730
1041
|
const maxEventVersion = freshEvents.reduce((max, event) => Math.max(max, typeof event.version === "number" ? event.version : 0), 0);
|
|
731
1042
|
subscriberVersion = Math.max(subscriberVersion, version ?? 0, maxEventVersion);
|
|
732
1043
|
}
|
|
733
|
-
const transport = getOrCreateTransport(pollUrl, sseUrl);
|
|
1044
|
+
const transport = getOrCreateTransport(pollUrl, sseUrl, resolveGatewayBinding(sseUrl));
|
|
734
1045
|
transport.add(id, {
|
|
735
1046
|
onEvents,
|
|
736
1047
|
pauseWhenHidden,
|
|
@@ -786,7 +1097,7 @@ export const useFileWatcher = useDbSync;
|
|
|
786
1097
|
* );
|
|
787
1098
|
*/
|
|
788
1099
|
export function useScreenRefreshKey(options = {}) {
|
|
789
|
-
const { pollUrl = agentNativePath(options.pollUrl ?? "/_agent-native/poll"), sseUrl = resolveSseUrl(options.sseUrl), interval = 2000, fallbackInterval = Math.max(options.fallbackInterval ?? SSE_FALLBACK_INTERVAL_MS, interval), pauseWhenHidden =
|
|
1100
|
+
const { pollUrl = agentNativePath(options.pollUrl ?? "/_agent-native/poll"), sseUrl = resolveSseUrl(options.sseUrl), interval = 2000, fallbackInterval = Math.max(options.fallbackInterval ?? SSE_FALLBACK_INTERVAL_MS, interval), pauseWhenHidden = false, } = options;
|
|
790
1101
|
const idleInterval = options.interval === undefined ? IDLE_POLL_INTERVAL_MS : interval;
|
|
791
1102
|
const [key, setKey] = useState(0);
|
|
792
1103
|
useEffect(() => {
|
|
@@ -804,7 +1115,7 @@ export function useScreenRefreshKey(options = {}) {
|
|
|
804
1115
|
const maxEventVersion = freshEvents.reduce((max, event) => Math.max(max, typeof event.version === "number" ? event.version : 0), 0);
|
|
805
1116
|
subscriberVersion = Math.max(subscriberVersion, version ?? 0, maxEventVersion);
|
|
806
1117
|
}
|
|
807
|
-
const transport = getOrCreateTransport(pollUrl, sseUrl);
|
|
1118
|
+
const transport = getOrCreateTransport(pollUrl, sseUrl, resolveGatewayBinding(sseUrl));
|
|
808
1119
|
transport.add(id, {
|
|
809
1120
|
onEvents,
|
|
810
1121
|
pauseWhenHidden,
|