@agent-native/core 0.79.17 → 0.79.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +14 -0
- package/corpus/core/docs/content/file-uploads.md +11 -4
- package/corpus/core/docs/content/locales/ar-SA/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/de-DE/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/es-ES/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/fr-FR/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/hi-IN/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/ja-JP/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/ko-KR/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/pt-BR/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/zh-CN/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/locales/zh-TW/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/multi-app-workspace.md +3 -3
- package/corpus/core/docs/content/template-clips.md +14 -5
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/builder-engine.ts +8 -3
- package/corpus/core/src/cli/mcp.ts +11 -6
- package/corpus/core/src/client/AssistantChat.tsx +6 -2
- package/corpus/core/src/client/chat/markdown-renderer.tsx +1 -0
- package/corpus/core/src/client/i18n.tsx +77 -65
- package/corpus/core/src/client/index.ts +7 -1
- package/corpus/core/src/client/org/OrgSwitcher.tsx +5 -5
- package/corpus/core/src/client/org/TeamPage.tsx +11 -3
- package/corpus/core/src/client/settings/SettingsTabsPage.tsx +216 -0
- package/corpus/core/src/client/settings/index.ts +5 -0
- package/corpus/core/src/file-upload/index.ts +1 -0
- package/corpus/core/src/file-upload/registry.ts +22 -6
- package/corpus/core/src/file-upload/types.ts +6 -1
- package/corpus/core/src/integrations/adapters/email.ts +26 -18
- package/corpus/core/src/integrations/adapters/slack.ts +8 -7
- package/corpus/core/src/integrations/adapters/telegram.ts +9 -11
- package/corpus/core/src/integrations/adapters/whatsapp.ts +12 -9
- package/corpus/core/src/integrations/plugin.ts +79 -13
- package/corpus/core/src/onboarding/default-steps.ts +6 -3
- package/corpus/core/src/onboarding/types.ts +1 -1
- package/corpus/core/src/org/handlers.ts +1 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +4 -7
- package/corpus/core/src/server/better-auth-instance.ts +19 -62
- package/corpus/core/src/server/core-routes-plugin.ts +93 -180
- package/corpus/core/src/server/create-server.ts +55 -116
- package/corpus/core/src/server/email-actions.ts +3 -6
- package/corpus/core/src/server/email.ts +52 -17
- package/corpus/core/src/server/index.ts +2 -1
- package/corpus/core/src/server/scoped-key-storage.ts +223 -0
- package/corpus/core/src/shared/agent-env.ts +3 -3
- package/corpus/core/src/sharing/actions/share-resource.ts +1 -1
- package/corpus/core/src/styles/agent-native.css +47 -3
- package/corpus/core/src/templates/workspace-root/AGENTS.md +3 -2
- package/corpus/core/src/templates/workspace-root/README.md +1 -1
- package/corpus/core/src/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
- package/corpus/core/src/terminal/pty-server.ts +3 -38
- package/corpus/core/src/triggers/dispatcher.ts +1 -2
- package/corpus/templates/.retired/issues/package.json +7 -0
- package/corpus/templates/.retired/meeting-notes/package.json +7 -0
- package/corpus/templates/.retired/recruiting/package.json +7 -0
- package/corpus/templates/.retired/scheduling/package.json +7 -0
- package/corpus/templates/.retired/voice/package.json +7 -0
- package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -18
- package/corpus/templates/analytics/app/global.css +15 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +7 -1
- package/corpus/templates/analytics/app/i18n-data.ts +71 -2
- package/corpus/templates/analytics/app/pages/Ask.tsx +1 -1
- package/corpus/templates/analytics/app/pages/Settings.tsx +120 -73
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +0 -11
- package/corpus/templates/analytics/app/routes/catalog.tsx +33 -176
- package/corpus/templates/analytics/app/routes/team.tsx +3 -2
- package/corpus/templates/analytics/changelog/2026-06-26-dashboard-templates-are-tucked-into-settings-and-show-simple.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-the-ask-tab-uses-a-softer-dark-gray-canvas-while-sidebar-cha.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-the-sessions-page-shows-a-single-page-title-instead-of-repea.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +37 -28
- package/corpus/templates/assets/app/routes/settings.tsx +65 -43
- package/corpus/templates/assets/app/routes/team.tsx +2 -10
- package/corpus/templates/brain/app/routes/settings.tsx +390 -358
- package/corpus/templates/brain/app/routes/team.tsx +2 -8
- package/corpus/templates/calendar/actions/db-connect.ts +5 -29
- package/corpus/templates/calendar/app/components/CloudUpgrade.tsx +8 -51
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +2 -1
- package/corpus/templates/calendar/app/components/calendar/GoogleSetupWizard.tsx +4 -2
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +0 -2
- package/corpus/templates/calendar/app/pages/Settings.tsx +304 -271
- package/corpus/templates/calendar/app/routes/_app.team.tsx +2 -17
- package/corpus/templates/calendar/server/handlers/google-auth.ts +22 -9
- package/corpus/templates/calendar/server/lib/booking-emails.ts +1 -1
- package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +1 -1
- package/corpus/templates/calendar/server/lib/google-calendar.ts +48 -28
- package/corpus/templates/chat/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +4 -2
- package/corpus/templates/chat/app/routes/settings.tsx +54 -54
- package/corpus/templates/chat/app/routes/team.tsx +2 -10
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +7 -2
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +1 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +7 -0
- package/corpus/templates/clips/AGENTS.md +8 -0
- package/corpus/templates/clips/actions/invite-member.ts +1 -1
- package/corpus/templates/clips/actions/request-transcript.ts +1 -1
- package/corpus/templates/clips/app/components/library/library-layout.tsx +325 -333
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +80 -40
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +2 -0
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +629 -643
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +263 -158
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +10 -2
- package/corpus/templates/clips/changelog/2026-06-26-long-desktop-recordings-are-checkpointed-so-macos-finalizati.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-non-mac-desktop-recordings-wait-for-upload-transcription.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-recording-details-button-stays-at-the-far-right-on-small-screen.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-s3-compatible-storage-keys-now-save-securely-from-clips-sett.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-shared-clip-links-guide-agents-through-processing-transcripts.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-the-agent-sidebar-now-slides-in-smoothly-without-duplicate-e.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-the-clip-details-sidebar-now-collapses-into-a-slide-out-pane.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +55 -3
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +217 -5
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +176 -5
- package/corpus/templates/clips/server/lib/public-agent-context.ts +31 -0
- package/corpus/templates/clips/server/lib/s3-upload-provider.ts +60 -14
- package/corpus/templates/clips/server/lib/video-storage.ts +37 -9
- package/corpus/templates/clips/server/routes/api/agent-transcript.json.get.ts +5 -0
- package/corpus/templates/content/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +1 -0
- package/corpus/templates/content/app/routes/_app.settings.tsx +54 -55
- package/corpus/templates/content/app/routes/_app.team.tsx +2 -28
- package/corpus/templates/content/server/lib/notion.ts +43 -11
- package/corpus/templates/content/server/routes/api/notion/auth-url.get.ts +2 -2
- package/corpus/templates/content/server/routes/api/notion/status.get.ts +3 -3
- package/corpus/templates/design/app/routes/settings.tsx +60 -38
- package/corpus/templates/design/app/routes/team.tsx +2 -10
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +2 -2
- package/corpus/templates/dispatch/app/routes/settings.tsx +70 -55
- package/corpus/templates/dispatch/app/routes/team.tsx +5 -1
- package/corpus/templates/forms/actions/db-connect.ts +7 -36
- package/corpus/templates/forms/actions/navigate.ts +2 -2
- package/corpus/templates/forms/app/components/CloudUpgrade.tsx +8 -47
- package/corpus/templates/forms/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/forms/app/components/layout/Layout.tsx +42 -25
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +35 -76
- package/corpus/templates/forms/app/global.css +9 -25
- package/corpus/templates/forms/app/hooks/use-navigation-state.ts +4 -4
- package/corpus/templates/forms/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/forms/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/forms/app/i18n/en-US.ts +1 -0
- package/corpus/templates/forms/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/forms/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/forms/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/forms/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/forms/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/forms/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/forms/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/forms/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/forms/app/lib/route-prewarm.ts +9 -8
- package/corpus/templates/forms/app/pages/AskPage.tsx +70 -0
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +74 -81
- package/corpus/templates/forms/app/root.tsx +1 -1
- package/corpus/templates/forms/app/routes/_app.ask.tsx +14 -0
- package/corpus/templates/forms/app/routes/_app.settings.tsx +54 -54
- package/corpus/templates/forms/app/routes/_app.team.tsx +2 -9
- package/corpus/templates/forms/app/routes/_index.tsx +21 -130
- package/corpus/templates/forms/changelog/2026-06-26-ask-forms-opens-as-a-standard-app-tab-with-a-simpler-sidebar.md +6 -0
- package/corpus/templates/forms/changelog/2026-06-26-forms-are-shown-in-a-tighter-row-list-with-a-denser-sidebar.md +6 -0
- package/corpus/templates/forms/shared/navigation.ts +4 -2
- package/corpus/templates/macros/app/routes/settings.tsx +54 -54
- package/corpus/templates/macros/app/routes/team.tsx +2 -10
- package/corpus/templates/mail/actions/helpers.ts +2 -2
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +2 -1
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +5 -5
- package/corpus/templates/mail/app/routes/team.tsx +3 -2
- package/corpus/templates/mail/server/handlers/emails.ts +3 -2
- package/corpus/templates/mail/server/handlers/google-auth.ts +19 -12
- package/corpus/templates/mail/server/lib/automation-engine.ts +3 -2
- package/corpus/templates/mail/server/lib/email-state.ts +2 -3
- package/corpus/templates/mail/server/lib/google-auth.ts +28 -11
- package/corpus/templates/mail/server/lib/jobs.ts +3 -2
- package/corpus/templates/mail/server/onboarding.ts +9 -6
- package/corpus/templates/mail/server/routes/api/attachments.get.ts +3 -3
- package/corpus/templates/plan/actions/request-plan-access.ts +1 -1
- package/corpus/templates/plan/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +56 -4
- package/corpus/templates/plan/app/global.css +8 -3
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +4 -2
- package/corpus/templates/plan/app/lib/route-prewarm.ts +0 -4
- package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
- package/corpus/templates/plan/app/routes/settings.tsx +75 -73
- package/corpus/templates/plan/app/routes/team.tsx +2 -8
- package/corpus/templates/plan/changelog/2026-06-26-canvas-grid-panning-now-stays-smooth-and-fills-the-workspace.md +6 -0
- package/corpus/templates/plan/server/lib/comment-notifications.ts +1 -1
- package/corpus/templates/slides/actions/check-image-gen.ts +2 -1
- package/corpus/templates/slides/actions/db-connect.ts +7 -45
- package/corpus/templates/slides/actions/edit-image.ts +6 -3
- package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
- package/corpus/templates/slides/actions/generate-image.ts +2 -2
- package/corpus/templates/slides/actions/generate-slides-ai.ts +5 -3
- package/corpus/templates/slides/actions/image-gen-status.ts +4 -3
- package/corpus/templates/slides/actions/image-search.ts +6 -3
- package/corpus/templates/slides/actions/search-images.ts +6 -3
- package/corpus/templates/slides/app/components/CloudUpgrade.tsx +8 -51
- package/corpus/templates/slides/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -2
- package/corpus/templates/slides/app/routes/settings.tsx +54 -54
- package/corpus/templates/slides/app/routes/team.tsx +2 -12
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +9 -9
- package/corpus/templates/slides/server/handlers/image-gen.ts +5 -1
- package/corpus/templates/slides/server/handlers/image-providers/gemini.ts +9 -1
- package/corpus/templates/slides/server/handlers/image-providers/index.ts +18 -8
- package/corpus/templates/slides/server/handlers/image-providers/openai.ts +10 -4
- package/corpus/templates/slides/server/handlers/image-providers/types.ts +1 -0
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +59 -34
- package/corpus/templates/slides/server/register-secrets.ts +60 -0
- package/corpus/templates/videos/actions/db-connect.ts +7 -45
- package/corpus/templates/videos/app/components/CloudUpgrade.tsx +8 -51
- package/corpus/templates/videos/app/components/Sidebar.tsx +1 -9
- package/corpus/templates/videos/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +0 -3
- package/corpus/templates/videos/app/routes/settings.tsx +54 -54
- package/corpus/templates/videos/app/routes/team.tsx +2 -8
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +8 -3
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +3 -4
- package/dist/cli/mcp.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +6 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
- package/dist/client/chat/markdown-renderer.js +1 -0
- package/dist/client/chat/markdown-renderer.js.map +1 -1
- package/dist/client/i18n.d.ts.map +1 -1
- package/dist/client/i18n.js +20 -9
- package/dist/client/i18n.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts +3 -3
- package/dist/client/org/OrgSwitcher.js +2 -2
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts +6 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +2 -2
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/settings/SettingsTabsPage.d.ts +27 -0
- package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -0
- package/dist/client/settings/SettingsTabsPage.js +108 -0
- package/dist/client/settings/SettingsTabsPage.js.map +1 -0
- package/dist/client/settings/index.d.ts +1 -0
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js +1 -0
- package/dist/client/settings/index.js.map +1 -1
- package/dist/file-upload/index.d.ts +1 -1
- package/dist/file-upload/index.d.ts.map +1 -1
- package/dist/file-upload/index.js +1 -1
- package/dist/file-upload/index.js.map +1 -1
- package/dist/file-upload/registry.d.ts +1 -0
- package/dist/file-upload/registry.d.ts.map +1 -1
- package/dist/file-upload/registry.js +24 -6
- package/dist/file-upload/registry.js.map +1 -1
- package/dist/file-upload/types.d.ts +6 -1
- package/dist/file-upload/types.d.ts.map +1 -1
- package/dist/file-upload/types.js.map +1 -1
- package/dist/integrations/adapters/email.d.ts.map +1 -1
- package/dist/integrations/adapters/email.js +18 -18
- package/dist/integrations/adapters/email.js.map +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +8 -7
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/adapters/telegram.d.ts.map +1 -1
- package/dist/integrations/adapters/telegram.js +9 -9
- package/dist/integrations/adapters/telegram.js.map +1 -1
- package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
- package/dist/integrations/adapters/whatsapp.js +10 -9
- package/dist/integrations/adapters/whatsapp.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +47 -13
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/onboarding/default-steps.d.ts.map +1 -1
- package/dist/onboarding/default-steps.js +6 -5
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/onboarding/types.d.ts +1 -1
- package/dist/onboarding/types.d.ts.map +1 -1
- package/dist/onboarding/types.js.map +1 -1
- package/dist/org/handlers.js +1 -1
- package/dist/org/handlers.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +4 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +2 -2
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +17 -56
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +67 -153
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/create-server.d.ts +3 -9
- package/dist/server/create-server.d.ts.map +1 -1
- package/dist/server/create-server.js +37 -91
- package/dist/server/create-server.js.map +1 -1
- package/dist/server/email-actions.d.ts +2 -3
- package/dist/server/email-actions.d.ts.map +1 -1
- package/dist/server/email-actions.js +3 -6
- package/dist/server/email-actions.js.map +1 -1
- package/dist/server/email.d.ts +3 -3
- package/dist/server/email.d.ts.map +1 -1
- package/dist/server/email.js +40 -19
- package/dist/server/email.js.map +1 -1
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/scoped-key-storage.d.ts +22 -0
- package/dist/server/scoped-key-storage.d.ts.map +1 -0
- package/dist/server/scoped-key-storage.js +152 -0
- package/dist/server/scoped-key-storage.js.map +1 -0
- package/dist/shared/agent-env.d.ts +3 -3
- package/dist/shared/agent-env.d.ts.map +1 -1
- package/dist/shared/agent-env.js +3 -3
- package/dist/shared/agent-env.js.map +1 -1
- package/dist/sharing/actions/share-resource.js +1 -1
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/styles/agent-native.css +47 -3
- package/dist/templates/workspace-root/AGENTS.md +3 -2
- package/dist/templates/workspace-root/README.md +1 -1
- package/dist/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
- package/dist/terminal/pty-server.d.ts.map +1 -1
- package/dist/terminal/pty-server.js +3 -36
- package/dist/terminal/pty-server.js.map +1 -1
- package/dist/triggers/dispatcher.js +1 -1
- package/dist/triggers/dispatcher.js.map +1 -1
- package/docs/content/file-uploads.md +11 -4
- package/docs/content/locales/ar-SA/multi-app-workspace.md +3 -3
- package/docs/content/locales/de-DE/multi-app-workspace.md +3 -3
- package/docs/content/locales/es-ES/multi-app-workspace.md +3 -3
- package/docs/content/locales/fr-FR/multi-app-workspace.md +3 -3
- package/docs/content/locales/hi-IN/multi-app-workspace.md +3 -3
- package/docs/content/locales/ja-JP/multi-app-workspace.md +3 -3
- package/docs/content/locales/ko-KR/multi-app-workspace.md +3 -3
- package/docs/content/locales/pt-BR/multi-app-workspace.md +3 -3
- package/docs/content/locales/zh-CN/multi-app-workspace.md +3 -3
- package/docs/content/locales/zh-TW/multi-app-workspace.md +3 -3
- package/docs/content/multi-app-workspace.md +3 -3
- package/docs/content/template-clips.md +14 -5
- package/package.json +1 -1
- package/src/templates/workspace-root/AGENTS.md +3 -2
- package/src/templates/workspace-root/README.md +1 -1
- package/src/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
- package/corpus/core/src/server/env-var-writes.ts +0 -16
- package/corpus/templates/analytics/app/pages/Team.tsx +0 -9
- package/corpus/templates/calendar/app/pages/Team.tsx +0 -12
- package/corpus/templates/mail/app/pages/Team.tsx +0 -17
- package/dist/server/env-var-writes.d.ts +0 -10
- package/dist/server/env-var-writes.d.ts.map +0 -1
- package/dist/server/env-var-writes.js +0 -18
- package/dist/server/env-var-writes.js.map +0 -1
|
@@ -125,6 +125,8 @@ export async function trackSignupEvent({
|
|
|
125
125
|
// Persistent auth secret
|
|
126
126
|
// ---------------------------------------------------------------------------
|
|
127
127
|
|
|
128
|
+
let inMemoryDevAuthSecret: string | undefined;
|
|
129
|
+
|
|
128
130
|
/**
|
|
129
131
|
* Resolve the Better Auth signing secret.
|
|
130
132
|
*
|
|
@@ -133,13 +135,9 @@ export async function trackSignupEvent({
|
|
|
133
135
|
* 2. Hosted workspace deploys can derive a per-purpose secret from the
|
|
134
136
|
* already-required `A2A_SECRET` root. This keeps fresh workspace branches
|
|
135
137
|
* bootable without reusing the raw A2A key as a cookie-signing key.
|
|
136
|
-
* 3. `.env.local` in the template cwd —
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* it's safe to persist credentials here.
|
|
140
|
-
* 4. Generate a new random 32-byte hex, write it to `.env.local`, and use
|
|
141
|
-
* it. Subsequent restarts re-read the same file — so session cookies
|
|
142
|
-
* signed by a previous boot remain valid across dev-server restarts.
|
|
138
|
+
* 3. Existing `.env.local` values in the template cwd — read-only
|
|
139
|
+
* compatibility for projects that already configured this secret.
|
|
140
|
+
* 4. Generate a per-process in-memory random 32-byte hex in development.
|
|
143
141
|
*
|
|
144
142
|
* Why this matters: before this helper existed, missing `BETTER_AUTH_SECRET`
|
|
145
143
|
* fell through to `GOOGLE_CLIENT_SECRET` / `ACCESS_TOKEN` / a hardcoded
|
|
@@ -147,8 +145,8 @@ export async function trackSignupEvent({
|
|
|
147
145
|
* boot would re-fall back to the hardcoded value (still stable) — but
|
|
148
146
|
* rotating Google credentials, toggling `ACCESS_TOKEN`, or churning the
|
|
149
147
|
* fallback chain would invalidate every signed cookie and force everyone
|
|
150
|
-
* to sign in again.
|
|
151
|
-
*
|
|
148
|
+
* to sign in again. We still read explicit env configuration, but never
|
|
149
|
+
* auto-write a generated secret into env files.
|
|
152
150
|
*/
|
|
153
151
|
function resolveAuthSecret(): string {
|
|
154
152
|
if (process.env.BETTER_AUTH_SECRET) return process.env.BETTER_AUTH_SECRET;
|
|
@@ -177,47 +175,26 @@ function resolveAuthSecret(): string {
|
|
|
177
175
|
);
|
|
178
176
|
}
|
|
179
177
|
|
|
180
|
-
// Dev: persist a generated secret to .env.local so sessions survive
|
|
181
|
-
// dev-server restarts. Falls back to an in-memory random secret only if
|
|
182
|
-
// the filesystem isn't writable (rare in dev, e.g. read-only mounts) —
|
|
183
|
-
// sessions reset on every dev-process restart in that case, which is
|
|
184
|
-
// fine.
|
|
185
|
-
//
|
|
186
178
|
// SECURITY (audit 09 LOW-2): the previous fallback chain
|
|
187
179
|
// (`GOOGLE_CLIENT_SECRET || ACCESS_TOKEN || hardcoded`) reused
|
|
188
180
|
// cross-purpose secrets and a public hardcoded literal as the cookie
|
|
189
181
|
// HMAC. Dropped entirely — better to mint an ephemeral secret than to
|
|
190
182
|
// re-use a Google client secret or a known string.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
process.env.BETTER_AUTH_SECRET = existing; // guard:allow-env-mutation — boot-time secret resolution from .env.local, runs once at module init
|
|
196
|
-
return existing;
|
|
197
|
-
}
|
|
183
|
+
const existing = readEnvLocalSecret(
|
|
184
|
+
path.resolve(process.cwd(), ".env.local"),
|
|
185
|
+
);
|
|
186
|
+
if (existing) return existing;
|
|
198
187
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
process.env.BETTER_AUTH_SECRET = generated; // guard:allow-env-mutation — boot-time secret generation, runs once at module init before any request
|
|
202
|
-
console.log(
|
|
203
|
-
"[agent-native] Generated a persistent BETTER_AUTH_SECRET in .env.local. " +
|
|
204
|
-
"Sessions will now survive dev-server restarts. " +
|
|
205
|
-
"(Delete .env.local to rotate; set BETTER_AUTH_SECRET in .env to override.)",
|
|
206
|
-
);
|
|
207
|
-
return generated;
|
|
208
|
-
} catch {
|
|
209
|
-
// Filesystem unwritable (read-only mount, sandboxed test env, etc.).
|
|
210
|
-
// Mint a per-process random secret so cookies stay unique per boot.
|
|
211
|
-
// Sessions reset when the dev process restarts — acceptable for dev.
|
|
212
|
-
const ephemeral = crypto.randomBytes(32).toString("hex");
|
|
188
|
+
if (!inMemoryDevAuthSecret) {
|
|
189
|
+
inMemoryDevAuthSecret = crypto.randomBytes(32).toString("hex");
|
|
213
190
|
console.warn(
|
|
214
|
-
"[agent-native]
|
|
215
|
-
"
|
|
216
|
-
"
|
|
217
|
-
"
|
|
191
|
+
"[agent-native] BETTER_AUTH_SECRET is not configured. Using an ephemeral " +
|
|
192
|
+
"in-memory development secret. Sessions will reset every time this " +
|
|
193
|
+
"process restarts. Set BETTER_AUTH_SECRET in your environment to keep " +
|
|
194
|
+
"sessions valid across restarts.",
|
|
218
195
|
);
|
|
219
|
-
return ephemeral;
|
|
220
196
|
}
|
|
197
|
+
return inMemoryDevAuthSecret;
|
|
221
198
|
}
|
|
222
199
|
|
|
223
200
|
function readEnvLocalSecret(envLocalPath: string): string | undefined {
|
|
@@ -234,26 +211,6 @@ function readEnvLocalSecret(envLocalPath: string): string | undefined {
|
|
|
234
211
|
}
|
|
235
212
|
}
|
|
236
213
|
|
|
237
|
-
function appendEnvLocalSecret(envLocalPath: string, secret: string): void {
|
|
238
|
-
const header =
|
|
239
|
-
"# Auto-generated by agent-native on first boot. Gitignored.\n" +
|
|
240
|
-
"# Keeps signed session cookies valid across dev-server restarts.\n" +
|
|
241
|
-
"# Delete this file (or this line) to rotate the secret.\n";
|
|
242
|
-
const line = `BETTER_AUTH_SECRET=${secret}\n`;
|
|
243
|
-
|
|
244
|
-
// If the file already exists, just append; otherwise create with header.
|
|
245
|
-
if (fs.existsSync(envLocalPath)) {
|
|
246
|
-
const existing = fs.readFileSync(envLocalPath, "utf8");
|
|
247
|
-
const needsLeadingNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
248
|
-
fs.appendFileSync(
|
|
249
|
-
envLocalPath,
|
|
250
|
-
(needsLeadingNewline ? "\n" : "") + "\n" + header + line,
|
|
251
|
-
);
|
|
252
|
-
} else {
|
|
253
|
-
fs.writeFileSync(envLocalPath, header + line, { mode: 0o600 });
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
214
|
function normalizeTrackingSlug(value: string | undefined): string | undefined {
|
|
258
215
|
const trimmed = value?.trim();
|
|
259
216
|
if (!trimmed) return undefined;
|
|
@@ -912,7 +869,7 @@ async function createBetterAuthInstance(
|
|
|
912
869
|
const appUrl = getAppProductionUrl();
|
|
913
870
|
const cookieNamespace = resolveAuthCookieNamespace();
|
|
914
871
|
const requireEmailVerification =
|
|
915
|
-
isEmailConfigured() && !shouldSkipEmailVerification();
|
|
872
|
+
(await isEmailConfigured()) && !shouldSkipEmailVerification();
|
|
916
873
|
|
|
917
874
|
const shouldMirrorGoogleAccountTokens =
|
|
918
875
|
(config?.googleScopes?.length ?? 0) > 0;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
1
|
import {
|
|
4
2
|
defineEventHandler,
|
|
5
3
|
setResponseStatus,
|
|
@@ -46,7 +44,7 @@ import { mountDbAdminRoutes } from "../db-admin/routes.js";
|
|
|
46
44
|
import { getDbExec } from "../db/client.js";
|
|
47
45
|
import {
|
|
48
46
|
uploadFile,
|
|
49
|
-
|
|
47
|
+
getActiveFileUploadProviderForRequest,
|
|
50
48
|
listFileUploadProviders,
|
|
51
49
|
} from "../file-upload/index.js";
|
|
52
50
|
import { handleMcpConnect } from "../mcp/connect-route.js";
|
|
@@ -57,10 +55,8 @@ import {
|
|
|
57
55
|
} from "../mcp/oauth-route.js";
|
|
58
56
|
import { registerBuiltinNotificationChannels } from "../notifications/channels.js";
|
|
59
57
|
import { createNotificationsHandler } from "../notifications/routes.js";
|
|
60
|
-
import { listOnboardingSteps } from "../onboarding/registry.js";
|
|
61
58
|
import { getOrgContext } from "../org/context.js";
|
|
62
59
|
import { createProgressHandler } from "../progress/routes.js";
|
|
63
|
-
import { findWorkspaceRoot } from "../scripts/utils.js";
|
|
64
60
|
import { registerFrameworkSecrets } from "../secrets/register-framework-secrets.js";
|
|
65
61
|
import {
|
|
66
62
|
createListSecretsHandler,
|
|
@@ -124,14 +120,12 @@ import {
|
|
|
124
120
|
getAllowedCorsOrigin,
|
|
125
121
|
readCorsAllowedOrigins,
|
|
126
122
|
} from "./cors-origins.js";
|
|
127
|
-
import { upsertEnvFile } from "./create-server.js";
|
|
128
123
|
import type { EnvKeyConfig } from "./create-server.js";
|
|
129
124
|
import {
|
|
130
125
|
canUseDeployCredentialFallbackForRequest,
|
|
131
126
|
resolveSecret,
|
|
132
127
|
} from "./credential-provider.js";
|
|
133
128
|
import { createEmbedStartRouteHandler } from "./embed-route.js";
|
|
134
|
-
import { isEnvVarWriteAllowed } from "./env-var-writes.js";
|
|
135
129
|
import {
|
|
136
130
|
getH3App,
|
|
137
131
|
awaitBootstrap,
|
|
@@ -151,6 +145,12 @@ import { createOpenRouteHandler } from "./open-route.js";
|
|
|
151
145
|
import { createPollEventsHandler } from "./poll-events.js";
|
|
152
146
|
import { createPollHandler } from "./poll.js";
|
|
153
147
|
import { runWithRequestContext } from "./request-context.js";
|
|
148
|
+
import {
|
|
149
|
+
findUnsupportedScopedKeyNames,
|
|
150
|
+
saveKeyValuesToScopedSecrets,
|
|
151
|
+
ScopedKeyStorageError,
|
|
152
|
+
type ScopedKeySaveRequestScope,
|
|
153
|
+
} from "./scoped-key-storage.js";
|
|
154
154
|
import { createTranscribeVoiceHandler } from "./transcribe-voice.js";
|
|
155
155
|
import { createVoiceProvidersStatusHandler } from "./voice-providers-status.js";
|
|
156
156
|
|
|
@@ -340,10 +340,6 @@ function parseBuilderCallbackBoolean(
|
|
|
340
340
|
return /^(1|true)$/i.test(value);
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
-
const PROVIDER_ENV_VAR_KEYS = new Set(
|
|
344
|
-
Object.values(PROVIDER_ENV_META).map(({ envVar }) => envVar),
|
|
345
|
-
);
|
|
346
|
-
|
|
347
343
|
// Raster-only data-URI allowlist for avatar writes. SVG is deliberately absent:
|
|
348
344
|
// data:image/svg+xml payloads can carry inline <script> and event-handler
|
|
349
345
|
// attributes that execute when the browser renders them as an <img> src or
|
|
@@ -652,7 +648,7 @@ export interface CoreRoutesPluginOptions {
|
|
|
652
648
|
* GET /_agent-native/ping — health check
|
|
653
649
|
* GET /_agent-native/health — DB liveness probe + scale-to-zero warmup
|
|
654
650
|
* GET /_agent-native/env-status — env key configuration status (when envKeys provided)
|
|
655
|
-
* POST /_agent-native/env-vars —
|
|
651
|
+
* POST /_agent-native/env-vars — compatibility route that saves keys to scoped DB secrets
|
|
656
652
|
* GET /_agent-native/application-state/:key — read application state
|
|
657
653
|
* PUT /_agent-native/application-state/:key — write application state
|
|
658
654
|
* DELETE /_agent-native/application-state/:key — delete application state
|
|
@@ -681,20 +677,9 @@ export function createCoreRoutesPlugin(
|
|
|
681
677
|
try {
|
|
682
678
|
await awaitBootstrap(nitroApp);
|
|
683
679
|
|
|
684
|
-
//
|
|
685
|
-
//
|
|
686
|
-
//
|
|
687
|
-
// vars (Netlify dashboard, process-level) always win.
|
|
688
|
-
//
|
|
689
|
-
// GATED: only rehydrate into `process.env` on local-dev SQLite (or
|
|
690
|
-
// with the explicit single-tenant opt-in). On a shared-DB hosted
|
|
691
|
-
// multi-tenant deploy the `persisted-env-vars` row is deployment-wide
|
|
692
|
-
// global state — pushing user-supplied values into `process.env` from
|
|
693
|
-
// it would let any one tenant's writes (or a stale dev seed) leak
|
|
694
|
-
// into every other tenant's process. The opt-out scrub of legacy
|
|
695
|
-
// BUILDER_* values still runs unconditionally so existing rows on
|
|
696
|
-
// multi-tenant deploys self-heal, but new env-var writes never land
|
|
697
|
-
// in `process.env` outside the allowed contexts.
|
|
680
|
+
// Legacy cleanup: key saves now go to scoped app_secrets rows. Do not
|
|
681
|
+
// rehydrate the old deployment-global `persisted-env-vars` row into
|
|
682
|
+
// process.env; keep only the Builder scrub so stale leaked keys self-heal.
|
|
698
683
|
try {
|
|
699
684
|
const persisted = (await getSetting("persisted-env-vars")) as Record<
|
|
700
685
|
string,
|
|
@@ -702,15 +687,10 @@ export function createCoreRoutesPlugin(
|
|
|
702
687
|
> | null;
|
|
703
688
|
if (persisted) {
|
|
704
689
|
const builderKeys = new Set<string>(BUILDER_ENV_KEYS);
|
|
705
|
-
const writesAllowed = isEnvVarWriteAllowed();
|
|
706
690
|
let scrubbed = 0;
|
|
707
|
-
for (const
|
|
691
|
+
for (const k of Object.keys(persisted)) {
|
|
708
692
|
if (builderKeys.has(k)) {
|
|
709
693
|
scrubbed++;
|
|
710
|
-
continue;
|
|
711
|
-
}
|
|
712
|
-
if (writesAllowed && typeof v === "string" && !process.env[k]) {
|
|
713
|
-
process.env[k] = v;
|
|
714
694
|
}
|
|
715
695
|
}
|
|
716
696
|
if (scrubbed > 0) {
|
|
@@ -2229,24 +2209,7 @@ export function createCoreRoutesPlugin(
|
|
|
2229
2209
|
];
|
|
2230
2210
|
{
|
|
2231
2211
|
const envKeys = [...frameworkEnvKeys, ...(options.envKeys ?? [])];
|
|
2232
|
-
|
|
2233
|
-
// Onboarding form fields are resolved per-request so late-registered
|
|
2234
|
-
// steps (and template overrides) are picked up without a restart.
|
|
2235
|
-
// Builder CLI auth writes scoped Builder credentials through the
|
|
2236
|
-
// credential provider, never through the deploy-global env sink.
|
|
2237
|
-
const collectOnboardingKeys = (): Set<string> => {
|
|
2238
|
-
const keys = new Set<string>();
|
|
2239
|
-
for (const step of listOnboardingSteps()) {
|
|
2240
|
-
for (const method of step.methods) {
|
|
2241
|
-
if (method.kind === "form") {
|
|
2242
|
-
for (const field of method.payload.fields) {
|
|
2243
|
-
if (field?.key) keys.add(field.key);
|
|
2244
|
-
}
|
|
2245
|
-
}
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
return keys;
|
|
2249
|
-
};
|
|
2212
|
+
const allowedEnvKeyNames = envKeys.map(({ key }) => key);
|
|
2250
2213
|
|
|
2251
2214
|
getH3App(nitroApp).use(
|
|
2252
2215
|
`${P}/env-status`,
|
|
@@ -2264,12 +2227,11 @@ export function createCoreRoutesPlugin(
|
|
|
2264
2227
|
}
|
|
2265
2228
|
return Promise.all(
|
|
2266
2229
|
envKeys.map(async (cfg) => {
|
|
2267
|
-
const
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
: !!process.env[cfg.key];
|
|
2230
|
+
const configured =
|
|
2231
|
+
Boolean(process.env[cfg.key]) ||
|
|
2232
|
+
(await runWithRequestContext({ userEmail, orgId }, () =>
|
|
2233
|
+
resolveSecret(cfg.key).then(Boolean),
|
|
2234
|
+
));
|
|
2273
2235
|
return {
|
|
2274
2236
|
key: cfg.key,
|
|
2275
2237
|
label: cfg.label,
|
|
@@ -2290,101 +2252,37 @@ export function createCoreRoutesPlugin(
|
|
|
2290
2252
|
return { error: "Method not allowed" };
|
|
2291
2253
|
}
|
|
2292
2254
|
|
|
2293
|
-
// Env vars are deployment-wide globals, not per-tenant. On any
|
|
2294
|
-
// shared-DB multi-tenant deploy, allowing authenticated users to
|
|
2295
|
-
// write here lets one tenant overwrite Stripe / OpenAI / Sentry
|
|
2296
|
-
// keys for every other tenant. Disable the endpoint outside of
|
|
2297
|
-
// local-dev SQLite or an explicit single-tenant opt-in, and
|
|
2298
|
-
// direct callers to scoped secret/credential stores instead.
|
|
2299
|
-
if (!isEnvVarWriteAllowed()) {
|
|
2300
|
-
setResponseStatus(event, 403);
|
|
2301
|
-
return {
|
|
2302
|
-
error:
|
|
2303
|
-
"env-vars endpoint disabled on multi-tenant deployments. Use scoped secrets or credentials for user/org API keys.",
|
|
2304
|
-
};
|
|
2305
|
-
}
|
|
2306
|
-
|
|
2307
2255
|
const body = await readBody(event);
|
|
2308
|
-
const { vars } = body as {
|
|
2256
|
+
const { vars, scope } = body as {
|
|
2309
2257
|
vars?: Array<{ key: string; value: string }>;
|
|
2258
|
+
scope?: ScopedKeySaveRequestScope;
|
|
2310
2259
|
};
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
return { error: "vars array required" };
|
|
2315
|
-
}
|
|
2316
|
-
|
|
2317
|
-
const allowedKeys = new Set<string>([
|
|
2318
|
-
...envKeys.map((k) => k.key),
|
|
2319
|
-
...collectOnboardingKeys(),
|
|
2320
|
-
]);
|
|
2321
|
-
const blockedEnvVarWriteKeys = new Set<string>(BUILDER_ENV_KEYS);
|
|
2322
|
-
const isWritableEnvKey = (key: string) =>
|
|
2323
|
-
allowedKeys.has(key) && !blockedEnvVarWriteKeys.has(key);
|
|
2324
|
-
|
|
2325
|
-
const filtered = vars.filter(
|
|
2326
|
-
(v) =>
|
|
2327
|
-
typeof v.key === "string" &&
|
|
2328
|
-
isWritableEnvKey(v.key) &&
|
|
2329
|
-
typeof v.value === "string" &&
|
|
2330
|
-
v.value.trim().length > 0,
|
|
2260
|
+
const unsupportedKeys = findUnsupportedScopedKeyNames(
|
|
2261
|
+
vars,
|
|
2262
|
+
allowedEnvKeyNames,
|
|
2331
2263
|
);
|
|
2332
|
-
if (
|
|
2264
|
+
if (unsupportedKeys.length > 0) {
|
|
2333
2265
|
setResponseStatus(event, 400);
|
|
2334
|
-
const rejectedEmpty = vars.some(
|
|
2335
|
-
(v) =>
|
|
2336
|
-
typeof v.key === "string" &&
|
|
2337
|
-
isWritableEnvKey(v.key) &&
|
|
2338
|
-
(typeof v.value !== "string" || v.value.trim().length === 0),
|
|
2339
|
-
);
|
|
2340
2266
|
return {
|
|
2341
|
-
error:
|
|
2342
|
-
? "Env values must be non-empty — refusing to clear a saved key"
|
|
2343
|
-
: "No recognized env keys in request",
|
|
2267
|
+
error: `Unsupported env key${unsupportedKeys.length === 1 ? "" : "s"}: ${unsupportedKeys.join(", ")}`,
|
|
2344
2268
|
};
|
|
2345
2269
|
}
|
|
2346
2270
|
|
|
2347
|
-
// Write to .env file. When inside a workspace, write to the
|
|
2348
|
-
// workspace root .env so keys are shared across every app. The
|
|
2349
|
-
// per-app .env still wins at load time if it also defines a key.
|
|
2350
2271
|
try {
|
|
2351
|
-
const
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
// Update process.env immediately
|
|
2366
|
-
for (const { key, value } of filtered) {
|
|
2367
|
-
process.env[key] = value;
|
|
2368
|
-
}
|
|
2369
|
-
|
|
2370
|
-
// Persist to settings table for serverless cold-start recovery.
|
|
2371
|
-
try {
|
|
2372
|
-
const envMap: Record<string, string> = {};
|
|
2373
|
-
for (const { key, value } of filtered) envMap[key] = value;
|
|
2374
|
-
const existing =
|
|
2375
|
-
((await getSetting("persisted-env-vars")) as Record<
|
|
2376
|
-
string,
|
|
2377
|
-
string
|
|
2378
|
-
> | null) ?? {};
|
|
2379
|
-
await putSetting("persisted-env-vars", {
|
|
2380
|
-
...existing,
|
|
2381
|
-
...envMap,
|
|
2382
|
-
});
|
|
2383
|
-
} catch {
|
|
2384
|
-
// DB not ready yet — skip
|
|
2272
|
+
const result = await saveKeyValuesToScopedSecrets(
|
|
2273
|
+
event,
|
|
2274
|
+
vars,
|
|
2275
|
+
scope,
|
|
2276
|
+
);
|
|
2277
|
+
return { saved: result.saved, storage: "scoped-secrets" };
|
|
2278
|
+
} catch (err) {
|
|
2279
|
+
if (err instanceof ScopedKeyStorageError) {
|
|
2280
|
+
setResponseStatus(event, err.statusCode);
|
|
2281
|
+
return { error: err.message };
|
|
2282
|
+
}
|
|
2283
|
+
setResponseStatus(event, 500);
|
|
2284
|
+
return { error: "Failed to save keys" };
|
|
2385
2285
|
}
|
|
2386
|
-
|
|
2387
|
-
return { saved: filtered.map((v) => v.key) };
|
|
2388
2286
|
}),
|
|
2389
2287
|
);
|
|
2390
2288
|
}
|
|
@@ -2729,54 +2627,69 @@ export function createCoreRoutesPlugin(
|
|
|
2729
2627
|
getH3App(nitroApp).use(
|
|
2730
2628
|
`${P}/file-upload/status`,
|
|
2731
2629
|
defineEventHandler(async (event) => {
|
|
2732
|
-
const active = getActiveFileUploadProvider();
|
|
2733
2630
|
// resolveBuilderPrivateKey() reads per-user credentials from app_secrets
|
|
2734
2631
|
// (DB), which requires request context (AsyncLocalStorage) to know which
|
|
2735
2632
|
// user to scope by. Without runWithRequestContext() the ALS store is empty
|
|
2736
2633
|
// and it falls back to process.env only — missing OAuth-connected users.
|
|
2737
2634
|
const session = await getSession(event).catch(() => null);
|
|
2738
2635
|
const userEmail = session?.email;
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2636
|
+
const resolveStatus = async () => {
|
|
2637
|
+
const active = await getActiveFileUploadProviderForRequest();
|
|
2638
|
+
let builderConfigured = !!process.env.BUILDER_PRIVATE_KEY;
|
|
2639
|
+
try {
|
|
2640
|
+
const { resolveBuilderPrivateKey } =
|
|
2641
|
+
await import("./credential-provider.js");
|
|
2642
|
+
builderConfigured = await resolveBuilderPrivateKey().then(
|
|
2643
|
+
(k) => !!k,
|
|
2644
|
+
);
|
|
2645
|
+
} catch {
|
|
2646
|
+
// fall back to env check above
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
const providers = await Promise.all(
|
|
2650
|
+
listFileUploadProviders().map(async (p) => {
|
|
2651
|
+
const scopedConfigured = p.isConfiguredForRequest
|
|
2652
|
+
? await p.isConfiguredForRequest().catch(() => false)
|
|
2653
|
+
: false;
|
|
2654
|
+
return {
|
|
2655
|
+
id: p.id,
|
|
2656
|
+
name: p.name,
|
|
2657
|
+
configured: p.isConfigured() || scopedConfigured,
|
|
2658
|
+
};
|
|
2659
|
+
}),
|
|
2660
|
+
);
|
|
2661
|
+
|
|
2662
|
+
// When the builder builtin is selected via env var, its sync
|
|
2663
|
+
// isConfigured() doesn't reflect per-user OAuth credentials. Use
|
|
2664
|
+
// builderConfigured so status reflects this specific request.
|
|
2665
|
+
const isBuilderEnvActive = active?.id === "builder";
|
|
2666
|
+
const configured = isBuilderEnvActive
|
|
2667
|
+
? builderConfigured
|
|
2668
|
+
: !!active || builderConfigured;
|
|
2669
|
+
const activeProvider = isBuilderEnvActive
|
|
2670
|
+
? builderConfigured
|
|
2768
2671
|
? { id: "builder", name: "Builder.io" }
|
|
2769
|
-
: null
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2672
|
+
: null
|
|
2673
|
+
: active
|
|
2674
|
+
? { id: active.id, name: active.name }
|
|
2675
|
+
: builderConfigured
|
|
2676
|
+
? { id: "builder", name: "Builder.io" }
|
|
2677
|
+
: null;
|
|
2678
|
+
|
|
2679
|
+
return {
|
|
2680
|
+
configured,
|
|
2681
|
+
activeProvider,
|
|
2682
|
+
providers,
|
|
2683
|
+
builderConfigured,
|
|
2684
|
+
};
|
|
2779
2685
|
};
|
|
2686
|
+
|
|
2687
|
+
return userEmail
|
|
2688
|
+
? runWithRequestContext(
|
|
2689
|
+
{ userEmail, orgId: session?.orgId },
|
|
2690
|
+
resolveStatus,
|
|
2691
|
+
)
|
|
2692
|
+
: resolveStatus();
|
|
2780
2693
|
}),
|
|
2781
2694
|
);
|
|
2782
2695
|
|