@agent-native/core 0.92.0 → 0.92.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +14 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/application-state/store.ts +12 -1
- package/corpus/core/src/client/AssistantChat.tsx +27 -14
- package/corpus/core/src/client/PoweredByBadge.tsx +1 -8
- package/corpus/core/src/client/agent-chat-adapter.ts +37 -10
- package/corpus/core/src/client/chat/widgets/DataTableWidget.tsx +52 -1
- package/corpus/core/src/client/db-admin/TableEditor.tsx +49 -0
- package/corpus/core/src/client/db-admin/export-utils.ts +13 -4
- package/corpus/core/src/client/db-admin/useAgentSync.ts +72 -0
- package/corpus/core/src/client/error-capture.ts +69 -7
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +5 -1
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +53 -8
- package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +5 -1
- package/corpus/core/src/client/extensions/portable-extension.ts +1 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +12 -9
- package/corpus/core/src/client/org/TeamPage.tsx +77 -71
- package/corpus/core/src/client/settings/SettingsPanel.tsx +205 -52
- package/corpus/core/src/client/settings/SettingsSection.tsx +8 -1
- package/corpus/core/src/client/settings/SettingsTabsPage.tsx +25 -9
- package/corpus/core/src/db-admin/agent-tools.ts +8 -2
- package/corpus/core/src/db-admin/operations.ts +116 -4
- package/corpus/core/src/db-admin/routes.ts +1 -0
- package/corpus/core/src/db-admin/types.ts +4 -0
- package/corpus/core/src/extensions/html-shell.ts +5 -4
- package/corpus/core/src/extensions/routes.ts +10 -0
- package/corpus/core/src/navigation/index.ts +1 -1
- package/corpus/core/src/resources/handlers.ts +10 -8
- package/corpus/core/src/server/poll.ts +293 -8
- package/corpus/core/src/styles/agent-native.css +27 -0
- package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +7 -0
- package/corpus/core/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/core/src/templates/default/AGENTS.md +4 -2
- package/corpus/core/src/templates/headless/AGENTS.md +4 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/core/src/templates/workspace-core/AGENTS.md +7 -1
- package/corpus/core/src/templates/workspace-root/AGENTS.md +7 -1
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/analytics/AGENTS.md +33 -14
- package/corpus/templates/analytics/actions/capture-test-error.ts +4 -0
- package/corpus/templates/analytics/actions/get-analytics-alert-rule-defaults.ts +23 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +1 -1
- package/corpus/templates/analytics/actions/list-analysis-revisions.ts +40 -0
- package/corpus/templates/analytics/actions/list-dashboard-revisions.ts +40 -0
- package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +299 -0
- package/corpus/templates/analytics/actions/navigate.ts +4 -2
- package/corpus/templates/analytics/actions/restore-analysis-revision.ts +43 -0
- package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +68 -0
- package/corpus/templates/analytics/actions/save-analytics-alert-rule.ts +14 -0
- package/corpus/templates/analytics/actions/save-monitor.ts +1 -1
- package/corpus/templates/analytics/actions/view-screen.ts +24 -0
- package/corpus/templates/analytics/app/components/analysis/AnalysisHistoryPanel.tsx +181 -0
- package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +184 -0
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +22 -16
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +27 -21
- package/corpus/templates/analytics/app/hooks/use-analysis-revisions.ts +43 -0
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +110 -0
- package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +43 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +8 -3
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +64 -2
- package/corpus/templates/analytics/app/i18n-data.ts +783 -3
- package/corpus/templates/analytics/app/pages/Agents.tsx +359 -19
- package/corpus/templates/analytics/app/pages/Settings.tsx +3 -2
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +34 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +28 -0
- package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +18 -1
- package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +7 -10
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +479 -23
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +0 -9
- package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +11 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +9 -1
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +6 -3
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +26 -30
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +9 -99
- package/corpus/templates/analytics/app/pages/settings/AlertRulesSettingsCard.tsx +262 -104
- package/corpus/templates/analytics/app/routes/team.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-07-08-admins-can-audit-dashboard-usage-ownership-and-cleanup-signa.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-agent-monitoring-stays-available-to-non-admins.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-alert-rules-are-easier-to-scan-expand-and-edit-from-settings.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-forms-remember-last-email-recipients.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-rules-can-now-use-per-rule-slack-and-webhook.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-usage-now-counts-explorer-dashboard-traffic.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-demo-mode-session-emails-are-filtered-and-anonymized.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-adds-stack-traces-and-frequency-bars.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-now-shows-the-latest-occurrence-message-a.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-monitoring-errors-only-show-test-action-when-empty.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-production-session-replay-now-requires-private-blob-storage-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-shared-extension-links-now-show-a-clear-message-when-you-do-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-team-settings-show-access-controls-next-to-member-lists.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-uptime-monitors-now-use-a-10-second-request-timeout-by-defau.md +6 -0
- package/corpus/templates/analytics/server/db/schema-monitoring.ts +1 -1
- package/corpus/templates/analytics/server/db/schema.ts +56 -0
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +92 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +334 -5
- package/corpus/templates/analytics/server/lib/error-capture.ts +231 -36
- package/corpus/templates/analytics/server/lib/session-replay.ts +114 -8
- package/corpus/templates/analytics/server/lib/uptime-monitors.ts +5 -4
- package/corpus/templates/analytics/server/plugins/db.ts +112 -2
- package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +1 -0
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/assets/AGENTS.md +4 -0
- package/corpus/templates/assets/app/routes/settings.tsx +1 -1
- package/corpus/templates/assets/app/routes/team.tsx +1 -1
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/brain/AGENTS.md +4 -0
- package/corpus/templates/brain/app/routes/team.tsx +1 -1
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/calendar/AGENTS.md +4 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +11 -2
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +21 -8
- package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +7 -1
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -2
- package/corpus/templates/calendar/app/lib/popover-click-guard.ts +48 -4
- package/corpus/templates/calendar/app/pages/Settings.tsx +1 -1
- package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-07-08-clicking-empty-calendar-space-closes-an-open-event-popover-b.md +6 -0
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/chat/AGENTS.md +4 -0
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/chat/app/routes/settings.tsx +2 -2
- package/corpus/templates/chat/app/routes/team.tsx +1 -1
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/finalize-recording.ts +9 -3
- package/corpus/templates/clips/actions/set-thumbnail.ts +11 -2
- package/corpus/templates/clips/app/components/meetings/canvas-editor.tsx +1 -7
- package/corpus/templates/clips/app/components/player/player-controls.tsx +21 -13
- package/corpus/templates/clips/app/components/player/video-player.tsx +30 -75
- package/corpus/templates/clips/app/i18n/ar-SA.ts +6 -5
- package/corpus/templates/clips/app/i18n/de-DE.ts +6 -6
- package/corpus/templates/clips/app/i18n/en-US.ts +6 -5
- package/corpus/templates/clips/app/i18n/es-ES.ts +6 -5
- package/corpus/templates/clips/app/i18n/fr-FR.ts +6 -6
- package/corpus/templates/clips/app/i18n/hi-IN.ts +6 -5
- package/corpus/templates/clips/app/i18n/ja-JP.ts +6 -5
- package/corpus/templates/clips/app/i18n/ko-KR.ts +6 -5
- package/corpus/templates/clips/app/i18n/pt-BR.ts +6 -5
- package/corpus/templates/clips/app/i18n/zh-CN.ts +6 -5
- package/corpus/templates/clips/app/i18n/zh-TW.ts +6 -5
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +51 -118
- package/corpus/templates/clips/changelog/2026-07-08-hosted-clip-uploads-now-clear-failed-buffered-chunks.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-hosted-recording-uploads-now-avoid-sql-chunk-storage.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-meeting-recaps-now-keep-summaries-action-items-and-transcrip.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-video-playback-controls-now-match-loom-style-5-second-skips-.md +6 -0
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +63 -0
- package/corpus/templates/clips/server/lib/video-storage.ts +4 -0
- package/corpus/templates/clips/server/routes/api/recordings/[recordingId]/thumbnail.post.ts +19 -13
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +40 -1
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/content/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/content/AGENTS.md +4 -0
- package/corpus/templates/content/app/routes/_app.settings.tsx +2 -2
- package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/design/AGENTS.md +4 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +12 -9
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +57 -13
- package/corpus/templates/design/app/routes/team.tsx +1 -1
- package/corpus/templates/design/changelog/2026-07-08-local-images-added-to-designs-now-upload-to-file-storage-ins.md +6 -0
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/dispatch/AGENTS.md +4 -0
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/dispatch/app/routes/settings.tsx +2 -2
- package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/forms/AGENTS.md +4 -0
- package/corpus/templates/forms/app/routes/_app.settings.tsx +2 -2
- package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/forms/shared/navigation.ts +1 -1
- package/corpus/templates/macros/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/macros/AGENTS.md +4 -0
- package/corpus/templates/macros/app/routes/settings.tsx +2 -2
- package/corpus/templates/macros/app/routes/team.tsx +1 -1
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +5 -1
- package/corpus/templates/mail/AGENTS.md +4 -0
- package/corpus/templates/mail/changelog/2026-07-08-mail-attachments-in-hosted-environments-now-require-file-sto.md +6 -0
- package/corpus/templates/mail/server/handlers/media.ts +26 -1
- package/corpus/templates/mail/server/lib/outgoing-email.ts +24 -1
- package/corpus/templates/mail/server/lib/upload-store.ts +2 -1
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/plan/AGENTS.md +4 -0
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/plan/app/routes/settings.tsx +2 -2
- package/corpus/templates/plan/app/routes/team.tsx +1 -1
- package/corpus/templates/plan/changelog/2026-07-08-hosted-plan-images-now-require-connected-storage.md +6 -0
- package/corpus/templates/plan/server/lib/plan-assets.ts +33 -4
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +7 -0
- package/corpus/templates/slides/AGENTS.md +4 -0
- package/corpus/templates/slides/actions/generate-image-api.ts +15 -3
- package/corpus/templates/slides/app/routes/settings.tsx +2 -2
- package/corpus/templates/slides/app/routes/team.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-07-08-generated-slide-images-now-return-hosted-file-storage-urls-i.md +6 -0
- package/corpus/templates/slides/shared/api.ts +1 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +8 -2
- package/dist/application-state/store.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +24 -13
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/PoweredByBadge.d.ts +1 -1
- package/dist/client/PoweredByBadge.d.ts.map +1 -1
- package/dist/client/PoweredByBadge.js +3 -9
- package/dist/client/PoweredByBadge.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +28 -9
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
- package/dist/client/chat/widgets/DataTableWidget.js +19 -2
- package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
- package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
- package/dist/client/db-admin/TableEditor.js +19 -2
- package/dist/client/db-admin/TableEditor.js.map +1 -1
- package/dist/client/db-admin/export-utils.d.ts +2 -0
- package/dist/client/db-admin/export-utils.d.ts.map +1 -1
- package/dist/client/db-admin/export-utils.js +11 -3
- package/dist/client/db-admin/export-utils.js.map +1 -1
- package/dist/client/db-admin/useAgentSync.d.ts.map +1 -1
- package/dist/client/db-admin/useAgentSync.js +63 -0
- package/dist/client/db-admin/useAgentSync.js.map +1 -1
- package/dist/client/error-capture.d.ts.map +1 -1
- package/dist/client/error-capture.js +41 -7
- package/dist/client/error-capture.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +3 -1
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +32 -5
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.js +3 -1
- package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
- package/dist/client/extensions/portable-extension.d.ts.map +1 -1
- package/dist/client/extensions/portable-extension.js +1 -0
- package/dist/client/extensions/portable-extension.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +11 -6
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +5 -5
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +37 -14
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/SettingsSection.js +1 -1
- package/dist/client/settings/SettingsSection.js.map +1 -1
- package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
- package/dist/client/settings/SettingsTabsPage.js +21 -10
- package/dist/client/settings/SettingsTabsPage.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db-admin/agent-tools.d.ts.map +1 -1
- package/dist/db-admin/agent-tools.js +7 -2
- package/dist/db-admin/agent-tools.js.map +1 -1
- package/dist/db-admin/operations.d.ts.map +1 -1
- package/dist/db-admin/operations.js +90 -4
- package/dist/db-admin/operations.js.map +1 -1
- package/dist/db-admin/routes.d.ts.map +1 -1
- package/dist/db-admin/routes.js +1 -0
- package/dist/db-admin/routes.js.map +1 -1
- package/dist/db-admin/types.d.ts +4 -0
- package/dist/db-admin/types.d.ts.map +1 -1
- package/dist/db-admin/types.js.map +1 -1
- package/dist/extensions/html-shell.d.ts +5 -4
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/routes.d.ts.map +1 -1
- package/dist/extensions/routes.js +8 -0
- package/dist/extensions/routes.js.map +1 -1
- package/dist/navigation/index.d.ts +1 -1
- package/dist/navigation/index.d.ts.map +1 -1
- package/dist/navigation/index.js +1 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +6 -1
- package/dist/resources/handlers.d.ts.map +1 -1
- package/dist/resources/handlers.js +9 -8
- package/dist/resources/handlers.js.map +1 -1
- package/dist/server/poll.d.ts +12 -4
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +236 -9
- package/dist/server/poll.js.map +1 -1
- package/dist/styles/agent-native.css +27 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/default/.agents/skills/security/SKILL.md +7 -0
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
- package/dist/templates/default/AGENTS.md +4 -2
- package/dist/templates/headless/AGENTS.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
- package/dist/templates/workspace-core/AGENTS.md +7 -1
- package/dist/templates/workspace-root/AGENTS.md +7 -1
- package/package.json +1 -1
- package/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/default/.agents/skills/security/SKILL.md +7 -0
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
- package/src/templates/default/AGENTS.md +4 -2
- package/src/templates/headless/AGENTS.md +4 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
- package/src/templates/workspace-core/AGENTS.md +7 -1
- package/src/templates/workspace-root/AGENTS.md +7 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/db-admin/operations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Database admin operations.\n *\n * Pure, dialect-agnostic, RAW/UNSCOPED helpers backing the Supabase-Studio-like\n * DB admin. These run the FULL database with no per-user `accessFilter`\n * scoping. Callers MUST gate access before invoking them. The built-in core\n * route gates this to dev + localhost; production-reachable surfaces must pass\n * an explicit runtime for the target database and enforce their own admin-only\n * checks before reading or mutating.\n *\n * All access goes through the unified `getDbExec()` client, which uses `?`\n * placeholders (auto-converted to `$1,$2,…` for Postgres) and returns rows\n * keyed by column name. Identifiers are validated against a strict pattern and\n * always double-quoted; values are ALWAYS parameterized — never interpolated.\n */\nimport {\n getDbExec,\n getDialect,\n type DbExec,\n type Dialect,\n} from \"../db/client.js\";\nimport { notifyActionChange } from \"../server/action-change.js\";\nimport type {\n DbAdminColumn,\n DbAdminDialect,\n DbAdminFilter,\n DbAdminForeignKey,\n DbAdminIndex,\n DbAdminMutation,\n DbAdminMutationResult,\n DbAdminQueryResult,\n DbAdminRowsRequest,\n DbAdminRowsResult,\n DbAdminTableSchema,\n DbAdminTableSummary,\n} from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Identifier validation + quoting\n// ---------------------------------------------------------------------------\n\nconst IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport interface DbAdminRuntime {\n db?: DbExec;\n dialect?: Dialect;\n notifyChange?: () => Promise<void>;\n}\n\n/** Throw on any identifier that isn't a plain `[A-Za-z_][A-Za-z0-9_]*`. */\nfunction assertIdent(name: string, kind = \"identifier\"): string {\n if (typeof name !== \"string\" || !IDENT_RE.test(name)) {\n throw new Error(`Invalid ${kind}: ${JSON.stringify(name)}`);\n }\n return name;\n}\n\n/** Double-quote an already-validated identifier (valid in PG and SQLite). */\nfunction quoteIdent(name: string): string {\n return `\"${assertIdent(name)}\"`;\n}\n\nfunction db(runtime?: DbAdminRuntime): DbExec {\n return runtime?.db ?? getDbExec();\n}\n\nfunction dialect(runtime?: DbAdminRuntime): DbAdminDialect {\n return (runtime?.dialect ?? getDialect()) as DbAdminDialect;\n}\n\nfunction isPostgresRuntime(runtime?: DbAdminRuntime): boolean {\n return dialect(runtime) === \"postgres\";\n}\n\n// ---------------------------------------------------------------------------\n// Notify the UI after a real mutation so polling refetches.\n// ---------------------------------------------------------------------------\n\nasync function notifyDbAdminChange(runtime?: DbAdminRuntime): Promise<void> {\n if (runtime?.notifyChange) {\n await runtime.notifyChange();\n return;\n }\n // The UI keys on useChangeVersions([\"db-admin\",\"action\"]). notifyActionChange\n // records a \"db-admin\" change AND a marker; the action route layer's generic\n // \"action\" source is covered by passing the db-admin action name through the\n // same primitive that the action surface uses.\n await notifyActionChange({ actionName: \"db-admin\" }).catch(() => {});\n}\n\n// ---------------------------------------------------------------------------\n// listTables\n// ---------------------------------------------------------------------------\n\nexport async function listTables(runtime?: DbAdminRuntime): Promise<{\n dialect: DbAdminDialect;\n tables: DbAdminTableSummary[];\n}> {\n const client = db(runtime);\n const summaries: DbAdminTableSummary[] = [];\n\n if (isPostgresRuntime(runtime)) {\n const res = await client.execute(\n `SELECT table_name AS name, table_type AS type\n FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_type IN ('BASE TABLE', 'VIEW')\n ORDER BY table_name`,\n );\n for (const row of res.rows) {\n const name = String((row as any).name);\n const type = (row as any).type === \"VIEW\" ? \"view\" : \"table\";\n summaries.push({\n name,\n type,\n rowCount: type === \"view\" ? null : await safeRowCount(name, runtime),\n });\n }\n } else {\n const res = await client.execute(\n `SELECT name, type FROM sqlite_master\n WHERE type IN ('table', 'view')\n AND name NOT LIKE 'sqlite_%'\n ORDER BY name`,\n );\n for (const row of res.rows) {\n const name = String((row as any).name);\n const type = (row as any).type === \"view\" ? \"view\" : \"table\";\n summaries.push({\n name,\n type,\n rowCount: type === \"view\" ? null : await safeRowCount(name, runtime),\n });\n }\n }\n\n return { dialect: dialect(runtime), tables: summaries };\n}\n\nasync function safeRowCount(\n table: string,\n runtime?: DbAdminRuntime,\n): Promise<number | null> {\n try {\n const client = db(runtime);\n const res = await client.execute(\n `SELECT COUNT(*) AS c FROM ${quoteIdent(table)}`,\n );\n const c = (res.rows[0] as any)?.c;\n const n = Number(c);\n return Number.isFinite(n) ? n : null;\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// getTableSchema\n// ---------------------------------------------------------------------------\n\nexport async function getTableSchema(\n table: string,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminTableSchema> {\n assertIdent(table, \"table name\");\n return isPostgresRuntime(runtime)\n ? getTableSchemaPostgres(table, runtime)\n : getTableSchemaSqlite(table, runtime);\n}\n\nasync function getTableSchemaPostgres(\n table: string,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminTableSchema> {\n const client = db(runtime);\n\n const typeRes = await client.execute({\n sql: `SELECT table_type AS type FROM information_schema.tables\n WHERE table_schema = 'public' AND table_name = ?`,\n args: [table],\n });\n const type = (typeRes.rows[0] as any)?.type === \"VIEW\" ? \"view\" : \"table\";\n\n const colRes = await client.execute({\n sql: `SELECT\n column_name AS name,\n data_type AS type,\n CASE WHEN is_nullable = 'NO' THEN 0 ELSE 1 END AS nullable,\n column_default AS dflt\n FROM information_schema.columns\n WHERE table_schema = 'public' AND table_name = ?\n ORDER BY ordinal_position`,\n args: [table],\n });\n\n const pkRes = await client.execute({\n sql: `SELECT kcu.column_name AS col\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.table_name = ?\n AND tc.table_schema = 'public'\n AND tc.constraint_type = 'PRIMARY KEY'\n ORDER BY kcu.ordinal_position`,\n args: [table],\n });\n const primaryKey = pkRes.rows.map((r) => String((r as any).col));\n const pkSet = new Set(primaryKey);\n\n const fkRes = await client.execute({\n sql: `SELECT\n kcu.column_name AS col,\n ccu.table_name AS ref_table,\n ccu.column_name AS ref_col\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n AND tc.table_schema = ccu.table_schema\n WHERE tc.table_name = ?\n AND tc.table_schema = 'public'\n AND tc.constraint_type = 'FOREIGN KEY'`,\n args: [table],\n });\n const foreignKeys: DbAdminForeignKey[] = fkRes.rows.map((r) => ({\n column: String((r as any).col),\n refTable: String((r as any).ref_table),\n refColumn: String((r as any).ref_col),\n }));\n\n const idxRes = await client.execute({\n sql: `SELECT indexname AS name, indexdef AS def\n FROM pg_indexes\n WHERE schemaname = 'public' AND tablename = ?`,\n args: [table],\n });\n const indexes: DbAdminIndex[] = idxRes.rows.map((r) => {\n const def = String((r as any).def ?? \"\");\n const colMatch = def.match(/\\(([^)]+)\\)/);\n const columns = colMatch\n ? colMatch[1]\n .split(\",\")\n .map((c) => c.trim().replace(/^\"|\"$/g, \"\"))\n .filter(Boolean)\n : [];\n return {\n name: String((r as any).name),\n unique: /\\bUNIQUE\\b/i.test(def),\n columns,\n };\n });\n\n const columns: DbAdminColumn[] = colRes.rows.map((r) => {\n const name = String((r as any).name);\n const dflt = (r as any).dflt;\n const defaultValue = dflt == null ? null : String(dflt);\n return {\n name,\n type: String((r as any).type ?? \"ANY\"),\n nullable: Number((r as any).nullable) === 1,\n pk: pkSet.has(name),\n defaultValue,\n // Postgres serial/identity columns default to a sequence call.\n autoIncrement:\n defaultValue != null &&\n (/nextval\\(/i.test(defaultValue) || /identity/i.test(defaultValue)),\n };\n });\n\n return {\n name: table,\n type,\n columns,\n primaryKey,\n foreignKeys,\n indexes,\n rowCount: type === \"view\" ? null : await safeRowCount(table, runtime),\n };\n}\n\nasync function getTableSchemaSqlite(\n table: string,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminTableSchema> {\n const client = db(runtime);\n\n const typeRes = await client.execute({\n sql: `SELECT type FROM sqlite_master WHERE name = ? AND type IN ('table','view')`,\n args: [table],\n });\n const type = (typeRes.rows[0] as any)?.type === \"view\" ? \"view\" : \"table\";\n\n const colRes = await client.execute(\n `PRAGMA table_info(${quoteIdent(table)})`,\n );\n const columns: DbAdminColumn[] = colRes.rows.map((r) => {\n const name = String((r as any).name);\n const dflt = (r as any).dflt_value;\n return {\n name,\n type: String((r as any).type ?? \"ANY\") || \"ANY\",\n nullable: Number((r as any).notnull) === 0,\n pk: Number((r as any).pk) > 0,\n defaultValue: dflt == null ? null : String(dflt),\n };\n });\n\n // PK order follows the pk index from table_info (1-based, 0 = not pk).\n const primaryKey = colRes.rows\n .filter((r) => Number((r as any).pk) > 0)\n .sort((a, b) => Number((a as any).pk) - Number((b as any).pk))\n .map((r) => String((r as any).name));\n\n // INTEGER PRIMARY KEY in SQLite is an alias for the rowid (autoincrementing).\n if (primaryKey.length === 1) {\n const pkCol = columns.find((c) => c.name === primaryKey[0]);\n if (pkCol && /^integer$/i.test(pkCol.type)) {\n pkCol.autoIncrement = true;\n }\n }\n\n const fkRes = await client.execute(\n `PRAGMA foreign_key_list(${quoteIdent(table)})`,\n );\n const foreignKeys: DbAdminForeignKey[] = fkRes.rows.map((r) => ({\n column: String((r as any).from),\n refTable: String((r as any).table),\n refColumn: String((r as any).to),\n }));\n\n const idxListRes = await client.execute(\n `PRAGMA index_list(${quoteIdent(table)})`,\n );\n const indexes: DbAdminIndex[] = [];\n for (const idx of idxListRes.rows) {\n const idxName = String((idx as any).name);\n if (idxName.startsWith(\"sqlite_\")) continue;\n const infoRes = await client.execute(\n `PRAGMA index_info(${quoteIdent(idxName)})`,\n );\n indexes.push({\n name: idxName,\n unique: Number((idx as any).unique) === 1,\n columns: infoRes.rows\n .map((c) => (c as any).name)\n .filter((n): n is string => typeof n === \"string\"),\n });\n }\n\n return {\n name: table,\n type,\n columns,\n primaryKey,\n foreignKeys,\n indexes,\n rowCount: type === \"view\" ? null : await safeRowCount(table, runtime),\n };\n}\n\n// ---------------------------------------------------------------------------\n// getRows\n// ---------------------------------------------------------------------------\n\nconst SAFE_OPS = new Set([\n \"eq\",\n \"neq\",\n \"lt\",\n \"lte\",\n \"gt\",\n \"gte\",\n \"like\",\n \"ilike\",\n \"in\",\n \"is_null\",\n \"not_null\",\n]);\n\nconst OP_SQL: Record<string, string> = {\n eq: \"=\",\n neq: \"<>\",\n lt: \"<\",\n lte: \"<=\",\n gt: \">\",\n gte: \">=\",\n like: \"LIKE\",\n};\n\n/** Build a parameterized WHERE clause + args from filters. */\nfunction buildWhere(\n filters: DbAdminFilter[] | undefined,\n runtime?: DbAdminRuntime,\n): {\n clause: string;\n args: unknown[];\n} {\n if (!filters || filters.length === 0) return { clause: \"\", args: [] };\n const parts: string[] = [];\n const args: unknown[] = [];\n for (const f of filters) {\n const col = quoteIdent(f.column);\n if (!SAFE_OPS.has(f.op)) {\n throw new Error(`Invalid filter op: ${JSON.stringify(f.op)}`);\n }\n switch (f.op) {\n case \"is_null\":\n parts.push(`${col} IS NULL`);\n break;\n case \"not_null\":\n parts.push(`${col} IS NOT NULL`);\n break;\n case \"in\": {\n const values = Array.isArray(f.value) ? f.value : [f.value];\n if (values.length === 0) {\n // `col IN ()` is invalid SQL; an empty set matches nothing.\n parts.push(`1 = 0`);\n break;\n }\n parts.push(`${col} IN (${values.map(() => \"?\").join(\", \")})`);\n args.push(...values);\n break;\n }\n case \"ilike\": {\n // SQLite LIKE is case-insensitive for ASCII by default; Postgres has\n // a dedicated ILIKE operator.\n if (isPostgresRuntime(runtime)) {\n parts.push(`${col} ILIKE ?`);\n } else {\n parts.push(`${col} LIKE ?`);\n }\n args.push(f.value);\n break;\n }\n default: {\n parts.push(`${col} ${OP_SQL[f.op]} ?`);\n args.push(f.value);\n break;\n }\n }\n }\n return { clause: parts.length ? ` WHERE ${parts.join(\" AND \")}` : \"\", args };\n}\n\nfunction buildOrderBy(sort: DbAdminRowsRequest[\"sort\"]): string {\n if (!sort || sort.length === 0) return \"\";\n const parts = sort.map((s) => {\n const dir = s.dir === \"desc\" ? \"DESC\" : \"ASC\";\n return `${quoteIdent(s.column)} ${dir}`;\n });\n return ` ORDER BY ${parts.join(\", \")}`;\n}\n\nexport async function getRows(\n table: string,\n req: DbAdminRowsRequest,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminRowsResult> {\n assertIdent(table, \"table name\");\n const client = db(runtime);\n const schema = await getTableSchema(table, runtime);\n\n const page = Math.max(1, Math.floor(req.page) || 1);\n const pageSize = Math.min(1000, Math.max(1, Math.floor(req.pageSize) || 50));\n const offset = (page - 1) * pageSize;\n\n const where = buildWhere(req.filters, runtime);\n const orderBy = buildOrderBy(req.sort);\n const quoted = quoteIdent(table);\n\n const countRes = await client.execute({\n sql: `SELECT COUNT(*) AS c FROM ${quoted}${where.clause}`,\n args: where.args,\n });\n const total = Number((countRes.rows[0] as any)?.c ?? 0) || 0;\n\n const rowsRes = await client.execute({\n sql: `SELECT * FROM ${quoted}${where.clause}${orderBy} LIMIT ? OFFSET ?`,\n args: [...where.args, pageSize, offset],\n });\n\n return {\n columns: schema.columns,\n rows: rowsRes.rows as Record<string, unknown>[],\n total,\n page,\n pageSize,\n };\n}\n\n// ---------------------------------------------------------------------------\n// applyMutations\n// ---------------------------------------------------------------------------\n\nfunction buildInsert(\n table: string,\n row: Record<string, unknown>,\n): { sql: string; args: unknown[] } {\n const cols = Object.keys(row);\n if (cols.length === 0) {\n throw new Error(\"Cannot insert an empty row\");\n }\n cols.forEach((c) => assertIdent(c, \"column name\"));\n const sql = `INSERT INTO ${quoteIdent(table)} (${cols\n .map(quoteIdent)\n .join(\", \")}) VALUES (${cols.map(() => \"?\").join(\", \")})`;\n return { sql, args: cols.map((c) => row[c]) };\n}\n\nfunction buildUpdate(\n table: string,\n set: Record<string, unknown>,\n where: Record<string, unknown>,\n): { sql: string; args: unknown[] } {\n const setCols = Object.keys(set);\n const whereCols = Object.keys(where);\n if (setCols.length === 0) throw new Error(\"Update requires a non-empty set\");\n if (whereCols.length === 0) {\n throw new Error(\"Update requires a non-empty where clause\");\n }\n setCols.forEach((c) => assertIdent(c, \"column name\"));\n whereCols.forEach((c) => assertIdent(c, \"column name\"));\n const setSql = setCols.map((c) => `${quoteIdent(c)} = ?`).join(\", \");\n const whereSql = whereCols.map((c) => `${quoteIdent(c)} = ?`).join(\" AND \");\n const sql = `UPDATE ${quoteIdent(table)} SET ${setSql} WHERE ${whereSql}`;\n return {\n sql,\n args: [...setCols.map((c) => set[c]), ...whereCols.map((c) => where[c])],\n };\n}\n\nfunction buildDelete(\n table: string,\n where: Record<string, unknown>,\n): { sql: string; args: unknown[] } {\n const whereCols = Object.keys(where);\n if (whereCols.length === 0) {\n throw new Error(\"Delete requires a non-empty where clause\");\n }\n whereCols.forEach((c) => assertIdent(c, \"column name\"));\n const whereSql = whereCols.map((c) => `${quoteIdent(c)} = ?`).join(\" AND \");\n const sql = `DELETE FROM ${quoteIdent(table)} WHERE ${whereSql}`;\n return { sql, args: whereCols.map((c) => where[c]) };\n}\n\nexport async function applyMutations(\n table: string,\n m: DbAdminMutation,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminMutationResult> {\n assertIdent(table, \"table name\");\n\n const statements: { sql: string; args: unknown[] }[] = [];\n for (const row of m.inserts ?? []) statements.push(buildInsert(table, row));\n for (const u of m.updates ?? []) {\n statements.push(buildUpdate(table, u.set, u.where));\n }\n for (const where of m.deletes ?? []) {\n statements.push(buildDelete(table, where));\n }\n\n const result: DbAdminMutationResult = {\n sql: statements.map((s) => s.sql),\n inserted: 0,\n updated: 0,\n deleted: 0,\n };\n\n if (m.dryRun) {\n // dryRun returns the SQL strings WITHOUT executing.\n return result;\n }\n\n // getDbExec() does not expose a transaction handle, so statements run\n // sequentially. A failure mid-batch surfaces as a thrown error with the\n // counts accumulated so far; callers should treat a partial batch as a\n // failure and re-run with a corrected payload.\n const client = db(runtime);\n const insertCount = m.inserts?.length ?? 0;\n const updateCount = m.updates?.length ?? 0;\n\n let executed = 0;\n for (const stmt of statements) {\n const res = await client.execute({ sql: stmt.sql, args: stmt.args });\n if (executed < insertCount) {\n result.inserted += 1;\n } else if (executed < insertCount + updateCount) {\n result.updated += res.rowsAffected || 0;\n } else {\n result.deleted += res.rowsAffected || 0;\n }\n executed += 1;\n }\n\n if (statements.length > 0) await notifyDbAdminChange(runtime);\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// runSql\n// ---------------------------------------------------------------------------\n\n/** Error thrown when a destructive statement is run without confirmation. */\nexport class DbAdminConfirmRequiredError extends Error {\n readonly needsConfirm = true;\n constructor(message: string) {\n super(message);\n this.name = \"DbAdminConfirmRequiredError\";\n }\n}\n\n/** Strip `--` line comments and `/* *\\/` block comments from SQL. */\nfunction stripComments(sql: string): string {\n return sql.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \").replace(/--[^\\n\\r]*/g, \" \");\n}\n\nfunction isMutatingSql(sql: string): boolean {\n const head = stripComments(sql).trim().toLowerCase();\n return /^(insert|update|delete|replace|create|alter|drop|truncate|merge|pragma\\s+\\w+\\s*=)/.test(\n head,\n );\n}\n\n/** Detect destructive ops on comment-stripped SQL. */\nfunction isDestructiveSql(sql: string): boolean {\n const cleaned = stripComments(sql).trim();\n const lower = cleaned.toLowerCase();\n if (/^drop\\b/.test(lower)) return true;\n if (/^truncate\\b/.test(lower)) return true;\n if (/^delete\\b/.test(lower) && !/\\bwhere\\b/.test(lower)) return true;\n if (/^update\\b/.test(lower) && !/\\bwhere\\b/.test(lower)) return true;\n return false;\n}\n\n/** A leading SELECT (or CTE that ends in SELECT) with no LIMIT clause. */\nfunction isBareSelectWithoutLimit(sql: string): boolean {\n const cleaned = stripComments(sql).trim();\n const lower = cleaned.toLowerCase();\n const isSelect = /^(select|with)\\b/.test(lower);\n if (!isSelect) return false;\n if (/\\blimit\\b/.test(lower)) return false;\n return true;\n}\n\nexport async function runSql(\n sql: string,\n params: unknown[] | undefined,\n opts: { confirmDestructive?: boolean } = {},\n runtime?: DbAdminRuntime,\n): Promise<DbAdminQueryResult> {\n if (typeof sql !== \"string\" || !sql.trim()) {\n throw new Error(\"SQL is required\");\n }\n\n if (isDestructiveSql(sql) && !opts.confirmDestructive) {\n throw new DbAdminConfirmRequiredError(\n \"This statement is destructive (DROP / TRUNCATE / unscoped DELETE or UPDATE). Re-run with confirmDestructive: true to proceed.\",\n );\n }\n\n // Guardrail: auto-append LIMIT 100 to a bare SELECT so an accidental\n // full-table scan can't dump a huge result set.\n let finalSql = sql.trim().replace(/;\\s*$/, \"\");\n if (isBareSelectWithoutLimit(finalSql)) {\n finalSql = `${finalSql} LIMIT 100`;\n }\n\n const client = db(runtime);\n const started = Date.now();\n const res = await client.execute(\n params && params.length > 0 ? { sql: finalSql, args: params } : finalSql,\n );\n const durationMs = Date.now() - started;\n\n const rows = (res.rows ?? []) as Record<string, unknown>[];\n const columns =\n rows.length > 0 && rows[0] && typeof rows[0] === \"object\"\n ? Object.keys(rows[0])\n : [];\n\n if (isMutatingSql(finalSql)) await notifyDbAdminChange(runtime);\n\n return {\n columns,\n rows,\n rowsAffected: res.rowsAffected ?? 0,\n durationMs,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/db-admin/operations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Database admin operations.\n *\n * Pure, dialect-agnostic, RAW/UNSCOPED helpers backing the Supabase-Studio-like\n * DB admin. These run the FULL database with no per-user `accessFilter`\n * scoping. Callers MUST gate access before invoking them. The built-in core\n * route gates this to dev + localhost; production-reachable surfaces must pass\n * an explicit runtime for the target database and enforce their own admin-only\n * checks before reading or mutating.\n *\n * All access goes through the unified `getDbExec()` client, which uses `?`\n * placeholders (auto-converted to `$1,$2,…` for Postgres) and returns rows\n * keyed by column name. Identifiers are validated against a strict pattern and\n * always double-quoted; values are ALWAYS parameterized — never interpolated.\n */\nimport {\n getDbExec,\n getDialect,\n type DbExec,\n type Dialect,\n} from \"../db/client.js\";\nimport { notifyActionChange } from \"../server/action-change.js\";\nimport type {\n DbAdminColumn,\n DbAdminDialect,\n DbAdminFilter,\n DbAdminForeignKey,\n DbAdminIndex,\n DbAdminMutation,\n DbAdminMutationResult,\n DbAdminQueryResult,\n DbAdminRowsRequest,\n DbAdminRowsResult,\n DbAdminTableSchema,\n DbAdminTableSummary,\n} from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Identifier validation + quoting\n// ---------------------------------------------------------------------------\n\nconst IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\nconst LARGE_CELL_PREVIEW_CHARS = 16 * 1024;\nconst LARGE_CELL_SUFFIX =\n \"\\n...[db-admin truncated large cell; request includeLargeCells=true for the full value]\";\n\nexport interface DbAdminRuntime {\n db?: DbExec;\n dialect?: Dialect;\n notifyChange?: () => Promise<void>;\n}\n\n/** Throw on any identifier that isn't a plain `[A-Za-z_][A-Za-z0-9_]*`. */\nfunction assertIdent(name: string, kind = \"identifier\"): string {\n if (typeof name !== \"string\" || !IDENT_RE.test(name)) {\n throw new Error(`Invalid ${kind}: ${JSON.stringify(name)}`);\n }\n return name;\n}\n\n/** Double-quote an already-validated identifier (valid in PG and SQLite). */\nfunction quoteIdent(name: string): string {\n return `\"${assertIdent(name)}\"`;\n}\n\nfunction db(runtime?: DbAdminRuntime): DbExec {\n return runtime?.db ?? getDbExec();\n}\n\nfunction dialect(runtime?: DbAdminRuntime): DbAdminDialect {\n return (runtime?.dialect ?? getDialect()) as DbAdminDialect;\n}\n\nfunction isPostgresRuntime(runtime?: DbAdminRuntime): boolean {\n return dialect(runtime) === \"postgres\";\n}\n\nfunction isPreviewableLargeColumn(column: DbAdminColumn): boolean {\n const type = column.type.toLowerCase();\n return /\\b(text|char|varchar|character|jsonb?|xml|clob)\\b/.test(type);\n}\n\nfunction markLargeValuePreviewColumns(\n columns: DbAdminColumn[],\n includeLargeCells: boolean,\n): DbAdminColumn[] {\n if (includeLargeCells) return columns;\n return columns.map((column) =>\n isPreviewableLargeColumn(column)\n ? { ...column, largeValuePreview: true }\n : column,\n );\n}\n\nfunction buildRowsSelectList(\n columns: DbAdminColumn[],\n includeLargeCells: boolean,\n): string {\n if (includeLargeCells) {\n return columns.map((column) => quoteIdent(column.name)).join(\", \");\n }\n\n return columns\n .map((column) => {\n const quoted = quoteIdent(column.name);\n if (!isPreviewableLargeColumn(column)) return quoted;\n const textValue = `CAST(${quoted} AS TEXT)`;\n return `CASE WHEN length(${textValue}) > ${LARGE_CELL_PREVIEW_CHARS} THEN substr(${textValue}, 1, ${LARGE_CELL_PREVIEW_CHARS}) || '${LARGE_CELL_SUFFIX.replace(/'/g, \"''\")}' ELSE ${textValue} END AS ${quoted}`;\n })\n .join(\", \");\n}\n\nfunction truncateLargeResultCells(rows: Record<string, unknown>[]): {\n rows: Record<string, unknown>[];\n truncatedCells: number;\n} {\n let truncatedCells = 0;\n const mapped = rows.map((row) => {\n let changed = false;\n const next: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) {\n if (\n typeof value === \"string\" &&\n value.length > LARGE_CELL_PREVIEW_CHARS\n ) {\n next[key] =\n `${value.slice(0, LARGE_CELL_PREVIEW_CHARS)}${LARGE_CELL_SUFFIX}`;\n truncatedCells += 1;\n changed = true;\n } else {\n next[key] = value;\n }\n }\n return changed ? next : row;\n });\n return { rows: mapped, truncatedCells };\n}\n\nfunction countTruncatedResultCells(rows: Record<string, unknown>[]): number {\n let truncatedCells = 0;\n for (const row of rows) {\n for (const value of Object.values(row)) {\n if (typeof value === \"string\" && value.endsWith(LARGE_CELL_SUFFIX)) {\n truncatedCells += 1;\n }\n }\n }\n return truncatedCells;\n}\n\nfunction containsLargeCellPreview(value: unknown): boolean {\n if (typeof value === \"string\") return value.endsWith(LARGE_CELL_SUFFIX);\n if (Array.isArray(value)) return value.some(containsLargeCellPreview);\n if (value && typeof value === \"object\") {\n return Object.values(value as Record<string, unknown>).some(\n containsLargeCellPreview,\n );\n }\n return false;\n}\n\nfunction assertNoLargeCellPreviewMutation(\n row: Record<string, unknown>,\n context: string,\n): void {\n for (const [column, value] of Object.entries(row)) {\n if (containsLargeCellPreview(value)) {\n throw new Error(\n `Refusing to ${context} with previewed large-cell value in column \"${column}\". Reload the row with includeLargeCells=true before saving.`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Notify the UI after a real mutation so polling refetches.\n// ---------------------------------------------------------------------------\n\nasync function notifyDbAdminChange(runtime?: DbAdminRuntime): Promise<void> {\n if (runtime?.notifyChange) {\n await runtime.notifyChange();\n return;\n }\n // The UI keys on useChangeVersions([\"db-admin\",\"action\"]). notifyActionChange\n // records a \"db-admin\" change AND a marker; the action route layer's generic\n // \"action\" source is covered by passing the db-admin action name through the\n // same primitive that the action surface uses.\n await notifyActionChange({ actionName: \"db-admin\" }).catch(() => {});\n}\n\n// ---------------------------------------------------------------------------\n// listTables\n// ---------------------------------------------------------------------------\n\nexport async function listTables(runtime?: DbAdminRuntime): Promise<{\n dialect: DbAdminDialect;\n tables: DbAdminTableSummary[];\n}> {\n const client = db(runtime);\n const summaries: DbAdminTableSummary[] = [];\n\n if (isPostgresRuntime(runtime)) {\n const res = await client.execute(\n `SELECT table_name AS name, table_type AS type\n FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_type IN ('BASE TABLE', 'VIEW')\n ORDER BY table_name`,\n );\n for (const row of res.rows) {\n const name = String((row as any).name);\n const type = (row as any).type === \"VIEW\" ? \"view\" : \"table\";\n summaries.push({\n name,\n type,\n rowCount: type === \"view\" ? null : await safeRowCount(name, runtime),\n });\n }\n } else {\n const res = await client.execute(\n `SELECT name, type FROM sqlite_master\n WHERE type IN ('table', 'view')\n AND name NOT LIKE 'sqlite_%'\n ORDER BY name`,\n );\n for (const row of res.rows) {\n const name = String((row as any).name);\n const type = (row as any).type === \"view\" ? \"view\" : \"table\";\n summaries.push({\n name,\n type,\n rowCount: type === \"view\" ? null : await safeRowCount(name, runtime),\n });\n }\n }\n\n return { dialect: dialect(runtime), tables: summaries };\n}\n\nasync function safeRowCount(\n table: string,\n runtime?: DbAdminRuntime,\n): Promise<number | null> {\n try {\n const client = db(runtime);\n const res = await client.execute(\n `SELECT COUNT(*) AS c FROM ${quoteIdent(table)}`,\n );\n const c = (res.rows[0] as any)?.c;\n const n = Number(c);\n return Number.isFinite(n) ? n : null;\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// getTableSchema\n// ---------------------------------------------------------------------------\n\nexport async function getTableSchema(\n table: string,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminTableSchema> {\n assertIdent(table, \"table name\");\n return isPostgresRuntime(runtime)\n ? getTableSchemaPostgres(table, runtime)\n : getTableSchemaSqlite(table, runtime);\n}\n\nasync function getTableSchemaPostgres(\n table: string,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminTableSchema> {\n const client = db(runtime);\n\n const typeRes = await client.execute({\n sql: `SELECT table_type AS type FROM information_schema.tables\n WHERE table_schema = 'public' AND table_name = ?`,\n args: [table],\n });\n const type = (typeRes.rows[0] as any)?.type === \"VIEW\" ? \"view\" : \"table\";\n\n const colRes = await client.execute({\n sql: `SELECT\n column_name AS name,\n data_type AS type,\n CASE WHEN is_nullable = 'NO' THEN 0 ELSE 1 END AS nullable,\n column_default AS dflt\n FROM information_schema.columns\n WHERE table_schema = 'public' AND table_name = ?\n ORDER BY ordinal_position`,\n args: [table],\n });\n\n const pkRes = await client.execute({\n sql: `SELECT kcu.column_name AS col\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.table_name = ?\n AND tc.table_schema = 'public'\n AND tc.constraint_type = 'PRIMARY KEY'\n ORDER BY kcu.ordinal_position`,\n args: [table],\n });\n const primaryKey = pkRes.rows.map((r) => String((r as any).col));\n const pkSet = new Set(primaryKey);\n\n const fkRes = await client.execute({\n sql: `SELECT\n kcu.column_name AS col,\n ccu.table_name AS ref_table,\n ccu.column_name AS ref_col\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n AND tc.table_schema = ccu.table_schema\n WHERE tc.table_name = ?\n AND tc.table_schema = 'public'\n AND tc.constraint_type = 'FOREIGN KEY'`,\n args: [table],\n });\n const foreignKeys: DbAdminForeignKey[] = fkRes.rows.map((r) => ({\n column: String((r as any).col),\n refTable: String((r as any).ref_table),\n refColumn: String((r as any).ref_col),\n }));\n\n const idxRes = await client.execute({\n sql: `SELECT indexname AS name, indexdef AS def\n FROM pg_indexes\n WHERE schemaname = 'public' AND tablename = ?`,\n args: [table],\n });\n const indexes: DbAdminIndex[] = idxRes.rows.map((r) => {\n const def = String((r as any).def ?? \"\");\n const colMatch = def.match(/\\(([^)]+)\\)/);\n const columns = colMatch\n ? colMatch[1]\n .split(\",\")\n .map((c) => c.trim().replace(/^\"|\"$/g, \"\"))\n .filter(Boolean)\n : [];\n return {\n name: String((r as any).name),\n unique: /\\bUNIQUE\\b/i.test(def),\n columns,\n };\n });\n\n const columns: DbAdminColumn[] = colRes.rows.map((r) => {\n const name = String((r as any).name);\n const dflt = (r as any).dflt;\n const defaultValue = dflt == null ? null : String(dflt);\n return {\n name,\n type: String((r as any).type ?? \"ANY\"),\n nullable: Number((r as any).nullable) === 1,\n pk: pkSet.has(name),\n defaultValue,\n // Postgres serial/identity columns default to a sequence call.\n autoIncrement:\n defaultValue != null &&\n (/nextval\\(/i.test(defaultValue) || /identity/i.test(defaultValue)),\n };\n });\n\n return {\n name: table,\n type,\n columns,\n primaryKey,\n foreignKeys,\n indexes,\n rowCount: type === \"view\" ? null : await safeRowCount(table, runtime),\n };\n}\n\nasync function getTableSchemaSqlite(\n table: string,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminTableSchema> {\n const client = db(runtime);\n\n const typeRes = await client.execute({\n sql: `SELECT type FROM sqlite_master WHERE name = ? AND type IN ('table','view')`,\n args: [table],\n });\n const type = (typeRes.rows[0] as any)?.type === \"view\" ? \"view\" : \"table\";\n\n const colRes = await client.execute(\n `PRAGMA table_info(${quoteIdent(table)})`,\n );\n const columns: DbAdminColumn[] = colRes.rows.map((r) => {\n const name = String((r as any).name);\n const dflt = (r as any).dflt_value;\n return {\n name,\n type: String((r as any).type ?? \"ANY\") || \"ANY\",\n nullable: Number((r as any).notnull) === 0,\n pk: Number((r as any).pk) > 0,\n defaultValue: dflt == null ? null : String(dflt),\n };\n });\n\n // PK order follows the pk index from table_info (1-based, 0 = not pk).\n const primaryKey = colRes.rows\n .filter((r) => Number((r as any).pk) > 0)\n .sort((a, b) => Number((a as any).pk) - Number((b as any).pk))\n .map((r) => String((r as any).name));\n\n // INTEGER PRIMARY KEY in SQLite is an alias for the rowid (autoincrementing).\n if (primaryKey.length === 1) {\n const pkCol = columns.find((c) => c.name === primaryKey[0]);\n if (pkCol && /^integer$/i.test(pkCol.type)) {\n pkCol.autoIncrement = true;\n }\n }\n\n const fkRes = await client.execute(\n `PRAGMA foreign_key_list(${quoteIdent(table)})`,\n );\n const foreignKeys: DbAdminForeignKey[] = fkRes.rows.map((r) => ({\n column: String((r as any).from),\n refTable: String((r as any).table),\n refColumn: String((r as any).to),\n }));\n\n const idxListRes = await client.execute(\n `PRAGMA index_list(${quoteIdent(table)})`,\n );\n const indexes: DbAdminIndex[] = [];\n for (const idx of idxListRes.rows) {\n const idxName = String((idx as any).name);\n if (idxName.startsWith(\"sqlite_\")) continue;\n const infoRes = await client.execute(\n `PRAGMA index_info(${quoteIdent(idxName)})`,\n );\n indexes.push({\n name: idxName,\n unique: Number((idx as any).unique) === 1,\n columns: infoRes.rows\n .map((c) => (c as any).name)\n .filter((n): n is string => typeof n === \"string\"),\n });\n }\n\n return {\n name: table,\n type,\n columns,\n primaryKey,\n foreignKeys,\n indexes,\n rowCount: type === \"view\" ? null : await safeRowCount(table, runtime),\n };\n}\n\n// ---------------------------------------------------------------------------\n// getRows\n// ---------------------------------------------------------------------------\n\nconst SAFE_OPS = new Set([\n \"eq\",\n \"neq\",\n \"lt\",\n \"lte\",\n \"gt\",\n \"gte\",\n \"like\",\n \"ilike\",\n \"in\",\n \"is_null\",\n \"not_null\",\n]);\n\nconst OP_SQL: Record<string, string> = {\n eq: \"=\",\n neq: \"<>\",\n lt: \"<\",\n lte: \"<=\",\n gt: \">\",\n gte: \">=\",\n like: \"LIKE\",\n};\n\n/** Build a parameterized WHERE clause + args from filters. */\nfunction buildWhere(\n filters: DbAdminFilter[] | undefined,\n runtime?: DbAdminRuntime,\n): {\n clause: string;\n args: unknown[];\n} {\n if (!filters || filters.length === 0) return { clause: \"\", args: [] };\n const parts: string[] = [];\n const args: unknown[] = [];\n for (const f of filters) {\n const col = quoteIdent(f.column);\n if (!SAFE_OPS.has(f.op)) {\n throw new Error(`Invalid filter op: ${JSON.stringify(f.op)}`);\n }\n switch (f.op) {\n case \"is_null\":\n parts.push(`${col} IS NULL`);\n break;\n case \"not_null\":\n parts.push(`${col} IS NOT NULL`);\n break;\n case \"in\": {\n const values = Array.isArray(f.value) ? f.value : [f.value];\n if (values.length === 0) {\n // `col IN ()` is invalid SQL; an empty set matches nothing.\n parts.push(`1 = 0`);\n break;\n }\n parts.push(`${col} IN (${values.map(() => \"?\").join(\", \")})`);\n args.push(...values);\n break;\n }\n case \"ilike\": {\n // SQLite LIKE is case-insensitive for ASCII by default; Postgres has\n // a dedicated ILIKE operator.\n if (isPostgresRuntime(runtime)) {\n parts.push(`${col} ILIKE ?`);\n } else {\n parts.push(`${col} LIKE ?`);\n }\n args.push(f.value);\n break;\n }\n default: {\n parts.push(`${col} ${OP_SQL[f.op]} ?`);\n args.push(f.value);\n break;\n }\n }\n }\n return { clause: parts.length ? ` WHERE ${parts.join(\" AND \")}` : \"\", args };\n}\n\nfunction buildOrderBy(sort: DbAdminRowsRequest[\"sort\"]): string {\n if (!sort || sort.length === 0) return \"\";\n const parts = sort.map((s) => {\n const dir = s.dir === \"desc\" ? \"DESC\" : \"ASC\";\n return `${quoteIdent(s.column)} ${dir}`;\n });\n return ` ORDER BY ${parts.join(\", \")}`;\n}\n\nexport async function getRows(\n table: string,\n req: DbAdminRowsRequest,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminRowsResult> {\n assertIdent(table, \"table name\");\n const client = db(runtime);\n const schema = await getTableSchema(table, runtime);\n\n const page = Math.max(1, Math.floor(req.page) || 1);\n const pageSize = Math.min(1000, Math.max(1, Math.floor(req.pageSize) || 50));\n const offset = (page - 1) * pageSize;\n\n const where = buildWhere(req.filters, runtime);\n const orderBy = buildOrderBy(req.sort);\n const quoted = quoteIdent(table);\n const includeLargeCells = req.includeLargeCells === true;\n const selectList = buildRowsSelectList(schema.columns, includeLargeCells);\n\n const countRes = await client.execute({\n sql: `SELECT COUNT(*) AS c FROM ${quoted}${where.clause}`,\n args: where.args,\n });\n const total = Number((countRes.rows[0] as any)?.c ?? 0) || 0;\n\n const rowsRes = await client.execute({\n sql: `SELECT ${selectList} FROM ${quoted}${where.clause}${orderBy} LIMIT ? OFFSET ?`,\n args: [...where.args, pageSize, offset],\n });\n const rows = rowsRes.rows as Record<string, unknown>[];\n\n return {\n columns: markLargeValuePreviewColumns(schema.columns, includeLargeCells),\n rows,\n total,\n page,\n pageSize,\n truncatedCells: includeLargeCells ? 0 : countTruncatedResultCells(rows),\n };\n}\n\n// ---------------------------------------------------------------------------\n// applyMutations\n// ---------------------------------------------------------------------------\n\nfunction buildInsert(\n table: string,\n row: Record<string, unknown>,\n): { sql: string; args: unknown[] } {\n const cols = Object.keys(row);\n if (cols.length === 0) {\n throw new Error(\"Cannot insert an empty row\");\n }\n assertNoLargeCellPreviewMutation(row, \"insert\");\n cols.forEach((c) => assertIdent(c, \"column name\"));\n const sql = `INSERT INTO ${quoteIdent(table)} (${cols\n .map(quoteIdent)\n .join(\", \")}) VALUES (${cols.map(() => \"?\").join(\", \")})`;\n return { sql, args: cols.map((c) => row[c]) };\n}\n\nfunction buildUpdate(\n table: string,\n set: Record<string, unknown>,\n where: Record<string, unknown>,\n): { sql: string; args: unknown[] } {\n const setCols = Object.keys(set);\n const whereCols = Object.keys(where);\n if (setCols.length === 0) throw new Error(\"Update requires a non-empty set\");\n if (whereCols.length === 0) {\n throw new Error(\"Update requires a non-empty where clause\");\n }\n assertNoLargeCellPreviewMutation(set, \"update\");\n assertNoLargeCellPreviewMutation(where, \"match rows\");\n setCols.forEach((c) => assertIdent(c, \"column name\"));\n whereCols.forEach((c) => assertIdent(c, \"column name\"));\n const setSql = setCols.map((c) => `${quoteIdent(c)} = ?`).join(\", \");\n const whereSql = whereCols.map((c) => `${quoteIdent(c)} = ?`).join(\" AND \");\n const sql = `UPDATE ${quoteIdent(table)} SET ${setSql} WHERE ${whereSql}`;\n return {\n sql,\n args: [...setCols.map((c) => set[c]), ...whereCols.map((c) => where[c])],\n };\n}\n\nfunction buildDelete(\n table: string,\n where: Record<string, unknown>,\n): { sql: string; args: unknown[] } {\n const whereCols = Object.keys(where);\n if (whereCols.length === 0) {\n throw new Error(\"Delete requires a non-empty where clause\");\n }\n assertNoLargeCellPreviewMutation(where, \"delete\");\n whereCols.forEach((c) => assertIdent(c, \"column name\"));\n const whereSql = whereCols.map((c) => `${quoteIdent(c)} = ?`).join(\" AND \");\n const sql = `DELETE FROM ${quoteIdent(table)} WHERE ${whereSql}`;\n return { sql, args: whereCols.map((c) => where[c]) };\n}\n\nexport async function applyMutations(\n table: string,\n m: DbAdminMutation,\n runtime?: DbAdminRuntime,\n): Promise<DbAdminMutationResult> {\n assertIdent(table, \"table name\");\n\n const statements: { sql: string; args: unknown[] }[] = [];\n for (const row of m.inserts ?? []) statements.push(buildInsert(table, row));\n for (const u of m.updates ?? []) {\n statements.push(buildUpdate(table, u.set, u.where));\n }\n for (const where of m.deletes ?? []) {\n statements.push(buildDelete(table, where));\n }\n\n const result: DbAdminMutationResult = {\n sql: statements.map((s) => s.sql),\n inserted: 0,\n updated: 0,\n deleted: 0,\n };\n\n if (m.dryRun) {\n // dryRun returns the SQL strings WITHOUT executing.\n return result;\n }\n\n // getDbExec() does not expose a transaction handle, so statements run\n // sequentially. A failure mid-batch surfaces as a thrown error with the\n // counts accumulated so far; callers should treat a partial batch as a\n // failure and re-run with a corrected payload.\n const client = db(runtime);\n const insertCount = m.inserts?.length ?? 0;\n const updateCount = m.updates?.length ?? 0;\n\n let executed = 0;\n for (const stmt of statements) {\n const res = await client.execute({ sql: stmt.sql, args: stmt.args });\n if (executed < insertCount) {\n result.inserted += 1;\n } else if (executed < insertCount + updateCount) {\n result.updated += res.rowsAffected || 0;\n } else {\n result.deleted += res.rowsAffected || 0;\n }\n executed += 1;\n }\n\n if (statements.length > 0) await notifyDbAdminChange(runtime);\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// runSql\n// ---------------------------------------------------------------------------\n\n/** Error thrown when a destructive statement is run without confirmation. */\nexport class DbAdminConfirmRequiredError extends Error {\n readonly needsConfirm = true;\n constructor(message: string) {\n super(message);\n this.name = \"DbAdminConfirmRequiredError\";\n }\n}\n\n/** Strip `--` line comments and `/* *\\/` block comments from SQL. */\nfunction stripComments(sql: string): string {\n return sql.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \").replace(/--[^\\n\\r]*/g, \" \");\n}\n\nfunction isMutatingSql(sql: string): boolean {\n const head = stripComments(sql).trim().toLowerCase();\n return /^(insert|update|delete|replace|create|alter|drop|truncate|merge|pragma\\s+\\w+\\s*=)/.test(\n head,\n );\n}\n\n/** Detect destructive ops on comment-stripped SQL. */\nfunction isDestructiveSql(sql: string): boolean {\n const cleaned = stripComments(sql).trim();\n const lower = cleaned.toLowerCase();\n if (/^drop\\b/.test(lower)) return true;\n if (/^truncate\\b/.test(lower)) return true;\n if (/^delete\\b/.test(lower) && !/\\bwhere\\b/.test(lower)) return true;\n if (/^update\\b/.test(lower) && !/\\bwhere\\b/.test(lower)) return true;\n return false;\n}\n\n/** A leading SELECT (or CTE that ends in SELECT) with no LIMIT clause. */\nfunction isBareSelectWithoutLimit(sql: string): boolean {\n const cleaned = stripComments(sql).trim();\n const lower = cleaned.toLowerCase();\n const isSelect = /^(select|with)\\b/.test(lower);\n if (!isSelect) return false;\n if (/\\blimit\\b/.test(lower)) return false;\n return true;\n}\n\nexport async function runSql(\n sql: string,\n params: unknown[] | undefined,\n opts: { confirmDestructive?: boolean } = {},\n runtime?: DbAdminRuntime,\n): Promise<DbAdminQueryResult> {\n if (typeof sql !== \"string\" || !sql.trim()) {\n throw new Error(\"SQL is required\");\n }\n\n if (isDestructiveSql(sql) && !opts.confirmDestructive) {\n throw new DbAdminConfirmRequiredError(\n \"This statement is destructive (DROP / TRUNCATE / unscoped DELETE or UPDATE). Re-run with confirmDestructive: true to proceed.\",\n );\n }\n\n // Guardrail: auto-append LIMIT 100 to a bare SELECT so an accidental\n // full-table scan can't dump a huge result set.\n let finalSql = sql.trim().replace(/;\\s*$/, \"\");\n if (isBareSelectWithoutLimit(finalSql)) {\n finalSql = `${finalSql} LIMIT 100`;\n }\n\n const client = db(runtime);\n const started = Date.now();\n const res = await client.execute(\n params && params.length > 0 ? { sql: finalSql, args: params } : finalSql,\n );\n const durationMs = Date.now() - started;\n\n const truncation = truncateLargeResultCells(\n (res.rows ?? []) as Record<string, unknown>[],\n );\n const rows = truncation.rows;\n const columns =\n rows.length > 0 && rows[0] && typeof rows[0] === \"object\"\n ? Object.keys(rows[0])\n : [];\n\n if (isMutatingSql(finalSql)) await notifyDbAdminChange(runtime);\n\n return {\n columns,\n rows,\n rowsAffected: res.rowsAffected ?? 0,\n durationMs,\n truncatedCells: truncation.truncatedCells,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/db-admin/routes.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAmBD,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,GAAG,EACb,OAAO,GAAE,yBAA8B,GACtC,IAAI,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/db-admin/routes.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAmBD,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,GAAG,EACb,OAAO,GAAE,yBAA8B,GACtC,IAAI,CAyGN"}
|
package/dist/db-admin/routes.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/db-admin/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * HTTP routes for the dev-mode database admin.\n *\n * Mounted under `/_agent-native/db-admin/*`. EVERY handler self-gates on\n * `NODE_ENV === \"development\"` (this is the authoritative gate — see\n * `isDevEnvironment`). Real logins work locally; there is no localhost or\n * `AUTH_MODE=local` shim. The DB admin exposes raw, unscoped full-database\n * access and must NEVER be reachable in a deployed / production-mode app.\n */\nimport {\n defineEventHandler,\n getMethod,\n setResponseHeader,\n setResponseStatus,\n} from \"h3\";\nimport type { H3Event } from \"h3\";\n\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport {\n applyMutations,\n getRows,\n getTableSchema,\n listTables,\n runSql,\n DbAdminConfirmRequiredError,\n} from \"./operations.js\";\nimport type { DbAdminMutation, DbAdminRowsRequest } from \"./types.js\";\n\nexport interface MountDbAdminRoutesOptions {\n routePrefix?: string;\n}\n\n/** Authoritative gate for the DB admin: development mode only.\n * Available purely on `NODE_ENV === \"development\"` — real logins work locally\n * and there is no localhost / `AUTH_MODE=local` shim. The normal\n * `/_agent-native/*` auth layer still requires a signed-in user on top of this. */\nfunction isDevEnvironment(): boolean {\n return process.env.NODE_ENV === \"development\";\n}\n\nfunction decodeSegment(value: string | undefined): string | undefined {\n if (!value) return undefined;\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nexport function mountDbAdminRoutes(\n nitroApp: any,\n options: MountDbAdminRoutesOptions = {},\n): void {\n const routePrefix = options.routePrefix ?? \"/_agent-native\";\n const basePath = `${routePrefix}/db-admin`;\n\n getH3App(nitroApp).use(\n basePath,\n defineEventHandler(async (event: H3Event) => {\n setResponseHeader(event, \"Cache-Control\", \"no-store\");\n\n // Authoritative gate: development mode only (NODE_ENV === \"development\").\n if (!isDevEnvironment()) {\n setResponseStatus(event, 403);\n return {\n ok: false,\n error: \"DB admin is only available in development mode.\",\n };\n }\n\n const method = getMethod(event);\n // event.path is relative to the mount base path under h3's .use().\n const raw = (event.path || \"/\").split(\"?\")[0];\n const segments = raw\n .replace(/^\\/+/, \"\")\n .split(\"/\")\n .filter(Boolean)\n .map(decodeSegment);\n\n try {\n // GET /overview\n if (segments[0] === \"overview\" && segments.length === 1) {\n if (method !== \"GET\") return methodNotAllowed(event);\n const result = await listTables();\n return { ok: true, ...result };\n }\n\n // /table/:name/...\n if (segments[0] === \"table\") {\n const name = segments[1];\n if (!name) return badRequest(event, \"Table name is required\");\n const sub = segments[2];\n\n if (sub === \"schema\" && segments.length === 3) {\n if (method !== \"GET\") return methodNotAllowed(event);\n const table = await getTableSchema(name);\n return { ok: true, table };\n }\n\n if (sub === \"rows\" && segments.length === 3) {\n if (method !== \"POST\") return methodNotAllowed(event);\n const body = await readBody<Partial<DbAdminRowsRequest>>(event);\n const result = await getRows(name, {\n page: Number(body.page) || 1,\n pageSize: Number(body.pageSize) || 50,\n sort: body.sort,\n filters: body.filters,\n });\n return { ok: true, ...result };\n }\n\n if (sub === \"mutate\" && segments.length === 3) {\n if (method !== \"POST\") return methodNotAllowed(event);\n const body = await readBody<DbAdminMutation>(event);\n const result = await applyMutations(name, body ?? {});\n return { ok: true, ...result };\n }\n\n return notFound(event, \"Unknown db-admin table route\");\n }\n\n // POST /query\n if (segments[0] === \"query\" && segments.length === 1) {\n if (method !== \"POST\") return methodNotAllowed(event);\n const body = await readBody<{\n sql?: string;\n params?: unknown[];\n confirmDestructive?: boolean;\n }>(event);\n try {\n const result = await runSql(\n String(body.sql ?? \"\"),\n Array.isArray(body.params) ? body.params : undefined,\n { confirmDestructive: body.confirmDestructive === true },\n );\n return { ok: true, ...result };\n } catch (err) {\n if (err instanceof DbAdminConfirmRequiredError) {\n setResponseStatus(event, 400);\n return {\n ok: false,\n error: err.message,\n needsConfirm: true,\n };\n }\n throw err;\n }\n }\n\n return notFound(event, \"Unknown db-admin route\");\n } catch (err) {\n setResponseStatus(event, 500);\n return { ok: false, error: String(err) };\n }\n }),\n );\n}\n\nfunction methodNotAllowed(event: H3Event) {\n setResponseStatus(event, 405);\n return { ok: false, error: \"Method not allowed\" };\n}\n\nfunction badRequest(event: H3Event, error: string) {\n setResponseStatus(event, 400);\n return { ok: false, error };\n}\n\nfunction notFound(event: H3Event, error: string) {\n setResponseStatus(event, 404);\n return { ok: false, error };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/db-admin/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * HTTP routes for the dev-mode database admin.\n *\n * Mounted under `/_agent-native/db-admin/*`. EVERY handler self-gates on\n * `NODE_ENV === \"development\"` (this is the authoritative gate — see\n * `isDevEnvironment`). Real logins work locally; there is no localhost or\n * `AUTH_MODE=local` shim. The DB admin exposes raw, unscoped full-database\n * access and must NEVER be reachable in a deployed / production-mode app.\n */\nimport {\n defineEventHandler,\n getMethod,\n setResponseHeader,\n setResponseStatus,\n} from \"h3\";\nimport type { H3Event } from \"h3\";\n\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport {\n applyMutations,\n getRows,\n getTableSchema,\n listTables,\n runSql,\n DbAdminConfirmRequiredError,\n} from \"./operations.js\";\nimport type { DbAdminMutation, DbAdminRowsRequest } from \"./types.js\";\n\nexport interface MountDbAdminRoutesOptions {\n routePrefix?: string;\n}\n\n/** Authoritative gate for the DB admin: development mode only.\n * Available purely on `NODE_ENV === \"development\"` — real logins work locally\n * and there is no localhost / `AUTH_MODE=local` shim. The normal\n * `/_agent-native/*` auth layer still requires a signed-in user on top of this. */\nfunction isDevEnvironment(): boolean {\n return process.env.NODE_ENV === \"development\";\n}\n\nfunction decodeSegment(value: string | undefined): string | undefined {\n if (!value) return undefined;\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nexport function mountDbAdminRoutes(\n nitroApp: any,\n options: MountDbAdminRoutesOptions = {},\n): void {\n const routePrefix = options.routePrefix ?? \"/_agent-native\";\n const basePath = `${routePrefix}/db-admin`;\n\n getH3App(nitroApp).use(\n basePath,\n defineEventHandler(async (event: H3Event) => {\n setResponseHeader(event, \"Cache-Control\", \"no-store\");\n\n // Authoritative gate: development mode only (NODE_ENV === \"development\").\n if (!isDevEnvironment()) {\n setResponseStatus(event, 403);\n return {\n ok: false,\n error: \"DB admin is only available in development mode.\",\n };\n }\n\n const method = getMethod(event);\n // event.path is relative to the mount base path under h3's .use().\n const raw = (event.path || \"/\").split(\"?\")[0];\n const segments = raw\n .replace(/^\\/+/, \"\")\n .split(\"/\")\n .filter(Boolean)\n .map(decodeSegment);\n\n try {\n // GET /overview\n if (segments[0] === \"overview\" && segments.length === 1) {\n if (method !== \"GET\") return methodNotAllowed(event);\n const result = await listTables();\n return { ok: true, ...result };\n }\n\n // /table/:name/...\n if (segments[0] === \"table\") {\n const name = segments[1];\n if (!name) return badRequest(event, \"Table name is required\");\n const sub = segments[2];\n\n if (sub === \"schema\" && segments.length === 3) {\n if (method !== \"GET\") return methodNotAllowed(event);\n const table = await getTableSchema(name);\n return { ok: true, table };\n }\n\n if (sub === \"rows\" && segments.length === 3) {\n if (method !== \"POST\") return methodNotAllowed(event);\n const body = await readBody<Partial<DbAdminRowsRequest>>(event);\n const result = await getRows(name, {\n page: Number(body.page) || 1,\n pageSize: Number(body.pageSize) || 50,\n sort: body.sort,\n filters: body.filters,\n includeLargeCells: body.includeLargeCells === true,\n });\n return { ok: true, ...result };\n }\n\n if (sub === \"mutate\" && segments.length === 3) {\n if (method !== \"POST\") return methodNotAllowed(event);\n const body = await readBody<DbAdminMutation>(event);\n const result = await applyMutations(name, body ?? {});\n return { ok: true, ...result };\n }\n\n return notFound(event, \"Unknown db-admin table route\");\n }\n\n // POST /query\n if (segments[0] === \"query\" && segments.length === 1) {\n if (method !== \"POST\") return methodNotAllowed(event);\n const body = await readBody<{\n sql?: string;\n params?: unknown[];\n confirmDestructive?: boolean;\n }>(event);\n try {\n const result = await runSql(\n String(body.sql ?? \"\"),\n Array.isArray(body.params) ? body.params : undefined,\n { confirmDestructive: body.confirmDestructive === true },\n );\n return { ok: true, ...result };\n } catch (err) {\n if (err instanceof DbAdminConfirmRequiredError) {\n setResponseStatus(event, 400);\n return {\n ok: false,\n error: err.message,\n needsConfirm: true,\n };\n }\n throw err;\n }\n }\n\n return notFound(event, \"Unknown db-admin route\");\n } catch (err) {\n setResponseStatus(event, 500);\n return { ok: false, error: String(err) };\n }\n }),\n );\n}\n\nfunction methodNotAllowed(event: H3Event) {\n setResponseStatus(event, 405);\n return { ok: false, error: \"Method not allowed\" };\n}\n\nfunction badRequest(event: H3Event, error: string) {\n setResponseStatus(event, 400);\n return { ok: false, error };\n}\n\nfunction notFound(event: H3Event, error: string) {\n setResponseStatus(event, 404);\n return { ok: false, error };\n}\n"]}
|
package/dist/db-admin/types.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface DbAdminColumn {
|
|
|
13
13
|
pk: boolean;
|
|
14
14
|
defaultValue: string | null;
|
|
15
15
|
autoIncrement?: boolean;
|
|
16
|
+
largeValuePreview?: boolean;
|
|
16
17
|
}
|
|
17
18
|
export interface DbAdminForeignKey {
|
|
18
19
|
column: string;
|
|
@@ -53,6 +54,7 @@ export interface DbAdminRowsRequest {
|
|
|
53
54
|
pageSize: number;
|
|
54
55
|
sort?: DbAdminSort[];
|
|
55
56
|
filters?: DbAdminFilter[];
|
|
57
|
+
includeLargeCells?: boolean;
|
|
56
58
|
}
|
|
57
59
|
export interface DbAdminRowsResult {
|
|
58
60
|
columns: DbAdminColumn[];
|
|
@@ -60,6 +62,7 @@ export interface DbAdminRowsResult {
|
|
|
60
62
|
total: number;
|
|
61
63
|
page: number;
|
|
62
64
|
pageSize: number;
|
|
65
|
+
truncatedCells?: number;
|
|
63
66
|
}
|
|
64
67
|
export interface DbAdminMutation {
|
|
65
68
|
inserts?: Record<string, unknown>[];
|
|
@@ -81,5 +84,6 @@ export interface DbAdminQueryResult {
|
|
|
81
84
|
rows: Record<string, unknown>[];
|
|
82
85
|
rowsAffected: number;
|
|
83
86
|
durationMs: number;
|
|
87
|
+
truncatedCells?: number;
|
|
84
88
|
}
|
|
85
89
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/db-admin/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,IAAI,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,EAAE,EAAE,OAAO,CAAC;IACZ,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/db-admin/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/db-admin/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Shared contract types for the dev-mode database admin (Supabase-Studio-like).\n *\n * The backend (operations / routes / agent tools) and the frontend both import\n * these so request/response shapes stay in lockstep. Keep this file free of any\n * runtime imports — it is a pure type module.\n */\n\nexport type DbAdminDialect = \"sqlite\" | \"postgres\" | \"d1\";\n\nexport interface DbAdminColumn {\n name: string;\n type: string;\n nullable: boolean;\n pk: boolean;\n defaultValue: string | null;\n autoIncrement?: boolean;\n}\n\nexport interface DbAdminForeignKey {\n column: string;\n refTable: string;\n refColumn: string;\n}\n\nexport interface DbAdminIndex {\n name: string;\n unique: boolean;\n columns: string[];\n}\n\nexport interface DbAdminTableSummary {\n name: string;\n type: \"table\" | \"view\";\n rowCount: number | null;\n}\n\nexport interface DbAdminTableSchema {\n name: string;\n type: \"table\" | \"view\";\n columns: DbAdminColumn[];\n primaryKey: string[];\n foreignKeys: DbAdminForeignKey[];\n indexes: DbAdminIndex[];\n rowCount: number | null;\n}\n\nexport type DbAdminFilterOp =\n | \"eq\"\n | \"neq\"\n | \"lt\"\n | \"lte\"\n | \"gt\"\n | \"gte\"\n | \"like\"\n | \"ilike\"\n | \"in\"\n | \"is_null\"\n | \"not_null\";\n\nexport interface DbAdminFilter {\n column: string;\n op: DbAdminFilterOp;\n value?: unknown;\n}\n\nexport interface DbAdminSort {\n column: string;\n dir: \"asc\" | \"desc\";\n}\n\nexport interface DbAdminRowsRequest {\n page: number;\n pageSize: number;\n sort?: DbAdminSort[];\n filters?: DbAdminFilter[];\n}\n\nexport interface DbAdminRowsResult {\n columns: DbAdminColumn[];\n rows: Record<string, unknown>[];\n total: number;\n page: number;\n pageSize: number;\n}\n\nexport interface DbAdminMutation {\n inserts?: Record<string, unknown>[];\n updates?: { where: Record<string, unknown>; set: Record<string, unknown> }[];\n deletes?: Record<string, unknown>[];\n dryRun?: boolean;\n}\n\nexport interface DbAdminMutationResult {\n sql: string[];\n inserted: number;\n updated: number;\n deleted: number;\n}\n\nexport interface DbAdminQueryResult {\n columns: string[];\n rows: Record<string, unknown>[];\n rowsAffected: number;\n durationMs: number;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/db-admin/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Shared contract types for the dev-mode database admin (Supabase-Studio-like).\n *\n * The backend (operations / routes / agent tools) and the frontend both import\n * these so request/response shapes stay in lockstep. Keep this file free of any\n * runtime imports — it is a pure type module.\n */\n\nexport type DbAdminDialect = \"sqlite\" | \"postgres\" | \"d1\";\n\nexport interface DbAdminColumn {\n name: string;\n type: string;\n nullable: boolean;\n pk: boolean;\n defaultValue: string | null;\n autoIncrement?: boolean;\n largeValuePreview?: boolean;\n}\n\nexport interface DbAdminForeignKey {\n column: string;\n refTable: string;\n refColumn: string;\n}\n\nexport interface DbAdminIndex {\n name: string;\n unique: boolean;\n columns: string[];\n}\n\nexport interface DbAdminTableSummary {\n name: string;\n type: \"table\" | \"view\";\n rowCount: number | null;\n}\n\nexport interface DbAdminTableSchema {\n name: string;\n type: \"table\" | \"view\";\n columns: DbAdminColumn[];\n primaryKey: string[];\n foreignKeys: DbAdminForeignKey[];\n indexes: DbAdminIndex[];\n rowCount: number | null;\n}\n\nexport type DbAdminFilterOp =\n | \"eq\"\n | \"neq\"\n | \"lt\"\n | \"lte\"\n | \"gt\"\n | \"gte\"\n | \"like\"\n | \"ilike\"\n | \"in\"\n | \"is_null\"\n | \"not_null\";\n\nexport interface DbAdminFilter {\n column: string;\n op: DbAdminFilterOp;\n value?: unknown;\n}\n\nexport interface DbAdminSort {\n column: string;\n dir: \"asc\" | \"desc\";\n}\n\nexport interface DbAdminRowsRequest {\n page: number;\n pageSize: number;\n sort?: DbAdminSort[];\n filters?: DbAdminFilter[];\n includeLargeCells?: boolean;\n}\n\nexport interface DbAdminRowsResult {\n columns: DbAdminColumn[];\n rows: Record<string, unknown>[];\n total: number;\n page: number;\n pageSize: number;\n truncatedCells?: number;\n}\n\nexport interface DbAdminMutation {\n inserts?: Record<string, unknown>[];\n updates?: { where: Record<string, unknown>; set: Record<string, unknown> }[];\n deletes?: Record<string, unknown>[];\n dryRun?: boolean;\n}\n\nexport interface DbAdminMutationResult {\n sql: string[];\n inserted: number;\n updated: number;\n deleted: number;\n}\n\nexport interface DbAdminQueryResult {\n columns: string[];\n rows: Record<string, unknown>[];\n rowsAffected: number;\n durationMs: number;\n truncatedCells?: number;\n}\n"]}
|
|
@@ -10,10 +10,11 @@ export declare const EXTENSION_IFRAME_META_CSP = "default-src 'none'; script-src
|
|
|
10
10
|
*
|
|
11
11
|
* 1. The iframe MUST be rendered with a `sandbox` attribute that does NOT
|
|
12
12
|
* include `allow-same-origin`. The viewer (`ExtensionViewer.tsx`,
|
|
13
|
-
* `EmbeddedExtension.tsx`)
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* `EmbeddedExtension.tsx`) normalizes the sandbox through
|
|
14
|
+
* `normalizeAgentNativeExtensionSandbox()`, which permits scripts, forms,
|
|
15
|
+
* popups, and downloads but strips `allow-same-origin`. Adding
|
|
16
|
+
* `allow-same-origin` would give the extension full DOM access to the
|
|
17
|
+
* parent window via cross-frame script.
|
|
17
18
|
*
|
|
18
19
|
* 2. Every reachable parent action must treat the postMessage payload as
|
|
19
20
|
* hostile. The bridge in `iframe-bridge.ts` enforces a path allowlist,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-shell.d.ts","sourceRoot":"","sources":["../../src/extensions/html-shell.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,yBAAyB,QAQ3B,CAAC;AAEZ,eAAO,MAAM,oBAAoB,QAA+E,CAAC;AAEjH,eAAO,MAAM,yBAAyB,sXAA4B,CAAC;AAEnE
|
|
1
|
+
{"version":3,"file":"html-shell.d.ts","sourceRoot":"","sources":["../../src/extensions/html-shell.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,yBAAyB,QAQ3B,CAAC;AAEZ,eAAO,MAAM,oBAAoB,QAA+E,CAAC;AAEjH,eAAO,MAAM,yBAAyB,sXAA4B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC9C,qFAAqF;IACrF,MAAM,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC;IACpC;;;OAGG;IACH,WAAW,CAAC,EAAE;QACZ,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;CACH;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,EACf,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CA6pBR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-shell.js","sourceRoot":"","sources":["../../src/extensions/html-shell.ts"],"names":[],"mappings":"AAAA,MAAM,yBAAyB,GAC7B,mXAAmX,CAAC;AAEtX,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,QAAQ;IACR,0BAA0B;IAC1B,4BAA4B;IAC5B,oBAAoB;IACpB,oBAAoB;IACpB,gCAAgC;IAChC,0CAA0C;CAC3C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,yBAAyB,oBAAoB,yBAAyB,GAAG,CAAC;AAEjH,MAAM,CAAC,MAAM,yBAAyB,GAAG,yBAAyB,CAAC;AAoEnE,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,SAAiB,EACjB,MAAe,EACf,WAAoB,EACpB,OAAgC;IAEhC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,eAAe,GAAG,mBAAmB,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAChC,OAAO,IAAI;QACT,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,OAAO;KACd,CACF,CAAC;IAEF,OAAO;iBACQ,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;;;;wDAIU,yBAAyB;IAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,uDAAuD,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAmFlI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBA4TK,eAAe;8BACV,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA+OjC,WAAW,CAAC,CAAC,CAAC,uBAAuB,eAAe,mBAAmB,eAAe,GAAG,CAAC,CAAC,CAAC,EAAE;GACnG,OAAO;;;;;;;;;;SAUD,CAAC;AACV,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC","sourcesContent":["const EXTENSION_IFRAME_CSP_BASE =\n \"default-src 'none'; script-src 'self' https://cdn.jsdelivr.net 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self'; img-src 'self' data: blob:; media-src 'self' data: blob:; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none';\";\n\nexport const EXTENSION_FRAME_ANCESTORS = [\n \"'self'\",\n \"https://agent-native.com\",\n \"https://*.agent-native.com\",\n \"http://localhost:*\",\n \"http://127.0.0.1:*\",\n \"https://*.claudemcpcontent.com\",\n \"https://*.web-sandbox.oaiusercontent.com\",\n].join(\" \");\n\nexport const EXTENSION_IFRAME_CSP = `${EXTENSION_IFRAME_CSP_BASE} frame-ancestors ${EXTENSION_FRAME_ANCESTORS};`;\n\nexport const EXTENSION_IFRAME_META_CSP = EXTENSION_IFRAME_CSP_BASE;\n\n/**\n * SECURITY — EXTENSION CONTENT IS UNTRUSTED.\n *\n * `${content}` (line ~Body) interpolates raw HTML/JS authored by a user. This\n * file is the boundary between framework-controlled HTML and user-controlled\n * HTML. Two non-negotiable invariants for every change here:\n *\n * 1. The iframe MUST be rendered with a `sandbox` attribute that does NOT\n * include `allow-same-origin`. The viewer (`ExtensionViewer.tsx`,\n * `EmbeddedExtension.tsx`) sets `sandbox=\"allow-scripts allow-forms\"` —\n * and that is the only acceptable shape. Adding `allow-same-origin`\n * would give the extension full DOM access to the parent window via\n * cross-frame script.\n *\n * 2. Every reachable parent action must treat the postMessage payload as\n * hostile. The bridge in `iframe-bridge.ts` enforces a path allowlist,\n * header sanitization, and method allowlist; do not relax those gates\n * for \"convenience\" in this file or any caller.\n *\n * For the trust model rationale, see audit 05-tools-sandbox.md (C1) and the\n * `extensions` skill. When in doubt, fail closed.\n *\n * BACKWARDS COMPAT — the iframe injects helpers under both their canonical\n * `extension*` names (`extensionFetch`, `extensionData`, `extensionId`,\n * `extensionBinding`) AND legacy `tool*` aliases (`toolFetch`, `toolData`,\n * `toolId`, `toolBinding`) so existing user-authored extension bodies that\n * pre-date the rename keep working. Same for layout opt-ins:\n * `data-extension-layout=\"full-bleed\"` / `data-extension-padding=\"none\"` /\n * class `agent-native-extension-bleed` / CSS var\n * `--agent-native-extension-padding` are canonical; the `data-tool-*`,\n * `agent-native-tool-bleed`, and `--agent-native-tool-padding` variants are\n * accepted as aliases.\n */\n\nexport interface ExtensionRenderBinding {\n /** Email of the user who authored / owns the extension. */\n authorEmail: string;\n /** Email of the user currently viewing/running the extension. */\n viewerEmail: string;\n /** True when viewer === author. */\n isAuthor: boolean;\n /**\n * Resolved role for the viewer (\"owner\" | \"admin\" | \"editor\" | \"viewer\").\n *\n * TODO(security, audit H4): the host-side bridge does not yet gate any\n * helper based on this value — every viewer gets the same powers as the\n * author. The role is plumbed through so a follow-up PR can constrain\n * `appAction` / `dbExec` / `extensionFetch` for non-author viewers (and\n * eventually require an explicit consent step before running a shared\n * extension, audit C1). For now this is metadata only.\n */\n role: \"owner\" | \"admin\" | \"editor\" | \"viewer\";\n /** Where the extension definition came from. Database extensions are the default. */\n source?: \"database\" | \"local-files\";\n /**\n * Fine-grained helper permissions for local file extensions. Database-backed\n * extensions keep using the role table in the parent bridge.\n */\n permissions?: {\n appActions?: string[];\n extensionData?: boolean;\n sql?: boolean;\n externalFetch?: boolean;\n };\n}\n\nexport function buildExtensionHtml(\n content: string,\n themeVars: string,\n isDark: boolean,\n extensionId?: string,\n binding?: ExtensionRenderBinding,\n): string {\n const extensionIdJson = JSON.stringify(extensionId ?? \"\");\n const extensionIdAttr = escapeHtmlAttribute(extensionId ?? \"\");\n const bindingJson = JSON.stringify(\n binding ?? {\n authorEmail: \"\",\n viewerEmail: \"\",\n isAuthor: true,\n role: \"owner\",\n },\n );\n\n return `<!DOCTYPE html>\n<html lang=\"en\"${isDark ? ' class=\"dark\"' : \"\"}>\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta http-equiv=\"Content-Security-Policy\" content=\"${EXTENSION_IFRAME_META_CSP}\" />\n ${binding && !binding.isAuthor ? `<meta name=\"agent-native-extension-author\" content=\"${escapeHtmlAttribute(binding.authorEmail)}\" />` : \"\"}\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300..700&display=swap\" rel=\"stylesheet\" />\n <script>\n var _extensionErrors = [];\n var _extensionErrorDetails = [];\n var _consoleLogs = [];\n var _networkLogs = [];\n\n var _origConsole = { log: console.log, warn: console.warn, error: console.error, info: console.info };\n function _wrapConsole(level, orig) {\n return function() {\n var args = Array.prototype.slice.call(arguments);\n var msg = args.map(function(a) {\n try { return typeof a === 'object' ? JSON.stringify(a) : String(a); }\n catch(e) { return String(a); }\n }).join(' ');\n if (_consoleLogs.length >= 50) _consoleLogs.shift();\n _consoleLogs.push({ level: level, message: msg });\n orig.apply(console, arguments);\n };\n }\n console.log = _wrapConsole('log', _origConsole.log);\n console.warn = _wrapConsole('warn', _origConsole.warn);\n console.error = _wrapConsole('error', _origConsole.error);\n console.info = _wrapConsole('info', _origConsole.info);\n\n function _collectError(message, stack) {\n if (!message) return;\n if (message === 'Script error.' || message === 'Script error') message = 'Runtime error';\n if (_extensionErrors.indexOf(message) !== -1) return;\n _extensionErrors.push(message);\n _extensionErrorDetails.push({ message: message, stack: stack || '' });\n _renderErrorToast();\n }\n\n function _renderErrorToast() {\n var toast = document.getElementById('__extension-error-toast');\n if (!toast) return;\n var msg = document.getElementById('__extension-error-msg');\n if (!msg || _extensionErrors.length === 0) return;\n if (_extensionErrors.length === 1) {\n msg.textContent = _extensionErrors[0];\n } else {\n msg.textContent = _extensionErrors.length + ' errors — ' + _extensionErrors[_extensionErrors.length - 1];\n }\n toast.style.display = 'block';\n }\n\n window.addEventListener('error', function(event) {\n var msg = event.message || '';\n if (msg.indexOf('Alpine Expression Error') === 0) return;\n var stack = event.error && event.error.stack ? event.error.stack : '';\n _collectError(msg, stack);\n });\n\n window.addEventListener('unhandledrejection', function(event) {\n var msg = event.reason && event.reason.message ? event.reason.message : String(event.reason);\n var stack = event.reason && event.reason.stack ? event.reason.stack : '';\n _collectError(msg, stack);\n });\n </script>\n <!--\n SECURITY: pinned to exact patch versions + SRI integrity hashes. A\n malicious republish of @tailwindcss/browser@4.x or alpinejs@3.x would\n otherwise inject code into every extension. To bump these versions:\n 1. npm view @tailwindcss/browser version (or alpinejs)\n 2. curl -sL https://cdn.jsdelivr.net/npm/@tailwindcss/browser@<v> \\\\\n | openssl dgst -sha384 -binary | openssl base64 -A\n 3. Update the URL + integrity hash below in lockstep.\n -->\n <script\n src=\"https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.2.4\"\n integrity=\"sha384-yNSZBFvuOWcmww494a9+1zNuvgUGEXoWkein7cxP8wHUTi3iXCU4vJ7hr3tzBCml\"\n crossorigin=\"anonymous\"\n ></script>\n <script\n defer\n src=\"https://cdn.jsdelivr.net/npm/alpinejs@3.15.11/dist/cdn.min.js\"\n integrity=\"sha384-WPtu0YHhJ3arcykfnv1JgUffWDSKRnqnDeTpJUbOc2os2moEmLkIdaeR0trPN4be\"\n crossorigin=\"anonymous\"\n ></script>\n <style>${themeVars}</style>\n <style type=\"text/tailwindcss\">\n @custom-variant dark (&:where(.dark, .dark *));\n @theme {\n --color-border: hsl(var(--border));\n --color-input: hsl(var(--input));\n --color-ring: hsl(var(--ring));\n --color-background: hsl(var(--background));\n --color-foreground: hsl(var(--foreground));\n --color-primary: hsl(var(--primary));\n --color-primary-foreground: hsl(var(--primary-foreground));\n --color-secondary: hsl(var(--secondary));\n --color-secondary-foreground: hsl(var(--secondary-foreground));\n --color-destructive: hsl(var(--destructive));\n --color-destructive-foreground: hsl(var(--destructive-foreground));\n --color-muted: hsl(var(--muted));\n --color-muted-foreground: hsl(var(--muted-foreground));\n --color-accent: hsl(var(--accent));\n --color-accent-foreground: hsl(var(--accent-foreground));\n --color-popover: hsl(var(--popover));\n --color-popover-foreground: hsl(var(--popover-foreground));\n --color-card: hsl(var(--card));\n --color-card-foreground: hsl(var(--card-foreground));\n --color-sidebar: hsl(var(--sidebar-background));\n --color-sidebar-foreground: hsl(var(--sidebar-foreground));\n --color-sidebar-primary: hsl(var(--sidebar-primary));\n --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));\n --color-sidebar-accent: hsl(var(--sidebar-accent));\n --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));\n --color-sidebar-border: hsl(var(--sidebar-border));\n --color-sidebar-ring: hsl(var(--sidebar-ring));\n --radius-lg: var(--radius);\n --radius-md: calc(var(--radius) - 2px);\n --radius-sm: calc(var(--radius) - 4px);\n }\n </style>\n\t <style>\n\t *, *::before, *::after { border-color: hsl(var(--border)); }\n\t html, body {\n\t /* Transparent so the iframe inherits the host surface (dashboard panel,\n\t sidebar, chat) instead of painting the browser's default white canvas.\n\t The dark class still flips the theme vars; content paints its own\n\t bg-background / bg-card surfaces. */\n\t background: transparent;\n\t }\n\t body {\n\t --agent-native-extension-padding: clamp(16px, 2vw, 24px);\n\t /* Legacy alias for pre-rename extension content (do not remove). */\n\t --agent-native-tool-padding: var(--agent-native-extension-padding);\n\t box-sizing: border-box;\n\t color: hsl(var(--foreground));\n\t font-family: 'Inter', sans-serif;\n\t margin: 0;\n\t min-height: 100vh;\n\t padding: var(--agent-native-extension-padding);\n\t }\n\t body:has(> [data-extension-layout=\"full-bleed\"]),\n\t body:has(> [data-extension-padding=\"none\"]),\n\t body:has(> .agent-native-extension-bleed),\n\t /* Legacy aliases (do not remove). */\n\t body:has(> [data-tool-layout=\"full-bleed\"]),\n\t body:has(> [data-tool-padding=\"none\"]),\n\t body:has(> .agent-native-tool-bleed) {\n\t padding: 0;\n\t }\n\t </style>\n\t <script>\n\t var _extensionRequestSeq = 0;\n\t var _extensionPendingRequests = {};\n\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var message = event.data || {};\n\t if (\n\t message.type !== 'agent-native-extension-response' &&\n\t message.type !== 'agent-native-tool-response'\n\t ) return;\n\t var pending = _extensionPendingRequests[message.requestId];\n\t if (!pending) return;\n\t delete _extensionPendingRequests[message.requestId];\n\t if (message.error) {\n\t pending.reject(new Error(message.error));\n\t } else {\n\t pending.resolve(message.response);\n\t }\n\t });\n\n\t function hostRequest(path, options) {\n\t options = options || {};\n\t return new Promise(function(resolve, reject) {\n\t var requestId = 'extension-req-' + (++_extensionRequestSeq);\n\t _extensionPendingRequests[requestId] = { resolve: resolve, reject: reject };\n\t window.parent.postMessage({\n\t type: 'agent-native-extension-request',\n\t requestId: requestId,\n\t path: path,\n\t options: {\n\t method: options.method || 'GET',\n\t headers: options.headers || {},\n\t body: options.body,\n\t },\n\t }, '*');\n\t setTimeout(function() {\n\t var pending = _extensionPendingRequests[requestId];\n\t if (!pending) return;\n\t delete _extensionPendingRequests[requestId];\n\t pending.reject(new Error('Extension host request timed out'));\n\t }, 30000);\n\t });\n\t }\n\n\t var _origHostRequest = hostRequest;\n\t hostRequest = function(path, options) {\n\t var entry = { path: path, method: (options && options.method) || 'GET' };\n\t return _origHostRequest(path, options).then(function(res) {\n\t entry.ok = res.ok;\n\t entry.status = res.status;\n\t if (!res.ok && res.body) {\n\t try { entry.error = typeof res.body === 'string' ? res.body.slice(0, 200) : JSON.stringify(res.body).slice(0, 200); } catch(e) {}\n\t }\n\t if (_networkLogs.length >= 20) _networkLogs.shift();\n\t _networkLogs.push(entry);\n\t return res;\n\t }, function(err) {\n\t entry.ok = false;\n\t entry.error = err.message;\n\t if (_networkLogs.length >= 20) _networkLogs.shift();\n\t _networkLogs.push(entry);\n\t throw err;\n\t });\n\t };\n\n\t function extensionFetch(url, options) {\n\t var opts = options || {};\n\t return hostRequest('/_agent-native/extensions/proxy', {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify({\n\t url: url,\n method: opts.method || 'GET',\n headers: opts.headers,\n body: opts.body,\n }),\n\t }).then(function(res) {\n\t var data = res.body;\n\t if (data.error && data.status === undefined) {\n\t throw new Error(data.error);\n\t }\n return {\n ok: data.status >= 200 && data.status < 300,\n status: data.status,\n\t json: function() { return Promise.resolve(data.body); },\n\t text: function() { return Promise.resolve(typeof data.body === 'string' ? data.body : JSON.stringify(data.body)); },\n\t };\n\t });\n\t }\n\n\t function _appendActionQuery(path, params) {\n\t var search = new URLSearchParams();\n\t params = params || {};\n\t Object.keys(params).forEach(function(key) {\n\t var value = params[key];\n\t if (value === undefined || value === null) return;\n\t if (Array.isArray(value)) {\n\t value.forEach(function(item) {\n\t if (item !== undefined && item !== null) {\n\t search.append(key, String(item));\n\t }\n\t });\n\t return;\n\t }\n\t search.set(key, String(value));\n\t });\n\t var qs = search.toString();\n\t return qs ? path + '?' + qs : path;\n\t }\n\n\t function _methodHintFromActionResponse(res) {\n\t if (!res || res.status !== 405) return null;\n\t var body = res.body || {};\n\t var message = typeof body === 'string' ? body : body.error;\n\t if (!message) return null;\n\t var match = String(message).match(/Use (GET|POST|PUT|PATCH|DELETE|HEAD)\\\\.?/i);\n\t return match ? match[1].toUpperCase() : null;\n\t }\n\n\t async function appAction(name, params) {\n\t params = params || {};\n\t if (name === 'navigate') {\n\t var navRes = await hostRequest('/_agent-native/application-state/navigate', {\n\t method: 'PUT',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify(params),\n\t });\n\t if (!navRes.ok) {\n\t var navErr = navRes.body || { error: navRes.statusText };\n\t throw new Error(navErr.error || 'Navigation failed: ' + navRes.status);\n\t }\n\t return navRes.body;\n\t }\n\t var path = '/_agent-native/actions/' + encodeURIComponent(name);\n\t var res = await hostRequest(path, {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify(params),\n\t });\n\n\t var retryMethod = _methodHintFromActionResponse(res);\n\t if (!res.ok && retryMethod && retryMethod !== 'POST') {\n\t var retryPath = path;\n\t var retryOptions = {\n\t method: retryMethod,\n\t headers: { 'Content-Type': 'application/json' },\n\t };\n\t if (retryMethod === 'GET' || retryMethod === 'HEAD') {\n\t retryPath = _appendActionQuery(path, params);\n\t } else {\n\t retryOptions.body = JSON.stringify(params);\n\t }\n\t res = await hostRequest(retryPath, retryOptions);\n\t }\n\n\t if (!res.ok) {\n\t var err = res.body || {};\n\t var rawError = typeof err === 'string' ? err : err.error;\n\t var message = (typeof rawError === 'string' && rawError.trim())\n\t ? rawError\n\t : (res.status === 404\n\t ? \"Action '\" + name + \"' is not available over HTTP (404). It may be agent-only (http: false); expose it with an HTTP-mounted action to call it from an extension.\"\n\t : \"Action '\" + name + \"' failed (\" + (res.status || 'network error') + \")\");\n\t throw new Error(message);\n\t }\n\t return res.body;\n\t }\n\n\t async function appFetch(path, options) {\n\t options = options || {};\n\t var res = await hostRequest(path, {\n\t ...options,\n\t headers: {\n\t 'Content-Type': 'application/json',\n\t ...(options.headers || {}),\n\t },\n\t });\n\t if (!res.ok) {\n\t var err = typeof res.body === 'object' && res.body ? res.body : { error: res.statusText };\n\t throw new Error(err.error || 'Request failed: ' + res.status);\n\t }\n\t return res.body;\n\t }\n\n\t function sendToChat(message, options) {\n\t options = options || {};\n\t var text = typeof message === 'string' ? message : JSON.stringify(message);\n\t window.parent.postMessage({\n\t type: 'agent-native-send-to-chat',\n\t message: text,\n\t context: options.context,\n\t submit: options.submit !== false,\n\t openSidebar: options.openSidebar !== false,\n\t }, '*');\n\t return { ok: true };\n\t }\n\n\t function inlineUiOutputKey() {\n\t var safeId = String(_extensionId || 'unknown').replace(/[^A-Za-z0-9_:-]/g, '') || 'unknown';\n\t return 'inline-ui:' + safeId + ':output';\n\t }\n\n\t async function outputToUi(value, options) {\n\t options = options || {};\n\t var key = inlineUiOutputKey();\n\t var payload = {\n\t value: value,\n\t updatedAt: new Date().toISOString(),\n\t extensionId: _extensionId,\n\t source: 'inline-ui',\n\t };\n\t if (options.label !== undefined) payload.label = options.label;\n\t if (options.context !== undefined) payload.context = options.context;\n\t if (options.meta !== undefined) payload.meta = options.meta;\n\t var output = await appFetch('/_agent-native/application-state/' + key, {\n\t method: 'PUT',\n\t headers: { 'X-Request-Source': 'inline-ui' },\n\t body: JSON.stringify(payload),\n\t });\n\t try {\n\t window.parent.postMessage({\n\t type: 'agent-native-ui-output',\n\t extensionId: _extensionId,\n\t key: key,\n\t value: value,\n\t output: output,\n\t }, '*');\n\t } catch (_) {}\n\t return { ok: true, key: key, output: output };\n\t }\n\n async function dbQuery(sql, args) {\n var body = { sql: sql };\n if (args) body.args = args;\n return appFetch('/_agent-native/extensions/sql/query', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n async function dbExec(sql, args) {\n var body = { sql: sql };\n if (args) body.args = args;\n return appFetch('/_agent-native/extensions/sql/exec', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n var _extensionId = ${extensionIdJson};\n var _extensionBinding = ${bindingJson};\n window.extensionBinding = _extensionBinding;\n // Legacy alias for extension bodies authored before the rename.\n window.toolBinding = _extensionBinding;\n // SECURITY (audit H4): announce the resolved binding to the parent so the\n // host bridge can gate dangerous helpers based on viewer role. Sent\n // BEFORE the user-authored content has a chance to run, so a malicious\n // extension body cannot suppress or rewrite the announcement. The parent\n // ignores subsequent announcements for the same iframe; see\n // ExtensionViewer.tsx / EmbeddedExtension.tsx.\n try {\n window.parent.postMessage(\n {\n type: 'agent-native-extension-binding',\n extensionId: _extensionId,\n binding: _extensionBinding,\n },\n '*',\n );\n } catch (_) {}\n // SECURITY: when the viewer is not the author of this extension, emit a\n // clear console warning. The bridge currently runs every helper with the\n // viewer's session — a malicious shared extension can call any action,\n // read any owned table row in scope, and resolve any user-scope secret.\n // A full consent step is tracked as TODO C1 in audit 05-tools-sandbox.md.\n if (_extensionBinding && !_extensionBinding.isAuthor) {\n try {\n console.warn(\n '[agent-native] Shared extension — running with viewer\\\\'s session. ' +\n 'Author: ' + (_extensionBinding.authorEmail || '<unknown>') + '. ' +\n 'Bridge calls (appAction, dbExec, extensionFetch) execute under ' +\n 'your account; they are gated by your permissions, not the ' +\n 'author\\\\'s. Do not run untrusted shared extensions.',\n );\n } catch (_) {}\n }\n\n var extensionData = {\n\t async list(collection, opts) {\n\t var limit = (opts && opts.limit) || 100;\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/extensions/data/' + _extensionId + '/' + encodeURIComponent(collection) + '?limit=' + limit + '&scope=' + scope);\n\t if (!res.ok) throw new Error('Failed to list extension data');\n\t return res.body;\n\t },\n async get(collection, id, opts) {\n var scope = (opts && opts.scope) || 'user';\n var items = await this.list(collection, { scope: scope });\n return (items || []).find(function(item) { return item.id === id; }) || null;\n },\n async set(collection, id, data, opts) {\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/extensions/data/' + _extensionId + '/' + encodeURIComponent(collection), {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify({ id: id, data: data, scope: scope }),\n\t });\n\t if (!res.ok) throw new Error('Failed to save extension data');\n\t return res.body;\n\t },\n\t async remove(collection, id, opts) {\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/extensions/data/' + _extensionId + '/' + encodeURIComponent(collection) + '/' + encodeURIComponent(id) + '?scope=' + scope, {\n\t method: 'DELETE',\n\t });\n\t if (!res.ok) throw new Error('Failed to delete extension data');\n\t return res.body;\n\t },\n\t };\n\n\t // Legacy aliases — extension bodies authored before the rename use\n\t // toolFetch, toolData, toolId. Keep these working forever.\n\t var toolFetch = extensionFetch;\n\t var toolData = extensionData;\n\t var _toolId = _extensionId;\n\t window.agentNative = Object.assign(window.agentNative || {}, {\n\t extensionId: _extensionId,\n\t extensionBinding: _extensionBinding,\n\t appAction: appAction,\n\t appFetch: appFetch,\n\t dbQuery: dbQuery,\n\t dbExec: dbExec,\n\t extensionFetch: extensionFetch,\n\t extensionData: extensionData,\n\t data: extensionData,\n\t sendToChat: sendToChat,\n\t chat: Object.assign({}, (window.agentNative && window.agentNative.chat) || {}, {\n\t send: sendToChat,\n\t }),\n\t ui: Object.assign({}, (window.agentNative && window.agentNative.ui) || {}, {\n\t output: outputToUi,\n\t }),\n\t });\n\t window.sendToAgentChat = sendToChat;\n\t </script>\n\t <style>\n\t #__extension-error-toast {\n\t display: none;\n\t position: fixed;\n\t bottom: 16px;\n\t right: 16px;\n\t max-width: 420px;\n\t background: hsl(var(--destructive));\n\t color: hsl(var(--destructive-foreground));\n\t border: 1px solid hsl(var(--destructive) / .6);\n\t border-radius: calc(var(--radius, .5rem) + 2px);\n\t padding: 12px 16px;\n\t font-size: 13px;\n\t line-height: 1.4;\n\t font-family: 'Inter', sans-serif;\n\t z-index: 9999;\n\t box-shadow: 0 4px 12px rgba(0,0,0,.15), 0 1px 3px rgba(0,0,0,.1);\n\t animation: __toast-in 0.2s ease-out;\n\t }\n\t @keyframes __toast-in {\n\t from { opacity: 0; transform: translateY(8px); }\n\t to { opacity: 1; transform: translateY(0); }\n\t }\n\t </style>\n\t <script>\n\t // Extension-point slot context: when an extension is rendered embedded\n\t // inside an ExtensionSlot, the host pushes a context object via\n\t // postMessage. Extensions read it synchronously via window.slotContext\n\t // or subscribe to changes via window.onSlotContext(fn). When rendered\n\t // full-page (no ?slot= param), slotContext stays null and extensions\n\t // branch on that.\n\t window.slotContext = null;\n\t var _slotContextSubscribers = [];\n\t window.onSlotContext = function(fn) {\n\t _slotContextSubscribers.push(fn);\n\t if (window.slotContext !== null) {\n\t try { fn(window.slotContext); } catch(_) {}\n\t }\n\t return function() {\n\t _slotContextSubscribers = _slotContextSubscribers.filter(function(f) { return f !== fn; });\n\t };\n\t };\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var msg = event.data;\n\t if (!msg || msg.type !== 'agent-native-slot-context') return;\n\t window.slotContext = msg.context || {};\n\t _slotContextSubscribers.forEach(function(fn) {\n\t try { fn(window.slotContext); } catch(_) {}\n\t });\n\t });\n\n\t // Auto-resize iframe renders. Persisted extension slots include ?slot=;\n\t // transient inline chat UI uses srcdoc, so detect that by parent frame.\n\t // The host listens for agent-native-extension-resize and adjusts height.\n\t if (new URLSearchParams(location.search).get('slot') || window.parent !== window) {\n\t var _lastH = 0;\n\t var _reportHeight = function() {\n\t var h = Math.max(\n\t document.documentElement.scrollHeight,\n\t document.body ? document.body.scrollHeight : 0,\n\t );\n\t if (h !== _lastH) {\n\t _lastH = h;\n\t window.parent.postMessage({ type: 'agent-native-extension-resize', height: h }, '*');\n\t }\n\t };\n\t if (typeof ResizeObserver !== 'undefined') {\n\t var _ro = new ResizeObserver(_reportHeight);\n\t document.addEventListener('DOMContentLoaded', function() {\n\t _ro.observe(document.documentElement);\n\t if (document.body) _ro.observe(document.body);\n\t });\n\t }\n\t // Initial reports — Alpine takes a tick to render after DOMContentLoaded.\n\t setTimeout(_reportHeight, 50);\n\t setTimeout(_reportHeight, 250);\n\t }\n\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var msg = event.data;\n\t if (!msg || msg.type !== 'agent-native-theme-update') return;\n\t var root = document.documentElement;\n\t if (msg.isDark !== undefined) {\n\t if (msg.isDark) root.classList.add('dark');\n\t else root.classList.remove('dark');\n\t }\n\t var vars = msg.vars || {};\n\t for (var key in vars) {\n\t if (vars.hasOwnProperty(key)) {\n\t root.style.setProperty(key, vars[key]);\n\t }\n\t }\n\t });\n\n\t document.addEventListener('keydown', function(e) {\n\t if ((e.metaKey || e.ctrlKey) && !e.altKey) {\n\t var key = (e.key || '').toLowerCase();\n\t if (key === 'c' || key === 'v' || key === 'x' || key === 'a' || key === 'z' || key === 'y') return;\n\t e.preventDefault();\n\t e.stopPropagation();\n\t window.parent.postMessage({\n\t type: 'agent-native-extension-keydown',\n\t key: e.key, code: e.code,\n\t metaKey: e.metaKey, ctrlKey: e.ctrlKey,\n\t shiftKey: e.shiftKey, altKey: e.altKey,\n\t }, '*');\n\t return;\n\t }\n\t if (e.key === 'Escape') {\n\t window.parent.postMessage({\n\t type: 'agent-native-extension-keydown',\n\t key: e.key, code: e.code,\n\t metaKey: false, ctrlKey: false,\n\t shiftKey: false, altKey: false,\n\t }, '*');\n\t }\n\t });\n\n\t document.addEventListener('DOMContentLoaded', function() {\n\t _renderErrorToast();\n\t var fixBtn = document.getElementById('__extension-error-fix');\n\t if (fixBtn) {\n\t fixBtn.addEventListener('click', function() {\n\t window.parent.postMessage({\n\t type: 'agent-native-extension-error-fix',\n\t errors: _extensionErrors,\n\t errorDetails: _extensionErrorDetails,\n\t consoleLogs: _consoleLogs.slice(-30),\n\t networkLogs: _networkLogs.slice(-15)\n\t }, '*');\n\t document.getElementById('__extension-error-toast').style.display = 'none';\n\t });\n\t }\n\t var dismissBtn = document.getElementById('__extension-error-dismiss');\n\t if (dismissBtn) {\n\t dismissBtn.addEventListener('click', function() {\n\t document.getElementById('__extension-error-toast').style.display = 'none';\n\t });\n\t }\n\t });\n\t </script>\n\t</head>\n\t<body${extensionId ? ` data-extension-id=\"${extensionIdAttr}\" data-tool-id=\"${extensionIdAttr}\"` : \"\"} class=\"text-foreground\">\n\t${content}\n\t<div id=\"__extension-error-toast\">\n\t <div style=\"display:flex;align-items:flex-start;gap:8px;\">\n\t <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0;margin-top:1px;\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/></svg>\n\t <span id=\"__extension-error-msg\" style=\"flex:1;overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;\"></span>\n\t <button id=\"__extension-error-fix\" style=\"cursor:pointer;border:none;background:rgba(255,255,255,.9);color:hsl(0 84.2% 40%);font-size:12px;font-weight:500;padding:4px 12px;border-radius:4px;flex-shrink:0;\">Fix</button>\n\t <button id=\"__extension-error-dismiss\" style=\"cursor:pointer;border:none;background:transparent;color:inherit;font-size:16px;padding:2px 6px;opacity:0.7;flex-shrink:0;\">×</button>\n\t </div>\n\t</div>\n\t</body>\n\t</html>`;\n}\n\nfunction escapeHtmlAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"html-shell.js","sourceRoot":"","sources":["../../src/extensions/html-shell.ts"],"names":[],"mappings":"AAAA,MAAM,yBAAyB,GAC7B,mXAAmX,CAAC;AAEtX,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,QAAQ;IACR,0BAA0B;IAC1B,4BAA4B;IAC5B,oBAAoB;IACpB,oBAAoB;IACpB,gCAAgC;IAChC,0CAA0C;CAC3C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,yBAAyB,oBAAoB,yBAAyB,GAAG,CAAC;AAEjH,MAAM,CAAC,MAAM,yBAAyB,GAAG,yBAAyB,CAAC;AAqEnE,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,SAAiB,EACjB,MAAe,EACf,WAAoB,EACpB,OAAgC;IAEhC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,eAAe,GAAG,mBAAmB,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAChC,OAAO,IAAI;QACT,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,OAAO;KACd,CACF,CAAC;IAEF,OAAO;iBACQ,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;;;;wDAIU,yBAAyB;IAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,uDAAuD,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAmFlI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBA4TK,eAAe;8BACV,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA+OjC,WAAW,CAAC,CAAC,CAAC,uBAAuB,eAAe,mBAAmB,eAAe,GAAG,CAAC,CAAC,CAAC,EAAE;GACnG,OAAO;;;;;;;;;;SAUD,CAAC;AACV,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC","sourcesContent":["const EXTENSION_IFRAME_CSP_BASE =\n \"default-src 'none'; script-src 'self' https://cdn.jsdelivr.net 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self'; img-src 'self' data: blob:; media-src 'self' data: blob:; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none';\";\n\nexport const EXTENSION_FRAME_ANCESTORS = [\n \"'self'\",\n \"https://agent-native.com\",\n \"https://*.agent-native.com\",\n \"http://localhost:*\",\n \"http://127.0.0.1:*\",\n \"https://*.claudemcpcontent.com\",\n \"https://*.web-sandbox.oaiusercontent.com\",\n].join(\" \");\n\nexport const EXTENSION_IFRAME_CSP = `${EXTENSION_IFRAME_CSP_BASE} frame-ancestors ${EXTENSION_FRAME_ANCESTORS};`;\n\nexport const EXTENSION_IFRAME_META_CSP = EXTENSION_IFRAME_CSP_BASE;\n\n/**\n * SECURITY — EXTENSION CONTENT IS UNTRUSTED.\n *\n * `${content}` (line ~Body) interpolates raw HTML/JS authored by a user. This\n * file is the boundary between framework-controlled HTML and user-controlled\n * HTML. Two non-negotiable invariants for every change here:\n *\n * 1. The iframe MUST be rendered with a `sandbox` attribute that does NOT\n * include `allow-same-origin`. The viewer (`ExtensionViewer.tsx`,\n * `EmbeddedExtension.tsx`) normalizes the sandbox through\n * `normalizeAgentNativeExtensionSandbox()`, which permits scripts, forms,\n * popups, and downloads but strips `allow-same-origin`. Adding\n * `allow-same-origin` would give the extension full DOM access to the\n * parent window via cross-frame script.\n *\n * 2. Every reachable parent action must treat the postMessage payload as\n * hostile. The bridge in `iframe-bridge.ts` enforces a path allowlist,\n * header sanitization, and method allowlist; do not relax those gates\n * for \"convenience\" in this file or any caller.\n *\n * For the trust model rationale, see audit 05-tools-sandbox.md (C1) and the\n * `extensions` skill. When in doubt, fail closed.\n *\n * BACKWARDS COMPAT — the iframe injects helpers under both their canonical\n * `extension*` names (`extensionFetch`, `extensionData`, `extensionId`,\n * `extensionBinding`) AND legacy `tool*` aliases (`toolFetch`, `toolData`,\n * `toolId`, `toolBinding`) so existing user-authored extension bodies that\n * pre-date the rename keep working. Same for layout opt-ins:\n * `data-extension-layout=\"full-bleed\"` / `data-extension-padding=\"none\"` /\n * class `agent-native-extension-bleed` / CSS var\n * `--agent-native-extension-padding` are canonical; the `data-tool-*`,\n * `agent-native-tool-bleed`, and `--agent-native-tool-padding` variants are\n * accepted as aliases.\n */\n\nexport interface ExtensionRenderBinding {\n /** Email of the user who authored / owns the extension. */\n authorEmail: string;\n /** Email of the user currently viewing/running the extension. */\n viewerEmail: string;\n /** True when viewer === author. */\n isAuthor: boolean;\n /**\n * Resolved role for the viewer (\"owner\" | \"admin\" | \"editor\" | \"viewer\").\n *\n * TODO(security, audit H4): the host-side bridge does not yet gate any\n * helper based on this value — every viewer gets the same powers as the\n * author. The role is plumbed through so a follow-up PR can constrain\n * `appAction` / `dbExec` / `extensionFetch` for non-author viewers (and\n * eventually require an explicit consent step before running a shared\n * extension, audit C1). For now this is metadata only.\n */\n role: \"owner\" | \"admin\" | \"editor\" | \"viewer\";\n /** Where the extension definition came from. Database extensions are the default. */\n source?: \"database\" | \"local-files\";\n /**\n * Fine-grained helper permissions for local file extensions. Database-backed\n * extensions keep using the role table in the parent bridge.\n */\n permissions?: {\n appActions?: string[];\n extensionData?: boolean;\n sql?: boolean;\n externalFetch?: boolean;\n };\n}\n\nexport function buildExtensionHtml(\n content: string,\n themeVars: string,\n isDark: boolean,\n extensionId?: string,\n binding?: ExtensionRenderBinding,\n): string {\n const extensionIdJson = JSON.stringify(extensionId ?? \"\");\n const extensionIdAttr = escapeHtmlAttribute(extensionId ?? \"\");\n const bindingJson = JSON.stringify(\n binding ?? {\n authorEmail: \"\",\n viewerEmail: \"\",\n isAuthor: true,\n role: \"owner\",\n },\n );\n\n return `<!DOCTYPE html>\n<html lang=\"en\"${isDark ? ' class=\"dark\"' : \"\"}>\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta http-equiv=\"Content-Security-Policy\" content=\"${EXTENSION_IFRAME_META_CSP}\" />\n ${binding && !binding.isAuthor ? `<meta name=\"agent-native-extension-author\" content=\"${escapeHtmlAttribute(binding.authorEmail)}\" />` : \"\"}\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300..700&display=swap\" rel=\"stylesheet\" />\n <script>\n var _extensionErrors = [];\n var _extensionErrorDetails = [];\n var _consoleLogs = [];\n var _networkLogs = [];\n\n var _origConsole = { log: console.log, warn: console.warn, error: console.error, info: console.info };\n function _wrapConsole(level, orig) {\n return function() {\n var args = Array.prototype.slice.call(arguments);\n var msg = args.map(function(a) {\n try { return typeof a === 'object' ? JSON.stringify(a) : String(a); }\n catch(e) { return String(a); }\n }).join(' ');\n if (_consoleLogs.length >= 50) _consoleLogs.shift();\n _consoleLogs.push({ level: level, message: msg });\n orig.apply(console, arguments);\n };\n }\n console.log = _wrapConsole('log', _origConsole.log);\n console.warn = _wrapConsole('warn', _origConsole.warn);\n console.error = _wrapConsole('error', _origConsole.error);\n console.info = _wrapConsole('info', _origConsole.info);\n\n function _collectError(message, stack) {\n if (!message) return;\n if (message === 'Script error.' || message === 'Script error') message = 'Runtime error';\n if (_extensionErrors.indexOf(message) !== -1) return;\n _extensionErrors.push(message);\n _extensionErrorDetails.push({ message: message, stack: stack || '' });\n _renderErrorToast();\n }\n\n function _renderErrorToast() {\n var toast = document.getElementById('__extension-error-toast');\n if (!toast) return;\n var msg = document.getElementById('__extension-error-msg');\n if (!msg || _extensionErrors.length === 0) return;\n if (_extensionErrors.length === 1) {\n msg.textContent = _extensionErrors[0];\n } else {\n msg.textContent = _extensionErrors.length + ' errors — ' + _extensionErrors[_extensionErrors.length - 1];\n }\n toast.style.display = 'block';\n }\n\n window.addEventListener('error', function(event) {\n var msg = event.message || '';\n if (msg.indexOf('Alpine Expression Error') === 0) return;\n var stack = event.error && event.error.stack ? event.error.stack : '';\n _collectError(msg, stack);\n });\n\n window.addEventListener('unhandledrejection', function(event) {\n var msg = event.reason && event.reason.message ? event.reason.message : String(event.reason);\n var stack = event.reason && event.reason.stack ? event.reason.stack : '';\n _collectError(msg, stack);\n });\n </script>\n <!--\n SECURITY: pinned to exact patch versions + SRI integrity hashes. A\n malicious republish of @tailwindcss/browser@4.x or alpinejs@3.x would\n otherwise inject code into every extension. To bump these versions:\n 1. npm view @tailwindcss/browser version (or alpinejs)\n 2. curl -sL https://cdn.jsdelivr.net/npm/@tailwindcss/browser@<v> \\\\\n | openssl dgst -sha384 -binary | openssl base64 -A\n 3. Update the URL + integrity hash below in lockstep.\n -->\n <script\n src=\"https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.2.4\"\n integrity=\"sha384-yNSZBFvuOWcmww494a9+1zNuvgUGEXoWkein7cxP8wHUTi3iXCU4vJ7hr3tzBCml\"\n crossorigin=\"anonymous\"\n ></script>\n <script\n defer\n src=\"https://cdn.jsdelivr.net/npm/alpinejs@3.15.11/dist/cdn.min.js\"\n integrity=\"sha384-WPtu0YHhJ3arcykfnv1JgUffWDSKRnqnDeTpJUbOc2os2moEmLkIdaeR0trPN4be\"\n crossorigin=\"anonymous\"\n ></script>\n <style>${themeVars}</style>\n <style type=\"text/tailwindcss\">\n @custom-variant dark (&:where(.dark, .dark *));\n @theme {\n --color-border: hsl(var(--border));\n --color-input: hsl(var(--input));\n --color-ring: hsl(var(--ring));\n --color-background: hsl(var(--background));\n --color-foreground: hsl(var(--foreground));\n --color-primary: hsl(var(--primary));\n --color-primary-foreground: hsl(var(--primary-foreground));\n --color-secondary: hsl(var(--secondary));\n --color-secondary-foreground: hsl(var(--secondary-foreground));\n --color-destructive: hsl(var(--destructive));\n --color-destructive-foreground: hsl(var(--destructive-foreground));\n --color-muted: hsl(var(--muted));\n --color-muted-foreground: hsl(var(--muted-foreground));\n --color-accent: hsl(var(--accent));\n --color-accent-foreground: hsl(var(--accent-foreground));\n --color-popover: hsl(var(--popover));\n --color-popover-foreground: hsl(var(--popover-foreground));\n --color-card: hsl(var(--card));\n --color-card-foreground: hsl(var(--card-foreground));\n --color-sidebar: hsl(var(--sidebar-background));\n --color-sidebar-foreground: hsl(var(--sidebar-foreground));\n --color-sidebar-primary: hsl(var(--sidebar-primary));\n --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));\n --color-sidebar-accent: hsl(var(--sidebar-accent));\n --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));\n --color-sidebar-border: hsl(var(--sidebar-border));\n --color-sidebar-ring: hsl(var(--sidebar-ring));\n --radius-lg: var(--radius);\n --radius-md: calc(var(--radius) - 2px);\n --radius-sm: calc(var(--radius) - 4px);\n }\n </style>\n\t <style>\n\t *, *::before, *::after { border-color: hsl(var(--border)); }\n\t html, body {\n\t /* Transparent so the iframe inherits the host surface (dashboard panel,\n\t sidebar, chat) instead of painting the browser's default white canvas.\n\t The dark class still flips the theme vars; content paints its own\n\t bg-background / bg-card surfaces. */\n\t background: transparent;\n\t }\n\t body {\n\t --agent-native-extension-padding: clamp(16px, 2vw, 24px);\n\t /* Legacy alias for pre-rename extension content (do not remove). */\n\t --agent-native-tool-padding: var(--agent-native-extension-padding);\n\t box-sizing: border-box;\n\t color: hsl(var(--foreground));\n\t font-family: 'Inter', sans-serif;\n\t margin: 0;\n\t min-height: 100vh;\n\t padding: var(--agent-native-extension-padding);\n\t }\n\t body:has(> [data-extension-layout=\"full-bleed\"]),\n\t body:has(> [data-extension-padding=\"none\"]),\n\t body:has(> .agent-native-extension-bleed),\n\t /* Legacy aliases (do not remove). */\n\t body:has(> [data-tool-layout=\"full-bleed\"]),\n\t body:has(> [data-tool-padding=\"none\"]),\n\t body:has(> .agent-native-tool-bleed) {\n\t padding: 0;\n\t }\n\t </style>\n\t <script>\n\t var _extensionRequestSeq = 0;\n\t var _extensionPendingRequests = {};\n\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var message = event.data || {};\n\t if (\n\t message.type !== 'agent-native-extension-response' &&\n\t message.type !== 'agent-native-tool-response'\n\t ) return;\n\t var pending = _extensionPendingRequests[message.requestId];\n\t if (!pending) return;\n\t delete _extensionPendingRequests[message.requestId];\n\t if (message.error) {\n\t pending.reject(new Error(message.error));\n\t } else {\n\t pending.resolve(message.response);\n\t }\n\t });\n\n\t function hostRequest(path, options) {\n\t options = options || {};\n\t return new Promise(function(resolve, reject) {\n\t var requestId = 'extension-req-' + (++_extensionRequestSeq);\n\t _extensionPendingRequests[requestId] = { resolve: resolve, reject: reject };\n\t window.parent.postMessage({\n\t type: 'agent-native-extension-request',\n\t requestId: requestId,\n\t path: path,\n\t options: {\n\t method: options.method || 'GET',\n\t headers: options.headers || {},\n\t body: options.body,\n\t },\n\t }, '*');\n\t setTimeout(function() {\n\t var pending = _extensionPendingRequests[requestId];\n\t if (!pending) return;\n\t delete _extensionPendingRequests[requestId];\n\t pending.reject(new Error('Extension host request timed out'));\n\t }, 30000);\n\t });\n\t }\n\n\t var _origHostRequest = hostRequest;\n\t hostRequest = function(path, options) {\n\t var entry = { path: path, method: (options && options.method) || 'GET' };\n\t return _origHostRequest(path, options).then(function(res) {\n\t entry.ok = res.ok;\n\t entry.status = res.status;\n\t if (!res.ok && res.body) {\n\t try { entry.error = typeof res.body === 'string' ? res.body.slice(0, 200) : JSON.stringify(res.body).slice(0, 200); } catch(e) {}\n\t }\n\t if (_networkLogs.length >= 20) _networkLogs.shift();\n\t _networkLogs.push(entry);\n\t return res;\n\t }, function(err) {\n\t entry.ok = false;\n\t entry.error = err.message;\n\t if (_networkLogs.length >= 20) _networkLogs.shift();\n\t _networkLogs.push(entry);\n\t throw err;\n\t });\n\t };\n\n\t function extensionFetch(url, options) {\n\t var opts = options || {};\n\t return hostRequest('/_agent-native/extensions/proxy', {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify({\n\t url: url,\n method: opts.method || 'GET',\n headers: opts.headers,\n body: opts.body,\n }),\n\t }).then(function(res) {\n\t var data = res.body;\n\t if (data.error && data.status === undefined) {\n\t throw new Error(data.error);\n\t }\n return {\n ok: data.status >= 200 && data.status < 300,\n status: data.status,\n\t json: function() { return Promise.resolve(data.body); },\n\t text: function() { return Promise.resolve(typeof data.body === 'string' ? data.body : JSON.stringify(data.body)); },\n\t };\n\t });\n\t }\n\n\t function _appendActionQuery(path, params) {\n\t var search = new URLSearchParams();\n\t params = params || {};\n\t Object.keys(params).forEach(function(key) {\n\t var value = params[key];\n\t if (value === undefined || value === null) return;\n\t if (Array.isArray(value)) {\n\t value.forEach(function(item) {\n\t if (item !== undefined && item !== null) {\n\t search.append(key, String(item));\n\t }\n\t });\n\t return;\n\t }\n\t search.set(key, String(value));\n\t });\n\t var qs = search.toString();\n\t return qs ? path + '?' + qs : path;\n\t }\n\n\t function _methodHintFromActionResponse(res) {\n\t if (!res || res.status !== 405) return null;\n\t var body = res.body || {};\n\t var message = typeof body === 'string' ? body : body.error;\n\t if (!message) return null;\n\t var match = String(message).match(/Use (GET|POST|PUT|PATCH|DELETE|HEAD)\\\\.?/i);\n\t return match ? match[1].toUpperCase() : null;\n\t }\n\n\t async function appAction(name, params) {\n\t params = params || {};\n\t if (name === 'navigate') {\n\t var navRes = await hostRequest('/_agent-native/application-state/navigate', {\n\t method: 'PUT',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify(params),\n\t });\n\t if (!navRes.ok) {\n\t var navErr = navRes.body || { error: navRes.statusText };\n\t throw new Error(navErr.error || 'Navigation failed: ' + navRes.status);\n\t }\n\t return navRes.body;\n\t }\n\t var path = '/_agent-native/actions/' + encodeURIComponent(name);\n\t var res = await hostRequest(path, {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify(params),\n\t });\n\n\t var retryMethod = _methodHintFromActionResponse(res);\n\t if (!res.ok && retryMethod && retryMethod !== 'POST') {\n\t var retryPath = path;\n\t var retryOptions = {\n\t method: retryMethod,\n\t headers: { 'Content-Type': 'application/json' },\n\t };\n\t if (retryMethod === 'GET' || retryMethod === 'HEAD') {\n\t retryPath = _appendActionQuery(path, params);\n\t } else {\n\t retryOptions.body = JSON.stringify(params);\n\t }\n\t res = await hostRequest(retryPath, retryOptions);\n\t }\n\n\t if (!res.ok) {\n\t var err = res.body || {};\n\t var rawError = typeof err === 'string' ? err : err.error;\n\t var message = (typeof rawError === 'string' && rawError.trim())\n\t ? rawError\n\t : (res.status === 404\n\t ? \"Action '\" + name + \"' is not available over HTTP (404). It may be agent-only (http: false); expose it with an HTTP-mounted action to call it from an extension.\"\n\t : \"Action '\" + name + \"' failed (\" + (res.status || 'network error') + \")\");\n\t throw new Error(message);\n\t }\n\t return res.body;\n\t }\n\n\t async function appFetch(path, options) {\n\t options = options || {};\n\t var res = await hostRequest(path, {\n\t ...options,\n\t headers: {\n\t 'Content-Type': 'application/json',\n\t ...(options.headers || {}),\n\t },\n\t });\n\t if (!res.ok) {\n\t var err = typeof res.body === 'object' && res.body ? res.body : { error: res.statusText };\n\t throw new Error(err.error || 'Request failed: ' + res.status);\n\t }\n\t return res.body;\n\t }\n\n\t function sendToChat(message, options) {\n\t options = options || {};\n\t var text = typeof message === 'string' ? message : JSON.stringify(message);\n\t window.parent.postMessage({\n\t type: 'agent-native-send-to-chat',\n\t message: text,\n\t context: options.context,\n\t submit: options.submit !== false,\n\t openSidebar: options.openSidebar !== false,\n\t }, '*');\n\t return { ok: true };\n\t }\n\n\t function inlineUiOutputKey() {\n\t var safeId = String(_extensionId || 'unknown').replace(/[^A-Za-z0-9_:-]/g, '') || 'unknown';\n\t return 'inline-ui:' + safeId + ':output';\n\t }\n\n\t async function outputToUi(value, options) {\n\t options = options || {};\n\t var key = inlineUiOutputKey();\n\t var payload = {\n\t value: value,\n\t updatedAt: new Date().toISOString(),\n\t extensionId: _extensionId,\n\t source: 'inline-ui',\n\t };\n\t if (options.label !== undefined) payload.label = options.label;\n\t if (options.context !== undefined) payload.context = options.context;\n\t if (options.meta !== undefined) payload.meta = options.meta;\n\t var output = await appFetch('/_agent-native/application-state/' + key, {\n\t method: 'PUT',\n\t headers: { 'X-Request-Source': 'inline-ui' },\n\t body: JSON.stringify(payload),\n\t });\n\t try {\n\t window.parent.postMessage({\n\t type: 'agent-native-ui-output',\n\t extensionId: _extensionId,\n\t key: key,\n\t value: value,\n\t output: output,\n\t }, '*');\n\t } catch (_) {}\n\t return { ok: true, key: key, output: output };\n\t }\n\n async function dbQuery(sql, args) {\n var body = { sql: sql };\n if (args) body.args = args;\n return appFetch('/_agent-native/extensions/sql/query', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n async function dbExec(sql, args) {\n var body = { sql: sql };\n if (args) body.args = args;\n return appFetch('/_agent-native/extensions/sql/exec', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n var _extensionId = ${extensionIdJson};\n var _extensionBinding = ${bindingJson};\n window.extensionBinding = _extensionBinding;\n // Legacy alias for extension bodies authored before the rename.\n window.toolBinding = _extensionBinding;\n // SECURITY (audit H4): announce the resolved binding to the parent so the\n // host bridge can gate dangerous helpers based on viewer role. Sent\n // BEFORE the user-authored content has a chance to run, so a malicious\n // extension body cannot suppress or rewrite the announcement. The parent\n // ignores subsequent announcements for the same iframe; see\n // ExtensionViewer.tsx / EmbeddedExtension.tsx.\n try {\n window.parent.postMessage(\n {\n type: 'agent-native-extension-binding',\n extensionId: _extensionId,\n binding: _extensionBinding,\n },\n '*',\n );\n } catch (_) {}\n // SECURITY: when the viewer is not the author of this extension, emit a\n // clear console warning. The bridge currently runs every helper with the\n // viewer's session — a malicious shared extension can call any action,\n // read any owned table row in scope, and resolve any user-scope secret.\n // A full consent step is tracked as TODO C1 in audit 05-tools-sandbox.md.\n if (_extensionBinding && !_extensionBinding.isAuthor) {\n try {\n console.warn(\n '[agent-native] Shared extension — running with viewer\\\\'s session. ' +\n 'Author: ' + (_extensionBinding.authorEmail || '<unknown>') + '. ' +\n 'Bridge calls (appAction, dbExec, extensionFetch) execute under ' +\n 'your account; they are gated by your permissions, not the ' +\n 'author\\\\'s. Do not run untrusted shared extensions.',\n );\n } catch (_) {}\n }\n\n var extensionData = {\n\t async list(collection, opts) {\n\t var limit = (opts && opts.limit) || 100;\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/extensions/data/' + _extensionId + '/' + encodeURIComponent(collection) + '?limit=' + limit + '&scope=' + scope);\n\t if (!res.ok) throw new Error('Failed to list extension data');\n\t return res.body;\n\t },\n async get(collection, id, opts) {\n var scope = (opts && opts.scope) || 'user';\n var items = await this.list(collection, { scope: scope });\n return (items || []).find(function(item) { return item.id === id; }) || null;\n },\n async set(collection, id, data, opts) {\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/extensions/data/' + _extensionId + '/' + encodeURIComponent(collection), {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify({ id: id, data: data, scope: scope }),\n\t });\n\t if (!res.ok) throw new Error('Failed to save extension data');\n\t return res.body;\n\t },\n\t async remove(collection, id, opts) {\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/extensions/data/' + _extensionId + '/' + encodeURIComponent(collection) + '/' + encodeURIComponent(id) + '?scope=' + scope, {\n\t method: 'DELETE',\n\t });\n\t if (!res.ok) throw new Error('Failed to delete extension data');\n\t return res.body;\n\t },\n\t };\n\n\t // Legacy aliases — extension bodies authored before the rename use\n\t // toolFetch, toolData, toolId. Keep these working forever.\n\t var toolFetch = extensionFetch;\n\t var toolData = extensionData;\n\t var _toolId = _extensionId;\n\t window.agentNative = Object.assign(window.agentNative || {}, {\n\t extensionId: _extensionId,\n\t extensionBinding: _extensionBinding,\n\t appAction: appAction,\n\t appFetch: appFetch,\n\t dbQuery: dbQuery,\n\t dbExec: dbExec,\n\t extensionFetch: extensionFetch,\n\t extensionData: extensionData,\n\t data: extensionData,\n\t sendToChat: sendToChat,\n\t chat: Object.assign({}, (window.agentNative && window.agentNative.chat) || {}, {\n\t send: sendToChat,\n\t }),\n\t ui: Object.assign({}, (window.agentNative && window.agentNative.ui) || {}, {\n\t output: outputToUi,\n\t }),\n\t });\n\t window.sendToAgentChat = sendToChat;\n\t </script>\n\t <style>\n\t #__extension-error-toast {\n\t display: none;\n\t position: fixed;\n\t bottom: 16px;\n\t right: 16px;\n\t max-width: 420px;\n\t background: hsl(var(--destructive));\n\t color: hsl(var(--destructive-foreground));\n\t border: 1px solid hsl(var(--destructive) / .6);\n\t border-radius: calc(var(--radius, .5rem) + 2px);\n\t padding: 12px 16px;\n\t font-size: 13px;\n\t line-height: 1.4;\n\t font-family: 'Inter', sans-serif;\n\t z-index: 9999;\n\t box-shadow: 0 4px 12px rgba(0,0,0,.15), 0 1px 3px rgba(0,0,0,.1);\n\t animation: __toast-in 0.2s ease-out;\n\t }\n\t @keyframes __toast-in {\n\t from { opacity: 0; transform: translateY(8px); }\n\t to { opacity: 1; transform: translateY(0); }\n\t }\n\t </style>\n\t <script>\n\t // Extension-point slot context: when an extension is rendered embedded\n\t // inside an ExtensionSlot, the host pushes a context object via\n\t // postMessage. Extensions read it synchronously via window.slotContext\n\t // or subscribe to changes via window.onSlotContext(fn). When rendered\n\t // full-page (no ?slot= param), slotContext stays null and extensions\n\t // branch on that.\n\t window.slotContext = null;\n\t var _slotContextSubscribers = [];\n\t window.onSlotContext = function(fn) {\n\t _slotContextSubscribers.push(fn);\n\t if (window.slotContext !== null) {\n\t try { fn(window.slotContext); } catch(_) {}\n\t }\n\t return function() {\n\t _slotContextSubscribers = _slotContextSubscribers.filter(function(f) { return f !== fn; });\n\t };\n\t };\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var msg = event.data;\n\t if (!msg || msg.type !== 'agent-native-slot-context') return;\n\t window.slotContext = msg.context || {};\n\t _slotContextSubscribers.forEach(function(fn) {\n\t try { fn(window.slotContext); } catch(_) {}\n\t });\n\t });\n\n\t // Auto-resize iframe renders. Persisted extension slots include ?slot=;\n\t // transient inline chat UI uses srcdoc, so detect that by parent frame.\n\t // The host listens for agent-native-extension-resize and adjusts height.\n\t if (new URLSearchParams(location.search).get('slot') || window.parent !== window) {\n\t var _lastH = 0;\n\t var _reportHeight = function() {\n\t var h = Math.max(\n\t document.documentElement.scrollHeight,\n\t document.body ? document.body.scrollHeight : 0,\n\t );\n\t if (h !== _lastH) {\n\t _lastH = h;\n\t window.parent.postMessage({ type: 'agent-native-extension-resize', height: h }, '*');\n\t }\n\t };\n\t if (typeof ResizeObserver !== 'undefined') {\n\t var _ro = new ResizeObserver(_reportHeight);\n\t document.addEventListener('DOMContentLoaded', function() {\n\t _ro.observe(document.documentElement);\n\t if (document.body) _ro.observe(document.body);\n\t });\n\t }\n\t // Initial reports — Alpine takes a tick to render after DOMContentLoaded.\n\t setTimeout(_reportHeight, 50);\n\t setTimeout(_reportHeight, 250);\n\t }\n\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var msg = event.data;\n\t if (!msg || msg.type !== 'agent-native-theme-update') return;\n\t var root = document.documentElement;\n\t if (msg.isDark !== undefined) {\n\t if (msg.isDark) root.classList.add('dark');\n\t else root.classList.remove('dark');\n\t }\n\t var vars = msg.vars || {};\n\t for (var key in vars) {\n\t if (vars.hasOwnProperty(key)) {\n\t root.style.setProperty(key, vars[key]);\n\t }\n\t }\n\t });\n\n\t document.addEventListener('keydown', function(e) {\n\t if ((e.metaKey || e.ctrlKey) && !e.altKey) {\n\t var key = (e.key || '').toLowerCase();\n\t if (key === 'c' || key === 'v' || key === 'x' || key === 'a' || key === 'z' || key === 'y') return;\n\t e.preventDefault();\n\t e.stopPropagation();\n\t window.parent.postMessage({\n\t type: 'agent-native-extension-keydown',\n\t key: e.key, code: e.code,\n\t metaKey: e.metaKey, ctrlKey: e.ctrlKey,\n\t shiftKey: e.shiftKey, altKey: e.altKey,\n\t }, '*');\n\t return;\n\t }\n\t if (e.key === 'Escape') {\n\t window.parent.postMessage({\n\t type: 'agent-native-extension-keydown',\n\t key: e.key, code: e.code,\n\t metaKey: false, ctrlKey: false,\n\t shiftKey: false, altKey: false,\n\t }, '*');\n\t }\n\t });\n\n\t document.addEventListener('DOMContentLoaded', function() {\n\t _renderErrorToast();\n\t var fixBtn = document.getElementById('__extension-error-fix');\n\t if (fixBtn) {\n\t fixBtn.addEventListener('click', function() {\n\t window.parent.postMessage({\n\t type: 'agent-native-extension-error-fix',\n\t errors: _extensionErrors,\n\t errorDetails: _extensionErrorDetails,\n\t consoleLogs: _consoleLogs.slice(-30),\n\t networkLogs: _networkLogs.slice(-15)\n\t }, '*');\n\t document.getElementById('__extension-error-toast').style.display = 'none';\n\t });\n\t }\n\t var dismissBtn = document.getElementById('__extension-error-dismiss');\n\t if (dismissBtn) {\n\t dismissBtn.addEventListener('click', function() {\n\t document.getElementById('__extension-error-toast').style.display = 'none';\n\t });\n\t }\n\t });\n\t </script>\n\t</head>\n\t<body${extensionId ? ` data-extension-id=\"${extensionIdAttr}\" data-tool-id=\"${extensionIdAttr}\"` : \"\"} class=\"text-foreground\">\n\t${content}\n\t<div id=\"__extension-error-toast\">\n\t <div style=\"display:flex;align-items:flex-start;gap:8px;\">\n\t <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0;margin-top:1px;\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/></svg>\n\t <span id=\"__extension-error-msg\" style=\"flex:1;overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;\"></span>\n\t <button id=\"__extension-error-fix\" style=\"cursor:pointer;border:none;background:rgba(255,255,255,.9);color:hsl(0 84.2% 40%);font-size:12px;font-weight:500;padding:4px 12px;border-radius:4px;flex-shrink:0;\">Fix</button>\n\t <button id=\"__extension-error-dismiss\" style=\"cursor:pointer;border:none;background:transparent;color:inherit;font-size:16px;padding:2px 6px;opacity:0.7;flex-shrink:0;\">×</button>\n\t </div>\n\t</div>\n\t</body>\n\t</html>`;\n}\n\nfunction escapeHtmlAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/extensions/routes.ts"],"names":[],"mappings":"AAgEA,wBAAgB,uBAAuB,2FA2CtC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/extensions/routes.ts"],"names":[],"mappings":"AAgEA,wBAAgB,uBAAuB,2FA2CtC;AAm1BD,eAAO,MAAM,kBAAkB,QACqa,CAAC;AAMrc,eAAO,MAAM,gBAAgB,QACwkB,CAAC;AAMtmB,eAAO,MAAM,oBAAoB,QACgB,CAAC;AAMlD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ/D"}
|
|
@@ -57,6 +57,7 @@ export function createExtensionsHandler() {
|
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
+
const MAX_EXTENSION_DATA_BYTES = 1024 * 1024;
|
|
60
61
|
function normalizeExtensionUserEmail(email) {
|
|
61
62
|
return email.trim().toLowerCase();
|
|
62
63
|
}
|
|
@@ -414,6 +415,13 @@ async function handleExtensionDataUpsert(event, extensionId, collection, userEma
|
|
|
414
415
|
}
|
|
415
416
|
const itemId = String(body.id || randomUUID());
|
|
416
417
|
const data = typeof body.data === "string" ? body.data : JSON.stringify(body.data);
|
|
418
|
+
if (Buffer.byteLength(data, "utf8") > MAX_EXTENSION_DATA_BYTES) {
|
|
419
|
+
setResponseStatus(event, 413);
|
|
420
|
+
return {
|
|
421
|
+
error: "Extension data is too large for SQL storage. Store large files, base64, or blobs in file storage and save only a URL or handle.",
|
|
422
|
+
maxBytes: MAX_EXTENSION_DATA_BYTES,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
417
425
|
const now = new Date().toISOString();
|
|
418
426
|
const scope = body.scope === "org" ? "org" : "user";
|
|
419
427
|
const orgId = getRequestOrgId();
|