@agent-native/core 0.169.1 → 0.170.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +4 -1
- package/bin/agent-native.js +23 -5
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/app/i18n-data.ts +28 -0
- package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
- package/corpus/templates/analytics/app/routes/$.tsx +10 -0
- package/corpus/templates/analytics/app/routes.ts +3 -1
- package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
- package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
- package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
- package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
- package/corpus/templates/analytics/server/lib/slack.ts +4 -2
- package/corpus/templates/analytics/vitest.config.ts +6 -1
- package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/assets/app/routes/library.tsx +5 -3
- package/corpus/templates/assets/app/routes.ts +3 -1
- package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
- package/corpus/templates/assets/vitest.config.ts +6 -1
- package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
- package/corpus/templates/brain/app/routes/sources.tsx +8 -3
- package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
- package/corpus/templates/brain/vitest.config.ts +1 -0
- package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
- package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
- package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
- package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
- package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
- package/corpus/templates/calendar/app/routes.ts +3 -1
- package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
- package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
- package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
- package/corpus/templates/calendar/server/onboarding.ts +85 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/calendar/shared/api.ts +9 -1
- package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/chat/app/routes.ts +3 -1
- package/corpus/templates/chat/vitest.config.ts +8 -0
- package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/clips/actions/get-meeting.ts +9 -4
- package/corpus/templates/clips/actions/list-recordings.ts +16 -3
- package/corpus/templates/clips/actions/search-meetings.ts +1 -0
- package/corpus/templates/clips/actions/view-screen.ts +8 -1
- package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
- package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
- package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
- package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
- package/corpus/templates/clips/desktop/src/app.tsx +53 -24
- package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
- package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
- package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
- package/corpus/templates/clips/server/lib/emails.ts +17 -33
- package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
- package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
- package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
- package/corpus/templates/content/app/i18n-data.ts +25 -0
- package/corpus/templates/content/app/routes.ts +3 -1
- package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
- package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
- package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
- package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
- package/corpus/templates/content/vitest.config.ts +7 -1
- package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1383 -88
- package/corpus/templates/design/actions/generate-design.ts +98 -47
- package/corpus/templates/design/actions/get-design-system.ts +6 -1
- package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2057 -141
- package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
- package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -1
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
- package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +11 -4
- package/corpus/templates/design/app/i18n-data.ts +1 -0
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
- package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +77 -35
- package/corpus/templates/design/app/pages/DesignSystems.tsx +136 -42
- package/corpus/templates/design/app/pages/Index.tsx +2 -0
- package/corpus/templates/design/app/pages/Templates.tsx +0 -10
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
- package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
- package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
- package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
- package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
- package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
- package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
- package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
- package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
- package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
- package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
- package/corpus/templates/design/app/routes.ts +3 -1
- package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
- package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
- package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
- package/corpus/templates/design/package.json +2 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
- package/corpus/templates/design/shared/canvas-math.ts +612 -206
- package/corpus/templates/design/shared/pen-path.ts +37 -0
- package/corpus/templates/design/vitest.config.ts +7 -1
- package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
- package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
- package/corpus/templates/dispatch/app/routes.ts +3 -1
- package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/factory/.env.example +2 -7
- package/corpus/templates/factory/AGENTS.md +3 -0
- package/corpus/templates/factory/README.md +5 -3
- package/corpus/templates/factory/actions/create-factory.ts +16 -3
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
- package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
- package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
- package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
- package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
- package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
- package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
- package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
- package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
- package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
- package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
- package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
- package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
- package/corpus/templates/factory/app/routes/factory.tsx +84 -11
- package/corpus/templates/factory/app/routes.ts +3 -1
- package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
- package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
- package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
- package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
- package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
- package/corpus/templates/factory/vitest.config.ts +17 -2
- package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
- package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
- package/corpus/templates/forms/vitest.config.ts +1 -0
- package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/macros/app/routes.ts +3 -1
- package/corpus/templates/macros/vitest.config.ts +6 -1
- package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
- package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
- package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
- package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
- package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
- package/corpus/templates/mail/app/routes/$.tsx +9 -0
- package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
- package/corpus/templates/mail/app/routes/$view.tsx +47 -1
- package/corpus/templates/mail/app/routes.ts +3 -1
- package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
- package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
- package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
- package/corpus/templates/mail/server/onboarding.ts +66 -18
- package/corpus/templates/mail/vitest.config.ts +6 -1
- package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/plan/app/routes/settings.tsx +4 -1
- package/corpus/templates/plan/app/routes.ts +3 -1
- package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/plan/netlify.toml +1 -1
- package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/slides/actions/patch-deck.ts +79 -10
- package/corpus/templates/slides/actions/update-slide.ts +11 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
- package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
- package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
- package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
- package/corpus/templates/slides/app/routes.ts +3 -1
- package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
- package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
- package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
- package/corpus/templates/slides/tsconfig.json +5 -0
- package/corpus/templates/slides/vitest.config.ts +6 -1
- package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
- package/corpus/templates/tasks/app/routes.ts +3 -1
- package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/tasks/vitest.config.ts +7 -1
- package/dist/action.d.ts +91 -0
- package/dist/action.js +50 -0
- package/dist/agent/abort-reasons.d.ts +38 -0
- package/dist/agent/abort-reasons.js +49 -0
- package/dist/agent/engine/ai-sdk-engine.js +8 -5
- package/dist/agent/engine/anthropic-engine.js +7 -5
- package/dist/agent/engine/first-event-timeout.d.ts +42 -17
- package/dist/agent/engine/first-event-timeout.js +67 -25
- package/dist/agent/production-agent.d.ts +23 -0
- package/dist/agent/production-agent.js +107 -102
- package/dist/agent/run-loop-with-resume.d.ts +2 -28
- package/dist/agent/run-loop-with-resume.js +25 -40
- package/dist/agent/run-manager.js +5 -4
- package/dist/agent/run-store.d.ts +55 -0
- package/dist/agent/run-store.js +124 -1
- package/dist/agent/tool-search.js +2 -1
- package/dist/agent/types.d.ts +9 -4
- package/dist/app-config/configuration-error.d.ts +11 -0
- package/dist/app-config/configuration-error.js +14 -0
- package/dist/app-config/index.d.ts +1 -0
- package/dist/app-config/index.js +1 -0
- package/dist/app-config/integrations.d.ts +1 -0
- package/dist/app-config/integrations.js +10 -0
- package/dist/app-config/plugins.d.ts +34 -0
- package/dist/app-config/plugins.js +39 -0
- package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
- package/dist/app-config/run-lifecycle-invariants.js +18 -25
- package/dist/app-config/schema.d.ts +16 -0
- package/dist/app-config/schema.js +2 -0
- package/dist/chat-threads/schema-migrations.js +20 -0
- package/dist/chat-threads/store.js +21 -4
- package/dist/cli/native-dependencies.d.ts +4 -0
- package/dist/cli/native-dependencies.js +15 -0
- package/dist/client/EnvironmentBadge.d.ts +1 -1
- package/dist/client/EnvironmentBadge.js +40 -5
- package/dist/client/MultiTabAssistantChat.d.ts +1 -1
- package/dist/client/MultiTabAssistantChat.js +35 -14
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/agent-page/use-jobs.d.ts +2 -1
- package/dist/client/agent-page/use-jobs.js +3 -5
- package/dist/client/agent-sidebar-state.js +3 -1
- package/dist/client/blocks/library/code-tabs.js +5 -0
- package/dist/client/blocks/library/code.js +1 -0
- package/dist/client/chat-first/apps-rail.js +2 -2
- package/dist/client/chat-model-groups.d.ts +12 -0
- package/dist/client/chat-model-groups.js +3 -2
- package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
- package/dist/client/integrations/GoogleProductLogo.js +45 -0
- package/dist/client/integrations/index.d.ts +2 -0
- package/dist/client/integrations/index.js +2 -0
- package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
- package/dist/client/integrations/workspace-provider-oauth.js +13 -0
- package/dist/client/resources/mcp-integration-catalog.js +0 -29
- package/dist/client/settings/SettingsTabsPage.js +10 -6
- package/dist/client/sharing/ShareButton.js +11 -2
- package/dist/client/use-chat-models.d.ts +6 -0
- package/dist/client/use-chat-models.js +10 -0
- package/dist/client/use-db-sync.js +27 -9
- package/dist/connections/catalog.d.ts +111 -9
- package/dist/connections/catalog.js +86 -30
- package/dist/db/create-get-db.js +18 -0
- package/dist/db/ddl-guard.d.ts +0 -4
- package/dist/db/ddl-guard.js +46 -0
- package/dist/deploy/build.d.ts +19 -0
- package/dist/deploy/build.js +190 -16
- package/dist/deploy/function-bundle.d.ts +45 -0
- package/dist/deploy/function-bundle.js +337 -0
- package/dist/deploy/workspace-deploy.js +19 -1
- package/dist/eject/workspace-connections.js +4 -0
- package/dist/email-catalog/registry.d.ts +4 -0
- package/dist/email-catalog/registry.js +79 -14
- package/dist/extensions/content-patch.js +14 -2
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/plugin.d.ts +10 -0
- package/dist/integrations/plugin.js +40 -6
- package/dist/jobs/actions/run-automation-now.d.ts +2 -1
- package/dist/jobs/actions/run-automation-now.js +11 -5
- package/dist/jobs/frontmatter.js +53 -2
- package/dist/jobs/run-now.d.ts +11 -1
- package/dist/jobs/run-now.js +42 -7
- package/dist/jobs/scheduler.d.ts +1 -0
- package/dist/jobs/scheduler.js +2 -1
- package/dist/localization/core-messages/ar-SA.js +3 -0
- package/dist/localization/core-messages/de-DE.js +3 -0
- package/dist/localization/core-messages/en-US.d.ts +3 -0
- package/dist/localization/core-messages/en-US.js +3 -0
- package/dist/localization/core-messages/es-ES.js +3 -0
- package/dist/localization/core-messages/fr-FR.js +3 -0
- package/dist/localization/core-messages/hi-IN.js +3 -0
- package/dist/localization/core-messages/ja-JP.js +3 -0
- package/dist/localization/core-messages/ko-KR.js +3 -0
- package/dist/localization/core-messages/pt-BR.js +3 -0
- package/dist/localization/core-messages/zh-CN.js +3 -0
- package/dist/localization/core-messages/zh-TW.js +3 -0
- package/dist/localization/core-messages.d.ts +3 -0
- package/dist/localization/default-messages.d.ts +2 -5
- package/dist/localization/default-messages.js +2 -5
- package/dist/mcp/build-server.d.ts +9 -0
- package/dist/mcp/build-server.js +37 -8
- package/dist/mcp-client/oauth-client.d.ts +7 -0
- package/dist/mcp-client/oauth-client.js +12 -1
- package/dist/oauth-tokens/index.d.ts +1 -1
- package/dist/oauth-tokens/index.js +1 -1
- package/dist/oauth-tokens/lifecycle.d.ts +11 -0
- package/dist/oauth-tokens/lifecycle.js +17 -0
- package/dist/oauth-tokens/store.js +7 -0
- package/dist/observability/posthog-ai.d.ts +15 -1
- package/dist/observability/posthog-ai.js +24 -12
- package/dist/observability/routes.d.ts +3 -3
- package/dist/observability/traces.js +158 -28
- package/dist/onboarding/app-profile.js +2 -2
- package/dist/onboarding/plugin.js +10 -2
- package/dist/onboarding/types.d.ts +2 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/provider-api/index.js +2 -0
- package/dist/resources/store.js +13 -4
- package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
- package/dist/secrets/register-framework-secrets.js +1 -1
- package/dist/server/action-discovery.js +5 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
- package/dist/server/agent-chat/action-filters-a2a.js +48 -9
- package/dist/server/agent-chat-plugin.js +36 -9
- package/dist/server/agent-discovery.js +43 -20
- package/dist/server/auth.js +18 -16
- package/dist/server/beta-opt-out-html.js +45 -4
- package/dist/server/better-auth-instance.d.ts +2 -1
- package/dist/server/better-auth-instance.js +23 -7
- package/dist/server/builder-design-systems.d.ts +4 -1
- package/dist/server/builder-design-systems.js +87 -6
- package/dist/server/builder-oauth.d.ts +1 -7
- package/dist/server/builder-oauth.js +80 -163
- package/dist/server/core-routes-plugin.d.ts +29 -0
- package/dist/server/core-routes-plugin.js +100 -20
- package/dist/server/default-plugins.d.ts +18 -0
- package/dist/server/default-plugins.js +22 -0
- package/dist/server/edge.d.ts +1 -0
- package/dist/server/edge.js +1 -0
- package/dist/server/framework-request-handler.js +31 -3
- package/dist/server/google-oauth.d.ts +3 -0
- package/dist/server/google-oauth.js +3 -0
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +3 -3
- package/dist/server/onboarding-html.js +37 -3
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/server/workspace-provider-oauth.d.ts +6 -1
- package/dist/server/workspace-provider-oauth.js +72 -20
- package/dist/shared/agent-sidebar-url.d.ts +1 -0
- package/dist/shared/agent-sidebar-url.js +1 -0
- package/dist/shared/environment-lanes.d.ts +2 -0
- package/dist/shared/environment-lanes.js +3 -1
- package/dist/shared/index.d.ts +3 -1
- package/dist/shared/index.js +3 -1
- package/dist/shared/surface-visibility.d.ts +31 -0
- package/dist/shared/surface-visibility.js +57 -0
- package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/chat/app/routes.ts +3 -1
- package/dist/templates/chat/vitest.config.ts +8 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/default/app/routes.ts +3 -1
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/tracking/registry.d.ts +11 -0
- package/dist/tracking/registry.js +5 -2
- package/dist/triggers/actions.js +10 -3
- package/dist/usage/store.js +23 -3
- package/dist/user-profile/actions/get-auth-methods.js +18 -5
- package/dist/vite/client.js +24 -5
- package/docs/content/actions-access-control.mdx +43 -4
- package/docs/content/actions-defining.mdx +16 -0
- package/docs/content/template-clips-capture-everywhere.mdx +29 -30
- package/docs/content/template-clips-developers.mdx +4 -4
- package/docs/content/template-clips.mdx +3 -1
- package/package.json +2 -2
- package/src/eject/workspace-connections.ts +4 -0
- package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/chat/app/routes.ts +3 -1
- package/src/templates/chat/vitest.config.ts +8 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/default/app/routes.ts +3 -1
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
|
@@ -10,6 +10,8 @@ const GCS_CHUNK_SIZE = 16 * 1024 * 1024;
|
|
|
10
10
|
const MAX_CHUNK_RETRIES = 5;
|
|
11
11
|
const DEFAULT_MAX_CODE_FILES = 50;
|
|
12
12
|
const DEFAULT_MAX_TOTAL_CODE_BYTES = 2 * 1024 * 1024;
|
|
13
|
+
const DEFAULT_BUILDER_DOC_PAGE_SIZE = 40;
|
|
14
|
+
const MAX_BUILDER_DOC_PAGES = 100;
|
|
13
15
|
const MAX_DOC_CONTENT_CHARS = 4_000;
|
|
14
16
|
const MAX_GITHUB_FILES = 50;
|
|
15
17
|
const MAX_GITHUB_TOTAL_BYTES = 2 * 1024 * 1024;
|
|
@@ -654,7 +656,35 @@ function normalizeBuilderDesignSystemDocument(value) {
|
|
|
654
656
|
: undefined,
|
|
655
657
|
};
|
|
656
658
|
}
|
|
657
|
-
|
|
659
|
+
function normalizeBuilderDesignSystemStatus(value) {
|
|
660
|
+
if (typeof value !== "string")
|
|
661
|
+
return "in-progress";
|
|
662
|
+
switch (value.trim().toLowerCase()) {
|
|
663
|
+
case "ready":
|
|
664
|
+
return "ready";
|
|
665
|
+
case "complete":
|
|
666
|
+
case "done":
|
|
667
|
+
case "success":
|
|
668
|
+
return "complete";
|
|
669
|
+
case "completed":
|
|
670
|
+
return "completed";
|
|
671
|
+
case "error":
|
|
672
|
+
return "error";
|
|
673
|
+
case "failed":
|
|
674
|
+
case "failure":
|
|
675
|
+
return "failed";
|
|
676
|
+
case "cancelled":
|
|
677
|
+
case "canceled":
|
|
678
|
+
return "cancelled";
|
|
679
|
+
default:
|
|
680
|
+
return "in-progress";
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function isConfirmedBuilderDesignSystemStatus(value) {
|
|
684
|
+
const status = normalizeBuilderDesignSystemStatus(value);
|
|
685
|
+
return status === "ready" || status === "complete" || status === "completed";
|
|
686
|
+
}
|
|
687
|
+
async function fetchBuilderDesignSystemDocsResponse(designSystemId, options) {
|
|
658
688
|
const credentials = await resolveBuilderDesignSystemCredentials();
|
|
659
689
|
const url = makeBuilderDesignSystemUrl(`${encodeURIComponent(designSystemId)}/docs`, credentials);
|
|
660
690
|
if (options.page !== undefined)
|
|
@@ -671,13 +701,61 @@ export async function fetchBuilderDesignSystemDocs(designSystemId, options = {})
|
|
|
671
701
|
});
|
|
672
702
|
await assertOk(response, "Builder design-system docs fetch failed");
|
|
673
703
|
const json = (await response.json());
|
|
674
|
-
if (
|
|
704
|
+
if (Array.isArray(json)) {
|
|
705
|
+
return {
|
|
706
|
+
docs: json.map(normalizeBuilderDesignSystemDocument),
|
|
707
|
+
completionConfirmed: false,
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
if (!json || typeof json !== "object") {
|
|
711
|
+
throw new Error("Builder design-system docs fetch returned an invalid response.");
|
|
712
|
+
}
|
|
713
|
+
const envelope = json;
|
|
714
|
+
const rawDocs = envelope.docs ?? envelope.items;
|
|
715
|
+
if (!Array.isArray(rawDocs)) {
|
|
675
716
|
throw new Error("Builder design-system docs fetch returned an invalid response.");
|
|
676
717
|
}
|
|
677
|
-
|
|
718
|
+
const rawStatus = envelope.status ?? envelope.builderStatus;
|
|
719
|
+
const status = typeof rawStatus === "string"
|
|
720
|
+
? normalizeBuilderDesignSystemStatus(rawStatus)
|
|
721
|
+
: undefined;
|
|
722
|
+
const isTerminalFailure = status === "error" || status === "failed" || status === "cancelled";
|
|
723
|
+
return {
|
|
724
|
+
docs: rawDocs.map(normalizeBuilderDesignSystemDocument),
|
|
725
|
+
completionConfirmed: !isTerminalFailure &&
|
|
726
|
+
(envelope.complete === true ||
|
|
727
|
+
envelope.completed === true ||
|
|
728
|
+
isConfirmedBuilderDesignSystemStatus(status)),
|
|
729
|
+
...(status ? { status } : {}),
|
|
730
|
+
};
|
|
678
731
|
}
|
|
679
|
-
export async function
|
|
680
|
-
|
|
732
|
+
export async function fetchBuilderDesignSystemDocs(designSystemId, options = {}) {
|
|
733
|
+
return (await fetchBuilderDesignSystemDocsResponse(designSystemId, options))
|
|
734
|
+
.docs;
|
|
735
|
+
}
|
|
736
|
+
export async function hydrateBuilderDesignSystemReference(reference, options = {
|
|
737
|
+
page: 0,
|
|
738
|
+
pageSize: DEFAULT_BUILDER_DOC_PAGE_SIZE,
|
|
739
|
+
}) {
|
|
740
|
+
const pageSize = options.pageSize && options.pageSize > 0
|
|
741
|
+
? options.pageSize
|
|
742
|
+
: DEFAULT_BUILDER_DOC_PAGE_SIZE;
|
|
743
|
+
const docs = [];
|
|
744
|
+
let page = Math.max(0, options.page ?? 0);
|
|
745
|
+
let completionConfirmed = false;
|
|
746
|
+
let builderStatus = reference.builderStatus;
|
|
747
|
+
for (let pageNumber = 0; pageNumber < MAX_BUILDER_DOC_PAGES; pageNumber++) {
|
|
748
|
+
const response = await fetchBuilderDesignSystemDocsResponse(reference.builderDesignSystemId, { ...options, page, pageSize });
|
|
749
|
+
docs.push(...response.docs);
|
|
750
|
+
completionConfirmed ||= response.completionConfirmed;
|
|
751
|
+
builderStatus = response.status ?? builderStatus;
|
|
752
|
+
if (response.docs.length < pageSize)
|
|
753
|
+
break;
|
|
754
|
+
page += 1;
|
|
755
|
+
if (pageNumber === MAX_BUILDER_DOC_PAGES - 1) {
|
|
756
|
+
throw new Error("Builder design-system docs fetch exceeded the safe pagination limit.");
|
|
757
|
+
}
|
|
758
|
+
}
|
|
681
759
|
const tokenValues = {};
|
|
682
760
|
for (const doc of docs) {
|
|
683
761
|
if (!doc.tokenValues)
|
|
@@ -689,9 +767,12 @@ export async function hydrateBuilderDesignSystemReference(reference, options = {
|
|
|
689
767
|
}
|
|
690
768
|
return {
|
|
691
769
|
...reference,
|
|
770
|
+
...(builderStatus ? { builderStatus } : {}),
|
|
692
771
|
docs,
|
|
693
772
|
tokenValues,
|
|
694
773
|
docCount: docs.length,
|
|
774
|
+
completionConfirmed: completionConfirmed ||
|
|
775
|
+
isConfirmedBuilderDesignSystemStatus(builderStatus),
|
|
695
776
|
};
|
|
696
777
|
}
|
|
697
778
|
/**
|
|
@@ -771,7 +852,7 @@ export async function indexBuilderDesignSystem(options) {
|
|
|
771
852
|
builderUrl: branchUrl ||
|
|
772
853
|
builderProjectBranchUrl(indexed.projectId, indexed.branchName) ||
|
|
773
854
|
builderDesignSystemUrl(indexed.designSystemId),
|
|
774
|
-
status:
|
|
855
|
+
status: normalizeBuilderDesignSystemStatus(indexed.status),
|
|
775
856
|
};
|
|
776
857
|
}
|
|
777
858
|
/**
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
export declare const BUILDER_OAUTH_ISSUER = "https://mcp.builder.io";
|
|
2
2
|
export declare const BUILDER_OAUTH_RESOURCE = "https://api.builder.io";
|
|
3
|
-
export declare const BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA = "https://mcp.builder.io/.well-known/oauth-protected-resource/api";
|
|
4
|
-
export declare const BUILDER_OAUTH_AUTHORIZATION_METADATA = "https://mcp.builder.io/.well-known/oauth-authorization-server";
|
|
5
|
-
export declare const BUILDER_OAUTH_AUTHORIZATION_ENDPOINT = "https://mcp.builder.io/oauth/authorize";
|
|
6
|
-
export declare const BUILDER_OAUTH_TOKEN_ENDPOINT = "https://mcp.builder.io/oauth/token";
|
|
7
|
-
export declare const BUILDER_OAUTH_REGISTRATION_ENDPOINT = "https://mcp.builder.io/oauth/register";
|
|
8
|
-
export declare const BUILDER_OAUTH_REVOCATION_ENDPOINT = "https://mcp.builder.io/oauth/revoke";
|
|
9
3
|
export declare const BUILDER_OAUTH_SCOPE = "builder:ai:invoke";
|
|
10
4
|
export declare const BUILDER_OAUTH_SCOPES: readonly ["builder:ai:invoke"];
|
|
11
5
|
export type BuilderOAuthPendingFlow = {
|
|
@@ -32,12 +26,12 @@ export declare function startBuilderOAuthAuthorization(input: {
|
|
|
32
26
|
}>;
|
|
33
27
|
export declare function finishBuilderOAuthAuthorization(input: {
|
|
34
28
|
ownerEmail: string;
|
|
29
|
+
orgId?: string;
|
|
35
30
|
code: string;
|
|
36
31
|
iss?: string;
|
|
37
32
|
pending: BuilderOAuthPendingFlow;
|
|
38
33
|
}): Promise<void>;
|
|
39
34
|
export declare function markBuilderOAuthReconnectRequired(ownerEmail: string): Promise<void>;
|
|
40
|
-
export declare function builderOAuthReconnectRequired(ownerEmail: string): Promise<boolean>;
|
|
41
35
|
export declare function getBuilderOAuthSession(ownerEmail: string): Promise<BuilderOAuthSession | null>;
|
|
42
36
|
export declare function hasBuilderOAuthSession(ownerEmail: string): Promise<boolean>;
|
|
43
37
|
export declare function resolveBuilderOAuthRequestAccess(input: {
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { finishMcpOAuthAuthorization, getMcpOAuthAccessToken, markMcpOAuthReconnectRequired, readMcpOAuthCredentials, revokeMcpOAuthCredentials, saveMcpOAuthCredentials, startMcpOAuthAuthorization, validateMcpOAuthCallbackIssuer, } from "../mcp-client/oauth-client.js";
|
|
2
3
|
import { getOAuthTokens } from "../oauth-tokens/store.js";
|
|
3
|
-
import {
|
|
4
|
+
import { resolveOrgIdForEmail } from "../org/context.js";
|
|
4
5
|
export const BUILDER_OAUTH_ISSUER = "https://mcp.builder.io";
|
|
5
6
|
export const BUILDER_OAUTH_RESOURCE = "https://api.builder.io";
|
|
6
|
-
export const BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA = "https://mcp.builder.io/.well-known/oauth-protected-resource/api";
|
|
7
|
-
export const BUILDER_OAUTH_AUTHORIZATION_METADATA = "https://mcp.builder.io/.well-known/oauth-authorization-server";
|
|
8
|
-
export const BUILDER_OAUTH_AUTHORIZATION_ENDPOINT = "https://mcp.builder.io/oauth/authorize";
|
|
9
|
-
export const BUILDER_OAUTH_TOKEN_ENDPOINT = "https://mcp.builder.io/oauth/token";
|
|
10
|
-
export const BUILDER_OAUTH_REGISTRATION_ENDPOINT = "https://mcp.builder.io/oauth/register";
|
|
11
|
-
export const BUILDER_OAUTH_REVOCATION_ENDPOINT = "https://mcp.builder.io/oauth/revoke";
|
|
12
7
|
export const BUILDER_OAUTH_SCOPE = "builder:ai:invoke";
|
|
13
8
|
export const BUILDER_OAUTH_SCOPES = [BUILDER_OAUTH_SCOPE];
|
|
9
|
+
// Folded with the owner so each owner gets their own (provider, account_id)
|
|
10
|
+
// row; a bare shared key would let only the first connector hold a grant.
|
|
14
11
|
const BUILDER_OAUTH_KEY = "builder-general-resource-v1";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
// Builder's general AI resource metadata lives at a non-default path; the
|
|
13
|
+
// default api.builder.io well-known describes its Figma integration instead.
|
|
14
|
+
// Point discovery here so live metadata resolves to the api.builder.io resource
|
|
15
|
+
// and the mcp.builder.io authorization server.
|
|
16
|
+
const BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA = "https://mcp.builder.io/.well-known/oauth-protected-resource/api";
|
|
17
|
+
// The Builder connection is shared by everyone in the caller's org: the
|
|
18
|
+
// credential is scoped to the org so every member reads the same token. Every
|
|
19
|
+
// user belongs to an org, so a missing org is a broken invariant, not a case
|
|
20
|
+
// to fall back on.
|
|
21
|
+
function normalizeOwnerEmail(ownerEmail) {
|
|
22
|
+
const email = ownerEmail.trim().toLowerCase();
|
|
23
|
+
if (!email)
|
|
21
24
|
throw new Error("Builder OAuth owner email is required");
|
|
25
|
+
return email;
|
|
26
|
+
}
|
|
27
|
+
// Read paths use this: a caller with no org simply has no Builder session, so
|
|
28
|
+
// engine detection and status checks get null instead of an exception.
|
|
29
|
+
async function resolveOwnerOptions(ownerEmail) {
|
|
30
|
+
const email = normalizeOwnerEmail(ownerEmail);
|
|
31
|
+
const orgId = await resolveOrgIdForEmail(email);
|
|
32
|
+
if (!orgId)
|
|
33
|
+
return null;
|
|
34
|
+
return orgOwnerOptions(orgId);
|
|
35
|
+
}
|
|
36
|
+
// Write paths use this: storing a Builder credential without an org is a broken
|
|
37
|
+
// invariant, so a missing org fails loudly rather than silently dropping it.
|
|
38
|
+
async function ownerOptions(ownerEmail) {
|
|
39
|
+
const options = await resolveOwnerOptions(ownerEmail);
|
|
40
|
+
if (!options) {
|
|
41
|
+
throw new Error(`Builder OAuth requires an organization for ${normalizeOwnerEmail(ownerEmail)}`);
|
|
42
|
+
}
|
|
43
|
+
return options;
|
|
44
|
+
}
|
|
45
|
+
function orgOwnerOptions(orgId) {
|
|
22
46
|
return {
|
|
23
|
-
key:
|
|
24
|
-
scope: "
|
|
25
|
-
scopeId,
|
|
47
|
+
key: builderOAuthKey(orgId),
|
|
48
|
+
scope: "org",
|
|
49
|
+
scopeId: orgId,
|
|
26
50
|
serverUrl: BUILDER_OAUTH_RESOURCE,
|
|
27
51
|
};
|
|
28
52
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
function reconnectKey(ownerEmail) {
|
|
33
|
-
return `builder-oauth-reconnect:user:${ownerOptions(ownerEmail).scopeId}`;
|
|
34
|
-
}
|
|
35
|
-
function discoveryState() {
|
|
36
|
-
return {
|
|
37
|
-
authorizationServerUrl: BUILDER_OAUTH_ISSUER,
|
|
38
|
-
authorizationServerMetadata: {
|
|
39
|
-
issuer: BUILDER_OAUTH_ISSUER,
|
|
40
|
-
authorization_endpoint: BUILDER_OAUTH_AUTHORIZATION_ENDPOINT,
|
|
41
|
-
token_endpoint: BUILDER_OAUTH_TOKEN_ENDPOINT,
|
|
42
|
-
registration_endpoint: BUILDER_OAUTH_REGISTRATION_ENDPOINT,
|
|
43
|
-
revocation_endpoint: BUILDER_OAUTH_REVOCATION_ENDPOINT,
|
|
44
|
-
// MCP SDK auth() reads these from the provided discovery blob and throws
|
|
45
|
-
// if they are missing — do not omit them when skipping live metadata fetch.
|
|
46
|
-
response_types_supported: ["code"],
|
|
47
|
-
grant_types_supported: ["authorization_code", "refresh_token"],
|
|
48
|
-
code_challenge_methods_supported: ["S256"],
|
|
49
|
-
},
|
|
50
|
-
resourceMetadataUrl: BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA,
|
|
51
|
-
resourceMetadata: {
|
|
52
|
-
resource: BUILDER_OAUTH_RESOURCE,
|
|
53
|
-
authorization_servers: [BUILDER_OAUTH_ISSUER],
|
|
54
|
-
},
|
|
55
|
-
};
|
|
53
|
+
function builderOAuthKey(orgId) {
|
|
54
|
+
const digest = createHash("sha256").update(orgId).digest("hex");
|
|
55
|
+
return `${BUILDER_OAUTH_KEY}:o:${digest}`;
|
|
56
56
|
}
|
|
57
57
|
function scopesFrom(credentials) {
|
|
58
58
|
const declared = credentials.tokens.scope;
|
|
@@ -72,35 +72,11 @@ function isBuilderDiscoveryState(value) {
|
|
|
72
72
|
if (!value || typeof value !== "object")
|
|
73
73
|
return false;
|
|
74
74
|
const discovery = value;
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const grantTypes = discovery.authorizationServerMetadata?.grant_types_supported;
|
|
78
|
-
const challengeMethods = discovery.authorizationServerMetadata?.code_challenge_methods_supported;
|
|
79
|
-
const resource = typeof discovery.resourceMetadata?.resource === "string"
|
|
80
|
-
? discovery.resourceMetadata.resource
|
|
81
|
-
: null;
|
|
82
|
-
return (discovery?.authorizationServerUrl === BUILDER_OAUTH_ISSUER &&
|
|
75
|
+
const resource = discovery.resourceMetadata?.resource;
|
|
76
|
+
return (discovery.authorizationServerUrl === BUILDER_OAUTH_ISSUER &&
|
|
83
77
|
discovery.authorizationServerMetadata?.issuer === BUILDER_OAUTH_ISSUER &&
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
discovery.authorizationServerMetadata?.token_endpoint ===
|
|
87
|
-
BUILDER_OAUTH_TOKEN_ENDPOINT &&
|
|
88
|
-
discovery.authorizationServerMetadata?.registration_endpoint ===
|
|
89
|
-
BUILDER_OAUTH_REGISTRATION_ENDPOINT &&
|
|
90
|
-
discovery.authorizationServerMetadata?.revocation_endpoint ===
|
|
91
|
-
BUILDER_OAUTH_REVOCATION_ENDPOINT &&
|
|
92
|
-
Array.isArray(responseTypes) &&
|
|
93
|
-
responseTypes.includes("code") &&
|
|
94
|
-
Array.isArray(grantTypes) &&
|
|
95
|
-
grantTypes.includes("authorization_code") &&
|
|
96
|
-
Array.isArray(challengeMethods) &&
|
|
97
|
-
challengeMethods.includes("S256") &&
|
|
98
|
-
discovery.resourceMetadataUrl ===
|
|
99
|
-
BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA &&
|
|
100
|
-
!!resource &&
|
|
101
|
-
resourceUrlsMatch(resource, BUILDER_OAUTH_RESOURCE) &&
|
|
102
|
-
Array.isArray(authorizationServers) &&
|
|
103
|
-
authorizationServers.includes(BUILDER_OAUTH_ISSUER));
|
|
78
|
+
typeof resource === "string" &&
|
|
79
|
+
resourceUrlsMatch(resource, BUILDER_OAUTH_RESOURCE));
|
|
104
80
|
}
|
|
105
81
|
function isBuilderCredential(credentials) {
|
|
106
82
|
return (resourceUrlsMatch(credentials.serverUrl, BUILDER_OAUTH_RESOURCE) &&
|
|
@@ -108,26 +84,16 @@ function isBuilderCredential(credentials) {
|
|
|
108
84
|
credentials.tokens.issuer === BUILDER_OAUTH_ISSUER &&
|
|
109
85
|
isBuilderDiscoveryState(credentials.discoveryState));
|
|
110
86
|
}
|
|
111
|
-
function sessionFrom(credentials) {
|
|
112
|
-
if (!isBuilderCredential(credentials))
|
|
113
|
-
return null;
|
|
114
|
-
const accessToken = credentials.tokens.access_token;
|
|
115
|
-
if (typeof accessToken !== "string" || !accessToken)
|
|
116
|
-
return null;
|
|
117
|
-
return {
|
|
118
|
-
accessToken,
|
|
119
|
-
expiresAt: credentials.tokenExpiresAt,
|
|
120
|
-
scopes: scopesFrom(credentials),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
87
|
export async function startBuilderOAuthAuthorization(input) {
|
|
124
|
-
|
|
88
|
+
// Start scopes nothing, so it validates the email without an org lookup;
|
|
89
|
+
// the org scope is resolved when the grant is stored and read.
|
|
90
|
+
normalizeOwnerEmail(input.ownerEmail);
|
|
125
91
|
const started = await startMcpOAuthAuthorization({
|
|
126
92
|
serverUrl: BUILDER_OAUTH_RESOURCE,
|
|
127
93
|
redirectUrl: input.redirectUri,
|
|
128
94
|
state: input.state,
|
|
129
95
|
scope: BUILDER_OAUTH_SCOPE,
|
|
130
|
-
|
|
96
|
+
resourceMetadataUrl: BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA,
|
|
131
97
|
});
|
|
132
98
|
return {
|
|
133
99
|
authorizationUrl: started.authorizationUrl.toString(),
|
|
@@ -140,9 +106,6 @@ export async function startBuilderOAuthAuthorization(input) {
|
|
|
140
106
|
};
|
|
141
107
|
}
|
|
142
108
|
export async function finishBuilderOAuthAuthorization(input) {
|
|
143
|
-
if (!isBuilderDiscoveryState(input.pending.discoveryState)) {
|
|
144
|
-
throw new Error("Builder OAuth pending flow has an invalid discovery binding");
|
|
145
|
-
}
|
|
146
109
|
validateMcpOAuthCallbackIssuer(input.pending.discoveryState, input.iss);
|
|
147
110
|
const result = await finishMcpOAuthAuthorization({
|
|
148
111
|
serverUrl: BUILDER_OAUTH_RESOURCE,
|
|
@@ -158,40 +121,41 @@ export async function finishBuilderOAuthAuthorization(input) {
|
|
|
158
121
|
throw new Error("Builder OAuth exchange returned credentials for another resource");
|
|
159
122
|
}
|
|
160
123
|
await saveMcpOAuthCredentials({
|
|
161
|
-
...
|
|
124
|
+
...(input.orgId
|
|
125
|
+
? orgOwnerOptions(input.orgId)
|
|
126
|
+
: await ownerOptions(input.ownerEmail)),
|
|
162
127
|
credentials: result.credentials,
|
|
163
128
|
});
|
|
164
|
-
await putSetting(reconnectKey(input.ownerEmail), {
|
|
165
|
-
required: false,
|
|
166
|
-
at: Date.now(),
|
|
167
|
-
}).catch(() => {
|
|
168
|
-
// coercion-ok: reconnect flag clear is best-effort after a successful grant.
|
|
169
|
-
});
|
|
170
129
|
}
|
|
171
130
|
export async function markBuilderOAuthReconnectRequired(ownerEmail) {
|
|
172
|
-
await
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
export async function builderOAuthReconnectRequired(ownerEmail) {
|
|
178
|
-
const row = await getSetting(reconnectKey(ownerEmail));
|
|
179
|
-
return row?.required === true;
|
|
131
|
+
const options = await resolveOwnerOptions(ownerEmail);
|
|
132
|
+
if (!options)
|
|
133
|
+
return;
|
|
134
|
+
await markMcpOAuthReconnectRequired(options);
|
|
180
135
|
}
|
|
181
136
|
export async function getBuilderOAuthSession(ownerEmail) {
|
|
182
|
-
|
|
137
|
+
const options = await resolveOwnerOptions(ownerEmail);
|
|
138
|
+
if (!options)
|
|
139
|
+
return null;
|
|
140
|
+
// Delegates refresh single-flight and reconnect latching to the shared
|
|
141
|
+
// credential lifecycle; a null token covers missing, expired-unrefreshable,
|
|
142
|
+
// and reconnect_required alike.
|
|
143
|
+
const accessToken = await getMcpOAuthAccessToken(options);
|
|
144
|
+
if (!accessToken)
|
|
183
145
|
return null;
|
|
184
|
-
const credentials = await readMcpOAuthCredentials(
|
|
146
|
+
const credentials = await readMcpOAuthCredentials(options);
|
|
185
147
|
if (!credentials || !isBuilderCredential(credentials))
|
|
186
148
|
return null;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
149
|
+
return {
|
|
150
|
+
accessToken,
|
|
151
|
+
expiresAt: credentials.tokenExpiresAt,
|
|
152
|
+
scopes: scopesFrom(credentials),
|
|
153
|
+
};
|
|
192
154
|
}
|
|
193
155
|
export async function hasBuilderOAuthSession(ownerEmail) {
|
|
194
|
-
const options =
|
|
156
|
+
const options = await resolveOwnerOptions(ownerEmail);
|
|
157
|
+
if (!options)
|
|
158
|
+
return false;
|
|
195
159
|
const stored = await getOAuthTokens("mcp", options.key, `${options.scope}:${options.scopeId}`);
|
|
196
160
|
return stored !== null;
|
|
197
161
|
}
|
|
@@ -202,60 +166,13 @@ export async function resolveBuilderOAuthRequestAccess(input) {
|
|
|
202
166
|
if (!session.scopes.includes(input.requiredScope)) {
|
|
203
167
|
throw new Error(`Builder OAuth connection does not grant ${input.requiredScope}`);
|
|
204
168
|
}
|
|
205
|
-
return { ...session, ownerEmail:
|
|
206
|
-
}
|
|
207
|
-
async function refreshBuilderOAuthSession(ownerEmail) {
|
|
208
|
-
const owner = crypto.randomUUID();
|
|
209
|
-
const leaseKey = refreshLeaseKey(ownerEmail);
|
|
210
|
-
const lease = await mutateSetting(leaseKey, (current) => {
|
|
211
|
-
if (typeof current?.expiresAt !== "number" ||
|
|
212
|
-
current.expiresAt <= Date.now()) {
|
|
213
|
-
return { owner, expiresAt: Date.now() + REFRESH_LEASE_MS };
|
|
214
|
-
}
|
|
215
|
-
return current;
|
|
216
|
-
});
|
|
217
|
-
if (lease.owner !== owner)
|
|
218
|
-
return waitForRefreshedSession(ownerEmail);
|
|
219
|
-
try {
|
|
220
|
-
const options = ownerOptions(ownerEmail);
|
|
221
|
-
const accessToken = await getMcpOAuthAccessToken(options);
|
|
222
|
-
const next = await readMcpOAuthCredentials(options);
|
|
223
|
-
if (!accessToken || !next || !isBuilderCredential(next)) {
|
|
224
|
-
throw new Error("Builder OAuth refresh failed");
|
|
225
|
-
}
|
|
226
|
-
return sessionFrom(next);
|
|
227
|
-
}
|
|
228
|
-
catch {
|
|
229
|
-
await markBuilderOAuthReconnectRequired(ownerEmail);
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
finally {
|
|
233
|
-
await mutateSetting(leaseKey, (current) => current?.owner === owner ? { owner: "", expiresAt: 0 } : (current ?? {}));
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
async function waitForRefreshedSession(ownerEmail) {
|
|
237
|
-
for (let waited = 0; waited < REFRESH_LEASE_MS; waited += REFRESH_WAIT_MS) {
|
|
238
|
-
await new Promise((resolve) => setTimeout(resolve, REFRESH_WAIT_MS));
|
|
239
|
-
const credentials = await readMcpOAuthCredentials(ownerOptions(ownerEmail));
|
|
240
|
-
if (!credentials || !isBuilderCredential(credentials))
|
|
241
|
-
return null;
|
|
242
|
-
if (typeof credentials.tokenExpiresAt !== "number" ||
|
|
243
|
-
credentials.tokenExpiresAt - Date.now() <= REFRESH_SKEW_MS) {
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
return sessionFrom(credentials);
|
|
247
|
-
}
|
|
248
|
-
return null;
|
|
169
|
+
return { ...session, ownerEmail: input.ownerEmail.trim().toLowerCase() };
|
|
249
170
|
}
|
|
250
171
|
export async function deleteBuilderOAuthSession(ownerEmail) {
|
|
251
|
-
const options =
|
|
172
|
+
const options = await resolveOwnerOptions(ownerEmail);
|
|
173
|
+
if (!options)
|
|
174
|
+
return { localDeleted: false, remoteRevoked: false };
|
|
252
175
|
const result = await revokeMcpOAuthCredentials(options);
|
|
253
|
-
await putSetting(reconnectKey(ownerEmail), {
|
|
254
|
-
required: false,
|
|
255
|
-
at: Date.now(),
|
|
256
|
-
}).catch(() => {
|
|
257
|
-
// coercion-ok: reconnect flag clear is best-effort after local revoke.
|
|
258
|
-
});
|
|
259
176
|
return {
|
|
260
177
|
localDeleted: result.local === "deleted",
|
|
261
178
|
remoteRevoked: result.remote === "succeeded",
|
|
@@ -305,6 +305,35 @@ export declare function readLegacyCoreRouteInitSettings(readSetting?: CoreRouteS
|
|
|
305
305
|
*/
|
|
306
306
|
export declare function shouldRunCoreRouteBootDatabaseWork(env?: NodeJS.ProcessEnv): boolean;
|
|
307
307
|
export declare function ensureS3FileUploadProvider(): void;
|
|
308
|
+
export interface OAuthCustodyBuilderKeyStatus {
|
|
309
|
+
privateKeyConfigured: boolean;
|
|
310
|
+
publicKeyConfigured: boolean;
|
|
311
|
+
orgName: string;
|
|
312
|
+
/**
|
|
313
|
+
* True when the key-pair lookup itself failed (credential store
|
|
314
|
+
* unreadable, org lookup error, a thrown import) rather than confirming
|
|
315
|
+
* no keys exist. privateKeyConfigured/publicKeyConfigured stay `false` in
|
|
316
|
+
* both cases — this is the only signal that tells "never configured"
|
|
317
|
+
* apart from "couldn't check right now", so a transient store blip can't
|
|
318
|
+
* read downstream as "the user never connected Builder keys".
|
|
319
|
+
*/
|
|
320
|
+
keyLookupFailed: boolean;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Resolves the classic Builder key-pair status for a request that already
|
|
324
|
+
* has Builder MCP OAuth custody (the connection-status handler's `configured`
|
|
325
|
+
* is already `true` by the time this runs — OAuth alone proves the chat
|
|
326
|
+
* gateway). Exported so the connection-status route's OAuth-custody branch is
|
|
327
|
+
* unit-testable without standing up the full plugin.
|
|
328
|
+
*/
|
|
329
|
+
export declare function resolveOAuthCustodyBuilderKeyStatus(dependencies?: {
|
|
330
|
+
resolveCredentialsDetailed: () => Promise<{
|
|
331
|
+
privateKey: string | null;
|
|
332
|
+
publicKey: string | null;
|
|
333
|
+
orgName: string | null;
|
|
334
|
+
lookupFailed: boolean;
|
|
335
|
+
}>;
|
|
336
|
+
}): Promise<OAuthCustodyBuilderKeyStatus>;
|
|
308
337
|
export declare function createCoreRoutesPlugin(options?: CoreRoutesPluginOptions): NitroPluginDef;
|
|
309
338
|
/**
|
|
310
339
|
* Default core routes plugin — mount with no configuration needed.
|