@agent-native/core 0.176.1 → 0.176.2-nightly-20260831184159
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/analytics/AGENTS.md +13 -2
- package/corpus/templates/analytics/CHANGELOG.md +8 -0
- package/corpus/templates/analytics/actions/certify-dashboard.ts +39 -0
- package/corpus/templates/analytics/actions/get-sql-dashboard.ts +1 -1
- package/corpus/templates/analytics/actions/list-analysis-revisions.ts +4 -2
- package/corpus/templates/analytics/actions/list-dashboard-revisions.ts +4 -2
- package/corpus/templates/analytics/actions/search-analytics-query-catalog.ts +1 -0
- package/corpus/templates/analytics/actions/search-dashboard-references.ts +2 -1
- package/corpus/templates/analytics/actions/set-workspace-feature-flag.ts +2 -2
- package/corpus/templates/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +16 -1
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +58 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +7 -19
- package/corpus/templates/analytics/app/global.css +0 -7
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/analytics/app/i18n-data.ts +42 -0
- package/corpus/templates/analytics/app/lib/track-metric.ts +15 -0
- package/corpus/templates/analytics/app/pages/NotFound.tsx +1 -1
- package/corpus/templates/analytics/app/pages/Placeholder.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +115 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +8 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +23 -25
- package/corpus/templates/analytics/app/root.tsx +5 -5
- package/corpus/templates/analytics/app/routes/_index.tsx +18 -20
- package/corpus/templates/analytics/app/routes/dashboard.tsx +1 -1
- package/corpus/templates/analytics/app/routes/home.tsx +39 -0
- package/corpus/templates/analytics/changelog/2026-08-27-show-analytics-s-own-registered-flags-in-fleet-feature-flag-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-28-analytics-loading-placeholders-now-use-a-smooth-whole-surfac.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-28-analytics-loading-states-use-a-softer-whole-surfac.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-28-analytics-sidebar-horizontal-spacing-is-tighter.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-28-sidebar-branding-matches-the-app-text-color-with-a-tighter-m.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-28-sidebar-branding-uses-a-monochrome-agent-native-mark.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-29-analytics-loading-shine-is-more-subtle.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-29-chat-edits-can-be-reverted-to-saved-checkpoints.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-29-dashboard-certification-lives-in-the-overflow-menu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-29-public-marketing-home.md +6 -0
- package/corpus/templates/analytics/package.json +2 -0
- package/corpus/templates/analytics/public/manifest.json +1 -1
- package/corpus/templates/analytics/server/db/schema.ts +4 -0
- package/corpus/templates/analytics/server/handlers/events.ts +10 -1
- package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +9 -1
- package/corpus/templates/analytics/server/handlers/session-replay.ts +10 -1
- package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +22 -2
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +82 -7
- package/corpus/templates/analytics/server/lib/dashboard-certification.ts +58 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +1 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +429 -46
- package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +204 -32
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +139 -0
- package/corpus/templates/analytics/server/plugins/auth.ts +1 -0
- package/corpus/templates/analytics/server/plugins/core-routes.ts +3 -2
- package/corpus/templates/analytics/server/plugins/db.ts +11 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/assets/app/components/layout/Header.tsx +2 -2
- package/corpus/templates/assets/app/components/layout/Layout.tsx +4 -3
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +14 -27
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -2
- package/corpus/templates/assets/app/root.tsx +29 -9
- package/corpus/templates/assets/app/routes/_index.tsx +15 -116
- package/corpus/templates/assets/app/routes/chat.$threadId.tsx +1 -1
- package/corpus/templates/assets/app/routes/home.tsx +137 -0
- package/corpus/templates/assets/app/routes/library.tsx +5 -1
- package/corpus/templates/assets/app/routes/settings.tsx +28 -25
- package/corpus/templates/assets/changelog/2026-08-26-templates-across-brand-kits.md +1 -0
- package/corpus/templates/assets/public/manifest.json +1 -1
- package/corpus/templates/assets/server/plugins/auth.ts +1 -0
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -3
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +10 -23
- package/corpus/templates/brain/app/lib/brain.ts +2 -2
- package/corpus/templates/brain/app/root.tsx +13 -3
- package/corpus/templates/brain/app/routes/_index.tsx +15 -55
- package/corpus/templates/brain/app/routes/home.tsx +76 -0
- package/corpus/templates/brain/app/routes.ts +1 -0
- package/corpus/templates/brain/public/manifest.json +1 -1
- package/corpus/templates/brain/server/lib/brain-health.ts +2 -2
- package/corpus/templates/brain/server/plugins/auth.ts +1 -1
- package/corpus/templates/brain/server/plugins/core-routes.ts +2 -1
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/calendar/CHANGELOG.md +12 -0
- package/corpus/templates/calendar/actions/event-action-helpers.ts +2 -1
- package/corpus/templates/calendar/actions/manage-event-draft.ts +1 -1
- package/corpus/templates/calendar/actions/update-event.ts +8 -1
- package/corpus/templates/calendar/amplify.yml +15 -0
- package/corpus/templates/calendar/app/components/calendar/ApolloPanel.tsx +2 -2
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +102 -109
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +23 -10
- package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +2 -11
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +150 -141
- package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +3 -1
- package/corpus/templates/calendar/app/components/calendar/EventDescription.tsx +2 -2
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +359 -222
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +13 -5
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +21 -9
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +21 -32
- package/corpus/templates/calendar/app/global.css +11 -0
- package/corpus/templates/calendar/app/hooks/use-meeting-start-notifications.ts +10 -0
- package/corpus/templates/calendar/app/hooks/use-navigation-state.ts +3 -3
- package/corpus/templates/calendar/app/i18n-data.ts +110 -0
- package/corpus/templates/calendar/app/lib/calendar-timezone.ts +12 -3
- package/corpus/templates/calendar/app/lib/event-popover-style.ts +43 -0
- package/corpus/templates/calendar/app/lib/mcp-embed.ts +8 -2
- package/corpus/templates/calendar/app/lib/utils.ts +3 -1
- package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -8
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +9 -11
- package/corpus/templates/calendar/app/pages/ManageBookingPage.tsx +2 -6
- package/corpus/templates/calendar/app/pages/NotFound.tsx +1 -1
- package/corpus/templates/calendar/app/pages/Settings.tsx +54 -0
- package/corpus/templates/calendar/app/root.tsx +9 -1
- package/corpus/templates/calendar/app/routes/{_app._index.tsx → _app.home.tsx} +1 -1
- package/corpus/templates/calendar/app/routes/_index.tsx +34 -0
- package/corpus/templates/calendar/app/routes/event.tsx +2 -6
- package/corpus/templates/calendar/changelog/2026-08-28-all-day-events-stay-in-the-compact-top-bar-in-day-and-week-v.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-calendar-organizer-note-emails-now-link-back-to-agent-native.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-calendar-shows-google-profile-photos-in-the-desktop-app.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-event-creators-can-choose-whether-a-meeting-shows-as-free-or.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-event-popovers-match-notion-calendar-s-density-a-284px-blurr.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-fixed-calendar-navigation-scheduling-permissions-and-action-.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-google-calendar-connections-use-the-registered-callback-on-m.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-sidebar-branding-matches-the-app-text-color-with-a-tighter-m.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-sidebar-branding-uses-a-monochrome-agent-native-mark.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-the-calendar-sidebar-keeps-the-settings-link-compact.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-28-the-calendar-sidebar-keeps-the-workspace-picker-compact.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-29-public-marketing-home.md +6 -0
- package/corpus/templates/calendar/public/manifest.json +1 -1
- package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
- package/corpus/templates/calendar/server/lib/emails.ts +2 -1
- package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +31 -5
- package/corpus/templates/calendar/server/lib/google-calendar.ts +4 -2
- package/corpus/templates/calendar/server/plugins/auth.ts +1 -0
- package/corpus/templates/calendar/server/plugins/core-routes.ts +5 -3
- package/corpus/templates/calendar/shared/event-permissions.ts +12 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/chat/AGENTS.md +5 -4
- package/corpus/templates/chat/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/chat/app/components/layout/Layout.tsx +5 -4
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +16 -25
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +5 -5
- package/corpus/templates/chat/app/root.tsx +16 -3
- package/corpus/templates/chat/app/routes/_index.tsx +17 -74
- package/corpus/templates/chat/app/routes/chat.$threadId.tsx +1 -1
- package/corpus/templates/chat/app/routes/home.tsx +94 -0
- package/corpus/templates/chat/netlify.toml +2 -1
- package/corpus/templates/chat/public/manifest.json +1 -1
- package/corpus/templates/chat/server/plugins/auth.ts +1 -0
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/clips/actions/add-comment.ts +18 -1
- package/corpus/templates/clips/actions/get-recording-player-data.ts +2 -0
- package/corpus/templates/clips/actions/list-comments.ts +2 -0
- package/corpus/templates/clips/actions/list-notifications.ts +60 -28
- package/corpus/templates/clips/actions/list-recording-mention-members.ts +64 -0
- package/corpus/templates/clips/actions/list-recordings.ts +1 -1
- package/corpus/templates/clips/actions/reply-to-comment.ts +17 -1
- package/corpus/templates/clips/actions/update-comment.ts +36 -2
- package/corpus/templates/clips/app/components/library/empty-state.tsx +1 -3
- package/corpus/templates/clips/app/components/library/library-grid.tsx +18 -6
- package/corpus/templates/clips/app/components/library/library-layout.tsx +6 -58
- package/corpus/templates/clips/app/components/library/recording-card.tsx +101 -3
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +2 -2
- package/corpus/templates/clips/app/components/player/comment-composer.tsx +284 -0
- package/corpus/templates/clips/app/components/player/comments-panel.tsx +162 -46
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +38 -133
- package/corpus/templates/clips/app/components/player/video-player.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +99 -20
- package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +110 -116
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +83 -60
- package/corpus/templates/clips/app/components/settings/ai-setup-section.tsx +17 -11
- package/corpus/templates/clips/app/components/settings/types.ts +5 -1
- package/corpus/templates/clips/app/components/settings/video-storage-section.tsx +21 -12
- package/corpus/templates/clips/app/global.css +0 -27
- package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +3 -17
- package/corpus/templates/clips/app/hooks/use-mention-members.ts +24 -0
- package/corpus/templates/clips/app/hooks/use-navigation-state.ts +2 -2
- package/corpus/templates/clips/app/i18n/en-US.ts +15 -0
- package/corpus/templates/clips/app/lib/recording-backup.ts +245 -0
- package/corpus/templates/clips/app/lib/recording-retry.ts +189 -0
- package/corpus/templates/clips/app/lib/recording-status.ts +32 -0
- package/corpus/templates/clips/app/root.tsx +11 -2
- package/corpus/templates/clips/app/routes/_app.home.tsx +62 -0
- package/corpus/templates/clips/app/routes/_app.notifications.tsx +45 -12
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +2 -0
- package/corpus/templates/clips/app/routes/_index.tsx +11 -40
- package/corpus/templates/clips/app/routes/download.tsx +148 -15
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +4 -3
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +6 -11
- package/corpus/templates/clips/app/routes/record.tsx +72 -13
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +40 -24
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +2 -7
- package/corpus/templates/clips/changelog/2026-08-28-chrome-extension-download-help.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-28-clips-loading-skeletons-use-a-softer-whole-surface.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-28-comment-composer-no-longer-has-an-outer-border.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-29-clips-loading-shine-is-more-subtle.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +377 -476
- package/corpus/templates/clips/desktop/src/components/ui/skeleton.tsx +1 -1
- package/corpus/templates/clips/desktop/src/components/ui/spinner.tsx +1 -17
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +4 -0
- package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +0 -8
- package/corpus/templates/clips/desktop/src/overlays/record-pill.tsx +221 -460
- package/corpus/templates/clips/desktop/src/styles.css +0 -40
- package/corpus/templates/clips/desktop/src/tailwind.css +28 -14
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +15 -11
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +9 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +192 -57
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +9 -3
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +97 -3
- package/corpus/templates/clips/public/manifest.json +1 -1
- package/corpus/templates/clips/server/db/schema.ts +1 -0
- package/corpus/templates/clips/server/lib/activity-notifications.ts +30 -5
- package/corpus/templates/clips/server/lib/comment-mentions.ts +23 -0
- package/corpus/templates/clips/server/lib/emails.ts +2 -2
- package/corpus/templates/clips/server/lib/recording-page-access.ts +16 -0
- package/corpus/templates/clips/server/lib/transactional-email-templates.ts +14 -7
- package/corpus/templates/clips/server/plugins/auth.ts +1 -0
- package/corpus/templates/clips/server/plugins/core-routes.ts +5 -0
- package/corpus/templates/clips/server/plugins/db.ts +5 -0
- package/corpus/templates/clips/server/routes/api/auth/google-calendar.get.ts +4 -2
- package/corpus/templates/clips/server/routes/api/clips-latest.json.get.ts +77 -22
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +11 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +4 -4
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/resume.get.ts +1 -1
- package/corpus/templates/clips/shared/comment-mentions.ts +71 -0
- package/corpus/templates/clips/shared/prerendered-public-paths.ts +1 -1
- package/corpus/templates/clips/shared/recording-core.ts +5 -0
- package/corpus/templates/clips/shared/recording-playhead.css +207 -0
- package/corpus/templates/clips/shared/recording-playhead.tsx +616 -0
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/content/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/content/CHANGELOG.md +6 -0
- package/corpus/templates/content/actions/_property-utils.ts +45 -9
- package/corpus/templates/content/actions/edit-document.ts +17 -0
- package/corpus/templates/content/actions/get-document.ts +31 -11
- package/corpus/templates/content/actions/list-document-properties.ts +30 -2
- package/corpus/templates/content/actions/list-document-versions.ts +49 -17
- package/corpus/templates/content/actions/list-documents.ts +13 -2
- package/corpus/templates/content/actions/restore-document-version.ts +8 -1
- package/corpus/templates/content/actions/update-document.ts +8 -0
- package/corpus/templates/content/app/components/QueryErrorState.tsx +1 -0
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +28 -8
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +94 -61
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +24 -10
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +16 -13
- package/corpus/templates/content/app/components/editor/database/settings.tsx +16 -13
- package/corpus/templates/content/app/components/layout/Layout.tsx +35 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -18
- package/corpus/templates/content/app/hooks/use-document-properties.ts +5 -3
- package/corpus/templates/content/app/hooks/use-documents.ts +3 -1
- package/corpus/templates/content/app/hooks/use-navigation-state.ts +3 -3
- package/corpus/templates/content/app/root.tsx +9 -4
- package/corpus/templates/content/app/routes/{_app._index.tsx → _app.home.tsx} +12 -4
- package/corpus/templates/content/app/routes/_index.tsx +33 -0
- package/corpus/templates/content/changelog/2026-08-26-shared-page-load-failures-now-stay-visible-and-safe.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +2 -2
- package/corpus/templates/content/e2e/playwright.config.ts +1 -1
- package/corpus/templates/content/package.json +2 -0
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +1 -1
- package/corpus/templates/content/public/manifest.json +1 -1
- package/corpus/templates/content/server/db/schema.ts +1 -0
- package/corpus/templates/content/server/lib/document-version-context.ts +67 -0
- package/corpus/templates/content/server/plugins/agent-chat.ts +155 -0
- package/corpus/templates/content/server/plugins/auth.ts +1 -0
- package/corpus/templates/content/server/plugins/core-routes.ts +3 -2
- package/corpus/templates/content/server/plugins/db.ts +5 -0
- package/corpus/templates/content/shared/api.ts +6 -4
- package/corpus/templates/crm/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +1 -1
- package/corpus/templates/crm/agent-native.app-skill.json +1 -1
- package/corpus/templates/crm/app/components/layout/CrmCommandMenu.tsx +1 -1
- package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +36 -1
- package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +3 -3
- package/corpus/templates/crm/app/root.tsx +28 -7
- package/corpus/templates/crm/app/routes/_index.tsx +28 -18
- package/corpus/templates/crm/app/routes/home.tsx +27 -0
- package/corpus/templates/crm/app/routes/setup.tsx +2 -2
- package/corpus/templates/crm/app/routes.ts +1 -0
- package/corpus/templates/crm/public/manifest.json +1 -1
- package/corpus/templates/crm/server/plugins/agent-chat.ts +81 -0
- package/corpus/templates/crm/server/plugins/auth.ts +1 -0
- package/corpus/templates/crm/server/plugins/core-routes.ts +2 -1
- package/corpus/templates/crm/server/plugins/db.ts +7 -1
- package/corpus/templates/crm/shared/crm-navigation.ts +3 -2
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +13 -0
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/design/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +22 -10
- package/corpus/templates/design/AGENTS.md +1 -1
- package/corpus/templates/design/actions/add-breakpoint.ts +3 -1
- package/corpus/templates/design/actions/add-fusion-screens.ts +2 -0
- package/corpus/templates/design/actions/add-localhost-screens.ts +16 -11
- package/corpus/templates/design/actions/apply-a11y-fix.ts +6 -8
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +3 -1
- package/corpus/templates/design/actions/apply-design-token-edit.ts +3 -1
- package/corpus/templates/design/actions/apply-motion-edit.ts +18 -13
- package/corpus/templates/design/actions/apply-shader-fill.ts +3 -1
- package/corpus/templates/design/actions/apply-source-edit.ts +6 -1
- package/corpus/templates/design/actions/apply-tweaks.ts +3 -1
- package/corpus/templates/design/actions/apply-visual-edit.ts +14 -9
- package/corpus/templates/design/actions/clone-creative-context-design.ts +6 -1
- package/corpus/templates/design/actions/create-component.ts +3 -1
- package/corpus/templates/design/actions/create-file.ts +3 -1
- package/corpus/templates/design/actions/delete-file.ts +3 -1
- package/corpus/templates/design/actions/detach-component-instance.ts +3 -1
- package/corpus/templates/design/actions/edit-design.ts +16 -11
- package/corpus/templates/design/actions/generate-design.ts +19 -14
- package/corpus/templates/design/actions/get-design-branch-diff.ts +26 -31
- package/corpus/templates/design/actions/get-design-review.ts +25 -31
- package/corpus/templates/design/actions/get-design-system-index-status.ts +55 -0
- package/corpus/templates/design/actions/get-design-system.ts +1 -1
- package/corpus/templates/design/actions/hydrate-figma-paste-images.ts +3 -1
- package/corpus/templates/design/actions/import-design-source.ts +16 -9
- package/corpus/templates/design/actions/import-design-tokens.ts +3 -1
- package/corpus/templates/design/actions/import-figma-clipboard.ts +28 -16
- package/corpus/templates/design/actions/import-figma-frame.ts +3 -1
- package/corpus/templates/design/actions/insert-asset.ts +3 -1
- package/corpus/templates/design/actions/insert-design-native-asset.ts +3 -1
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +3 -1
- package/corpus/templates/design/actions/list-design-versions.ts +23 -0
- package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +3 -1
- package/corpus/templates/design/actions/open-visual-edit.ts +23 -20
- package/corpus/templates/design/actions/present-design-variants.ts +7 -2
- package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +66 -10
- package/corpus/templates/design/actions/remove-breakpoint.ts +3 -1
- package/corpus/templates/design/actions/remove-motion-timeline.ts +3 -1
- package/corpus/templates/design/actions/restore-design-version.ts +16 -0
- package/corpus/templates/design/actions/set-layout-grid.ts +94 -0
- package/corpus/templates/design/actions/swap-component-instance.ts +6 -1
- package/corpus/templates/design/actions/update-design.ts +16 -11
- package/corpus/templates/design/actions/update-file.ts +2 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +25 -0
- package/corpus/templates/design/app/components/design/EditPanel.tsx +36 -8
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +6 -6
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +185 -29
- package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +4 -4
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +1 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +35 -10
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +16 -9
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +51 -21
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +18 -17
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +6 -1
- package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +3 -3
- package/corpus/templates/design/app/components/design/edit-panel/layout-grid-properties.tsx +88 -0
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +5 -2
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +8 -4
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +8 -103
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +68 -83
- package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +35 -10
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +29 -24
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +6 -0
- package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +72 -71
- package/corpus/templates/design/app/components/design/inspector/InspectorControlPopover.tsx +1 -1
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +9 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +8 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +32 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +8 -21
- package/corpus/templates/design/app/global.css +72 -1
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +32 -1
- package/corpus/templates/design/app/i18n-data.ts +116 -12
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +3 -1
- package/corpus/templates/design/app/lib/design-system-data.ts +36 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +170 -34
- package/corpus/templates/design/app/pages/DesignSystems.tsx +126 -11
- package/corpus/templates/design/app/pages/Index.tsx +15 -7
- package/corpus/templates/design/app/pages/NotFound.tsx +1 -1
- package/corpus/templates/design/app/pages/Templates.tsx +18 -3
- package/corpus/templates/design/app/pages/VisualEdit.tsx +1 -1
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +3 -3
- package/corpus/templates/design/app/pages/design-editor/commands/README.md +1 -0
- package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +2 -1
- package/corpus/templates/design/app/pages/design-editor/commands/set-layout-grid.ts +66 -0
- package/corpus/templates/design/app/pages/design-editor/design-data-geometry-utils.ts +5 -0
- package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +9 -1
- package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +39 -9
- package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +31 -2
- package/corpus/templates/design/app/pages/design-editor/geometry-persistence.ts +26 -0
- package/corpus/templates/design/app/pages/design-editor/intake-question-topics.ts +335 -0
- package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +8 -1
- package/corpus/templates/design/app/root.tsx +12 -2
- package/corpus/templates/design/app/routes/_index.tsx +14 -1
- package/corpus/templates/design/app/routes/home.tsx +21 -0
- package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +1 -1
- package/corpus/templates/design/changelog/2026-08-28-frames-can-carry-an-8px-layout-grid-that-positions-snap-to.md +6 -0
- package/corpus/templates/design/changelog/2026-08-28-x-and-y-are-always-whole-numbers.md +6 -0
- package/corpus/templates/design/public/manifest.json +1 -1
- package/corpus/templates/design/server/db/schema.ts +2 -0
- package/corpus/templates/design/server/handlers/design-system-builder-link.ts +84 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +9 -1
- package/corpus/templates/design/server/lib/design-versions.ts +1017 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +144 -0
- package/corpus/templates/design/server/plugins/auth.ts +1 -1
- package/corpus/templates/design/server/plugins/core-routes.ts +3 -2
- package/corpus/templates/design/server/plugins/db.ts +7 -0
- package/corpus/templates/design/server/routes/api/design-system-builder-link.get.ts +1 -0
- package/corpus/templates/design/shared/canvas-math.ts +106 -14
- package/corpus/templates/design/shared/layout-grid.ts +80 -0
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/dispatch/AGENTS.md +11 -13
- package/corpus/templates/dispatch/actions/list-workspace-connections.ts +10 -5
- package/corpus/templates/dispatch/app/i18n-data.ts +120 -0
- package/corpus/templates/dispatch/app/root.tsx +11 -1
- package/corpus/templates/dispatch/app/routes/_index.tsx +34 -7
- package/corpus/templates/dispatch/app/routes/home.tsx +7 -0
- package/corpus/templates/dispatch/package.json +1 -0
- package/corpus/templates/dispatch/public/manifest.json +1 -1
- package/corpus/templates/factory/.agents/skills/factory-graphs/SKILL.md +11 -2
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/factory/.env.example +2 -14
- package/corpus/templates/factory/AGENTS.md +12 -11
- package/corpus/templates/factory/README.md +15 -17
- package/corpus/templates/factory/actions/{babysit-agent-native-pull-request.ts → babysit-factory-pull-request.ts} +125 -88
- package/corpus/templates/factory/actions/create-factory-automation.ts +161 -0
- package/corpus/templates/factory/actions/create-factory.ts +4 -124
- package/corpus/templates/factory/actions/delete-factory.ts +11 -23
- package/corpus/templates/factory/actions/{start-builder-for-item.ts → dispatch-factory-item.ts} +169 -57
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +30 -10
- package/corpus/templates/factory/actions/get-triage-config.ts +22 -0
- package/corpus/templates/factory/actions/get-triage-item.ts +49 -2
- package/corpus/templates/factory/actions/{govern-agent-native-pull-request.ts → govern-factory-pull-request.ts} +95 -112
- package/corpus/templates/factory/actions/ingest-github-observation.ts +9 -2
- package/corpus/templates/factory/actions/list-factory-audit.ts +85 -12
- package/corpus/templates/factory/actions/list-factory-automation-templates.ts +56 -0
- package/corpus/templates/factory/actions/list-factory-automations.ts +36 -3
- package/corpus/templates/factory/actions/list-factory-graph-versions.ts +37 -10
- package/corpus/templates/factory/actions/list-triage-items.ts +120 -15
- package/corpus/templates/factory/actions/poll-github-sources.ts +102 -58
- package/corpus/templates/factory/actions/poll-sentry-errors.ts +73 -36
- package/corpus/templates/factory/actions/poll-slack-channel.ts +112 -28
- package/corpus/templates/factory/actions/{babysit-pull-request.ts → propose-pr-babysit-status.ts} +9 -47
- package/corpus/templates/factory/actions/reconcile-triage-run.ts +1 -1
- package/corpus/templates/factory/actions/save-factory-automation.ts +131 -33
- package/corpus/templates/factory/actions/save-factory-graph.ts +31 -8
- package/corpus/templates/factory/actions/save-triage-config.ts +7 -27
- package/corpus/templates/factory/actions/save-triage-rule.ts +1 -1
- package/corpus/templates/factory/app/components/factory/CreateFactoryAutomationView.tsx +258 -0
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +349 -106
- package/corpus/templates/factory/app/components/factory/FactoryAutomationFields.tsx +614 -0
- package/corpus/templates/factory/app/components/factory/FactoryInboxView.tsx +1136 -0
- package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +7 -14
- package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +4 -223
- package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +10 -205
- package/corpus/templates/factory/app/components/factory/SlackMrkdwn.tsx +100 -0
- package/corpus/templates/factory/app/components/factory/audit-filters.ts +30 -0
- package/corpus/templates/factory/app/components/factory/factory-automation-form.ts +120 -0
- package/corpus/templates/factory/app/components/factory/inbox-filters.ts +84 -0
- package/corpus/templates/factory/app/components/factory/inbox-source-url.ts +23 -0
- package/corpus/templates/factory/app/components/factory/slack-emoji.ts +165 -0
- package/corpus/templates/factory/app/components/factory/slack-mrkdwn.ts +128 -0
- package/corpus/templates/factory/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/factory/app/components/layout/Layout.tsx +63 -6
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +13 -26
- package/corpus/templates/factory/app/components/triage/triage-status-pill.tsx +63 -14
- package/corpus/templates/factory/app/global.css +106 -0
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +16 -10
- package/corpus/templates/factory/app/i18n/en-US.ts +154 -7
- package/corpus/templates/factory/app/lib/factory-tab-params.ts +59 -0
- package/corpus/templates/factory/app/lib/safe-http-url.ts +8 -0
- package/corpus/templates/factory/app/root.tsx +16 -3
- package/corpus/templates/factory/app/routes/_index.tsx +27 -5
- package/corpus/templates/factory/app/routes/factory.tsx +325 -733
- package/corpus/templates/factory/app/routes/home.tsx +13 -0
- package/corpus/templates/factory/app/routes/new-factory.tsx +3 -5
- package/corpus/templates/factory/changelog/2026-08-26-inbox-full-screen-thread.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-26-inbox-thread-and-audit-labels.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-27-audit-run-list-stacks.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-27-audit-run-names-wrap.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-27-factory-opens-on-inbox.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-27-github-repository-url.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-27-inbox-filters.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-27-polling-does-not-enable-automations.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-27-pr-babysit-can-poll-github.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-28-factory-automations-use-workspace-connections.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-28-inbox-approve-and-start-removed.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-28-pr-babysit-audit-shows-decisions.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-28-pr-babysit-reviews-next-github-prs.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-28-pr-babysit-sticky-out-of-scope.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-28-pr-babysit-uses-github-evidence.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-29-audit-filters-pagination-scroll.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-29-create-factory-automations.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-29-dispatch-reaction-argument.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-29-factory-action-names-match-behavior.md +6 -0
- package/corpus/templates/factory/public/manifest.json +1 -1
- package/corpus/templates/factory/server/connectors/slack.ts +8 -6
- package/corpus/templates/factory/server/db/schema.ts +23 -0
- package/corpus/templates/factory/server/lib/audit-cursor.ts +44 -0
- package/corpus/templates/factory/server/lib/factory-action-names.ts +15 -0
- package/corpus/templates/factory/server/lib/factory-audit-report.ts +29 -9
- package/corpus/templates/factory/server/lib/factory-automation-caller.ts +38 -0
- package/corpus/templates/factory/server/lib/factory-automation-config.ts +543 -0
- package/corpus/templates/factory/server/lib/factory-automation-plan.ts +0 -48
- package/corpus/templates/factory/server/lib/factory-automation-repair.ts +2 -18
- package/corpus/templates/factory/server/lib/factory-poll-cursors.ts +98 -0
- package/corpus/templates/factory/server/lib/factory-scope.ts +8 -0
- package/corpus/templates/factory/server/lib/github-repository.ts +104 -0
- package/corpus/templates/factory/server/lib/inbox-cursor.ts +34 -0
- package/corpus/templates/factory/server/lib/pr-babysit-prompt.ts +33 -0
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +58 -17
- package/corpus/templates/factory/server/lib/safe-http-url.ts +8 -0
- package/corpus/templates/factory/server/lib/slack-feedback-prompt.ts +19 -10
- package/corpus/templates/factory/server/lib/source-reaction.ts +37 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +18 -22
- package/corpus/templates/factory/server/plugins/auth.ts +1 -0
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +26 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +277 -164
- package/corpus/templates/factory/server/plugins/integrations.ts +5 -7
- package/corpus/templates/factory/server/triage/github-client.ts +274 -3
- package/corpus/templates/factory/server/triage/github-ingestion.ts +3 -1
- package/corpus/templates/factory/server/triage/metadata.ts +12 -0
- package/corpus/templates/factory/server/triage/pr-babysit.ts +22 -21
- package/corpus/templates/factory/server/triage/review-skill-alignment.ts +11 -11
- package/corpus/templates/factory/server/triage/review-state.ts +39 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +14 -6
- package/corpus/templates/factory/server/triage/slack-poller.ts +34 -65
- package/corpus/templates/factory/server/triage/slack-user-labels.ts +126 -0
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/forms/AGENTS.md +4 -3
- package/corpus/templates/forms/actions/response-insights.ts +4 -4
- package/corpus/templates/forms/actions/retry-response-deliveries.ts +26 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +8 -33
- package/corpus/templates/forms/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/forms/app/lib/route-prewarm.ts +1 -1
- package/corpus/templates/forms/app/root.tsx +3 -2
- package/corpus/templates/forms/app/routes/_app.home.tsx +47 -0
- package/corpus/templates/forms/app/routes/_app.tsx +2 -1
- package/corpus/templates/forms/app/routes/_index.tsx +10 -23
- package/corpus/templates/forms/public/manifest.json +1 -1
- package/corpus/templates/forms/server/db/schema.ts +64 -17
- package/corpus/templates/forms/server/handlers/submissions.ts +1022 -94
- package/corpus/templates/forms/server/lib/integrations.ts +100 -33
- package/corpus/templates/forms/server/middleware/00-public-cors.ts +1 -1
- package/corpus/templates/forms/server/plugins/auth.ts +1 -0
- package/corpus/templates/forms/server/plugins/core-routes.ts +1 -0
- package/corpus/templates/forms/server/plugins/db.ts +40 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/macros/actions/view-screen.ts +1 -1
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +9 -21
- package/corpus/templates/macros/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/macros/app/root.tsx +22 -8
- package/corpus/templates/macros/app/routes/_index.tsx +16 -291
- package/corpus/templates/macros/app/routes/home.tsx +312 -0
- package/corpus/templates/macros/server/plugins/auth.ts +9 -7
- package/corpus/templates/macros/server/plugins/core-routes.ts +1 -0
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/mail/.agents/skills/inbox-automations/SKILL.md +13 -2
- package/corpus/templates/mail/.agents/skills/inbox-reads-and-triage/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/mail/AGENTS.md +5 -2
- package/corpus/templates/mail/actions/apply-ai-filter.ts +294 -0
- package/corpus/templates/mail/actions/create-automation.ts +1 -0
- package/corpus/templates/mail/actions/get-ai-filter.ts +19 -0
- package/corpus/templates/mail/actions/manage-automations.ts +162 -157
- package/corpus/templates/mail/actions/manage-email-rules.ts +3 -0
- package/corpus/templates/mail/actions/navigate.ts +1 -1
- package/corpus/templates/mail/actions/update-automation.ts +1 -0
- package/corpus/templates/mail/actions/update-mail-preferences.ts +1 -0
- package/corpus/templates/mail/app/components/email/AiFilterDialog.tsx +127 -0
- package/corpus/templates/mail/app/components/email/EmailList.tsx +63 -0
- package/corpus/templates/mail/app/components/email/EmailThread.tsx +95 -0
- package/corpus/templates/mail/app/components/email/MobileActionBar.tsx +35 -3
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +17 -22
- package/corpus/templates/mail/app/components/settings/AiFilterSection.tsx +401 -0
- package/corpus/templates/mail/app/hooks/use-ai-filter.ts +48 -0
- package/corpus/templates/mail/app/hooks/use-automations.ts +1 -0
- package/corpus/templates/mail/app/hooks/use-emails.ts +11 -3
- package/corpus/templates/mail/app/i18n/en-US.ts +55 -0
- package/corpus/templates/mail/app/lib/automation-visibility.ts +17 -0
- package/corpus/templates/mail/app/pages/InboxPage.tsx +5 -2
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +16 -8
- package/corpus/templates/mail/app/pages/inbox-zero.ts +1 -2
- package/corpus/templates/mail/app/root.tsx +20 -8
- package/corpus/templates/mail/app/routes/_index.tsx +16 -55
- package/corpus/templates/mail/app/routes/home.tsx +71 -0
- package/corpus/templates/mail/changelog/2026-08-28-mail-settings-show-chat-created-automations.md +6 -0
- package/corpus/templates/mail/public/manifest.json +1 -1
- package/corpus/templates/mail/server/db/schema.ts +3 -0
- package/corpus/templates/mail/server/handlers/emails.ts +34 -11
- package/corpus/templates/mail/server/handlers/google-auth.ts +1 -1
- package/corpus/templates/mail/server/lib/ai-filter.ts +103 -0
- package/corpus/templates/mail/server/lib/automation-actions.ts +14 -9
- package/corpus/templates/mail/server/lib/automation-engine.ts +142 -18
- package/corpus/templates/mail/server/lib/automations.ts +9 -0
- package/corpus/templates/mail/server/lib/email-state.ts +7 -2
- package/corpus/templates/mail/server/lib/gmail-query.ts +10 -0
- package/corpus/templates/mail/server/lib/google-auth.ts +5 -8
- package/corpus/templates/mail/server/lib/jobs.ts +1 -5
- package/corpus/templates/mail/server/onboarding.ts +2 -2
- package/corpus/templates/mail/server/plugins/agent-chat.ts +5 -2
- package/corpus/templates/mail/server/plugins/auth.ts +1 -0
- package/corpus/templates/mail/server/plugins/core-routes.ts +4 -1
- package/corpus/templates/mail/server/plugins/db.ts +6 -0
- package/corpus/templates/mail/server/routes/api/attachments.get.ts +1 -5
- package/corpus/templates/mail/shared/ai-filter.ts +74 -0
- package/corpus/templates/mail/shared/types.ts +2 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/plan/actions/list-plan-versions.ts +20 -5
- package/corpus/templates/plan/agent-native.json +1 -4
- package/corpus/templates/plan/app/components/editor/PlanDocumentEditor.tsx +5 -2
- package/corpus/templates/plan/app/components/layout/Layout.tsx +41 -1
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +4 -16
- package/corpus/templates/plan/app/components/plan/PlanMarkdownEditor.tsx +7 -4
- package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +1 -1
- package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +15 -0
- package/corpus/templates/plan/app/components/plan/wireframe/kit/plan-wireframe-tokens.css +0 -15
- package/corpus/templates/plan/app/components/plan/wireframe/kit/primitives.tsx +2 -2
- package/corpus/templates/plan/app/hooks/use-plan-presence.ts +20 -10
- package/corpus/templates/plan/app/pages/PlansPage.tsx +2 -2
- package/corpus/templates/plan/app/root.tsx +13 -7
- package/corpus/templates/plan/app/routes/_index.tsx +31 -6
- package/corpus/templates/plan/app/routes/chat.tsx +3 -6
- package/corpus/templates/plan/app/routes/home.tsx +11 -0
- package/corpus/templates/plan/app/routes/local-plans.$slug.tsx +2 -6
- package/corpus/templates/plan/app/routes/plans.$id.tsx +3 -6
- package/corpus/templates/plan/app/routes/plans.tsx +3 -6
- package/corpus/templates/plan/app/routes/recaps.$id.tsx +3 -6
- package/corpus/templates/plan/app/routes/recaps.tsx +3 -6
- package/corpus/templates/plan/changelog/2026-08-28-plan-loading-skeletons-use-a-softer-whole-surface.md +6 -0
- package/corpus/templates/plan/changelog/2026-08-29-plan-loading-shine-is-more-subtle.md +6 -0
- package/corpus/templates/plan/public/manifest.json +1 -1
- package/corpus/templates/plan/server/db/schema.ts +1 -0
- package/corpus/templates/plan/server/lib/plan-versions.ts +57 -0
- package/corpus/templates/plan/server/plugins/agent-chat.ts +83 -0
- package/corpus/templates/plan/server/plugins/core-routes.ts +1 -0
- package/corpus/templates/plan/server/plugins/db.ts +10 -0
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/slides/CHANGELOG.md +9 -0
- package/corpus/templates/slides/actions/_deck-write.ts +65 -0
- package/corpus/templates/slides/actions/add-slide.ts +44 -24
- package/corpus/templates/slides/actions/clone-context-slide.ts +22 -12
- package/corpus/templates/slides/actions/create-deck.ts +36 -21
- package/corpus/templates/slides/actions/delete-design-system.ts +10 -3
- package/corpus/templates/slides/actions/import-file.ts +9 -3
- package/corpus/templates/slides/actions/import-pptx.ts +11 -4
- package/corpus/templates/slides/actions/list-deck-versions.ts +20 -8
- package/corpus/templates/slides/actions/patch-deck.ts +29 -3
- package/corpus/templates/slides/actions/restore-deck-version.ts +37 -22
- package/corpus/templates/slides/actions/save-deck.ts +35 -22
- package/corpus/templates/slides/actions/update-deck-aspect-ratio.ts +31 -16
- package/corpus/templates/slides/actions/update-slide.ts +250 -37
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +10 -4
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +2 -2
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +7 -8
- package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +78 -12
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +42 -4
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +381 -53
- package/corpus/templates/slides/app/components/editor/SlidesLayersPanel.tsx +20 -34
- package/corpus/templates/slides/app/components/editor/slide-style.ts +5 -0
- package/corpus/templates/slides/app/components/editor/style-clipboard.ts +2 -0
- package/corpus/templates/slides/app/components/layout/AgentWorkIndicator.tsx +18 -2
- package/corpus/templates/slides/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/slides/app/components/layout/Layout.tsx +39 -10
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +7 -20
- package/corpus/templates/slides/app/components/presentation/PresenterView.tsx +35 -15
- package/corpus/templates/slides/app/components/presentation/present-channel.ts +12 -0
- package/corpus/templates/slides/app/global.css +45 -13
- package/corpus/templates/slides/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +11 -0
- package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +133 -5
- package/corpus/templates/slides/app/lib/slide-image-replacement.ts +741 -17
- package/corpus/templates/slides/app/lib/validate-native-slide-html.ts +1 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +288 -95
- package/corpus/templates/slides/app/pages/DesignSystems.tsx +5 -5
- package/corpus/templates/slides/app/pages/Index.tsx +7 -7
- package/corpus/templates/slides/app/pages/NotFound.tsx +1 -1
- package/corpus/templates/slides/app/pages/SharedPresentation.tsx +1 -1
- package/corpus/templates/slides/app/root.tsx +4 -23
- package/corpus/templates/slides/app/routes/_index.tsx +18 -7
- package/corpus/templates/slides/app/routes/home.tsx +26 -0
- package/corpus/templates/slides/changelog/2026-08-27-image-fit-controls-apply-cover-crops-and-position.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-28-image-edits-persist-while-dropped-images-finish-uploading.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-28-shared-slides-with-a-style-block-render-again.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-28-slides-loading-skeletons-use-a-softer-whole-surface.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-28-standard-empty-home-layout.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-29-chat-imports-attached-decks-on-request.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-29-slides-loading-shine-is-more-subtle.md +6 -0
- package/corpus/templates/slides/package.json +3 -0
- package/corpus/templates/slides/public/manifest.json +1 -1
- package/corpus/templates/slides/server/db/schema.ts +1 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +1 -1
- package/corpus/templates/slides/server/lib/chat-attachments.ts +102 -7
- package/corpus/templates/slides/server/lib/deck-versions.ts +77 -2
- package/corpus/templates/slides/server/plugins/agent-chat.ts +95 -1
- package/corpus/templates/slides/server/plugins/auth.ts +1 -0
- package/corpus/templates/slides/server/plugins/core-routes.ts +8 -1
- package/corpus/templates/slides/server/plugins/db.ts +5 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +4 -0
- package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +47 -0
- package/corpus/templates/tasks/AGENTS.md +2 -1
- package/corpus/templates/tasks/README.md +3 -1
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +5 -18
- package/corpus/templates/tasks/app/root.tsx +19 -3
- package/corpus/templates/tasks/app/routes/_index.tsx +28 -14
- package/corpus/templates/tasks/app/routes/home.tsx +24 -0
- package/corpus/templates/tasks/public/manifest.json +1 -1
- package/corpus/templates/tasks/server/plugins/auth.ts +1 -0
- package/dist/a2a/client.d.ts +4 -0
- package/dist/a2a/client.js +15 -2
- package/dist/action.d.ts +3 -1
- package/dist/agent/engine/ai-sdk-engine.js +13 -9
- package/dist/agent/engine/anthropic-engine.js +2 -1
- package/dist/agent/engine/builder-engine.js +23 -5
- package/dist/agent/engine/limit-provider-tools.d.ts +3 -0
- package/dist/agent/engine/limit-provider-tools.js +23 -0
- package/dist/agent/engine/openai-compatible-endpoint.d.ts +2 -0
- package/dist/agent/engine/openai-compatible-endpoint.js +4 -0
- package/dist/agent/engine/output-tokens.d.ts +12 -6
- package/dist/agent/engine/output-tokens.js +42 -16
- package/dist/agent/engine/registry.d.ts +1 -1
- package/dist/agent/engine/registry.js +69 -16
- package/dist/agent/production-agent.js +107 -13
- package/dist/agent/run-manager.d.ts +9 -0
- package/dist/agent/run-manager.js +35 -6
- package/dist/agent/thread-data-builder.d.ts +6 -1
- package/dist/agent/thread-data-builder.js +20 -5
- package/dist/agent/types.d.ts +2 -0
- package/dist/app-config/agent.d.ts +4 -0
- package/dist/app-config/agent.js +44 -0
- package/dist/app-config/integrations.d.ts +1 -0
- package/dist/app-config/integrations.js +8 -0
- package/dist/app-config/migration.d.ts +1 -0
- package/dist/app-config/migration.js +4 -0
- package/dist/app-config/observability.d.ts +4 -1
- package/dist/app-config/observability.js +25 -1
- package/dist/app-config/schema.d.ts +9 -0
- package/dist/app-config/store.js +1 -0
- package/dist/client/AgentAskPopover.d.ts +2 -1
- package/dist/client/AgentAskPopover.js +2 -2
- package/dist/client/AgentPanel.d.ts +35 -10
- package/dist/client/AgentPanel.js +136 -119
- package/dist/client/AssistantChat.d.ts +9 -2
- package/dist/client/AssistantChat.js +161 -36
- package/dist/client/ConnectBuilderCard.js +3 -1
- package/dist/client/DefaultSpinner.d.ts +13 -1
- package/dist/client/DefaultSpinner.js +52 -46
- package/dist/client/FeedbackButton.d.ts +12 -0
- package/dist/client/FeedbackButton.js +62 -28
- package/dist/client/MultiTabAssistantChat.js +30 -11
- package/dist/client/NewWorkspaceAppFlow.js +5 -3
- package/dist/client/agent-chat/index.d.ts +1 -0
- package/dist/client/agent-chat/index.js +1 -0
- package/dist/client/agent-chat-adapter.js +16 -1
- package/dist/client/agent-chat.d.ts +9 -0
- package/dist/client/agent-chat.js +6 -3
- package/dist/client/agent-page/AgentJobsTab.d.ts +2 -1
- package/dist/client/agent-page/AgentJobsTab.js +8 -5
- package/dist/client/agent-page/AgentTabsPage.js +2 -2
- package/dist/client/analytics.d.ts +2 -0
- package/dist/client/analytics.js +86 -15
- package/dist/client/app-providers.js +13 -1
- package/dist/client/auth/AuthPage.d.ts +87 -0
- package/dist/client/auth/AuthPage.js +1847 -0
- package/dist/client/auth/ResetPasswordPage.d.ts +9 -0
- package/dist/client/auth/ResetPasswordPage.js +119 -0
- package/dist/client/auth/entry.d.ts +1 -0
- package/dist/client/auth/entry.js +15 -0
- package/dist/client/chat/message-components.d.ts +53 -0
- package/dist/client/chat/message-components.js +181 -11
- package/dist/client/chat/run-recovery.d.ts +4 -1
- package/dist/client/chat/run-recovery.js +30 -12
- package/dist/client/chat/tool-call-display.d.ts +4 -2
- package/dist/client/chat/tool-call-display.js +16 -11
- package/dist/client/chat-first.js +8 -2
- package/dist/client/chat-model-groups.js +11 -1
- package/dist/client/collab/index.d.ts +1 -1
- package/dist/client/components/CodeRequiredDialog.js +22 -35
- package/dist/client/components/icons/AgentNativeIcon.d.ts +3 -3
- package/dist/client/components/icons/AgentNativeIcon.js +4 -4
- package/dist/client/components/ui/message-scroller.js +1 -1
- package/dist/client/composer/runtime-adapters.js +2 -0
- package/dist/client/feedback-context.d.ts +1 -0
- package/dist/client/feedback-context.js +3 -2
- package/dist/client/host-bridge.d.ts +1 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts +2 -1
- package/dist/client/integrations/IntegrationsPanel.js +3 -3
- package/dist/client/observability/ThumbsFeedback.js +73 -10
- package/dist/client/onboarding/FirstRunOnboarding.js +24 -15
- package/dist/client/onboarding/OnboardingPanel.js +5 -3
- package/dist/client/onboarding/first-run-startup-gate.js +7 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts +2 -1
- package/dist/client/resources/McpIntegrationDialog.js +10 -2
- package/dist/client/session-replay.js +10 -0
- package/dist/client/settings/BuilderConnectPopover.d.ts +25 -0
- package/dist/client/settings/BuilderConnectPopover.js +55 -0
- package/dist/client/settings/SettingsPanel.js +21 -7
- package/dist/client/settings/SettingsTabsPage.d.ts +1 -1
- package/dist/client/settings/SettingsTabsPage.js +42 -25
- package/dist/client/settings/VoiceTranscriptionSection.js +16 -22
- package/dist/client/settings/index.d.ts +1 -0
- package/dist/client/settings/index.js +1 -0
- package/dist/client/settings/useBuilderStatus.d.ts +7 -0
- package/dist/client/settings/useBuilderStatus.js +77 -21
- package/dist/client/setup-connections/BuilderConnectCard.js +2 -1
- package/dist/client/setup-connections/useBuilderConnectCardController.d.ts +3 -1
- package/dist/client/setup-connections/useBuilderConnectCardController.js +4 -2
- package/dist/client/sse-event-processor.js +8 -0
- package/dist/client/terminal/AgentTerminal.js +6 -7
- package/dist/client/transcription/BuilderTranscriptionCta.js +17 -69
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/client/use-chat-models.js +5 -4
- package/dist/client/webmcp.d.ts +4 -0
- package/dist/client/webmcp.js +51 -4
- package/dist/collab/client.d.ts +13 -0
- package/dist/collab/client.js +96 -21
- package/dist/dashboard-storage/index.d.ts +1 -1
- package/dist/dashboard-storage/schema.d.ts +19 -0
- package/dist/dashboard-storage/schema.js +1 -0
- package/dist/dashboard-storage/store.d.ts +9 -0
- package/dist/dashboard-storage/store.js +93 -3
- package/dist/deploy/build.d.ts +19 -3
- package/dist/deploy/build.js +262 -10
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/ingestion/media.js +7 -2
- package/dist/integrations/config-store.js +2 -4
- package/dist/integrations/google-docs-poller.d.ts +1 -1
- package/dist/integrations/google-docs-poller.js +100 -24
- package/dist/integrations/plugin.js +45 -15
- package/dist/integrations/webhook-handler.js +2 -1
- package/dist/jobs/background-automation-runner.js +17 -1
- package/dist/localization/core-messages/ar-SA.js +19 -0
- package/dist/localization/core-messages/de-DE.js +19 -0
- package/dist/localization/core-messages/en-US.d.ts +19 -0
- package/dist/localization/core-messages/en-US.js +19 -0
- package/dist/localization/core-messages/es-ES.js +19 -0
- package/dist/localization/core-messages/fr-FR.js +19 -0
- package/dist/localization/core-messages/hi-IN.js +19 -0
- package/dist/localization/core-messages/ja-JP.js +19 -0
- package/dist/localization/core-messages/ko-KR.js +19 -0
- package/dist/localization/core-messages/pt-BR.js +19 -0
- package/dist/localization/core-messages/zh-CN.js +19 -0
- package/dist/localization/core-messages/zh-TW.js +19 -0
- package/dist/localization/core-messages.d.ts +19 -0
- package/dist/localization/default-messages.d.ts +11 -0
- package/dist/localization/default-messages.js +11 -0
- package/dist/mcp/analytics.d.ts +103 -0
- package/dist/mcp/analytics.js +204 -0
- package/dist/mcp/build-server.d.ts +7 -0
- package/dist/mcp/build-server.js +132 -35
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp/server.js +37 -8
- package/dist/mcp/stdio.js +1 -0
- package/dist/mcp-client/errors.js +30 -10
- package/dist/mcp-client/oauth-routes.d.ts +7 -2
- package/dist/mcp-client/oauth-routes.js +12 -3
- package/dist/mcp-client/routes.js +2 -1
- package/dist/oauth-tokens/store.js +6 -3
- package/dist/observability/routes.d.ts +5 -5
- package/dist/observability/routes.js +8 -2
- package/dist/observability/store.d.ts +1 -1
- package/dist/observability/store.js +18 -3
- package/dist/observability/types.d.ts +1 -0
- package/dist/onboarding/plugin.js +16 -4
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
- package/dist/provider-api/actions/provider-api.d.ts +12 -12
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-routes.d.ts +1 -6
- package/dist/server/action-routes.js +61 -18
- package/dist/server/agent-chat/plugin-options.d.ts +8 -1
- package/dist/server/agent-chat-plugin.d.ts +3 -0
- package/dist/server/agent-chat-plugin.js +49 -4
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-run-context.d.ts +1 -0
- package/dist/server/agent-run-context.js +6 -0
- package/dist/server/analytics.d.ts +3 -2
- package/dist/server/analytics.js +18 -7
- package/dist/server/app-url.d.ts +5 -2
- package/dist/server/app-url.js +4 -3
- package/dist/server/auth.d.ts +25 -0
- package/dist/server/auth.js +168 -21
- package/dist/server/better-auth-instance.js +18 -4
- package/dist/server/better-auth-migrations.d.ts +14 -0
- package/dist/server/better-auth-migrations.js +5 -1
- package/dist/server/builder-api-auth.js +30 -6
- package/dist/server/builder-browser.d.ts +10 -0
- package/dist/server/builder-browser.js +22 -5
- package/dist/server/builder-design-systems.d.ts +11 -0
- package/dist/server/builder-design-systems.js +52 -3
- package/dist/server/builder-oauth.d.ts +13 -6
- package/dist/server/builder-oauth.js +121 -63
- package/dist/server/capture-error.js +3 -0
- package/dist/server/cookie-namespace.d.ts +1 -0
- package/dist/server/cookie-namespace.js +3 -0
- package/dist/server/core-routes-plugin.d.ts +25 -9
- package/dist/server/core-routes-plugin.js +180 -76
- package/dist/server/credential-provider.js +22 -12
- package/dist/server/email.d.ts +4 -0
- package/dist/server/email.js +13 -5
- package/dist/server/framework-request-handler.js +6 -3
- package/dist/server/google-credential-check.d.ts +7 -3
- package/dist/server/google-credential-check.js +71 -0
- package/dist/server/google-oauth-credentials.d.ts +4 -3
- package/dist/server/google-oauth-credentials.js +7 -8
- package/dist/server/google-oauth.d.ts +9 -4
- package/dist/server/google-oauth.js +14 -93
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/jwks-secret-rotation.d.ts +29 -0
- package/dist/server/jwks-secret-rotation.js +150 -0
- package/dist/server/onboarding-html.d.ts +2 -14
- package/dist/server/onboarding-html.js +254 -2519
- package/dist/server/origin-allowlist.d.ts +15 -0
- package/dist/server/origin-allowlist.js +93 -0
- package/dist/server/release-migrations.js +48 -0
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/request-context.js +7 -2
- package/dist/server/self-dispatch.js +5 -0
- package/dist/server/sentry.js +5 -0
- package/dist/server/ssr-handler.js +5 -0
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/server/workspace-provider-oauth.d.ts +9 -0
- package/dist/server/workspace-provider-oauth.js +96 -31
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/shared/loading-labels.d.ts +1 -0
- package/dist/shared/loading-labels.js +55 -0
- package/dist/shared/qa-test-email.d.ts +1 -0
- package/dist/shared/qa-test-email.js +42 -0
- package/dist/shared/route-warmup-config.js +2 -2
- package/dist/shared/sign-in-journey.js +1 -1
- package/dist/shared/ssr-auth-redirect.d.ts +8 -0
- package/dist/shared/ssr-auth-redirect.js +56 -0
- package/dist/shared/test-traffic.d.ts +8 -0
- package/dist/shared/test-traffic.js +11 -0
- package/dist/styles/agent-native.css +50 -14
- package/dist/styles/blocks.css +0 -6
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -0
- package/dist/templates/chat/.agents/skills/secrets/SKILL.md +47 -0
- package/dist/templates/chat/AGENTS.md +5 -4
- package/dist/templates/chat/app/components/layout/Header.tsx +1 -1
- package/dist/templates/chat/app/components/layout/Layout.tsx +5 -4
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +16 -25
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +5 -5
- package/dist/templates/chat/app/root.tsx +16 -3
- package/dist/templates/chat/app/routes/_index.tsx +17 -74
- package/dist/templates/chat/app/routes/chat.$threadId.tsx +1 -1
- package/dist/templates/chat/app/routes/home.tsx +94 -0
- package/dist/templates/chat/netlify.toml +2 -1
- package/dist/templates/chat/public/manifest.json +1 -1
- package/dist/templates/chat/server/plugins/auth.ts +1 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +4 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +47 -0
- package/dist/templates/default/AGENTS.md +10 -6
- package/dist/templates/default/DEVELOPING.md +8 -1
- package/dist/templates/default/app/hooks/use-navigation-state.ts +1 -1
- package/dist/templates/default/app/root.tsx +10 -3
- package/dist/templates/default/app/routes/_index.tsx +10 -86
- package/dist/templates/default/app/routes/home.tsx +94 -0
- package/dist/templates/default/app/routes/settings.tsx +1 -1
- package/dist/templates/default/public/manifest.json +1 -1
- package/dist/templates/default/server/plugins/auth.ts +5 -0
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +47 -0
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +47 -0
- package/dist/templates/workspace-root/.env.example +3 -2
- package/dist/terminal/pty-server.d.ts +2 -0
- package/dist/terminal/pty-server.js +22 -5
- package/dist/tracking/registry.d.ts +1 -0
- package/dist/tracking/registry.js +12 -0
- package/dist/usage/store.d.ts +1 -0
- package/dist/usage/store.js +16 -7
- package/dist/vite/client.d.ts +1 -1
- package/dist/vite/client.js +59 -0
- package/dist/workspace-connections/index.d.ts +1 -1
- package/dist/workspace-connections/index.js +1 -1
- package/dist/workspace-connections/store.d.ts +1 -0
- package/dist/workspace-connections/store.js +4 -0
- package/docs/content/aws-amplify.mdx +179 -0
- package/docs/content/client-agent-chat.mdx +1 -1
- package/docs/content/deploy-an-app.mdx +2 -1
- package/docs/content/deployment.mdx +14 -3
- package/docs/content/environment-variables.mdx +1 -0
- package/docs/content/template-forms-agent.mdx +65 -0
- package/docs/content/template-forms-developers.mdx +220 -65
- package/docs/content/template-forms-features.mdx +154 -0
- package/docs/content/template-forms-integrations.mdx +40 -0
- package/docs/content/template-forms.mdx +49 -36
- package/docs/content/template-mail-developers.mdx +3 -3
- package/docs/content/toolkit-settings.mdx +3 -3
- package/docs/content/webmcp.mdx +31 -12
- package/package.json +3 -3
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -0
- package/src/templates/chat/.agents/skills/secrets/SKILL.md +47 -0
- package/src/templates/chat/AGENTS.md +5 -4
- package/src/templates/chat/app/components/layout/Header.tsx +1 -1
- package/src/templates/chat/app/components/layout/Layout.tsx +5 -4
- package/src/templates/chat/app/components/layout/Sidebar.tsx +16 -25
- package/src/templates/chat/app/hooks/use-navigation-state.ts +5 -5
- package/src/templates/chat/app/root.tsx +16 -3
- package/src/templates/chat/app/routes/_index.tsx +17 -74
- package/src/templates/chat/app/routes/chat.$threadId.tsx +1 -1
- package/src/templates/chat/app/routes/home.tsx +94 -0
- package/src/templates/chat/netlify.toml +2 -1
- package/src/templates/chat/public/manifest.json +1 -1
- package/src/templates/chat/server/plugins/auth.ts +1 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +4 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +47 -0
- package/src/templates/default/AGENTS.md +10 -6
- package/src/templates/default/DEVELOPING.md +8 -1
- package/src/templates/default/app/hooks/use-navigation-state.ts +1 -1
- package/src/templates/default/app/root.tsx +10 -3
- package/src/templates/default/app/routes/_index.tsx +10 -86
- package/src/templates/default/app/routes/home.tsx +94 -0
- package/src/templates/default/app/routes/settings.tsx +1 -1
- package/src/templates/default/public/manifest.json +1 -1
- package/src/templates/default/server/plugins/auth.ts +5 -0
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +47 -0
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +4 -0
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +47 -0
- package/src/templates/workspace-root/.env.example +3 -2
- package/corpus/templates/factory/actions/approve-factory-item.ts +0 -244
- package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +0 -33
- package/corpus/templates/factory/server/routes/_agent-native/factory/builder-callback.post.ts +0 -116
- package/corpus/templates/factory/server/triage/ai-services-git.ts +0 -205
- package/corpus/templates/factory/server/triage/builder-executor.ts +0 -123
- package/docs/content/template-forms-building-publishing.mdx +0 -135
- package/docs/content/template-forms-responses.mdx +0 -120
- /package/corpus/templates/clips/{server/lib → shared}/upload-interruption.ts +0 -0
package/dist/server/email.js
CHANGED
|
@@ -35,11 +35,14 @@ function resolveAttachments(args) {
|
|
|
35
35
|
}
|
|
36
36
|
return [...(args.attachments ?? []), getAgentNativeLogoAttachment()];
|
|
37
37
|
}
|
|
38
|
-
async function resolveEmailTransport() {
|
|
38
|
+
async function resolveEmailTransport(useDeploymentCredentials = false) {
|
|
39
|
+
const resolve = useDeploymentCredentials
|
|
40
|
+
? (key) => readDeployCredentialEnv(key) ?? null
|
|
41
|
+
: resolveSecret;
|
|
39
42
|
const [resendApiKey, sendgridApiKey, from] = await Promise.all([
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
resolve("RESEND_API_KEY"),
|
|
44
|
+
resolve("SENDGRID_API_KEY"),
|
|
45
|
+
resolve("EMAIL_FROM"),
|
|
43
46
|
]);
|
|
44
47
|
const resolvedFrom = from ?? undefined;
|
|
45
48
|
if (resendApiKey) {
|
|
@@ -177,7 +180,7 @@ function resolveAppSender(configuredFrom, appSender) {
|
|
|
177
180
|
};
|
|
178
181
|
}
|
|
179
182
|
async function deliverEmail(args, signal) {
|
|
180
|
-
const config = await resolveEmailTransport();
|
|
183
|
+
const config = await resolveEmailTransport(args.useDeploymentCredentials);
|
|
181
184
|
signal?.throwIfAborted();
|
|
182
185
|
const provider = config.provider;
|
|
183
186
|
const branded = resolveAppSender(config.from, args.appSender);
|
|
@@ -262,6 +265,11 @@ async function deliverEmail(args, signal) {
|
|
|
262
265
|
].filter((value) => Boolean(value));
|
|
263
266
|
if (categories.length)
|
|
264
267
|
sgPayload.categories = categories;
|
|
268
|
+
if (args.disableClickTracking) {
|
|
269
|
+
sgPayload.tracking_settings = {
|
|
270
|
+
click_tracking: { enable: false },
|
|
271
|
+
};
|
|
272
|
+
}
|
|
265
273
|
const sgHeaders = {};
|
|
266
274
|
if (args.inReplyTo)
|
|
267
275
|
sgHeaders["In-Reply-To"] = args.inReplyTo;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { setResponseHeader, setResponseStatus } from "h3";
|
|
1
|
+
import { getHeader, setResponseHeader, setResponseStatus } from "h3";
|
|
2
2
|
import { AppConfigurationError } from "../app-config/index.js";
|
|
3
3
|
import { getMissingDefaultPlugins } from "../deploy/route-discovery.js";
|
|
4
4
|
import { MCP_PUBLIC_ROUTE_PREFIX } from "../mcp/route-paths.js";
|
|
5
5
|
import { SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, } from "../shared/sign-in-journey.js";
|
|
6
|
+
import { SYNTHETIC_TRAFFIC_HEADER, isSyntheticTrafficValue, } from "../shared/test-traffic.js";
|
|
6
7
|
import { getConfiguredAppBasePath } from "./app-base-path.js";
|
|
7
8
|
import { captureError } from "./capture-error.js";
|
|
8
9
|
import { createCsrfMiddleware } from "./csrf.js";
|
|
@@ -244,10 +245,12 @@ function registerRequestContextBoundary(nitroApp) {
|
|
|
244
245
|
return;
|
|
245
246
|
if (h3[REQUEST_CONTEXT_BOUNDARY_KEY])
|
|
246
247
|
return;
|
|
247
|
-
const middleware = (
|
|
248
|
+
const middleware = (event, next) => {
|
|
248
249
|
if (hasRequestContext())
|
|
249
250
|
return next();
|
|
250
|
-
return runWithRequestContext({
|
|
251
|
+
return runWithRequestContext({
|
|
252
|
+
isSyntheticTraffic: isSyntheticTrafficValue(getHeader(event, SYNTHETIC_TRAFFIC_HEADER)),
|
|
253
|
+
}, () => next());
|
|
251
254
|
};
|
|
252
255
|
h3[REQUEST_CONTEXT_BOUNDARY_KEY] = middleware;
|
|
253
256
|
h3["~middleware"].unshift(middleware);
|
|
@@ -3,7 +3,7 @@ export type GoogleCredentialStatus =
|
|
|
3
3
|
"valid"
|
|
4
4
|
/** Google rejected the client id or secret — sign-in is broken. */
|
|
5
5
|
| "invalid"
|
|
6
|
-
/** No
|
|
6
|
+
/** No credentials are configured for the requested Google client. */
|
|
7
7
|
| "unconfigured"
|
|
8
8
|
/** Google could not be reached, or answered something unrecognised. */
|
|
9
9
|
| "unknown";
|
|
@@ -15,9 +15,12 @@ export interface GoogleCredentialCheck {
|
|
|
15
15
|
/**
|
|
16
16
|
* Where the probed pair came from. `active` is the pair Better Auth wired to
|
|
17
17
|
* the provider; `preferred` means auth had not initialised yet and this fell
|
|
18
|
-
* back to the preferred pair
|
|
18
|
+
* back to the preferred pair; `managed` is the deployment-level pair used by
|
|
19
|
+
* the unauthenticated workspace OAuth health contract; `user` means the app
|
|
20
|
+
* intentionally resolves a user-scoped pair after sign-in; `none` means the
|
|
21
|
+
* app declared that it does not expose deployment-level Google OAuth.
|
|
19
22
|
*/
|
|
20
|
-
credentialSource: "active" | "preferred";
|
|
23
|
+
credentialSource: "active" | "preferred" | "managed" | "user" | "none";
|
|
21
24
|
/** Google's `error` field, or the transport failure, when there was one. */
|
|
22
25
|
reason: string | null;
|
|
23
26
|
checkedAt: number;
|
|
@@ -36,3 +39,4 @@ export declare function checkGoogleSignInCredential(options?: {
|
|
|
36
39
|
ttlMs?: number;
|
|
37
40
|
now?: () => number;
|
|
38
41
|
}): Promise<GoogleCredentialCheck>;
|
|
42
|
+
export declare function checkGoogleManagedCredential(): Promise<GoogleCredentialCheck>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveSecretPair } from "./credential-provider.js";
|
|
1
2
|
import { describeGoogleSignInCredentialPairs, getActiveGoogleSignInCredentials, resolveGoogleSignInCredentials, } from "./google-oauth-credentials.js";
|
|
2
3
|
const GOOGLE_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token";
|
|
3
4
|
/**
|
|
@@ -11,9 +12,13 @@ const PROBE_REDIRECT_URI = "https://example.com/agent-native-credential-probe";
|
|
|
11
12
|
const DEFAULT_TTL_MS = 5 * 60 * 1000;
|
|
12
13
|
const REQUEST_TIMEOUT_MS = 10_000;
|
|
13
14
|
let cached = null;
|
|
15
|
+
let managedCached = null;
|
|
16
|
+
let managedInFlight = null;
|
|
14
17
|
/** Test seam: drop the memoised result. */
|
|
15
18
|
export function resetGoogleCredentialCheckCache() {
|
|
16
19
|
cached = null;
|
|
20
|
+
managedCached = null;
|
|
21
|
+
managedInFlight = null;
|
|
17
22
|
}
|
|
18
23
|
async function probeGoogle(clientId, clientSecret) {
|
|
19
24
|
let response;
|
|
@@ -113,3 +118,69 @@ export async function checkGoogleSignInCredential(options) {
|
|
|
113
118
|
}
|
|
114
119
|
return value;
|
|
115
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Ask Google about the deployment-level client used by managed workspace OAuth.
|
|
123
|
+
* This is separate from Better Auth sign-in because a deploy may intentionally
|
|
124
|
+
* use GOOGLE_SIGN_IN_* and GOOGLE_* as different clients.
|
|
125
|
+
*/
|
|
126
|
+
async function checkGoogleManagedCredentialOnce() {
|
|
127
|
+
const checkedAt = Date.now();
|
|
128
|
+
let credentials;
|
|
129
|
+
try {
|
|
130
|
+
credentials = await resolveSecretPair([
|
|
131
|
+
"GOOGLE_CLIENT_ID",
|
|
132
|
+
"GOOGLE_CLIENT_SECRET",
|
|
133
|
+
]);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return {
|
|
137
|
+
status: "unknown",
|
|
138
|
+
clientId: null,
|
|
139
|
+
mismatchedPairs: false,
|
|
140
|
+
credentialSource: "managed",
|
|
141
|
+
reason: "credential lookup failed",
|
|
142
|
+
checkedAt,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (!credentials) {
|
|
146
|
+
return {
|
|
147
|
+
status: "unconfigured",
|
|
148
|
+
clientId: null,
|
|
149
|
+
mismatchedPairs: false,
|
|
150
|
+
credentialSource: "managed",
|
|
151
|
+
reason: null,
|
|
152
|
+
checkedAt,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const [clientId, clientSecret] = credentials;
|
|
156
|
+
return {
|
|
157
|
+
...(await probeGoogle(clientId, clientSecret)),
|
|
158
|
+
clientId,
|
|
159
|
+
mismatchedPairs: false,
|
|
160
|
+
credentialSource: "managed",
|
|
161
|
+
checkedAt,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export async function checkGoogleManagedCredential() {
|
|
165
|
+
const at = Date.now();
|
|
166
|
+
if (managedCached && managedCached.expiresAt > at) {
|
|
167
|
+
return managedCached.value;
|
|
168
|
+
}
|
|
169
|
+
if (managedInFlight)
|
|
170
|
+
return managedInFlight;
|
|
171
|
+
const inFlight = checkGoogleManagedCredentialOnce();
|
|
172
|
+
managedInFlight = inFlight;
|
|
173
|
+
try {
|
|
174
|
+
const value = await inFlight;
|
|
175
|
+
// Keep transient Google or credential-store failures retryable while
|
|
176
|
+
// protecting the public health route from repeated definitive probes.
|
|
177
|
+
if (value.status !== "unknown") {
|
|
178
|
+
managedCached = { value, expiresAt: at + DEFAULT_TTL_MS };
|
|
179
|
+
}
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
if (managedInFlight === inFlight)
|
|
184
|
+
managedInFlight = null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -63,9 +63,10 @@ export declare function getActiveGoogleSignInCredentials(): {
|
|
|
63
63
|
/**
|
|
64
64
|
* Which sign-in credential pairs are configured, and whether they disagree.
|
|
65
65
|
*
|
|
66
|
-
* `mismatched` is
|
|
67
|
-
*
|
|
68
|
-
*
|
|
66
|
+
* `mismatched` is diagnostic only. Two pairs may name different clients when
|
|
67
|
+
* identity sign-in and provider APIs intentionally have separate OAuth apps.
|
|
68
|
+
* Callers must compare the pair used by their specific flow, not delete one
|
|
69
|
+
* based on this flag alone.
|
|
69
70
|
*/
|
|
70
71
|
export declare function describeGoogleSignInCredentialPairs(): {
|
|
71
72
|
signInClientId: string | null;
|
|
@@ -59,11 +59,9 @@ export async function resolveGoogleProviderCredentialCandidatesWithReader(option
|
|
|
59
59
|
export function resolveGoogleSignInCredentials() {
|
|
60
60
|
const signIn = readCredentialPair("GOOGLE_SIGN_IN_CLIENT_ID", "GOOGLE_SIGN_IN_CLIENT_SECRET");
|
|
61
61
|
const provider = readCredentialPair("GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET");
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
// sign-in
|
|
65
|
-
// callback kept using a stale GOOGLE_SIGN_IN_CLIENT_SECRET, so the repaired
|
|
66
|
-
// variable looked correct and changed nothing. Name the loser explicitly.
|
|
62
|
+
// Different clients can be intentional: sign-in uses GOOGLE_SIGN_IN_* while
|
|
63
|
+
// provider API flows use GOOGLE_CLIENT_*. Keep the warning because editing
|
|
64
|
+
// the provider pair cannot repair a sign-in pair that is actually active.
|
|
67
65
|
if (signIn && provider && signIn.clientId !== provider.clientId) {
|
|
68
66
|
console.warn("[agent-native][google-oauth] GOOGLE_SIGN_IN_CLIENT_ID and GOOGLE_CLIENT_ID " +
|
|
69
67
|
"are set to different Google clients. Sign-in uses GOOGLE_SIGN_IN_CLIENT_ID; " +
|
|
@@ -107,9 +105,10 @@ export function getActiveGoogleSignInCredentials() {
|
|
|
107
105
|
/**
|
|
108
106
|
* Which sign-in credential pairs are configured, and whether they disagree.
|
|
109
107
|
*
|
|
110
|
-
* `mismatched` is
|
|
111
|
-
*
|
|
112
|
-
*
|
|
108
|
+
* `mismatched` is diagnostic only. Two pairs may name different clients when
|
|
109
|
+
* identity sign-in and provider APIs intentionally have separate OAuth apps.
|
|
110
|
+
* Callers must compare the pair used by their specific flow, not delete one
|
|
111
|
+
* based on this flag alone.
|
|
113
112
|
*/
|
|
114
113
|
export function describeGoogleSignInCredentialPairs() {
|
|
115
114
|
const signIn = readCredentialPair("GOOGLE_SIGN_IN_CLIENT_ID", "GOOGLE_SIGN_IN_CLIENT_SECRET");
|
|
@@ -45,6 +45,10 @@ export declare function getOrigin(event: H3Event, options?: {
|
|
|
45
45
|
export declare function getAppBasePath(): string;
|
|
46
46
|
/** Build an absolute same-origin URL that preserves APP_BASE_PATH. */
|
|
47
47
|
export declare function getAppUrl(event: H3Event, path?: string): string;
|
|
48
|
+
export type OAuthRedirectUriOptions = {
|
|
49
|
+
/** Allow a known framework callback to bypass an app mount prefix. */
|
|
50
|
+
allowRootCallback?: boolean;
|
|
51
|
+
};
|
|
48
52
|
/**
|
|
49
53
|
* Validate a user-supplied `redirect_uri` for OAuth flows.
|
|
50
54
|
*
|
|
@@ -70,7 +74,7 @@ export declare function getAppUrl(event: H3Event, path?: string): string;
|
|
|
70
74
|
* loopback URIs, callers should validate those at the template level
|
|
71
75
|
* with a dedicated allowlist — this helper rejects them by design.
|
|
72
76
|
*/
|
|
73
|
-
export declare function isAllowedOAuthRedirectUri(candidate: string, event: H3Event, expectedOrigin?: string): boolean;
|
|
77
|
+
export declare function isAllowedOAuthRedirectUri(candidate: string, event: H3Event, expectedOrigin?: string, options?: OAuthRedirectUriOptions): boolean;
|
|
74
78
|
/**
|
|
75
79
|
* Resolve the `redirect_uri` for an outbound OAuth `auth-url` request.
|
|
76
80
|
*
|
|
@@ -85,7 +89,7 @@ export declare function isAllowedOAuthRedirectUri(candidate: string, event: H3Ev
|
|
|
85
89
|
* `defaultPath` (e.g. `"/_agent-native/google/desktop-callback"` for
|
|
86
90
|
* desktop flows).
|
|
87
91
|
*/
|
|
88
|
-
export declare function resolveOAuthRedirectUri(event: H3Event, defaultPath?: string): string | null;
|
|
92
|
+
export declare function resolveOAuthRedirectUri(event: H3Event, defaultPath?: string, options?: OAuthRedirectUriOptions): string | null;
|
|
89
93
|
export interface OAuthStatePayload {
|
|
90
94
|
redirectUri: string;
|
|
91
95
|
owner?: string;
|
|
@@ -183,8 +187,9 @@ export declare function encodeOAuthState(opts: EncodeOAuthStateOptions): string;
|
|
|
183
187
|
export declare function encodeOAuthState(redirectUri: string, owner?: string, desktop?: boolean, addAccount?: boolean, app?: string, returnUrl?: string, flowId?: string): string;
|
|
184
188
|
/**
|
|
185
189
|
* Decode and verify OAuth state from the callback's state query parameter.
|
|
186
|
-
*
|
|
187
|
-
*
|
|
190
|
+
* A fallback-shaped payload is returned when state is missing, malformed, or
|
|
191
|
+
* fails HMAC verification. That payload is untrusted; callers must validate
|
|
192
|
+
* the fields their flow requires before exchanging a code or redirecting.
|
|
188
193
|
*/
|
|
189
194
|
export declare function decodeOAuthState(stateParam: string | undefined, fallbackUri: string): OAuthStatePayload;
|
|
190
195
|
export interface OAuthOwnerResult {
|
|
@@ -17,6 +17,7 @@ import { hasBetterAuthUserEmail, trackSignupEvent, } from "./better-auth-instanc
|
|
|
17
17
|
import { getWorkspaceA2ADerivedSecret } from "./derived-secret.js";
|
|
18
18
|
import { writeDesktopSso } from "./desktop-sso.js";
|
|
19
19
|
import { appendSessionToOAuthReturnUrl } from "./oauth-return-url.js";
|
|
20
|
+
import { EXPLICIT_PUBLIC_ORIGIN_ENV_KEYS, firstOriginFromEnv, getConfiguredOriginAllowlist, isLoopbackHost, normalizeOrigin, WORKSPACE_GATEWAY_ORIGIN_ENV_KEYS, } from "./origin-allowlist.js";
|
|
20
21
|
import { isWorkspaceOAuthCallbackRelayEnabled } from "./workspace-oauth.js";
|
|
21
22
|
// ─── Platform Detection ─────────────────────────────────────────────────────
|
|
22
23
|
/** Return an HTML response with the correct Content-Type.
|
|
@@ -75,66 +76,6 @@ export function isElectron(event) {
|
|
|
75
76
|
export function isMobile(event) {
|
|
76
77
|
return /iPhone|iPad|iPod|Android/i.test(getHeader(event, "user-agent") || "");
|
|
77
78
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Build the static allowlist of origins we trust for `getOrigin`. Reads
|
|
80
|
-
* deployment-known public URLs. Each entry is normalised to
|
|
81
|
-
* `${proto}://${host}` (no path). Duplicates collapse, invalid entries are
|
|
82
|
-
* dropped silently.
|
|
83
|
-
*/
|
|
84
|
-
const EXPLICIT_PUBLIC_ORIGIN_ENV_KEYS = [
|
|
85
|
-
"WORKSPACE_OAUTH_ORIGIN",
|
|
86
|
-
"VITE_WORKSPACE_OAUTH_ORIGIN",
|
|
87
|
-
"APP_URL",
|
|
88
|
-
"VITE_APP_URL",
|
|
89
|
-
"BETTER_AUTH_URL",
|
|
90
|
-
"VITE_BETTER_AUTH_URL",
|
|
91
|
-
"URL",
|
|
92
|
-
"DEPLOY_URL",
|
|
93
|
-
];
|
|
94
|
-
const WORKSPACE_GATEWAY_ORIGIN_ENV_KEYS = [
|
|
95
|
-
"WORKSPACE_GATEWAY_URL",
|
|
96
|
-
"VITE_WORKSPACE_GATEWAY_URL",
|
|
97
|
-
];
|
|
98
|
-
function normalizeOrigin(raw) {
|
|
99
|
-
if (!raw)
|
|
100
|
-
return undefined;
|
|
101
|
-
try {
|
|
102
|
-
const u = new URL(raw);
|
|
103
|
-
return `${u.protocol}//${u.host}`;
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
return undefined;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
function addNormalizedOrigin(out, raw, options) {
|
|
110
|
-
const origin = normalizeOrigin(raw);
|
|
111
|
-
if (!origin)
|
|
112
|
-
return;
|
|
113
|
-
if (!options.allowLoopback && isLoopbackOrigin(origin))
|
|
114
|
-
return;
|
|
115
|
-
out.add(origin);
|
|
116
|
-
}
|
|
117
|
-
function firstOriginFromEnv(keys, options) {
|
|
118
|
-
for (const key of keys) {
|
|
119
|
-
const origin = normalizeOrigin(process.env[key]);
|
|
120
|
-
if (!origin)
|
|
121
|
-
continue;
|
|
122
|
-
if (!options.allowLoopback && isLoopbackOrigin(origin))
|
|
123
|
-
continue;
|
|
124
|
-
return origin;
|
|
125
|
-
}
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
|
-
function getConfiguredOriginAllowlist() {
|
|
129
|
-
const out = new Set();
|
|
130
|
-
for (const key of EXPLICIT_PUBLIC_ORIGIN_ENV_KEYS) {
|
|
131
|
-
addNormalizedOrigin(out, process.env[key], { allowLoopback: true });
|
|
132
|
-
}
|
|
133
|
-
for (const key of WORKSPACE_GATEWAY_ORIGIN_ENV_KEYS) {
|
|
134
|
-
addNormalizedOrigin(out, process.env[key], { allowLoopback: false });
|
|
135
|
-
}
|
|
136
|
-
return out;
|
|
137
|
-
}
|
|
138
79
|
/** Return whether a candidate is one of this deployment's configured origins. */
|
|
139
80
|
export function isConfiguredAppOrigin(value) {
|
|
140
81
|
const origin = normalizeOrigin(value);
|
|
@@ -150,30 +91,6 @@ function getWorkspaceCallbackOrigin() {
|
|
|
150
91
|
allowLoopback: false,
|
|
151
92
|
});
|
|
152
93
|
}
|
|
153
|
-
function isLoopbackHost(host) {
|
|
154
|
-
if (!host)
|
|
155
|
-
return false;
|
|
156
|
-
try {
|
|
157
|
-
const parsed = new URL(`http://${host}`);
|
|
158
|
-
return (parsed.hostname === "localhost" ||
|
|
159
|
-
parsed.hostname === "127.0.0.1" ||
|
|
160
|
-
parsed.hostname === "::1" ||
|
|
161
|
-
parsed.hostname === "[::1]");
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
function isLoopbackOrigin(origin) {
|
|
168
|
-
if (!origin)
|
|
169
|
-
return false;
|
|
170
|
-
try {
|
|
171
|
-
return isLoopbackHost(new URL(origin).host);
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
94
|
function isBuilderPreviewHost(host) {
|
|
178
95
|
if (!host)
|
|
179
96
|
return false;
|
|
@@ -281,9 +198,9 @@ function isRequestUnderAppBasePath(event) {
|
|
|
281
198
|
return (requestPath === `${basePath}/_agent-native` ||
|
|
282
199
|
requestPath.startsWith(`${basePath}/_agent-native/`));
|
|
283
200
|
}
|
|
284
|
-
function getDefaultOAuthRedirectUrl(event, path) {
|
|
201
|
+
function getDefaultOAuthRedirectUrl(event, path, options = {}) {
|
|
285
202
|
const cleanPath = path.startsWith("/") ? path : `/${path}`;
|
|
286
|
-
if (isWorkspaceOAuthCallbackRelayEnabled() &&
|
|
203
|
+
if ((isWorkspaceOAuthCallbackRelayEnabled() || options.allowRootCallback) &&
|
|
287
204
|
isFrameworkOAuthCallbackPath(cleanPath)) {
|
|
288
205
|
return `${getOrigin(event)}${cleanPath}`;
|
|
289
206
|
}
|
|
@@ -316,7 +233,7 @@ function getDefaultOAuthRedirectUrl(event, path) {
|
|
|
316
233
|
* loopback URIs, callers should validate those at the template level
|
|
317
234
|
* with a dedicated allowlist — this helper rejects them by design.
|
|
318
235
|
*/
|
|
319
|
-
export function isAllowedOAuthRedirectUri(candidate, event, expectedOrigin = getOrigin(event)) {
|
|
236
|
+
export function isAllowedOAuthRedirectUri(candidate, event, expectedOrigin = getOrigin(event), options = {}) {
|
|
320
237
|
if (typeof candidate !== "string" || candidate.length === 0)
|
|
321
238
|
return false;
|
|
322
239
|
let url;
|
|
@@ -346,7 +263,8 @@ export function isAllowedOAuthRedirectUri(candidate, event, expectedOrigin = get
|
|
|
346
263
|
const allowedPrefixes = basePath && isRequestUnderAppBasePath(event)
|
|
347
264
|
? [
|
|
348
265
|
`${basePath}/_agent-native/`,
|
|
349
|
-
...(isWorkspaceOAuthCallbackRelayEnabled()
|
|
266
|
+
...((isWorkspaceOAuthCallbackRelayEnabled() ||
|
|
267
|
+
options.allowRootCallback) &&
|
|
350
268
|
isFrameworkOAuthCallbackPath(url.pathname)
|
|
351
269
|
? ["/_agent-native/"]
|
|
352
270
|
: []),
|
|
@@ -371,12 +289,14 @@ export function isAllowedOAuthRedirectUri(candidate, event, expectedOrigin = get
|
|
|
371
289
|
* `defaultPath` (e.g. `"/_agent-native/google/desktop-callback"` for
|
|
372
290
|
* desktop flows).
|
|
373
291
|
*/
|
|
374
|
-
export function resolveOAuthRedirectUri(event, defaultPath = "/_agent-native/google/callback") {
|
|
292
|
+
export function resolveOAuthRedirectUri(event, defaultPath = "/_agent-native/google/callback", options = {}) {
|
|
375
293
|
const supplied = getQuery(event).redirect_uri;
|
|
376
294
|
if (typeof supplied === "string" && supplied.length > 0) {
|
|
377
|
-
return isAllowedOAuthRedirectUri(supplied, event)
|
|
295
|
+
return isAllowedOAuthRedirectUri(supplied, event, getOrigin(event), options)
|
|
296
|
+
? supplied
|
|
297
|
+
: null;
|
|
378
298
|
}
|
|
379
|
-
return getDefaultOAuthRedirectUrl(event, defaultPath);
|
|
299
|
+
return getDefaultOAuthRedirectUrl(event, defaultPath, options);
|
|
380
300
|
}
|
|
381
301
|
/**
|
|
382
302
|
* Ephemeral in-memory state-signing key for development. Generated lazily
|
|
@@ -489,8 +409,9 @@ export function encodeOAuthState(redirectUriOrOpts, owner, desktop, addAccount,
|
|
|
489
409
|
}
|
|
490
410
|
/**
|
|
491
411
|
* Decode and verify OAuth state from the callback's state query parameter.
|
|
492
|
-
*
|
|
493
|
-
*
|
|
412
|
+
* A fallback-shaped payload is returned when state is missing, malformed, or
|
|
413
|
+
* fails HMAC verification. That payload is untrusted; callers must validate
|
|
414
|
+
* the fields their flow requires before exchanging a code or redirecting.
|
|
494
415
|
*/
|
|
495
416
|
export function decodeOAuthState(stateParam, fallbackUri) {
|
|
496
417
|
if (stateParam) {
|
package/dist/server/index.d.ts
CHANGED
|
@@ -74,7 +74,7 @@ export { buildWorkspaceProviderAuthorizationUrl, createWorkspaceProviderOAuthHan
|
|
|
74
74
|
export { CredentialStoreUnavailableError, FeatureNotConfiguredError, hasBuilderPrivateKey, isBuilderEnvManaged, getBuilderProxyOrigin, getBuilderImageGenerationBaseUrl, getBuilderWebSearchBaseUrl, getBuilderAuthHeader, resolveBuilderPrivateKey, resolveBuilderAuthHeader, resolveHasBuilderPrivateKey, resolveHasCompleteBuilderConnection, resolveBuilderCredentials, resolveBuilderCredentialsDetailed, resolveBuilderGatewayCredentials, resolveBuilderGatewayCredentialsDetailed, resolveHasBuilderGatewayCredential, resolveBuilderCredentialSource, resolveBuilderCredential, readDeployCredentialEnv, writeBuilderCredentials, deleteBuilderCredentials, resolveSecret, type BuilderCredentialsDetailed, } from "./credential-provider.js";
|
|
75
75
|
export { canAuthorizeBuilderApiRequest, hasBuilderApiCredentialCustody, resolveBuilderApiAuthorization, } from "./builder-api-auth.js";
|
|
76
76
|
export { BUILDER_ASSETS_WRITE_SCOPE } from "./builder-oauth.js";
|
|
77
|
-
export { builderDesignSystemUrl, builderProjectBranchUrl, buildBuilderDesignSystemIndexFiles, collectBuilderDesignSystemGitHubFiles, createBuilderDesignSystemProxyFields, fetchBuilderDesignSystemDecodeJobStatus, fetchBuilderDesignSystemDocs, getBuilderDesignSystemsBaseUrl, hydrateBuilderDesignSystemReference, indexBuilderDesignSystem, localBuilderDesignSystemId, mimeTypeForBuilderDesignSystemFilename, parseBuilderDesignSystemProxyReference, startBuilderDesignSystemIndex, startBuilderDesignSystemUpload, type BuildBuilderDesignSystemIndexFilesOptions, type BuilderDesignSystemCodeFileInput, type BuilderDesignSystemDecodeJobStatus, type BuilderDesignSystemDocsOptions, type BuilderDesignSystemDocument, type BuilderDesignSystemHydratedReference, type BuilderDesignSystemIndexFile, type BuilderDesignSystemIndexFromSourcesOptions, type BuilderDesignSystemIndexOptions, type BuilderDesignSystemIndexResult, type BuilderDesignSystemStatus, type BuilderDesignSystemGitHubFile, type BuilderDesignSystemGitHubFileCollection, type BuilderDesignSystemGitHubSource, type BuilderDesignSystemUploadAttachment, type BuilderDesignSystemUploadSlot, type BuilderDesignSystemProxyFields, type BuilderDesignSystemProxyFieldsOptions, type BuilderDesignSystemProxyReference, type BuilderDesignSystemSourceKind, } from "./builder-design-systems.js";
|
|
77
|
+
export { builderDesignSystemUrl, builderProjectBranchUrl, buildBuilderDesignSystemIndexFiles, collectBuilderDesignSystemGitHubFiles, createBuilderDesignSystemProxyFields, fetchBuilderDesignSystemDecodeJobStatus, fetchBuilderDesignSystemDocs, fetchBuilderDesignSystemRecord, getBuilderDesignSystemsBaseUrl, hydrateBuilderDesignSystemReference, indexBuilderDesignSystem, localBuilderDesignSystemId, mimeTypeForBuilderDesignSystemFilename, parseBuilderDesignSystemProxyReference, startBuilderDesignSystemIndex, startBuilderDesignSystemUpload, type BuildBuilderDesignSystemIndexFilesOptions, type BuilderDesignSystemCodeFileInput, type BuilderDesignSystemDecodeJobStatus, type BuilderDesignSystemDocsOptions, type BuilderDesignSystemDocument, type BuilderDesignSystemHydratedReference, type BuilderDesignSystemIndexFile, type BuilderDesignSystemIndexFromSourcesOptions, type BuilderDesignSystemIndexOptions, type BuilderDesignSystemIndexResult, type BuilderDesignSystemRecord, type BuilderDesignSystemStatus, type BuilderDesignSystemGitHubFile, type BuilderDesignSystemGitHubFileCollection, type BuilderDesignSystemGitHubSource, type BuilderDesignSystemUploadAttachment, type BuilderDesignSystemUploadSlot, type BuilderDesignSystemProxyFields, type BuilderDesignSystemProxyFieldsOptions, type BuilderDesignSystemProxyReference, type BuilderDesignSystemSourceKind, } from "./builder-design-systems.js";
|
|
78
78
|
export { createBuilderProject, ensureBuilderProject, findBuilderProjectForRepo, getBuilderBranchProjectId, isBuilderBranchingEnabled, requestBuilderBrowserConnection, resolveBuilderBranchProjectId, resolveIsBuilderBranchingEnabled, runBuilderAgent, type BuilderProjectResult, type RunBuilderAgentResult, } from "./builder-browser.js";
|
|
79
79
|
export { ensureFusionContainer, sendFusionBranchMessage, pushFusionBranch, reserveFusionHostingSlug, deployFusionProject, getFusionDeploys, getFusionBranchEditorUrl, getFusionHostingUrl, type FusionBranchRef, type EnsureFusionContainerResult, type SendFusionMessageResult, } from "./fusion-app.js";
|
|
80
80
|
export { sendEmail, isEmailConfigured, getEmailReadiness, getEmailProvider, type EmailAttachment, type EmailReadiness, type EmailProvider, type SendEmailArgs, } from "./email.js";
|
package/dist/server/index.js
CHANGED
|
@@ -83,7 +83,7 @@ export { CredentialStoreUnavailableError, FeatureNotConfiguredError, hasBuilderP
|
|
|
83
83
|
resolveBuilderGatewayCredentials, resolveBuilderGatewayCredentialsDetailed, resolveHasBuilderGatewayCredential, resolveBuilderCredentialSource, resolveBuilderCredential, readDeployCredentialEnv, writeBuilderCredentials, deleteBuilderCredentials, resolveSecret, } from "./credential-provider.js";
|
|
84
84
|
export { canAuthorizeBuilderApiRequest, hasBuilderApiCredentialCustody, resolveBuilderApiAuthorization, } from "./builder-api-auth.js";
|
|
85
85
|
export { BUILDER_ASSETS_WRITE_SCOPE } from "./builder-oauth.js";
|
|
86
|
-
export { builderDesignSystemUrl, builderProjectBranchUrl, buildBuilderDesignSystemIndexFiles, collectBuilderDesignSystemGitHubFiles, createBuilderDesignSystemProxyFields, fetchBuilderDesignSystemDecodeJobStatus, fetchBuilderDesignSystemDocs, getBuilderDesignSystemsBaseUrl, hydrateBuilderDesignSystemReference, indexBuilderDesignSystem, localBuilderDesignSystemId, mimeTypeForBuilderDesignSystemFilename, parseBuilderDesignSystemProxyReference, startBuilderDesignSystemIndex, startBuilderDesignSystemUpload, } from "./builder-design-systems.js";
|
|
86
|
+
export { builderDesignSystemUrl, builderProjectBranchUrl, buildBuilderDesignSystemIndexFiles, collectBuilderDesignSystemGitHubFiles, createBuilderDesignSystemProxyFields, fetchBuilderDesignSystemDecodeJobStatus, fetchBuilderDesignSystemDocs, fetchBuilderDesignSystemRecord, getBuilderDesignSystemsBaseUrl, hydrateBuilderDesignSystemReference, indexBuilderDesignSystem, localBuilderDesignSystemId, mimeTypeForBuilderDesignSystemFilename, parseBuilderDesignSystemProxyReference, startBuilderDesignSystemIndex, startBuilderDesignSystemUpload, } from "./builder-design-systems.js";
|
|
87
87
|
export { createBuilderProject, ensureBuilderProject, findBuilderProjectForRepo, getBuilderBranchProjectId, isBuilderBranchingEnabled, requestBuilderBrowserConnection, resolveBuilderBranchProjectId, resolveIsBuilderBranchingEnabled, runBuilderAgent, } from "./builder-browser.js";
|
|
88
88
|
export { ensureFusionContainer, sendFusionBranchMessage, pushFusionBranch, reserveFusionHostingSlug, deployFusionProject, getFusionDeploys, getFusionBranchEditorUrl, getFusionHostingUrl, } from "./fusion-app.js";
|
|
89
89
|
export { sendEmail, isEmailConfigured, getEmailReadiness, getEmailProvider, } from "./email.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare function isJwksDecryptError(error: unknown): boolean;
|
|
2
|
+
export declare function resetJwksSecretRotationStateForTests(): void;
|
|
3
|
+
/**
|
|
4
|
+
* Verify the newest active JWKS key against the current secret and, only when
|
|
5
|
+
* it genuinely cannot be decrypted, expire the stale rows so Better Auth
|
|
6
|
+
* mints a fresh key on the next JWT it signs. Returns true when rows were
|
|
7
|
+
* expired (callers may retry the failed request once), false otherwise.
|
|
8
|
+
*/
|
|
9
|
+
export declare function healUndecryptableJwks(): Promise<boolean>;
|
|
10
|
+
type AuthHookLike = {
|
|
11
|
+
matcher: (context: any) => boolean;
|
|
12
|
+
handler: (context: any) => Promise<unknown>;
|
|
13
|
+
};
|
|
14
|
+
type AuthPluginLike = {
|
|
15
|
+
hooks?: {
|
|
16
|
+
before?: AuthHookLike[];
|
|
17
|
+
after?: AuthHookLike[];
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Wrap a Better Auth plugin's after-hooks so a JWKS decrypt failure heals and
|
|
22
|
+
* retries instead of failing the request. Built for the JWT plugin, whose
|
|
23
|
+
* `/get-session` hook only decorates the response with `set-auth-jwt`: when
|
|
24
|
+
* the retry still cannot sign, the header is skipped — loudly — because
|
|
25
|
+
* failing every session check over an optional header is exactly the outage
|
|
26
|
+
* this module exists to prevent.
|
|
27
|
+
*/
|
|
28
|
+
export declare function withJwksRotationRecovery<P extends AuthPluginLike>(plugin: P): P;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime recovery for Better Auth JWKS keys orphaned by an auth-secret
|
|
3
|
+
* rotation.
|
|
4
|
+
*
|
|
5
|
+
* Better Auth encrypts the persisted JWT signing key with the current
|
|
6
|
+
* `BETTER_AUTH_SECRET`. Rotating that secret leaves the newest `jwks` row
|
|
7
|
+
* undecryptable, and the JWT plugin decrypts it on every `/get-session`
|
|
8
|
+
* response (to emit `set-auth-jwt`) — so a rotation turns every session check
|
|
9
|
+
* into a 500 and signs the whole deployment out (2026-08-28 outage on the
|
|
10
|
+
* hosted design/clips apps). The release migration
|
|
11
|
+
* `better-auth-jwks-key-rotation-recovery` already expires stale rows, but
|
|
12
|
+
* release migrations do not reach every deployed database, so the same
|
|
13
|
+
* recovery must also run where the failure is actually observed.
|
|
14
|
+
*/
|
|
15
|
+
import { parseEnvelope, symmetricDecrypt } from "better-auth/crypto";
|
|
16
|
+
/** Better Auth's stable copy for this failure (plugins/jwt sign path). */
|
|
17
|
+
const JWKS_DECRYPT_ERROR_SNIPPET = "Failed to decrypt private key";
|
|
18
|
+
export function isJwksDecryptError(error) {
|
|
19
|
+
return (error instanceof Error && error.message.includes(JWKS_DECRYPT_ERROR_SNIPPET));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A failed heal must not be re-attempted on every request — under an outage
|
|
23
|
+
* every session check funnels here at once. One attempt per process per
|
|
24
|
+
* cooldown window; concurrent callers share the in-flight attempt.
|
|
25
|
+
*/
|
|
26
|
+
const HEAL_COOLDOWN_MS = 60_000;
|
|
27
|
+
let lastHealAttemptAt = 0;
|
|
28
|
+
let inFlightHeal;
|
|
29
|
+
export function resetJwksSecretRotationStateForTests() {
|
|
30
|
+
lastHealAttemptAt = 0;
|
|
31
|
+
inFlightHeal = undefined;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Verify the newest active JWKS key against the current secret and, only when
|
|
35
|
+
* it genuinely cannot be decrypted, expire the stale rows so Better Auth
|
|
36
|
+
* mints a fresh key on the next JWT it signs. Returns true when rows were
|
|
37
|
+
* expired (callers may retry the failed request once), false otherwise.
|
|
38
|
+
*/
|
|
39
|
+
export async function healUndecryptableJwks() {
|
|
40
|
+
if (inFlightHeal)
|
|
41
|
+
return inFlightHeal;
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
if (now - lastHealAttemptAt < HEAL_COOLDOWN_MS)
|
|
44
|
+
return false;
|
|
45
|
+
lastHealAttemptAt = now;
|
|
46
|
+
inFlightHeal = attemptHeal().finally(() => {
|
|
47
|
+
inFlightHeal = undefined;
|
|
48
|
+
});
|
|
49
|
+
return inFlightHeal;
|
|
50
|
+
}
|
|
51
|
+
async function attemptHeal() {
|
|
52
|
+
// Lazy imports keep this module cycle-free: better-auth-instance wraps the
|
|
53
|
+
// JWT plugin with `withJwksRotationRecovery` from this file.
|
|
54
|
+
const [{ getDbExec, isPostgres }, { getAuthSecret }] = await Promise.all([
|
|
55
|
+
import("../db/client.js"),
|
|
56
|
+
import("./better-auth-instance.js"),
|
|
57
|
+
]);
|
|
58
|
+
const table = isPostgres() ? '"jwks"' : "jwks";
|
|
59
|
+
const nowValue = isPostgres() ? new Date().toISOString() : Date.now();
|
|
60
|
+
const { rows } = await getDbExec().execute({
|
|
61
|
+
sql: `SELECT private_key FROM ${table} WHERE expires_at IS NULL OR expires_at > ? ORDER BY created_at DESC LIMIT 1`,
|
|
62
|
+
args: [nowValue],
|
|
63
|
+
});
|
|
64
|
+
const storedPrivateKey = rows[0]?.private_key;
|
|
65
|
+
// No active key: Better Auth mints one itself, nothing to heal.
|
|
66
|
+
if (typeof storedPrivateKey !== "string")
|
|
67
|
+
return false;
|
|
68
|
+
// Better Auth stores the ciphertext JSON-encoded; a non-string payload means
|
|
69
|
+
// private-key encryption is disabled and the decrypt failure came from
|
|
70
|
+
// somewhere else — expiring healthy keys would be worse than the 500.
|
|
71
|
+
// An unparseable stored key is "not the shape this heal owns", and false
|
|
72
|
+
// ("did not heal") is the typed answer callers distinguish from success.
|
|
73
|
+
let ciphertext;
|
|
74
|
+
try {
|
|
75
|
+
ciphertext = JSON.parse(storedPrivateKey);
|
|
76
|
+
// coercion-ok: false is the typed "did not heal" answer, documented above.
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (typeof ciphertext !== "string")
|
|
82
|
+
return false;
|
|
83
|
+
// Multi-version secrets (`BETTER_AUTH_SECRETS`, honored by Better Auth
|
|
84
|
+
// itself) wrap ciphertexts in a versioned envelope this single-secret heal
|
|
85
|
+
// cannot validate; leave those deployments to Better Auth's own rotation
|
|
86
|
+
// machinery instead of expiring keys we cannot assess.
|
|
87
|
+
if (parseEnvelope(ciphertext))
|
|
88
|
+
return false;
|
|
89
|
+
try {
|
|
90
|
+
await symmetricDecrypt({ key: getAuthSecret(), data: ciphertext });
|
|
91
|
+
// The key decrypts with the current secret — the observed failure was not
|
|
92
|
+
// a secret rotation. Leave the healthy key alone.
|
|
93
|
+
return false;
|
|
94
|
+
// coercion-ok: this decrypt is a probe; the throw is the positive signal.
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Confirmed: the newest active key does not decrypt with the current
|
|
98
|
+
// secret. Fall through to the loud expiry below.
|
|
99
|
+
}
|
|
100
|
+
console.error("[auth] The newest JWKS signing key cannot be decrypted with the current " +
|
|
101
|
+
"BETTER_AUTH_SECRET — the secret was rotated after the key was stored. " +
|
|
102
|
+
"Expiring stale JWKS keys so Better Auth mints a fresh one; users, " +
|
|
103
|
+
"sessions, and cookies are unaffected.");
|
|
104
|
+
const { expireJwksKeysAfterAuthSecretRotation } = await import("./better-auth-migrations.js");
|
|
105
|
+
await expireJwksKeysAfterAuthSecretRotation();
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Wrap a Better Auth plugin's after-hooks so a JWKS decrypt failure heals and
|
|
110
|
+
* retries instead of failing the request. Built for the JWT plugin, whose
|
|
111
|
+
* `/get-session` hook only decorates the response with `set-auth-jwt`: when
|
|
112
|
+
* the retry still cannot sign, the header is skipped — loudly — because
|
|
113
|
+
* failing every session check over an optional header is exactly the outage
|
|
114
|
+
* this module exists to prevent.
|
|
115
|
+
*/
|
|
116
|
+
export function withJwksRotationRecovery(plugin) {
|
|
117
|
+
const after = plugin.hooks?.after;
|
|
118
|
+
if (!after)
|
|
119
|
+
return plugin;
|
|
120
|
+
return {
|
|
121
|
+
...plugin,
|
|
122
|
+
hooks: {
|
|
123
|
+
...plugin.hooks,
|
|
124
|
+
after: after.map((hook) => ({
|
|
125
|
+
...hook,
|
|
126
|
+
handler: async (context) => {
|
|
127
|
+
try {
|
|
128
|
+
return await hook.handler(context);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
if (!isJwksDecryptError(error))
|
|
132
|
+
throw error;
|
|
133
|
+
if (await healUndecryptableJwks()) {
|
|
134
|
+
try {
|
|
135
|
+
return await hook.handler(context);
|
|
136
|
+
}
|
|
137
|
+
catch (retryError) {
|
|
138
|
+
if (!isJwksDecryptError(retryError))
|
|
139
|
+
throw retryError;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
console.error("[auth] Skipping the set-auth-jwt response header: the JWKS " +
|
|
143
|
+
"signing key is still undecryptable after rotation recovery.", error);
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
})),
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|