@agent-native/core 0.69.0 → 0.70.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -15
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +109 -0
- package/corpus/core/docs/design/durable-agent-runs.md +217 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/action.ts +89 -0
- package/corpus/core/src/agent/model-config.ts +0 -2
- package/corpus/core/src/agent/run-loop-with-resume.ts +48 -0
- package/corpus/core/src/changelog/parse.ts +245 -0
- package/corpus/core/src/cli/changelog.ts +199 -0
- package/corpus/core/src/cli/index.ts +19 -0
- package/corpus/core/src/cli/recap.ts +24 -1
- package/corpus/core/src/cli/skills.ts +74 -47
- package/corpus/core/src/client/AgentPanel.tsx +5 -3
- package/corpus/core/src/client/AssistantChat.tsx +8 -0
- package/corpus/core/src/client/CommandMenu.tsx +183 -75
- package/corpus/core/src/client/agent-chat-adapter.ts +44 -7
- package/corpus/core/src/client/analytics.ts +181 -0
- package/corpus/core/src/client/changelog/Changelog.tsx +321 -0
- package/corpus/core/src/client/client-surface.ts +41 -0
- package/corpus/core/src/client/composer/TiptapComposer.tsx +123 -12
- package/corpus/core/src/client/feedback-context.ts +4 -0
- package/corpus/core/src/client/index.ts +12 -0
- package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +54 -0
- package/corpus/core/src/client/settings/useBuilderStatus.ts +82 -20
- package/corpus/core/src/client/sse-event-processor.ts +7 -1
- package/corpus/core/src/mcp/build-server.ts +57 -1
- package/corpus/core/src/mcp/embed-app.ts +197 -7
- package/corpus/core/src/mcp/oauth-route.ts +109 -13
- package/corpus/core/src/server/attribution.ts +211 -0
- package/corpus/core/src/server/auth.ts +6 -0
- package/corpus/core/src/server/better-auth-instance.ts +49 -5
- package/corpus/core/src/server/builder-browser.ts +27 -1
- package/corpus/core/src/server/core-routes-plugin.ts +136 -0
- package/corpus/core/src/server/google-oauth.ts +19 -6
- package/corpus/core/src/server/onboarding-html.ts +35 -0
- package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
- package/corpus/core/src/styles/agent-conversation.css +21 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +22 -0
- package/corpus/templates/analytics/AGENTS.md +8 -1
- package/corpus/templates/analytics/CHANGELOG.md +10 -0
- package/corpus/templates/analytics/actions/install-dashboard-template.ts +99 -4
- package/corpus/templates/analytics/actions/open-traffic-dashboard.ts +1 -1
- package/corpus/templates/analytics/actions/update-dashboard.ts +39 -8
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -3
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +180 -144
- package/corpus/templates/analytics/app/components/layout/Header.tsx +2 -3
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -5
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +221 -215
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +6 -6
- package/corpus/templates/analytics/app/lib/demo-dashboard-path.ts +1 -1
- package/corpus/templates/analytics/app/lib/last-opened.ts +2 -1
- package/corpus/templates/analytics/app/pages/Settings.tsx +4 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +101 -99
- package/corpus/templates/analytics/app/pages/overview/OverviewPage.tsx +1 -1
- package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +18 -5
- package/corpus/templates/analytics/app/routes/catalog.tsx +1 -1
- package/corpus/templates/analytics/app/routes/dashboards.$id.tsx +9 -0
- package/corpus/templates/analytics/app/routes/traffic.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-06-23-long-dashboard-and-analysis-names-in-the-sidebar-now-truncat.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-23-open-any-dashboard-chart-full-screen-in-a-modal-from-the-pan.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-23-the-dashboards-and-analyses-sidebar-settings-buttons-now-sta.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +145 -0
- package/corpus/templates/analytics/server/db/index.ts +1 -1
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +9 -2
- package/corpus/templates/analytics/server/lib/demo-dashboards.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -2
- package/corpus/templates/analytics/server/plugins/core-routes.ts +6 -6
- package/corpus/templates/assets/CHANGELOG.md +10 -0
- package/corpus/templates/assets/actions/generate-image.ts +24 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/assets/app/global.css +17 -1
- package/corpus/templates/assets/app/root.tsx +7 -1
- package/corpus/templates/assets/app/routes/_index.tsx +94 -14
- package/corpus/templates/assets/app/routes/settings.tsx +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-chat-dates-in-the-sidebar-no-longer-wrap-onto-two-lines.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-clicking-image-video-or-refine-on-the-start-screen-now-drops.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-pick-your-image-generation-model-right-from-the-chat-model-m.md +6 -0
- package/corpus/templates/brain/CHANGELOG.md +10 -0
- package/corpus/templates/brain/app/root.tsx +7 -1
- package/corpus/templates/brain/app/routes/settings.tsx +8 -1
- package/corpus/templates/calendar/CHANGELOG.md +10 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +4 -0
- package/corpus/templates/calendar/app/root.tsx +7 -1
- package/corpus/templates/chat/CHANGELOG.md +10 -0
- package/corpus/templates/chat/app/root.tsx +7 -1
- package/corpus/templates/clips/CHANGELOG.md +10 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -20
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +33 -7
- package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +8 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +150 -20
- package/corpus/templates/clips/app/components/recorder/countdown-overlay.tsx +72 -48
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +7 -11
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +31 -0
- package/corpus/templates/clips/app/components/sharing/slack-share-hint.tsx +71 -0
- package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +35 -17
- package/corpus/templates/clips/app/root.tsx +7 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +15 -1
- package/corpus/templates/clips/app/routes/record.tsx +78 -5
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -5
- package/corpus/templates/clips/changelog/2026-06-23-clips-shared-in-slack-no-longer-show-a-could-not-start-playb.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-made-the-play-button-on-shared-and-embedded-clips-scale-with.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-public-clip-share-links-now-show-whether-they-ll-play-inline.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-removed-select-button-from-library-hover-a-clip-to-select-it.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-screen-camera-recordings-now-keep-the-presenter-s-face-in-th.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-shared-video-links-now-play-for-anyone-without-signing-in.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-skip-or-cancel-the-recording-countdown-with-buttons-beside-t.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-desktop-camera-bubble-now-looks-sharp-the-instant-it-ope.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-desktop-recording-widget-now-grows-downward-only-when-yo.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-recording-start-sound-is-now-a-softer-more-modern-chime.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +17 -8
- package/corpus/templates/clips/chrome-extension/src/background.ts +769 -180
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +177 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +466 -329
- package/corpus/templates/clips/chrome-extension/src/overlay.css +377 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.html +12 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +330 -0
- package/corpus/templates/clips/chrome-extension/src/permission.html +227 -0
- package/corpus/templates/clips/chrome-extension/src/permission.ts +105 -0
- package/corpus/templates/clips/chrome-extension/src/popup.html +3 -0
- package/corpus/templates/clips/chrome-extension/src/popup.ts +50 -2
- package/corpus/templates/clips/chrome-extension/src/styles.css +50 -0
- package/corpus/templates/clips/chrome-extension/vite.config.ts +3 -0
- package/corpus/templates/clips/desktop/src/lib/audio-cue.ts +41 -24
- package/corpus/templates/clips/desktop/src/lib/bubble-webrtc.ts +119 -2
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +20 -0
- package/corpus/templates/clips/desktop/src/main.tsx +3 -0
- package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +21 -2
- package/corpus/templates/clips/desktop/src/overlays/region-record-border.tsx +76 -0
- package/corpus/templates/clips/desktop/src/styles.css +119 -2
- package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +2 -1
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +140 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +4 -1
- package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +85 -6
- package/corpus/templates/clips/shared/share-attribution.ts +79 -0
- package/corpus/templates/content/AGENTS.md +20 -3
- package/corpus/templates/content/CHANGELOG.md +10 -0
- package/corpus/templates/content/actions/_database-utils.ts +15 -0
- package/corpus/templates/content/actions/_property-utils.ts +371 -4
- package/corpus/templates/content/actions/configure-document-property.ts +35 -1
- package/corpus/templates/content/actions/create-content-database.ts +5 -1
- package/corpus/templates/content/actions/delete-document-property.ts +52 -2
- package/corpus/templates/content/actions/duplicate-document-property.ts +34 -17
- package/corpus/templates/content/actions/reorder-document-property.ts +79 -0
- package/corpus/templates/content/actions/set-document-property.ts +39 -0
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +806 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +226 -68
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +59 -30
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +25 -1
- package/corpus/templates/content/app/components/editor/blockFieldSaveController.ts +180 -0
- package/corpus/templates/content/app/components/editor/blockFieldSaveRegistry.ts +179 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +244 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +132 -0
- package/corpus/templates/content/app/global.css +9 -0
- package/corpus/templates/content/app/hooks/use-document-properties.ts +21 -0
- package/corpus/templates/content/app/root.tsx +7 -1
- package/corpus/templates/content/server/db/schema.ts +30 -0
- package/corpus/templates/content/server/plugins/db.ts +87 -0
- package/corpus/templates/content/shared/api.ts +7 -0
- package/corpus/templates/content/shared/properties.ts +109 -0
- package/corpus/templates/design/CHANGELOG.md +10 -0
- package/corpus/templates/design/actions/generate-design.ts +4 -0
- package/corpus/templates/design/app/root.tsx +7 -1
- package/corpus/templates/design/app/routes/settings.tsx +10 -2
- package/corpus/templates/dispatch/CHANGELOG.md +10 -0
- package/corpus/templates/dispatch/app/root.tsx +7 -1
- package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +10 -0
- package/corpus/templates/forms/CHANGELOG.md +10 -0
- package/corpus/templates/forms/actions/export-responses.ts +6 -0
- package/corpus/templates/forms/actions/list-responses.ts +2 -0
- package/corpus/templates/forms/actions/response-insights.ts +2 -0
- package/corpus/templates/forms/app/pages/ResponsesPage.tsx +138 -1
- package/corpus/templates/forms/app/root.tsx +7 -1
- package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-the-page-each-submission-came-from-.md +6 -0
- package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-whether-feedback-came-from-the-web-.md +6 -0
- package/corpus/templates/forms/server/db/schema.ts +7 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +19 -2
- package/corpus/templates/forms/server/lib/integrations.ts +76 -2
- package/corpus/templates/forms/server/plugins/db.ts +20 -0
- package/corpus/templates/forms/shared/types.ts +12 -0
- package/corpus/templates/macros/CHANGELOG.md +10 -0
- package/corpus/templates/macros/app/root.tsx +7 -1
- package/corpus/templates/mail/CHANGELOG.md +10 -0
- package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +3 -0
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +27 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +31 -17
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -4
- package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +34 -24
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -4
- package/corpus/templates/plan/AGENTS.md +4 -0
- package/corpus/templates/plan/CHANGELOG.md +10 -0
- package/corpus/templates/plan/actions/view-screen.ts +5 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +98 -1
- package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +3 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +107 -7
- package/corpus/templates/plan/app/root.tsx +7 -1
- package/corpus/templates/plan/changelog/2026-06-23-large-diagrams-in-a-plan-now-scroll-within-their-block-inste.md +6 -0
- package/corpus/templates/plan/shared/share-attribution.ts +72 -0
- package/corpus/templates/slides/CHANGELOG.md +10 -0
- package/corpus/templates/slides/app/root.tsx +7 -1
- package/corpus/templates/videos/CHANGELOG.md +4 -151
- package/corpus/templates/videos/app/root.tsx +7 -1
- package/dist/action.js +87 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/model-config.d.ts +2 -2
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +0 -2
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +13 -0
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +44 -0
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/changelog/parse.d.ts +70 -0
- package/dist/changelog/parse.d.ts.map +1 -0
- package/dist/changelog/parse.js +200 -0
- package/dist/changelog/parse.js.map +1 -0
- package/dist/cli/changelog.d.ts +4 -0
- package/dist/cli/changelog.d.ts.map +1 -0
- package/dist/cli/changelog.js +166 -0
- package/dist/cli/changelog.js.map +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +22 -1
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -3
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +74 -47
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +5 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +6 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +2 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/CommandMenu.d.ts +17 -1
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +49 -13
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +43 -6
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts +18 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +177 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/changelog/Changelog.d.ts +47 -0
- package/dist/client/changelog/Changelog.d.ts.map +1 -0
- package/dist/client/changelog/Changelog.js +138 -0
- package/dist/client/changelog/Changelog.js.map +1 -0
- package/dist/client/client-surface.d.ts +17 -0
- package/dist/client/client-surface.d.ts.map +1 -0
- package/dist/client/client-surface.js +24 -0
- package/dist/client/client-surface.js.map +1 -0
- package/dist/client/composer/TiptapComposer.d.ts +26 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +27 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/feedback-context.d.ts +3 -0
- package/dist/client/feedback-context.d.ts.map +1 -1
- package/dist/client/feedback-context.js +2 -0
- package/dist/client/feedback-context.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- 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/mcp-apps/McpAppRenderer.d.ts +1 -0
- package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.js +42 -1
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +2 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +58 -10
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +7 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/mcp/build-server.d.ts +21 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +43 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +197 -7
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/oauth-route.d.ts.map +1 -1
- package/dist/mcp/oauth-route.js +95 -12
- package/dist/mcp/oauth-route.js.map +1 -1
- package/dist/server/attribution.d.ts +83 -0
- package/dist/server/attribution.d.ts.map +1 -0
- package/dist/server/attribution.js +178 -0
- package/dist/server/attribution.js.map +1 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +7 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +9 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +32 -2
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts +4 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +20 -1
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +25 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +101 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +16 -2
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +35 -0
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/styles/agent-conversation.css +21 -0
- package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/docs/design/durable-agent-runs.md +217 -0
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/corpus/templates/analytics/app/pages/About.tsx +0 -108
- package/corpus/templates/analytics/app/routes/about.tsx +0 -9
- /package/corpus/templates/analytics/app/routes/{dashboards.tsx → dashboards._index.tsx} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-route.js","sourceRoot":"","sources":["../../src/mcp/oauth-route.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Standard remote MCP OAuth 2.1 endpoints.\n *\n * These routes let MCP hosts such as Claude Code and ChatGPT authenticate\n * through their native remote-MCP OAuth flow instead of pasting bearer tokens.\n * The issued access tokens are audience-bound to `/_agent-native/mcp`, carry\n * the same user/org identity as the existing connect flow, and are mediated by\n * `verifyAuth` before any MCP tool/resource request runs.\n */\n\nimport type { H3Event } from \"h3\";\nimport { getHeader, getMethod, getQuery, setResponseStatus } from \"h3\";\nimport { createHash, createHmac, timingSafeEqual } from \"node:crypto\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { getConfiguredLoginHtml, getSession } from \"../server/auth.js\";\nimport { getAuthSecret } from \"../server/better-auth-instance.js\";\nimport { getOrgDomain } from \"../org/context.js\";\nimport {\n createOAuthCode,\n createOAuthRefreshToken,\n consumeOAuthCode,\n generateOpaqueToken,\n getOAuthClient,\n getOAuthCode,\n getOAuthRefreshToken,\n registerOAuthClient,\n touchOAuthRefreshToken,\n} from \"./oauth-store.js\";\nimport {\n MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS,\n MCP_OAUTH_DEFAULT_SCOPE,\n MCP_OAUTH_SCOPES,\n normalizeOAuthScope,\n signMcpOAuthAccessToken,\n} from \"./oauth-token.js\";\n\nexport interface McpOAuthRouteOptions {\n appId?: string;\n appName?: string;\n}\n\nfunction json(body: unknown, status = 200): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-store\",\n Pragma: \"no-cache\",\n },\n });\n}\n\nfunction html(body: string, status = 200): Response {\n return new Response(body, {\n status,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n },\n });\n}\n\nfunction redirect(location: string): Response {\n return new Response(null, {\n status: 302,\n headers: { Location: location, \"Cache-Control\": \"no-store\" },\n });\n}\n\nfunction isSameOriginPost(event: H3Event): boolean {\n const origin = getHeader(event, \"origin\");\n if (!origin) return true;\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer) return false;\n try {\n return new URL(origin).origin === new URL(issuer).origin;\n } catch {\n return false;\n }\n}\n\nfunction oauthError(\n error: string,\n description: string,\n status = 400,\n): Response {\n return json({ error, error_description: description }, status);\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction normalizeBasePath(raw: string | undefined): string {\n const trimmed = (raw ?? \"\").trim();\n if (!trimmed || trimmed === \"/\") return \"\";\n const withSlash = trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`;\n return withSlash.replace(/\\/+$/, \"\");\n}\n\nfunction configuredBasePath(): string {\n return normalizeBasePath(\n process.env.APP_BASE_PATH || process.env.VITE_APP_BASE_PATH,\n );\n}\n\nfunction stripTrailingSlash(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\nfunction configuredPublicBaseUrl(): string | undefined {\n for (const key of [\n \"WORKSPACE_OAUTH_ORIGIN\",\n \"VITE_WORKSPACE_OAUTH_ORIGIN\",\n \"APP_URL\",\n \"VITE_APP_URL\",\n \"BETTER_AUTH_URL\",\n \"VITE_BETTER_AUTH_URL\",\n ]) {\n const raw = process.env[key]?.trim();\n if (!raw) continue;\n try {\n const url = new URL(raw);\n url.search = \"\";\n url.hash = \"\";\n return stripTrailingSlash(`${url.origin}${url.pathname}`);\n } catch {\n // Ignore invalid operator-provided URL values and fall back to headers.\n }\n }\n return undefined;\n}\n\nfunction appendConfiguredBasePath(baseUrl: string): string {\n const basePath = configuredBasePath();\n if (!basePath) return stripTrailingSlash(baseUrl);\n try {\n const url = new URL(baseUrl);\n const pathname = normalizeBasePath(url.pathname);\n if (pathname === basePath || pathname.endsWith(`${basePath}`)) {\n return stripTrailingSlash(`${url.origin}${pathname}`);\n }\n return stripTrailingSlash(`${url.origin}${pathname}${basePath}`);\n } catch {\n return `${stripTrailingSlash(baseUrl)}${basePath}`;\n }\n}\n\nfunction deriveOrigin(event: H3Event): string {\n const forwardedProto = getHeader(event, \"x-forwarded-proto\");\n const host = getHeader(event, \"x-forwarded-host\") || getHeader(event, \"host\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (host && /^(localhost|127\\.0\\.0\\.1|\\[::1\\])(:|$)/.test(host)\n ? \"http\"\n : \"https\");\n return host ? `${proto}://${host}` : \"\";\n}\n\nexport function getMcpOAuthIssuer(event: H3Event): string | undefined {\n const baseUrl = configuredPublicBaseUrl() || deriveOrigin(event);\n if (!baseUrl) return undefined;\n return appendConfiguredBasePath(baseUrl);\n}\n\nexport function getMcpOAuthResource(event: H3Event): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer) return undefined;\n return `${issuer}/_agent-native/mcp`;\n}\n\n/**\n * All plausible MCP OAuth resource audiences for the given request, deduped.\n *\n * When a configured public base URL differs from the request-derived origin\n * (e.g. during Netlify deploy-preview or behind a reverse proxy), a token\n * minted against the configured URL must still verify against the request-\n * derived URL and vice-versa. Returns both so `verifyMcpOAuthAccessToken`\n * accepts either without issuing a 401.\n */\nexport function getMcpOAuthAudiences(event: H3Event): string[] {\n const derived = getMcpOAuthResource(event);\n const configured = (() => {\n const base = configuredPublicBaseUrl();\n if (!base) return undefined;\n // Re-apply base path if present so the configured resource is also\n // base-path-aware, consistent with how getMcpOAuthResource computes it.\n const withPath = appendConfiguredBasePath(base);\n return `${withPath}/_agent-native/mcp`;\n })();\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of [derived, configured]) {\n const n = r?.replace(/\\/+$/, \"\");\n if (n && !seen.has(n)) {\n seen.add(n);\n out.push(n);\n }\n }\n return out;\n}\n\nexport function getMcpOAuthProtectedResourceMetadataUrl(\n event: H3Event,\n): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer) return undefined;\n return `${issuer}/.well-known/oauth-protected-resource`;\n}\n\nexport function buildMcpOAuthChallenge(event: H3Event): string {\n const metadata = getMcpOAuthProtectedResourceMetadataUrl(event);\n const scope = MCP_OAUTH_DEFAULT_SCOPE;\n return metadata\n ? `Bearer resource_metadata=\"${metadata}\", scope=\"${scope}\"`\n : `Bearer scope=\"${scope}\"`;\n}\n\nfunction authorizationEndpoint(event: H3Event): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n return issuer ? `${issuer}/_agent-native/mcp/oauth/authorize` : undefined;\n}\n\nfunction tokenEndpoint(event: H3Event): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n return issuer ? `${issuer}/_agent-native/mcp/oauth/token` : undefined;\n}\n\nfunction registrationEndpoint(event: H3Event): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n return issuer ? `${issuer}/_agent-native/mcp/oauth/register` : undefined;\n}\n\nexport function handleMcpOAuthProtectedResourceMetadata(\n event: H3Event,\n): Response {\n if (getMethod(event) !== \"GET\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n const resource = getMcpOAuthResource(event);\n const issuer = getMcpOAuthIssuer(event);\n if (!resource || !issuer) {\n return oauthError(\"server_error\", \"Unable to derive MCP resource\", 500);\n }\n return json({\n resource,\n authorization_servers: [issuer],\n scopes_supported: MCP_OAUTH_SCOPES,\n resource_documentation: issuer,\n });\n}\n\nexport function handleMcpOAuthAuthorizationServerMetadata(\n event: H3Event,\n): Response {\n if (getMethod(event) !== \"GET\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n const issuer = getMcpOAuthIssuer(event);\n const authorize = authorizationEndpoint(event);\n const token = tokenEndpoint(event);\n const register = registrationEndpoint(event);\n if (!issuer || !authorize || !token || !register) {\n return oauthError(\"server_error\", \"Unable to derive OAuth endpoints\", 500);\n }\n return json({\n issuer,\n authorization_endpoint: authorize,\n token_endpoint: token,\n registration_endpoint: register,\n response_types_supported: [\"code\"],\n grant_types_supported: [\"authorization_code\", \"refresh_token\"],\n code_challenge_methods_supported: [\"S256\"],\n token_endpoint_auth_methods_supported: [\"none\"],\n scopes_supported: MCP_OAUTH_SCOPES,\n });\n}\n\n// Schemes that must never be accepted as a redirect target: they can execute\n// script or read local resources if a redirect is ever rendered in a browser\n// or webview context.\nconst DISALLOWED_REDIRECT_SCHEMES = new Set([\n \"javascript:\",\n \"data:\",\n \"vbscript:\",\n \"file:\",\n \"blob:\",\n \"about:\",\n]);\n\n// Native/desktop IDE clients (Cursor, VS Code, …) register a private-use URI\n// scheme callback such as `cursor://` or `vscode://` (RFC 8252 §7.1) instead of\n// an https/loopback URL. The authorization code is bound by PKCE (S256), so\n// delivering it through a client-registered app scheme is safe.\nfunction isPrivateUseRedirectScheme(protocol: string): boolean {\n if (DISALLOWED_REDIRECT_SCHEMES.has(protocol)) return false;\n // RFC 3986 scheme grammar: ALPHA *( ALPHA / DIGIT / \"+\" / \"-\" / \".\" ), with a\n // trailing \":\" from URL.protocol. Require a non-http(s) custom scheme here;\n // http/https are handled explicitly above.\n return /^[a-z][a-z0-9+.-]*:$/.test(protocol);\n}\n\nfunction isAllowedRedirectUri(value: unknown): value is string {\n if (typeof value !== \"string\" || value.length > 2048) return false;\n try {\n const url = new URL(value);\n if (url.hash) return false;\n if (url.username || url.password) return false;\n if (url.protocol === \"https:\") return true;\n if (url.protocol === \"http:\") {\n return (\n url.hostname === \"localhost\" ||\n url.hostname === \"127.0.0.1\" ||\n url.hostname === \"::1\" ||\n url.hostname === \"[::1]\"\n );\n }\n return isPrivateUseRedirectScheme(url.protocol);\n } catch {\n return false;\n }\n}\n\nfunction parseStringArray(value: unknown): string[] {\n return Array.isArray(value)\n ? value.filter((item): item is string => typeof item === \"string\")\n : [];\n}\n\nasync function handleRegister(event: H3Event): Promise<Response> {\n if (getMethod(event) !== \"POST\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n const body = ((await readBody(event).catch(() => ({}))) ?? {}) as Record<\n string,\n unknown\n >;\n const redirectUris = parseStringArray(body.redirect_uris);\n if (\n redirectUris.length === 0 ||\n redirectUris.length > 20 ||\n !redirectUris.every(isAllowedRedirectUri)\n ) {\n return oauthError(\n \"invalid_client_metadata\",\n \"redirect_uris must contain valid HTTPS or localhost callback URLs\",\n );\n }\n\n const grantTypes = parseStringArray(body.grant_types);\n if (\n grantTypes.length &&\n !grantTypes.every(\n (g) => g === \"authorization_code\" || g === \"refresh_token\",\n )\n ) {\n return oauthError(\"invalid_client_metadata\", \"Unsupported grant_type\");\n }\n const responseTypes = parseStringArray(body.response_types);\n if (responseTypes.length && !responseTypes.every((r) => r === \"code\")) {\n return oauthError(\"invalid_client_metadata\", \"Unsupported response_type\");\n }\n const method =\n typeof body.token_endpoint_auth_method === \"string\"\n ? body.token_endpoint_auth_method\n : \"none\";\n if (method !== \"none\") {\n return oauthError(\n \"invalid_client_metadata\",\n \"Only public OAuth clients are supported\",\n );\n }\n\n const clientName =\n typeof body.client_name === \"string\"\n ? body.client_name.trim().slice(0, 120)\n : null;\n let client;\n try {\n client = await registerOAuthClient({\n clientName,\n redirectUris: [...new Set(redirectUris)],\n grantTypes: grantTypes.length ? grantTypes : undefined,\n responseTypes: responseTypes.length ? responseTypes : undefined,\n tokenEndpointAuthMethod: method,\n });\n } catch (err: any) {\n if (err?.message === \"RATE_LIMITED\") {\n return oauthError(\"slow_down\", \"Too many client registrations\", 429);\n }\n throw err;\n }\n return json(\n {\n client_id: client.clientId,\n client_id_issued_at: Math.floor((client.createdAt ?? Date.now()) / 1000),\n client_name: client.clientName ?? undefined,\n redirect_uris: client.redirectUris,\n grant_types: client.grantTypes,\n response_types: client.responseTypes,\n token_endpoint_auth_method: client.tokenEndpointAuthMethod,\n },\n 201,\n );\n}\n\nfunction redirectWithOAuthError(params: {\n redirectUri: string;\n state?: string;\n error: string;\n description?: string;\n}): Response {\n const url = new URL(params.redirectUri);\n url.searchParams.set(\"error\", params.error);\n if (params.description) {\n url.searchParams.set(\"error_description\", params.description);\n }\n if (params.state) url.searchParams.set(\"state\", params.state);\n return redirect(url.toString());\n}\n\nfunction redirectWithCode(params: {\n redirectUri: string;\n code: string;\n state?: string;\n}): Response {\n const url = new URL(params.redirectUri);\n url.searchParams.set(\"code\", params.code);\n if (params.state) url.searchParams.set(\"state\", params.state);\n return redirect(url.toString());\n}\n\nfunction codeChallengeForVerifier(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\nfunction safeEqual(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n return aa.length === bb.length && timingSafeEqual(aa, bb);\n}\n\nfunction base64UrlEncode(value: Buffer | string): string {\n const buf = typeof value === \"string\" ? Buffer.from(value, \"utf8\") : value;\n return buf.toString(\"base64url\");\n}\n\nfunction base64UrlDecode(value: string): Buffer {\n return Buffer.from(value, \"base64url\");\n}\n\nfunction consentSigningKey(): string {\n return process.env.A2A_SECRET?.trim() || getAuthSecret();\n}\n\nfunction consentPayload(params: {\n email: string;\n clientId: string;\n redirectUri: string;\n resource: string;\n scope: string;\n codeChallenge: string;\n}): string {\n return JSON.stringify({\n ...params,\n exp: Math.floor(Date.now() / 1000) + 10 * 60,\n });\n}\n\nfunction signConsentToken(params: {\n email: string;\n clientId: string;\n redirectUri: string;\n resource: string;\n scope: string;\n codeChallenge: string;\n}): string {\n const payload = base64UrlEncode(consentPayload(params));\n const sig = base64UrlEncode(\n createHmac(\"sha256\", consentSigningKey()).update(payload).digest(),\n );\n return `${payload}.${sig}`;\n}\n\nfunction verifyConsentToken(\n token: string | undefined,\n expected: {\n email: string;\n clientId: string;\n redirectUri: string;\n resource: string;\n scope: string;\n codeChallenge: string;\n },\n): boolean {\n if (!token || !token.includes(\".\")) return false;\n const [payload, sig] = token.split(\".\", 2);\n if (!payload || !sig) return false;\n const expectedSig = base64UrlEncode(\n createHmac(\"sha256\", consentSigningKey()).update(payload).digest(),\n );\n if (!safeEqual(sig, expectedSig)) return false;\n try {\n const parsed = JSON.parse(base64UrlDecode(payload).toString(\"utf8\"));\n return (\n parsed.email === expected.email &&\n parsed.clientId === expected.clientId &&\n parsed.redirectUri === expected.redirectUri &&\n parsed.resource === expected.resource &&\n parsed.scope === expected.scope &&\n parsed.codeChallenge === expected.codeChallenge &&\n typeof parsed.exp === \"number\" &&\n parsed.exp * 1000 >= Date.now()\n );\n } catch {\n return false;\n }\n}\n\nfunction isValidCodeVerifier(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n value.length >= 43 &&\n value.length <= 128 &&\n /^[A-Za-z0-9._~-]+$/.test(value)\n );\n}\n\nfunction renderConsentPage(params: {\n appName: string;\n email: string;\n clientName: string;\n scopes: string[];\n fields: Record<string, string>;\n}): string {\n const hidden = Object.entries(params.fields)\n .map(\n ([key, value]) =>\n `<input type=\"hidden\" name=\"${escapeHtml(key)}\" value=\"${escapeHtml(value)}\">`,\n )\n .join(\"\\n\");\n const scopes = params.scopes\n .map((scope) => `<li><code>${escapeHtml(scope)}</code></li>`)\n .join(\"\");\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Authorize ${escapeHtml(params.appName)}</title>\n<style>\n :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #09090b; color: #f4f4f5; }\n body { min-height: 100vh; display: grid; place-items: center; margin: 0; padding: 24px; }\n main { width: min(520px, 100%); border: 1px solid #27272a; border-radius: 8px; background: #111113; padding: 24px; box-shadow: 0 24px 80px rgba(0,0,0,.35); }\n h1 { font-size: 22px; line-height: 1.2; margin: 0 0 10px; }\n p { color: #a1a1aa; line-height: 1.5; margin: 0 0 18px; }\n ul { margin: 0 0 22px; padding-left: 22px; color: #d4d4d8; }\n code { color: #67e8f9; }\n .actions { display: flex; gap: 10px; justify-content: flex-end; }\n button { border: 0; border-radius: 6px; padding: 10px 14px; font-weight: 650; cursor: pointer; }\n .primary { background: #f4f4f5; color: #09090b; }\n .secondary { background: #27272a; color: #f4f4f5; }\n</style>\n</head>\n<body>\n<main>\n <h1>Authorize ${escapeHtml(params.clientName)}</h1>\n <p>${escapeHtml(params.appName)} will let this MCP client act as ${escapeHtml(params.email)} for these scopes:</p>\n <ul>${scopes}</ul>\n <form method=\"post\">\n ${hidden}\n <div class=\"actions\">\n <button class=\"secondary\" type=\"submit\" name=\"decision\" value=\"deny\">Deny</button>\n <button class=\"primary\" type=\"submit\" name=\"decision\" value=\"approve\">Authorize</button>\n </div>\n </form>\n</main>\n</body>\n</html>`;\n}\n\nasync function resolveOrgDomain(\n orgId: string | undefined,\n): Promise<string | undefined> {\n if (!orgId) return undefined;\n try {\n return (await getOrgDomain(orgId)) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readOAuthParams(\n event: H3Event,\n): Promise<Record<string, string>> {\n if (getMethod(event) === \"GET\") {\n const query = getQuery(event);\n return Object.fromEntries(\n Object.entries(query).flatMap(([key, value]) =>\n typeof value === \"string\" ? [[key, value]] : [],\n ),\n );\n }\n const body = await readBody(event).catch(() => ({}));\n if (typeof body === \"string\") {\n return Object.fromEntries(new URLSearchParams(body));\n }\n if (body && typeof body === \"object\") {\n return Object.fromEntries(\n Object.entries(body as Record<string, unknown>).flatMap(([key, value]) =>\n typeof value === \"string\" ? [[key, value]] : [],\n ),\n );\n }\n return {};\n}\n\nasync function handleAuthorize(\n event: H3Event,\n options: McpOAuthRouteOptions,\n): Promise<Response> {\n const method = getMethod(event);\n if (method !== \"GET\" && method !== \"POST\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n if (method === \"POST\" && !isSameOriginPost(event)) {\n return oauthError(\n \"invalid_request\",\n \"Cross-origin authorize POST rejected\",\n 403,\n );\n }\n const params = await readOAuthParams(event);\n const state = params.state;\n const clientId = params.client_id;\n const redirectUri = params.redirect_uri;\n const resource = params.resource || getMcpOAuthResource(event);\n const expectedResource = getMcpOAuthResource(event);\n\n if (params.response_type !== \"code\") {\n return oauthError(\n \"unsupported_response_type\",\n \"response_type must be code\",\n );\n }\n if (!clientId || !redirectUri || !resource || resource !== expectedResource) {\n return oauthError(\"invalid_request\", \"Invalid OAuth authorization request\");\n }\n if (params.code_challenge_method !== \"S256\" || !params.code_challenge) {\n return oauthError(\"invalid_request\", \"PKCE S256 is required\");\n }\n\n const client = await getOAuthClient(clientId);\n if (!client || !client.redirectUris.includes(redirectUri)) {\n return oauthError(\"invalid_client\", \"Unknown client or redirect_uri\");\n }\n\n const session = await getSession(event);\n if (!session?.email) {\n if (params.prompt === \"none\") {\n return redirectWithOAuthError({\n redirectUri,\n state,\n error: \"login_required\",\n });\n }\n const loginHtml = getConfiguredLoginHtml(event);\n return loginHtml\n ? html(loginHtml, 200)\n : oauthError(\"login_required\", \"Sign in required\", 401);\n }\n\n const scope = normalizeOAuthScope(params.scope);\n if (!scope) {\n return redirectWithOAuthError({\n redirectUri,\n state,\n error: \"invalid_scope\",\n });\n }\n if (method === \"GET\") {\n return html(\n renderConsentPage({\n appName: options.appName || options.appId || \"Agent Native\",\n email: session.email,\n clientName: client.clientName || client.clientId,\n scopes: scope.split(/\\s+/),\n fields: {\n response_type: \"code\",\n client_id: clientId,\n redirect_uri: redirectUri,\n resource,\n scope,\n state: state ?? \"\",\n code_challenge: params.code_challenge,\n code_challenge_method: \"S256\",\n consent_token: signConsentToken({\n email: session.email,\n clientId,\n redirectUri,\n resource,\n scope,\n codeChallenge: params.code_challenge,\n }),\n },\n }),\n );\n }\n\n if (\n !verifyConsentToken(params.consent_token, {\n email: session.email,\n clientId,\n redirectUri,\n resource,\n scope,\n codeChallenge: params.code_challenge,\n })\n ) {\n return oauthError(\"invalid_request\", \"Invalid authorization consent token\");\n }\n\n if (params.decision !== \"approve\") {\n return redirectWithOAuthError({\n redirectUri,\n state,\n error: \"access_denied\",\n });\n }\n\n const orgDomain = await resolveOrgDomain(session.orgId);\n const code = await createOAuthCode({\n clientId,\n redirectUri,\n codeChallenge: params.code_challenge,\n codeChallengeMethod: \"S256\",\n ownerEmail: session.email,\n orgId: session.orgId ?? null,\n orgDomain: orgDomain ?? null,\n scope,\n resource,\n });\n return redirectWithCode({ redirectUri, state, code: code.code });\n}\n\nasync function issueTokenSet(params: {\n ownerEmail: string;\n orgId?: string | null;\n orgDomain?: string | null;\n clientId: string;\n scope: string;\n resource: string;\n issuer: string;\n}): Promise<Record<string, unknown>> {\n const refreshToken = generateOpaqueToken();\n await createOAuthRefreshToken({\n refreshToken,\n clientId: params.clientId,\n ownerEmail: params.ownerEmail,\n orgId: params.orgId ?? null,\n orgDomain: params.orgDomain ?? null,\n scope: params.scope,\n resource: params.resource,\n });\n const accessToken = await signMcpOAuthAccessToken(params);\n return {\n access_token: accessToken,\n token_type: \"Bearer\",\n expires_in: MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS,\n refresh_token: refreshToken,\n scope: params.scope,\n };\n}\n\nasync function handleAuthorizationCodeGrant(\n event: H3Event,\n body: Record<string, string>,\n): Promise<Response> {\n const code = body.code;\n const clientId = body.client_id;\n const redirectUri = body.redirect_uri;\n const verifier = body.code_verifier;\n if (!code || !clientId || !redirectUri || !isValidCodeVerifier(verifier)) {\n return oauthError(\"invalid_request\", \"Missing authorization-code fields\");\n }\n const row = await getOAuthCode(code);\n if (!row) return oauthError(\"invalid_grant\", \"Invalid or expired code\");\n if (row.clientId !== clientId || row.redirectUri !== redirectUri) {\n return oauthError(\"invalid_grant\", \"Code was issued to another client\");\n }\n const expectedChallenge = codeChallengeForVerifier(verifier);\n if (!safeEqual(expectedChallenge, row.codeChallenge)) {\n return oauthError(\"invalid_grant\", \"PKCE verification failed\");\n }\n const consumed = await consumeOAuthCode(code);\n if (!consumed) return oauthError(\"invalid_grant\", \"Invalid or expired code\");\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer)\n return oauthError(\"server_error\", \"Unable to derive issuer\", 500);\n return json(\n await issueTokenSet({\n ownerEmail: row.ownerEmail,\n orgId: row.orgId,\n orgDomain: row.orgDomain,\n clientId,\n scope: row.scope,\n resource: row.resource,\n issuer,\n }),\n );\n}\n\nasync function handleRefreshTokenGrant(\n event: H3Event,\n body: Record<string, string>,\n): Promise<Response> {\n const refreshToken = body.refresh_token;\n const clientId = body.client_id;\n if (!refreshToken) {\n return oauthError(\"invalid_request\", \"refresh_token is required\");\n }\n if (!clientId) {\n return oauthError(\"invalid_request\", \"client_id is required\");\n }\n const existing = await getOAuthRefreshToken(refreshToken);\n if (!existing) return oauthError(\"invalid_grant\", \"Invalid refresh token\");\n if (existing.clientId !== clientId) {\n return oauthError(\n \"invalid_grant\",\n \"Refresh token belongs to another client\",\n );\n }\n await touchOAuthRefreshToken(refreshToken).catch(() => undefined);\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer)\n return oauthError(\"server_error\", \"Unable to derive issuer\", 500);\n const accessToken = await signMcpOAuthAccessToken({\n ownerEmail: existing.ownerEmail,\n orgId: existing.orgId,\n orgDomain: existing.orgDomain,\n clientId: existing.clientId,\n scope: existing.scope,\n resource: existing.resource,\n issuer,\n });\n return json({\n access_token: accessToken,\n token_type: \"Bearer\",\n expires_in: MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS,\n refresh_token: refreshToken,\n scope: existing.scope,\n });\n}\n\nasync function handleToken(event: H3Event): Promise<Response> {\n if (getMethod(event) !== \"POST\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n const body = await readOAuthParams(event);\n switch (body.grant_type) {\n case \"authorization_code\":\n return handleAuthorizationCodeGrant(event, body);\n case \"refresh_token\":\n return handleRefreshTokenGrant(event, body);\n default:\n return oauthError(\"unsupported_grant_type\", \"Unsupported grant_type\");\n }\n}\n\nexport async function handleMcpOAuth(\n event: H3Event,\n subpath: string,\n options: McpOAuthRouteOptions = {},\n): Promise<Response> {\n const path = subpath.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n try {\n if (path === \"authorize\") return await handleAuthorize(event, options);\n if (path === \"token\") return await handleToken(event);\n if (path === \"register\") return await handleRegister(event);\n setResponseStatus(event, 404);\n return json({ error: \"Not found\" }, 404);\n } catch (err: any) {\n return oauthError(\n \"server_error\",\n err?.message || \"OAuth request failed\",\n 500,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"oauth-route.js","sourceRoot":"","sources":["../../src/mcp/oauth-route.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Standard remote MCP OAuth 2.1 endpoints.\n *\n * These routes let MCP hosts such as Claude Code and ChatGPT authenticate\n * through their native remote-MCP OAuth flow instead of pasting bearer tokens.\n * The issued access tokens are audience-bound to `/_agent-native/mcp`, carry\n * the same user/org identity as the existing connect flow, and are mediated by\n * `verifyAuth` before any MCP tool/resource request runs.\n */\n\nimport type { H3Event } from \"h3\";\nimport { getHeader, getMethod, getQuery, setResponseStatus } from \"h3\";\nimport { createHash, createHmac, timingSafeEqual } from \"node:crypto\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { getConfiguredLoginHtml, getSession } from \"../server/auth.js\";\nimport { getAuthSecret } from \"../server/better-auth-instance.js\";\nimport { getOrgDomain } from \"../org/context.js\";\nimport {\n createOAuthCode,\n createOAuthRefreshToken,\n consumeOAuthCode,\n generateOpaqueToken,\n getOAuthClient,\n getOAuthCode,\n getOAuthRefreshToken,\n registerOAuthClient,\n touchOAuthRefreshToken,\n} from \"./oauth-store.js\";\nimport {\n MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS,\n MCP_OAUTH_DEFAULT_SCOPE,\n MCP_OAUTH_SCOPES,\n normalizeOAuthScope,\n signMcpOAuthAccessToken,\n} from \"./oauth-token.js\";\n\nexport interface McpOAuthRouteOptions {\n appId?: string;\n appName?: string;\n}\n\nfunction json(body: unknown, status = 200): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-store\",\n Pragma: \"no-cache\",\n },\n });\n}\n\nfunction html(body: string, status = 200): Response {\n return new Response(body, {\n status,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n },\n });\n}\n\nfunction redirect(location: string): Response {\n return new Response(null, {\n status: 302,\n headers: { Location: location, \"Cache-Control\": \"no-store\" },\n });\n}\n\nfunction isSameOriginPost(event: H3Event): boolean {\n const origin = getHeader(event, \"origin\");\n if (!origin) return true;\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer) return false;\n try {\n return new URL(origin).origin === new URL(issuer).origin;\n } catch {\n return false;\n }\n}\n\nfunction oauthError(\n error: string,\n description: string,\n status = 400,\n): Response {\n return json({ error, error_description: description }, status);\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction normalizeBasePath(raw: string | undefined): string {\n const trimmed = (raw ?? \"\").trim();\n if (!trimmed || trimmed === \"/\") return \"\";\n const withSlash = trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`;\n return withSlash.replace(/\\/+$/, \"\");\n}\n\nfunction configuredBasePath(): string {\n return normalizeBasePath(\n process.env.APP_BASE_PATH || process.env.VITE_APP_BASE_PATH,\n );\n}\n\nfunction stripTrailingSlash(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\nfunction configuredPublicBaseUrl(): string | undefined {\n for (const key of [\n \"WORKSPACE_OAUTH_ORIGIN\",\n \"VITE_WORKSPACE_OAUTH_ORIGIN\",\n \"APP_URL\",\n \"VITE_APP_URL\",\n \"BETTER_AUTH_URL\",\n \"VITE_BETTER_AUTH_URL\",\n ]) {\n const raw = process.env[key]?.trim();\n if (!raw) continue;\n try {\n const url = new URL(raw);\n url.search = \"\";\n url.hash = \"\";\n return stripTrailingSlash(`${url.origin}${url.pathname}`);\n } catch {\n // Ignore invalid operator-provided URL values and fall back to headers.\n }\n }\n return undefined;\n}\n\nfunction appendConfiguredBasePath(baseUrl: string): string {\n const basePath = configuredBasePath();\n if (!basePath) return stripTrailingSlash(baseUrl);\n try {\n const url = new URL(baseUrl);\n const pathname = normalizeBasePath(url.pathname);\n if (pathname === basePath || pathname.endsWith(`${basePath}`)) {\n return stripTrailingSlash(`${url.origin}${pathname}`);\n }\n return stripTrailingSlash(`${url.origin}${pathname}${basePath}`);\n } catch {\n return `${stripTrailingSlash(baseUrl)}${basePath}`;\n }\n}\n\nfunction deriveOrigin(event: H3Event): string {\n const forwardedProto = getHeader(event, \"x-forwarded-proto\");\n const host = getHeader(event, \"x-forwarded-host\") || getHeader(event, \"host\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (host && /^(localhost|127\\.0\\.0\\.1|\\[::1\\])(:|$)/.test(host)\n ? \"http\"\n : \"https\");\n return host ? `${proto}://${host}` : \"\";\n}\n\nexport function getMcpOAuthIssuer(event: H3Event): string | undefined {\n const baseUrl = configuredPublicBaseUrl() || deriveOrigin(event);\n if (!baseUrl) return undefined;\n return appendConfiguredBasePath(baseUrl);\n}\n\nexport function getMcpOAuthResource(event: H3Event): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer) return undefined;\n return `${issuer}/_agent-native/mcp`;\n}\n\n/**\n * All plausible MCP OAuth resource audiences for the given request, deduped.\n *\n * When a configured public base URL differs from the request-derived origin\n * (e.g. during Netlify deploy-preview or behind a reverse proxy), a token\n * minted against the configured URL must still verify against the request-\n * derived URL and vice-versa. Returns both so `verifyMcpOAuthAccessToken`\n * accepts either without issuing a 401.\n */\nexport function getMcpOAuthAudiences(event: H3Event): string[] {\n const derived = getMcpOAuthResource(event);\n const configured = (() => {\n const base = configuredPublicBaseUrl();\n if (!base) return undefined;\n // Re-apply base path if present so the configured resource is also\n // base-path-aware, consistent with how getMcpOAuthResource computes it.\n const withPath = appendConfiguredBasePath(base);\n return `${withPath}/_agent-native/mcp`;\n })();\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of [derived, configured]) {\n const n = r?.replace(/\\/+$/, \"\");\n if (n && !seen.has(n)) {\n seen.add(n);\n out.push(n);\n }\n }\n return out;\n}\n\nexport function getMcpOAuthProtectedResourceMetadataUrl(\n event: H3Event,\n): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer) return undefined;\n return `${issuer}/.well-known/oauth-protected-resource`;\n}\n\nexport function buildMcpOAuthChallenge(event: H3Event): string {\n const metadata = getMcpOAuthProtectedResourceMetadataUrl(event);\n const scope = MCP_OAUTH_DEFAULT_SCOPE;\n return metadata\n ? `Bearer resource_metadata=\"${metadata}\", scope=\"${scope}\"`\n : `Bearer scope=\"${scope}\"`;\n}\n\nfunction authorizationEndpoint(event: H3Event): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n return issuer ? `${issuer}/_agent-native/mcp/oauth/authorize` : undefined;\n}\n\nfunction tokenEndpoint(event: H3Event): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n return issuer ? `${issuer}/_agent-native/mcp/oauth/token` : undefined;\n}\n\nfunction registrationEndpoint(event: H3Event): string | undefined {\n const issuer = getMcpOAuthIssuer(event);\n return issuer ? `${issuer}/_agent-native/mcp/oauth/register` : undefined;\n}\n\nexport function handleMcpOAuthProtectedResourceMetadata(\n event: H3Event,\n): Response {\n if (getMethod(event) !== \"GET\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n const resource = getMcpOAuthResource(event);\n const issuer = getMcpOAuthIssuer(event);\n if (!resource || !issuer) {\n return oauthError(\"server_error\", \"Unable to derive MCP resource\", 500);\n }\n return json({\n resource,\n authorization_servers: [issuer],\n scopes_supported: MCP_OAUTH_SCOPES,\n resource_documentation: issuer,\n });\n}\n\nexport function handleMcpOAuthAuthorizationServerMetadata(\n event: H3Event,\n): Response {\n if (getMethod(event) !== \"GET\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n const issuer = getMcpOAuthIssuer(event);\n const authorize = authorizationEndpoint(event);\n const token = tokenEndpoint(event);\n const register = registrationEndpoint(event);\n if (!issuer || !authorize || !token || !register) {\n return oauthError(\"server_error\", \"Unable to derive OAuth endpoints\", 500);\n }\n return json({\n issuer,\n authorization_endpoint: authorize,\n token_endpoint: token,\n registration_endpoint: register,\n response_types_supported: [\"code\"],\n grant_types_supported: [\"authorization_code\", \"refresh_token\"],\n code_challenge_methods_supported: [\"S256\"],\n token_endpoint_auth_methods_supported: [\"none\"],\n scopes_supported: MCP_OAUTH_SCOPES,\n });\n}\n\n// Schemes that must never be accepted as a redirect target: they can execute\n// script or read local resources if a redirect is ever rendered in a browser\n// or webview context.\nconst DISALLOWED_REDIRECT_SCHEMES = new Set([\n \"javascript:\",\n \"data:\",\n \"vbscript:\",\n \"file:\",\n \"blob:\",\n \"about:\",\n]);\n\n// Native/desktop IDE clients (Cursor, VS Code, …) register a private-use URI\n// scheme callback such as `cursor://` or `vscode://` (RFC 8252 §7.1) instead of\n// an https/loopback URL. The authorization code is bound by PKCE (S256), so\n// delivering it through a client-registered app scheme is safe.\nfunction isPrivateUseRedirectScheme(protocol: string): boolean {\n if (DISALLOWED_REDIRECT_SCHEMES.has(protocol)) return false;\n // RFC 3986 scheme grammar: ALPHA *( ALPHA / DIGIT / \"+\" / \"-\" / \".\" ), with a\n // trailing \":\" from URL.protocol. Require a non-http(s) custom scheme here;\n // http/https are handled explicitly above.\n return /^[a-z][a-z0-9+.-]*:$/.test(protocol);\n}\n\nfunction isAllowedRedirectUri(value: unknown): value is string {\n if (typeof value !== \"string\" || value.length > 2048) return false;\n try {\n const url = new URL(value);\n if (url.hash) return false;\n if (url.username || url.password) return false;\n if (url.protocol === \"https:\") return true;\n if (url.protocol === \"http:\") {\n return (\n url.hostname === \"localhost\" ||\n url.hostname === \"127.0.0.1\" ||\n url.hostname === \"::1\" ||\n url.hostname === \"[::1]\"\n );\n }\n return isPrivateUseRedirectScheme(url.protocol);\n } catch {\n return false;\n }\n}\n\nfunction parseStringArray(value: unknown): string[] {\n return Array.isArray(value)\n ? value.filter((item): item is string => typeof item === \"string\")\n : [];\n}\n\nasync function handleRegister(event: H3Event): Promise<Response> {\n if (getMethod(event) !== \"POST\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n const body = ((await readBody(event).catch(() => ({}))) ?? {}) as Record<\n string,\n unknown\n >;\n const redirectUris = parseStringArray(body.redirect_uris);\n if (\n redirectUris.length === 0 ||\n redirectUris.length > 20 ||\n !redirectUris.every(isAllowedRedirectUri)\n ) {\n return oauthError(\n \"invalid_client_metadata\",\n \"redirect_uris must contain valid HTTPS or localhost callback URLs\",\n );\n }\n\n const grantTypes = parseStringArray(body.grant_types);\n if (\n grantTypes.length &&\n !grantTypes.every(\n (g) => g === \"authorization_code\" || g === \"refresh_token\",\n )\n ) {\n return oauthError(\"invalid_client_metadata\", \"Unsupported grant_type\");\n }\n const responseTypes = parseStringArray(body.response_types);\n if (responseTypes.length && !responseTypes.every((r) => r === \"code\")) {\n return oauthError(\"invalid_client_metadata\", \"Unsupported response_type\");\n }\n const method =\n typeof body.token_endpoint_auth_method === \"string\"\n ? body.token_endpoint_auth_method\n : \"none\";\n if (method !== \"none\") {\n return oauthError(\n \"invalid_client_metadata\",\n \"Only public OAuth clients are supported\",\n );\n }\n\n const clientName =\n typeof body.client_name === \"string\"\n ? body.client_name.trim().slice(0, 120)\n : null;\n let client;\n try {\n client = await registerOAuthClient({\n clientName,\n redirectUris: [...new Set(redirectUris)],\n grantTypes: grantTypes.length ? grantTypes : undefined,\n responseTypes: responseTypes.length ? responseTypes : undefined,\n tokenEndpointAuthMethod: method,\n });\n } catch (err: any) {\n if (err?.message === \"RATE_LIMITED\") {\n return oauthError(\"slow_down\", \"Too many client registrations\", 429);\n }\n throw err;\n }\n return json(\n {\n client_id: client.clientId,\n client_id_issued_at: Math.floor((client.createdAt ?? Date.now()) / 1000),\n client_name: client.clientName ?? undefined,\n redirect_uris: client.redirectUris,\n grant_types: client.grantTypes,\n response_types: client.responseTypes,\n token_endpoint_auth_method: client.tokenEndpointAuthMethod,\n },\n 201,\n );\n}\n\nfunction redirectWithOAuthError(params: {\n redirectUri: string;\n state?: string;\n error: string;\n description?: string;\n}): Response {\n const url = new URL(params.redirectUri);\n url.searchParams.set(\"error\", params.error);\n if (params.description) {\n url.searchParams.set(\"error_description\", params.description);\n }\n if (params.state) url.searchParams.set(\"state\", params.state);\n return redirect(url.toString());\n}\n\nfunction buildCodeRedirectUrl(params: {\n redirectUri: string;\n code: string;\n state?: string;\n}): string {\n const url = new URL(params.redirectUri);\n url.searchParams.set(\"code\", params.code);\n if (params.state) url.searchParams.set(\"state\", params.state);\n return url.toString();\n}\n\nfunction redirectWithCode(params: {\n redirectUri: string;\n code: string;\n state?: string;\n}): Response {\n return redirect(buildCodeRedirectUrl(params));\n}\n\nfunction codeChallengeForVerifier(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\nfunction safeEqual(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n return aa.length === bb.length && timingSafeEqual(aa, bb);\n}\n\nfunction base64UrlEncode(value: Buffer | string): string {\n const buf = typeof value === \"string\" ? Buffer.from(value, \"utf8\") : value;\n return buf.toString(\"base64url\");\n}\n\nfunction base64UrlDecode(value: string): Buffer {\n return Buffer.from(value, \"base64url\");\n}\n\nfunction consentSigningKey(): string {\n return process.env.A2A_SECRET?.trim() || getAuthSecret();\n}\n\nfunction consentPayload(params: {\n email: string;\n clientId: string;\n redirectUri: string;\n resource: string;\n scope: string;\n codeChallenge: string;\n}): string {\n return JSON.stringify({\n ...params,\n exp: Math.floor(Date.now() / 1000) + 10 * 60,\n });\n}\n\nfunction signConsentToken(params: {\n email: string;\n clientId: string;\n redirectUri: string;\n resource: string;\n scope: string;\n codeChallenge: string;\n}): string {\n const payload = base64UrlEncode(consentPayload(params));\n const sig = base64UrlEncode(\n createHmac(\"sha256\", consentSigningKey()).update(payload).digest(),\n );\n return `${payload}.${sig}`;\n}\n\nfunction verifyConsentToken(\n token: string | undefined,\n expected: {\n email: string;\n clientId: string;\n redirectUri: string;\n resource: string;\n scope: string;\n codeChallenge: string;\n },\n): boolean {\n if (!token || !token.includes(\".\")) return false;\n const [payload, sig] = token.split(\".\", 2);\n if (!payload || !sig) return false;\n const expectedSig = base64UrlEncode(\n createHmac(\"sha256\", consentSigningKey()).update(payload).digest(),\n );\n if (!safeEqual(sig, expectedSig)) return false;\n try {\n const parsed = JSON.parse(base64UrlDecode(payload).toString(\"utf8\"));\n return (\n parsed.email === expected.email &&\n parsed.clientId === expected.clientId &&\n parsed.redirectUri === expected.redirectUri &&\n parsed.resource === expected.resource &&\n parsed.scope === expected.scope &&\n parsed.codeChallenge === expected.codeChallenge &&\n typeof parsed.exp === \"number\" &&\n parsed.exp * 1000 >= Date.now()\n );\n } catch {\n return false;\n }\n}\n\nfunction isValidCodeVerifier(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n value.length >= 43 &&\n value.length <= 128 &&\n /^[A-Za-z0-9._~-]+$/.test(value)\n );\n}\n\n// Shared styling for the browser-facing OAuth pages (consent + post-authorize\n// confirmation) so they read as one coherent dark surface.\nconst OAUTH_PAGE_BASE_STYLE = `\n :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #09090b; color: #f4f4f5; }\n body { min-height: 100vh; display: grid; place-items: center; margin: 0; padding: 24px; }\n main { width: min(520px, 100%); border: 1px solid #27272a; border-radius: 8px; background: #111113; padding: 24px; box-shadow: 0 24px 80px rgba(0,0,0,.35); }\n h1 { font-size: 22px; line-height: 1.2; margin: 0 0 10px; }\n p { color: #a1a1aa; line-height: 1.5; margin: 0 0 18px; }\n .actions { display: flex; gap: 10px; justify-content: flex-end; }\n button, .btn { border: 0; border-radius: 6px; padding: 10px 14px; font: inherit; font-weight: 650; cursor: pointer; text-decoration: none; display: inline-block; }\n .primary { background: #f4f4f5; color: #09090b; }\n .secondary { background: #27272a; color: #f4f4f5; }`;\n\nfunction renderConsentPage(params: {\n appName: string;\n email: string;\n clientName: string;\n scopes: string[];\n fields: Record<string, string>;\n}): string {\n const hidden = Object.entries(params.fields)\n .map(\n ([key, value]) =>\n `<input type=\"hidden\" name=\"${escapeHtml(key)}\" value=\"${escapeHtml(value)}\">`,\n )\n .join(\"\\n\");\n const scopes = params.scopes\n .map((scope) => `<li><code>${escapeHtml(scope)}</code></li>`)\n .join(\"\");\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Authorize ${escapeHtml(params.appName)}</title>\n<style>${OAUTH_PAGE_BASE_STYLE}\n ul { margin: 0 0 22px; padding-left: 22px; color: #d4d4d8; }\n code { color: #67e8f9; }\n</style>\n</head>\n<body>\n<main>\n <h1>Authorize ${escapeHtml(params.clientName)}</h1>\n <p>${escapeHtml(params.appName)} will let this MCP client act as ${escapeHtml(params.email)} for these scopes:</p>\n <ul>${scopes}</ul>\n <form method=\"post\">\n ${hidden}\n <div class=\"actions\">\n <button class=\"secondary\" type=\"submit\" name=\"decision\" value=\"deny\">Deny</button>\n <button class=\"primary\" type=\"submit\" name=\"decision\" value=\"approve\">Authorize</button>\n </div>\n </form>\n</main>\n</body>\n</html>`;\n}\n\n// Shown after the user approves a native/desktop client (cursor://, vscode://, …)\n// whose redirect is a private-use scheme. A bare 302 to a custom scheme hands the\n// code to the OS app but leaves the browser tab dangling on a blank/error page, so\n// we render a friendly confirmation that also re-fires the deep link (so the client\n// still receives the code) and tells the user they can return to their agent.\nfunction renderAuthorizedPage(params: {\n appName: string;\n clientName: string | null;\n redirectUrl: string;\n}): string {\n const friendlyClient = params.clientName?.trim() || null;\n const returnTarget = friendlyClient ?? \"your agent\";\n const openLabel = friendlyClient\n ? `Open ${escapeHtml(friendlyClient)}`\n : \"Return to your agent\";\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Authorized</title>\n<style>${OAUTH_PAGE_BASE_STYLE}\n main.success { text-align: center; }\n .check { width: 56px; height: 56px; margin: 4px auto 16px; display: grid; place-items: center; border-radius: 999px; background: rgba(34,197,94,.12); }\n .check svg { width: 30px; height: 30px; }\n .success .actions { justify-content: center; margin-top: 4px; }\n .hint { color: #71717a; font-size: 13px; margin: 18px 0 0; }\n</style>\n</head>\n<body>\n<main class=\"success\">\n <div class=\"check\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#22c55e\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\"></path>\n </svg>\n </div>\n <h1>You're all set</h1>\n <p>${escapeHtml(params.appName)} has authorized ${escapeHtml(returnTarget)}. You can return to ${escapeHtml(returnTarget)} to continue.</p>\n <div class=\"actions\">\n <a class=\"btn primary\" id=\"return-link\" href=\"${escapeHtml(params.redirectUrl)}\">${openLabel}</a>\n </div>\n <p class=\"hint\">You can close this tab.</p>\n</main>\n<script>\n (function () {\n var link = document.getElementById(\"return-link\");\n if (link && link.href) {\n try { window.location.href = link.href; } catch (e) {}\n }\n })();\n</script>\n</body>\n</html>`;\n}\n\nasync function resolveOrgDomain(\n orgId: string | undefined,\n): Promise<string | undefined> {\n if (!orgId) return undefined;\n try {\n return (await getOrgDomain(orgId)) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readOAuthParams(\n event: H3Event,\n): Promise<Record<string, string>> {\n if (getMethod(event) === \"GET\") {\n const query = getQuery(event);\n return Object.fromEntries(\n Object.entries(query).flatMap(([key, value]) =>\n typeof value === \"string\" ? [[key, value]] : [],\n ),\n );\n }\n const body = await readBody(event).catch(() => ({}));\n if (typeof body === \"string\") {\n return Object.fromEntries(new URLSearchParams(body));\n }\n if (body && typeof body === \"object\") {\n return Object.fromEntries(\n Object.entries(body as Record<string, unknown>).flatMap(([key, value]) =>\n typeof value === \"string\" ? [[key, value]] : [],\n ),\n );\n }\n return {};\n}\n\nasync function handleAuthorize(\n event: H3Event,\n options: McpOAuthRouteOptions,\n): Promise<Response> {\n const method = getMethod(event);\n if (method !== \"GET\" && method !== \"POST\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n if (method === \"POST\" && !isSameOriginPost(event)) {\n return oauthError(\n \"invalid_request\",\n \"Cross-origin authorize POST rejected\",\n 403,\n );\n }\n const params = await readOAuthParams(event);\n const state = params.state;\n const clientId = params.client_id;\n const redirectUri = params.redirect_uri;\n const resource = params.resource || getMcpOAuthResource(event);\n const expectedResource = getMcpOAuthResource(event);\n\n if (params.response_type !== \"code\") {\n return oauthError(\n \"unsupported_response_type\",\n \"response_type must be code\",\n );\n }\n if (!clientId || !redirectUri || !resource || resource !== expectedResource) {\n return oauthError(\"invalid_request\", \"Invalid OAuth authorization request\");\n }\n if (params.code_challenge_method !== \"S256\" || !params.code_challenge) {\n return oauthError(\"invalid_request\", \"PKCE S256 is required\");\n }\n\n const client = await getOAuthClient(clientId);\n if (!client || !client.redirectUris.includes(redirectUri)) {\n return oauthError(\"invalid_client\", \"Unknown client or redirect_uri\");\n }\n\n const session = await getSession(event);\n if (!session?.email) {\n if (params.prompt === \"none\") {\n return redirectWithOAuthError({\n redirectUri,\n state,\n error: \"login_required\",\n });\n }\n const loginHtml = getConfiguredLoginHtml(event);\n return loginHtml\n ? html(loginHtml, 200)\n : oauthError(\"login_required\", \"Sign in required\", 401);\n }\n\n const scope = normalizeOAuthScope(params.scope);\n if (!scope) {\n return redirectWithOAuthError({\n redirectUri,\n state,\n error: \"invalid_scope\",\n });\n }\n if (method === \"GET\") {\n return html(\n renderConsentPage({\n appName: options.appName || options.appId || \"Agent Native\",\n email: session.email,\n clientName: client.clientName || client.clientId,\n scopes: scope.split(/\\s+/),\n fields: {\n response_type: \"code\",\n client_id: clientId,\n redirect_uri: redirectUri,\n resource,\n scope,\n state: state ?? \"\",\n code_challenge: params.code_challenge,\n code_challenge_method: \"S256\",\n consent_token: signConsentToken({\n email: session.email,\n clientId,\n redirectUri,\n resource,\n scope,\n codeChallenge: params.code_challenge,\n }),\n },\n }),\n );\n }\n\n if (\n !verifyConsentToken(params.consent_token, {\n email: session.email,\n clientId,\n redirectUri,\n resource,\n scope,\n codeChallenge: params.code_challenge,\n })\n ) {\n return oauthError(\"invalid_request\", \"Invalid authorization consent token\");\n }\n\n if (params.decision !== \"approve\") {\n return redirectWithOAuthError({\n redirectUri,\n state,\n error: \"access_denied\",\n });\n }\n\n const orgDomain = await resolveOrgDomain(session.orgId);\n const code = await createOAuthCode({\n clientId,\n redirectUri,\n codeChallenge: params.code_challenge,\n codeChallengeMethod: \"S256\",\n ownerEmail: session.email,\n orgId: session.orgId ?? null,\n orgDomain: orgDomain ?? null,\n scope,\n resource,\n });\n\n // Native/desktop clients register a private-use scheme (cursor://, vscode://, …).\n // A 302 to that scheme opens the app but leaves the browser tab dangling, so we\n // render a friendly confirmation page that re-fires the deep link instead. For\n // https/loopback callbacks the client (or its local server) renders its own page,\n // so keep the standard redirect there.\n let isDeepLinkRedirect = false;\n try {\n const protocol = new URL(redirectUri).protocol;\n isDeepLinkRedirect =\n protocol !== \"http:\" &&\n protocol !== \"https:\" &&\n isPrivateUseRedirectScheme(protocol);\n } catch {\n isDeepLinkRedirect = false;\n }\n if (isDeepLinkRedirect) {\n return html(\n renderAuthorizedPage({\n appName: options.appName || options.appId || \"Agent Native\",\n clientName: client.clientName ?? null,\n redirectUrl: buildCodeRedirectUrl({\n redirectUri,\n state,\n code: code.code,\n }),\n }),\n );\n }\n return redirectWithCode({ redirectUri, state, code: code.code });\n}\n\nasync function issueTokenSet(params: {\n ownerEmail: string;\n orgId?: string | null;\n orgDomain?: string | null;\n clientId: string;\n scope: string;\n resource: string;\n issuer: string;\n}): Promise<Record<string, unknown>> {\n const refreshToken = generateOpaqueToken();\n await createOAuthRefreshToken({\n refreshToken,\n clientId: params.clientId,\n ownerEmail: params.ownerEmail,\n orgId: params.orgId ?? null,\n orgDomain: params.orgDomain ?? null,\n scope: params.scope,\n resource: params.resource,\n });\n const accessToken = await signMcpOAuthAccessToken(params);\n return {\n access_token: accessToken,\n token_type: \"Bearer\",\n expires_in: MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS,\n refresh_token: refreshToken,\n scope: params.scope,\n };\n}\n\nasync function handleAuthorizationCodeGrant(\n event: H3Event,\n body: Record<string, string>,\n): Promise<Response> {\n const code = body.code;\n const clientId = body.client_id;\n const redirectUri = body.redirect_uri;\n const verifier = body.code_verifier;\n if (!code || !clientId || !redirectUri || !isValidCodeVerifier(verifier)) {\n return oauthError(\"invalid_request\", \"Missing authorization-code fields\");\n }\n const row = await getOAuthCode(code);\n if (!row) return oauthError(\"invalid_grant\", \"Invalid or expired code\");\n if (row.clientId !== clientId || row.redirectUri !== redirectUri) {\n return oauthError(\"invalid_grant\", \"Code was issued to another client\");\n }\n const expectedChallenge = codeChallengeForVerifier(verifier);\n if (!safeEqual(expectedChallenge, row.codeChallenge)) {\n return oauthError(\"invalid_grant\", \"PKCE verification failed\");\n }\n const consumed = await consumeOAuthCode(code);\n if (!consumed) return oauthError(\"invalid_grant\", \"Invalid or expired code\");\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer)\n return oauthError(\"server_error\", \"Unable to derive issuer\", 500);\n return json(\n await issueTokenSet({\n ownerEmail: row.ownerEmail,\n orgId: row.orgId,\n orgDomain: row.orgDomain,\n clientId,\n scope: row.scope,\n resource: row.resource,\n issuer,\n }),\n );\n}\n\nasync function handleRefreshTokenGrant(\n event: H3Event,\n body: Record<string, string>,\n): Promise<Response> {\n const refreshToken = body.refresh_token;\n const clientId = body.client_id;\n if (!refreshToken) {\n return oauthError(\"invalid_request\", \"refresh_token is required\");\n }\n if (!clientId) {\n return oauthError(\"invalid_request\", \"client_id is required\");\n }\n const existing = await getOAuthRefreshToken(refreshToken);\n if (!existing) return oauthError(\"invalid_grant\", \"Invalid refresh token\");\n if (existing.clientId !== clientId) {\n return oauthError(\n \"invalid_grant\",\n \"Refresh token belongs to another client\",\n );\n }\n await touchOAuthRefreshToken(refreshToken).catch(() => undefined);\n const issuer = getMcpOAuthIssuer(event);\n if (!issuer)\n return oauthError(\"server_error\", \"Unable to derive issuer\", 500);\n const accessToken = await signMcpOAuthAccessToken({\n ownerEmail: existing.ownerEmail,\n orgId: existing.orgId,\n orgDomain: existing.orgDomain,\n clientId: existing.clientId,\n scope: existing.scope,\n resource: existing.resource,\n issuer,\n });\n return json({\n access_token: accessToken,\n token_type: \"Bearer\",\n expires_in: MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS,\n refresh_token: refreshToken,\n scope: existing.scope,\n });\n}\n\nasync function handleToken(event: H3Event): Promise<Response> {\n if (getMethod(event) !== \"POST\") {\n return oauthError(\"invalid_request\", \"Method not allowed\", 405);\n }\n const body = await readOAuthParams(event);\n switch (body.grant_type) {\n case \"authorization_code\":\n return handleAuthorizationCodeGrant(event, body);\n case \"refresh_token\":\n return handleRefreshTokenGrant(event, body);\n default:\n return oauthError(\"unsupported_grant_type\", \"Unsupported grant_type\");\n }\n}\n\nexport async function handleMcpOAuth(\n event: H3Event,\n subpath: string,\n options: McpOAuthRouteOptions = {},\n): Promise<Response> {\n const path = subpath.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n try {\n if (path === \"authorize\") return await handleAuthorize(event, options);\n if (path === \"token\") return await handleToken(event);\n if (path === \"register\") return await handleRegister(event);\n setResponseStatus(event, 404);\n return json({ error: \"Not found\" }, 404);\n } catch (err: any) {\n return oauthError(\n \"server_error\",\n err?.message || \"OAuth request failed\",\n 500,\n );\n }\n}\n"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-touch referral attribution — server side.
|
|
3
|
+
*
|
|
4
|
+
* The browser captures an anonymous visitor's *first* landing context (referral
|
|
5
|
+
* source, UTM params, referring host, landing path) and persists it across the
|
|
6
|
+
* signup boundary in a first-party cookie named `an_ft` (see
|
|
7
|
+
* `client/analytics.ts`). On signup, the auth hook reads that cookie off the
|
|
8
|
+
* request and enriches the canonical server-side `signup` event so we can
|
|
9
|
+
* measure where new users came from and how apps spread (virality).
|
|
10
|
+
*
|
|
11
|
+
* This module is intentionally pure and dependency-free so it is trivially
|
|
12
|
+
* unit-testable and can never throw into the signup path. The single hard rule:
|
|
13
|
+
* parsing untrusted cookie input must NEVER throw — every accessor is defensive.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* The decoded first-touch attribution object. Mirrors the compact JSON the
|
|
17
|
+
* client writes into the `an_ft` cookie / `an_attribution` localStorage key.
|
|
18
|
+
* Every field is optional — the client omits empty fields to keep the cookie
|
|
19
|
+
* small, and a malformed/absent cookie yields `null`.
|
|
20
|
+
*/
|
|
21
|
+
export interface FirstTouchAttribution {
|
|
22
|
+
/** Referral source bucket, e.g. "clip_share", "plan_share". */
|
|
23
|
+
ref?: string;
|
|
24
|
+
/** Referrer's stable user id (the clip/plan owner who shared the link). */
|
|
25
|
+
via?: string;
|
|
26
|
+
utm_source?: string;
|
|
27
|
+
utm_medium?: string;
|
|
28
|
+
utm_campaign?: string;
|
|
29
|
+
utm_content?: string;
|
|
30
|
+
utm_term?: string;
|
|
31
|
+
/** `window.location.pathname` of the first page the visitor landed on. */
|
|
32
|
+
landing_path?: string;
|
|
33
|
+
/** Host of `document.referrer` (scrubbed; host only, never a full URL). */
|
|
34
|
+
landing_referrer?: string;
|
|
35
|
+
/** ISO timestamp of when the visitor first landed. */
|
|
36
|
+
landed_at?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Cookie name written by the client (non-HttpOnly; non-sensitive). */
|
|
39
|
+
export declare const FIRST_TOUCH_COOKIE_NAME = "an_ft";
|
|
40
|
+
/**
|
|
41
|
+
* Parse a raw `Cookie:` header into a flat name→value map. Tolerates missing
|
|
42
|
+
* input, extra whitespace, `=` inside values, and malformed pairs. Never throws.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseCookieHeader(cookieHeader: string | null | undefined): Record<string, string>;
|
|
45
|
+
/**
|
|
46
|
+
* Decode a single cookie value into a `FirstTouchAttribution`. The value is the
|
|
47
|
+
* URL-encoded compact JSON written by the client. Returns `null` for empty,
|
|
48
|
+
* malformed, or non-object input. Only known string fields are copied through,
|
|
49
|
+
* each clamped to a sane max length as a defense against an oversized cookie.
|
|
50
|
+
*/
|
|
51
|
+
export declare function decodeFirstTouchValue(value: string | null | undefined): FirstTouchAttribution | null;
|
|
52
|
+
/**
|
|
53
|
+
* Read the `an_ft` first-touch attribution out of a raw `Cookie:` header.
|
|
54
|
+
* Returns `null` when the cookie is absent or unparseable. Never throws.
|
|
55
|
+
*/
|
|
56
|
+
export declare function readFirstTouchAttribution(cookieHeader: string | null | undefined): FirstTouchAttribution | null;
|
|
57
|
+
/**
|
|
58
|
+
* Derive the `referral_source` bucket from first-touch attribution per the
|
|
59
|
+
* contract:
|
|
60
|
+
* 1. explicit `ref` wins;
|
|
61
|
+
* 2. landing path under `/share/` => "clip_share";
|
|
62
|
+
* 3. landing path that looks like a public plan page
|
|
63
|
+
* (contains `/p/`, `/plan/`, or `/share-plan/`) => "plan_share";
|
|
64
|
+
* 4. a non-empty external referring host => "external";
|
|
65
|
+
* 5. otherwise => "direct".
|
|
66
|
+
*/
|
|
67
|
+
export declare function deriveReferralSource(ft: FirstTouchAttribution | null): string;
|
|
68
|
+
/**
|
|
69
|
+
* Compute the snake_case signup-event properties from first-touch attribution.
|
|
70
|
+
* Returns a clean object with `undefined` values omitted, ready to merge into
|
|
71
|
+
* the `signup` track call. Always sets `referral_source` (defaults to "direct").
|
|
72
|
+
*
|
|
73
|
+
* Pure and total — given any (or no) input it returns a well-formed object and
|
|
74
|
+
* never throws.
|
|
75
|
+
*/
|
|
76
|
+
export declare function deriveSignupAttribution(ft: FirstTouchAttribution | null): Record<string, string>;
|
|
77
|
+
/**
|
|
78
|
+
* Convenience: read the cookie header and derive signup attribution in one
|
|
79
|
+
* call. Never throws; falls back to `{ referral_source: "direct" }` on any
|
|
80
|
+
* error.
|
|
81
|
+
*/
|
|
82
|
+
export declare function signupAttributionFromCookieHeader(cookieHeader: string | null | undefined): Record<string, string>;
|
|
83
|
+
//# sourceMappingURL=attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../../src/server/attribution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,uEAAuE;AACvE,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAe/C;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcxB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,qBAAqB,GAAG,IAAI,CA8B9B;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACtC,qBAAqB,GAAG,IAAI,CAO9B;AAOD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,qBAAqB,GAAG,IAAI,GAAG,MAAM,CAa7E;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,qBAAqB,GAAG,IAAI,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAuBxB;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-touch referral attribution — server side.
|
|
3
|
+
*
|
|
4
|
+
* The browser captures an anonymous visitor's *first* landing context (referral
|
|
5
|
+
* source, UTM params, referring host, landing path) and persists it across the
|
|
6
|
+
* signup boundary in a first-party cookie named `an_ft` (see
|
|
7
|
+
* `client/analytics.ts`). On signup, the auth hook reads that cookie off the
|
|
8
|
+
* request and enriches the canonical server-side `signup` event so we can
|
|
9
|
+
* measure where new users came from and how apps spread (virality).
|
|
10
|
+
*
|
|
11
|
+
* This module is intentionally pure and dependency-free so it is trivially
|
|
12
|
+
* unit-testable and can never throw into the signup path. The single hard rule:
|
|
13
|
+
* parsing untrusted cookie input must NEVER throw — every accessor is defensive.
|
|
14
|
+
*/
|
|
15
|
+
/** Cookie name written by the client (non-HttpOnly; non-sensitive). */
|
|
16
|
+
export const FIRST_TOUCH_COOKIE_NAME = "an_ft";
|
|
17
|
+
const STRING_FIELDS = [
|
|
18
|
+
"ref",
|
|
19
|
+
"via",
|
|
20
|
+
"utm_source",
|
|
21
|
+
"utm_medium",
|
|
22
|
+
"utm_campaign",
|
|
23
|
+
"utm_content",
|
|
24
|
+
"utm_term",
|
|
25
|
+
"landing_path",
|
|
26
|
+
"landing_referrer",
|
|
27
|
+
"landed_at",
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* Parse a raw `Cookie:` header into a flat name→value map. Tolerates missing
|
|
31
|
+
* input, extra whitespace, `=` inside values, and malformed pairs. Never throws.
|
|
32
|
+
*/
|
|
33
|
+
export function parseCookieHeader(cookieHeader) {
|
|
34
|
+
const out = {};
|
|
35
|
+
if (!cookieHeader || typeof cookieHeader !== "string")
|
|
36
|
+
return out;
|
|
37
|
+
for (const part of cookieHeader.split(";")) {
|
|
38
|
+
const eq = part.indexOf("=");
|
|
39
|
+
if (eq === -1)
|
|
40
|
+
continue;
|
|
41
|
+
const name = part.slice(0, eq).trim();
|
|
42
|
+
if (!name)
|
|
43
|
+
continue;
|
|
44
|
+
const rawValue = part.slice(eq + 1).trim();
|
|
45
|
+
// First write wins so a duplicate cookie name can't clobber the first.
|
|
46
|
+
if (name in out)
|
|
47
|
+
continue;
|
|
48
|
+
out[name] = rawValue;
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Decode a single cookie value into a `FirstTouchAttribution`. The value is the
|
|
54
|
+
* URL-encoded compact JSON written by the client. Returns `null` for empty,
|
|
55
|
+
* malformed, or non-object input. Only known string fields are copied through,
|
|
56
|
+
* each clamped to a sane max length as a defense against an oversized cookie.
|
|
57
|
+
*/
|
|
58
|
+
export function decodeFirstTouchValue(value) {
|
|
59
|
+
if (!value || typeof value !== "string")
|
|
60
|
+
return null;
|
|
61
|
+
let decoded = value;
|
|
62
|
+
try {
|
|
63
|
+
decoded = decodeURIComponent(value);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Not valid percent-encoding — fall back to the raw value and let the JSON
|
|
67
|
+
// parse below decide whether it's usable.
|
|
68
|
+
decoded = value;
|
|
69
|
+
}
|
|
70
|
+
let parsed;
|
|
71
|
+
try {
|
|
72
|
+
parsed = JSON.parse(decoded);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const source = parsed;
|
|
81
|
+
const result = {};
|
|
82
|
+
let any = false;
|
|
83
|
+
for (const field of STRING_FIELDS) {
|
|
84
|
+
const raw = source[field];
|
|
85
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
86
|
+
result[field] = raw.slice(0, 120);
|
|
87
|
+
any = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return any ? result : null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Read the `an_ft` first-touch attribution out of a raw `Cookie:` header.
|
|
94
|
+
* Returns `null` when the cookie is absent or unparseable. Never throws.
|
|
95
|
+
*/
|
|
96
|
+
export function readFirstTouchAttribution(cookieHeader) {
|
|
97
|
+
try {
|
|
98
|
+
const cookies = parseCookieHeader(cookieHeader);
|
|
99
|
+
return decodeFirstTouchValue(cookies[FIRST_TOUCH_COOKIE_NAME]);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function isExternalReferrerHost(host) {
|
|
106
|
+
const trimmed = host?.trim();
|
|
107
|
+
return !!trimmed && trimmed.length > 0;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Derive the `referral_source` bucket from first-touch attribution per the
|
|
111
|
+
* contract:
|
|
112
|
+
* 1. explicit `ref` wins;
|
|
113
|
+
* 2. landing path under `/share/` => "clip_share";
|
|
114
|
+
* 3. landing path that looks like a public plan page
|
|
115
|
+
* (contains `/p/`, `/plan/`, or `/share-plan/`) => "plan_share";
|
|
116
|
+
* 4. a non-empty external referring host => "external";
|
|
117
|
+
* 5. otherwise => "direct".
|
|
118
|
+
*/
|
|
119
|
+
export function deriveReferralSource(ft) {
|
|
120
|
+
if (ft?.ref && ft.ref.trim())
|
|
121
|
+
return ft.ref.trim();
|
|
122
|
+
const path = ft?.landing_path ?? "";
|
|
123
|
+
if (path.startsWith("/share/"))
|
|
124
|
+
return "clip_share";
|
|
125
|
+
if (path.includes("/p/") ||
|
|
126
|
+
path.includes("/plan/") ||
|
|
127
|
+
path.includes("/share-plan/")) {
|
|
128
|
+
return "plan_share";
|
|
129
|
+
}
|
|
130
|
+
if (isExternalReferrerHost(ft?.landing_referrer))
|
|
131
|
+
return "external";
|
|
132
|
+
return "direct";
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Compute the snake_case signup-event properties from first-touch attribution.
|
|
136
|
+
* Returns a clean object with `undefined` values omitted, ready to merge into
|
|
137
|
+
* the `signup` track call. Always sets `referral_source` (defaults to "direct").
|
|
138
|
+
*
|
|
139
|
+
* Pure and total — given any (or no) input it returns a well-formed object and
|
|
140
|
+
* never throws.
|
|
141
|
+
*/
|
|
142
|
+
export function deriveSignupAttribution(ft) {
|
|
143
|
+
const out = {
|
|
144
|
+
referral_source: deriveReferralSource(ft),
|
|
145
|
+
};
|
|
146
|
+
if (!ft)
|
|
147
|
+
return out;
|
|
148
|
+
const setIf = (key, value) => {
|
|
149
|
+
const trimmed = value?.trim();
|
|
150
|
+
if (trimmed)
|
|
151
|
+
out[key] = trimmed;
|
|
152
|
+
};
|
|
153
|
+
setIf("referrer_user", ft.via);
|
|
154
|
+
setIf("referral_medium", ft.utm_medium);
|
|
155
|
+
setIf("referral_campaign", ft.utm_campaign);
|
|
156
|
+
setIf("utm_source", ft.utm_source);
|
|
157
|
+
setIf("utm_medium", ft.utm_medium);
|
|
158
|
+
setIf("utm_campaign", ft.utm_campaign);
|
|
159
|
+
setIf("utm_content", ft.utm_content);
|
|
160
|
+
setIf("utm_term", ft.utm_term);
|
|
161
|
+
setIf("first_touch_path", ft.landing_path);
|
|
162
|
+
setIf("landing_referrer", ft.landing_referrer);
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Convenience: read the cookie header and derive signup attribution in one
|
|
167
|
+
* call. Never throws; falls back to `{ referral_source: "direct" }` on any
|
|
168
|
+
* error.
|
|
169
|
+
*/
|
|
170
|
+
export function signupAttributionFromCookieHeader(cookieHeader) {
|
|
171
|
+
try {
|
|
172
|
+
return deriveSignupAttribution(readFirstTouchAttribution(cookieHeader));
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return { referral_source: "direct" };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/server/attribution.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * First-touch referral attribution — server side.\n *\n * The browser captures an anonymous visitor's *first* landing context (referral\n * source, UTM params, referring host, landing path) and persists it across the\n * signup boundary in a first-party cookie named `an_ft` (see\n * `client/analytics.ts`). On signup, the auth hook reads that cookie off the\n * request and enriches the canonical server-side `signup` event so we can\n * measure where new users came from and how apps spread (virality).\n *\n * This module is intentionally pure and dependency-free so it is trivially\n * unit-testable and can never throw into the signup path. The single hard rule:\n * parsing untrusted cookie input must NEVER throw — every accessor is defensive.\n */\n\n/**\n * The decoded first-touch attribution object. Mirrors the compact JSON the\n * client writes into the `an_ft` cookie / `an_attribution` localStorage key.\n * Every field is optional — the client omits empty fields to keep the cookie\n * small, and a malformed/absent cookie yields `null`.\n */\nexport interface FirstTouchAttribution {\n /** Referral source bucket, e.g. \"clip_share\", \"plan_share\". */\n ref?: string;\n /** Referrer's stable user id (the clip/plan owner who shared the link). */\n via?: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_content?: string;\n utm_term?: string;\n /** `window.location.pathname` of the first page the visitor landed on. */\n landing_path?: string;\n /** Host of `document.referrer` (scrubbed; host only, never a full URL). */\n landing_referrer?: string;\n /** ISO timestamp of when the visitor first landed. */\n landed_at?: string;\n}\n\n/** Cookie name written by the client (non-HttpOnly; non-sensitive). */\nexport const FIRST_TOUCH_COOKIE_NAME = \"an_ft\";\n\nconst STRING_FIELDS: Array<keyof FirstTouchAttribution> = [\n \"ref\",\n \"via\",\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n \"utm_content\",\n \"utm_term\",\n \"landing_path\",\n \"landing_referrer\",\n \"landed_at\",\n];\n\n/**\n * Parse a raw `Cookie:` header into a flat name→value map. Tolerates missing\n * input, extra whitespace, `=` inside values, and malformed pairs. Never throws.\n */\nexport function parseCookieHeader(\n cookieHeader: string | null | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {};\n if (!cookieHeader || typeof cookieHeader !== \"string\") return out;\n for (const part of cookieHeader.split(\";\")) {\n const eq = part.indexOf(\"=\");\n if (eq === -1) continue;\n const name = part.slice(0, eq).trim();\n if (!name) continue;\n const rawValue = part.slice(eq + 1).trim();\n // First write wins so a duplicate cookie name can't clobber the first.\n if (name in out) continue;\n out[name] = rawValue;\n }\n return out;\n}\n\n/**\n * Decode a single cookie value into a `FirstTouchAttribution`. The value is the\n * URL-encoded compact JSON written by the client. Returns `null` for empty,\n * malformed, or non-object input. Only known string fields are copied through,\n * each clamped to a sane max length as a defense against an oversized cookie.\n */\nexport function decodeFirstTouchValue(\n value: string | null | undefined,\n): FirstTouchAttribution | null {\n if (!value || typeof value !== \"string\") return null;\n let decoded = value;\n try {\n decoded = decodeURIComponent(value);\n } catch {\n // Not valid percent-encoding — fall back to the raw value and let the JSON\n // parse below decide whether it's usable.\n decoded = value;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(decoded);\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return null;\n }\n const source = parsed as Record<string, unknown>;\n const result: FirstTouchAttribution = {};\n let any = false;\n for (const field of STRING_FIELDS) {\n const raw = source[field];\n if (typeof raw === \"string\" && raw.length > 0) {\n result[field] = raw.slice(0, 120);\n any = true;\n }\n }\n return any ? result : null;\n}\n\n/**\n * Read the `an_ft` first-touch attribution out of a raw `Cookie:` header.\n * Returns `null` when the cookie is absent or unparseable. Never throws.\n */\nexport function readFirstTouchAttribution(\n cookieHeader: string | null | undefined,\n): FirstTouchAttribution | null {\n try {\n const cookies = parseCookieHeader(cookieHeader);\n return decodeFirstTouchValue(cookies[FIRST_TOUCH_COOKIE_NAME]);\n } catch {\n return null;\n }\n}\n\nfunction isExternalReferrerHost(host: string | undefined): boolean {\n const trimmed = host?.trim();\n return !!trimmed && trimmed.length > 0;\n}\n\n/**\n * Derive the `referral_source` bucket from first-touch attribution per the\n * contract:\n * 1. explicit `ref` wins;\n * 2. landing path under `/share/` => \"clip_share\";\n * 3. landing path that looks like a public plan page\n * (contains `/p/`, `/plan/`, or `/share-plan/`) => \"plan_share\";\n * 4. a non-empty external referring host => \"external\";\n * 5. otherwise => \"direct\".\n */\nexport function deriveReferralSource(ft: FirstTouchAttribution | null): string {\n if (ft?.ref && ft.ref.trim()) return ft.ref.trim();\n const path = ft?.landing_path ?? \"\";\n if (path.startsWith(\"/share/\")) return \"clip_share\";\n if (\n path.includes(\"/p/\") ||\n path.includes(\"/plan/\") ||\n path.includes(\"/share-plan/\")\n ) {\n return \"plan_share\";\n }\n if (isExternalReferrerHost(ft?.landing_referrer)) return \"external\";\n return \"direct\";\n}\n\n/**\n * Compute the snake_case signup-event properties from first-touch attribution.\n * Returns a clean object with `undefined` values omitted, ready to merge into\n * the `signup` track call. Always sets `referral_source` (defaults to \"direct\").\n *\n * Pure and total — given any (or no) input it returns a well-formed object and\n * never throws.\n */\nexport function deriveSignupAttribution(\n ft: FirstTouchAttribution | null,\n): Record<string, string> {\n const out: Record<string, string> = {\n referral_source: deriveReferralSource(ft),\n };\n if (!ft) return out;\n\n const setIf = (key: string, value: string | undefined) => {\n const trimmed = value?.trim();\n if (trimmed) out[key] = trimmed;\n };\n\n setIf(\"referrer_user\", ft.via);\n setIf(\"referral_medium\", ft.utm_medium);\n setIf(\"referral_campaign\", ft.utm_campaign);\n setIf(\"utm_source\", ft.utm_source);\n setIf(\"utm_medium\", ft.utm_medium);\n setIf(\"utm_campaign\", ft.utm_campaign);\n setIf(\"utm_content\", ft.utm_content);\n setIf(\"utm_term\", ft.utm_term);\n setIf(\"first_touch_path\", ft.landing_path);\n setIf(\"landing_referrer\", ft.landing_referrer);\n\n return out;\n}\n\n/**\n * Convenience: read the cookie header and derive signup attribution in one\n * call. Never throws; falls back to `{ referral_source: \"direct\" }` on any\n * error.\n */\nexport function signupAttributionFromCookieHeader(\n cookieHeader: string | null | undefined,\n): Record<string, string> {\n try {\n return deriveSignupAttribution(readFirstTouchAttribution(cookieHeader));\n } catch {\n return { referral_source: \"direct\" };\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/server/auth.js
CHANGED
|
@@ -1312,6 +1312,13 @@ function createAuthGuardFn() {
|
|
|
1312
1312
|
return;
|
|
1313
1313
|
if (p === "/_agent-native/speculation-rules.json")
|
|
1314
1314
|
return;
|
|
1315
|
+
// Liveness probe: always public so uptime monitors and the keep-warm cron
|
|
1316
|
+
// can reach the DB-warmup route without a session. It exposes no per-user
|
|
1317
|
+
// data (just ok/db/ms) and runs a trivial `SELECT 1`. Without this bypass
|
|
1318
|
+
// the gate below 401s anonymous /_agent-native/* requests before any DB
|
|
1319
|
+
// query, so the database would never get warmed.
|
|
1320
|
+
if (p === "/_agent-native/health")
|
|
1321
|
+
return;
|
|
1315
1322
|
if (isPublicPath(normalizedUrl, publicPaths))
|
|
1316
1323
|
return;
|
|
1317
1324
|
if (shouldBypassAuthForBuilderConnect(event, p))
|