@agent-native/core 0.141.7 → 0.144.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +9 -0
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/analytics/AGENTS.md +35 -38
- package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
- package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
- package/corpus/templates/analytics/actions/navigate.ts +4 -5
- package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +44 -11
- package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
- package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
- package/corpus/templates/analytics/app/i18n-data.ts +680 -0
- package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
- package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
- package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
- package/corpus/templates/analytics/netlify.toml +7 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
- package/corpus/templates/analytics/server/db/index.ts +27 -0
- package/corpus/templates/analytics/server/db/schema.ts +10 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +133 -44
- package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
- package/corpus/templates/analytics/server/plugins/db.ts +52 -18
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +28 -2
- package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
- package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
- package/corpus/templates/brain/app/routes/sources.tsx +15 -7
- package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
- package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/calendar/AGENTS.md +11 -32
- package/corpus/templates/calendar/actions/update-event.ts +107 -1
- package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
- package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
- package/corpus/templates/calendar/app/i18n-data.ts +20 -0
- package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
- package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
- package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
- package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
- package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +48 -20
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
- package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
- package/corpus/templates/clips/server/plugins/db.ts +214 -26
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
- package/corpus/templates/crm/server/plugins/db.ts +11 -8
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/design/actions/import-from-url.ts +1 -1
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
- package/corpus/templates/design/app/pages/Index.tsx +6 -2
- package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
- package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +37 -1
- package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/slides/AGENTS.md +7 -9
- package/corpus/templates/slides/_gitignore +1 -0
- package/corpus/templates/slides/actions/export-pptx.ts +402 -36
- package/corpus/templates/slides/actions/import-file.ts +46 -85
- package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
- package/corpus/templates/slides/actions/import-pptx.ts +85 -60
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +173 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
- package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
- package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +4 -0
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
- package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
- package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
- package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
- package/corpus/templates/slides/app/pages/Index.tsx +91 -1
- package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +236 -13
- package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
- package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
- package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
- package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -3
- package/corpus/templates/slides/server/lib/emails.ts +7 -2
- package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
- package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -3
- package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
- package/corpus/templates/slides/shared/upload-types.ts +3 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/agent/production-agent.d.ts +17 -0
- package/dist/agent/production-agent.js +72 -1
- package/dist/cli/agent-plugin.d.ts +112 -0
- package/dist/cli/agent-plugin.js +1081 -0
- package/dist/cli/app-skill.js +39 -1
- package/dist/cli/code-agent-executor.d.ts +3 -0
- package/dist/cli/code-agent-executor.js +51 -13
- package/dist/cli/index.js +13 -0
- package/dist/cli/templates-meta.js +1 -1
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.js +9 -2
- package/dist/client/AssistantChat.d.ts +8 -0
- package/dist/client/AssistantChat.js +23 -8
- package/dist/client/NewWorkspaceAppFlow.js +1 -0
- package/dist/client/agent-chat-adapter.js +123 -4
- package/dist/client/assistant-ui-recovery.d.ts +2 -1
- package/dist/client/assistant-ui-recovery.js +7 -3
- package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
- package/dist/client/org/TeamPage.js +1 -1
- package/dist/client/require-session.js +1 -1
- package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
- package/dist/client/resources/McpConnectionSuggestion.js +27 -10
- package/dist/client/resources/McpIntegrationDialog.js +77 -45
- package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
- package/dist/client/resources/mcp-integration-catalog.js +255 -2
- package/dist/client/resources/mcp-integration-logos.js +18 -2
- package/dist/client/settings/AccountSettingsCard.js +2 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts +9 -0
- package/dist/db/client.js +51 -16
- package/dist/db/create-get-db.js +2 -2
- package/dist/db/ddl-guard.d.ts +11 -10
- package/dist/db/ddl-guard.js +40 -12
- package/dist/deploy/build.d.ts +2 -0
- package/dist/deploy/build.js +97 -4
- package/dist/deploy/workspace-deploy.js +0 -2
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/guards/no-env-credentials.js +9 -0
- package/dist/ingestion/index.d.ts +1 -1
- package/dist/ingestion/pptx.d.ts +68 -0
- package/dist/ingestion/pptx.js +660 -213
- package/dist/integrations/plugin.js +9 -6
- package/dist/localization/default-messages.d.ts +54 -0
- package/dist/localization/default-messages.js +57 -2
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp-client/oauth-routes.d.ts +2 -0
- package/dist/mcp-client/oauth-routes.js +73 -6
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/onboarding/app-profile.js +11 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/store.js +15 -1
- package/dist/scripts/call-agent.js +34 -4
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +36 -1
- package/dist/server/agent-chat-plugin.js +29 -8
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +47 -11
- package/dist/server/better-auth-instance.js +5 -3
- package/dist/server/core-routes-plugin.d.ts +8 -1
- package/dist/server/core-routes-plugin.js +28 -3
- package/dist/server/credential-provider.d.ts +3 -3
- package/dist/server/credential-provider.js +90 -4
- package/dist/server/onboarding-html.d.ts +2 -0
- package/dist/server/onboarding-html.js +115 -29
- package/dist/server/self-dispatch.d.ts +5 -4
- package/dist/server/self-dispatch.js +25 -14
- package/dist/server/ssr-handler.d.ts +1 -1
- package/dist/server/ssr-handler.js +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/cache-control.d.ts +26 -2
- package/dist/shared/cache-control.js +43 -2
- package/dist/shared/password-policy.d.ts +3 -0
- package/dist/shared/password-policy.js +3 -0
- package/dist/sharing/actions/set-resource-visibility.js +16 -4
- package/dist/sharing/registry.d.ts +14 -0
- package/dist/styles/agent-native.css +6 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/workspace-root/AGENTS.md +7 -0
- package/dist/user-profile/actions/change-password.js +8 -3
- package/dist/user-profile/actions/set-password.js +5 -1
- package/dist/vite/action-types-plugin.js +59 -0
- package/docs/content/skills-guide.mdx +13 -0
- package/package.json +6 -2
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/workspace-root/AGENTS.md +7 -0
|
@@ -59,6 +59,29 @@ function createAbortError(): Error {
|
|
|
59
59
|
return error;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
function createDeadlineSignal(
|
|
63
|
+
parentSignal: AbortSignal | undefined,
|
|
64
|
+
timeoutMs: number,
|
|
65
|
+
): { signal: AbortSignal; cleanup: () => void } {
|
|
66
|
+
const controller = new AbortController();
|
|
67
|
+
const abortFromParent = () => controller.abort(parentSignal?.reason);
|
|
68
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
69
|
+
|
|
70
|
+
if (parentSignal?.aborted) {
|
|
71
|
+
abortFromParent();
|
|
72
|
+
} else {
|
|
73
|
+
parentSignal?.addEventListener("abort", abortFromParent, { once: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
signal: controller.signal,
|
|
78
|
+
cleanup: () => {
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
parentSignal?.removeEventListener("abort", abortFromParent);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
62
85
|
function createSqlQueryRelease(pool: SqlQuerySlotPool): () => void {
|
|
63
86
|
let released = false;
|
|
64
87
|
return () => {
|
|
@@ -117,21 +140,25 @@ export async function executeSqlQuery(
|
|
|
117
140
|
signal?: AbortSignal,
|
|
118
141
|
options?: { reportScreenshot?: boolean },
|
|
119
142
|
): Promise<SqlQueryResult> {
|
|
120
|
-
const
|
|
143
|
+
const deadline = createDeadlineSignal(
|
|
144
|
+
signal,
|
|
145
|
+
DASHBOARD_REPORT_ACTION_TIMEOUT_MS,
|
|
146
|
+
);
|
|
147
|
+
let release: (() => void) | undefined;
|
|
121
148
|
let data: DashboardPanelQueryResponse;
|
|
122
149
|
try {
|
|
150
|
+
release = await acquireSqlQuerySlot(source, deadline.signal);
|
|
123
151
|
data = await callAction<DashboardPanelQueryResponse>(
|
|
124
152
|
"query-dashboard-panel",
|
|
125
153
|
{ query: sql, source },
|
|
126
154
|
{
|
|
127
|
-
signal,
|
|
128
|
-
|
|
129
|
-
? { timeoutMs: DASHBOARD_REPORT_ACTION_TIMEOUT_MS }
|
|
130
|
-
: {}),
|
|
155
|
+
signal: deadline.signal,
|
|
156
|
+
timeoutMs: DASHBOARD_REPORT_ACTION_TIMEOUT_MS,
|
|
131
157
|
},
|
|
132
158
|
);
|
|
133
159
|
} finally {
|
|
134
|
-
release();
|
|
160
|
+
release?.();
|
|
161
|
+
deadline.cleanup();
|
|
135
162
|
}
|
|
136
163
|
|
|
137
164
|
if (typeof data?.error === "string") {
|
|
@@ -94,6 +94,8 @@ import {
|
|
|
94
94
|
type WalkthroughStep,
|
|
95
95
|
} from "@/lib/data-sources";
|
|
96
96
|
|
|
97
|
+
import { CustomApiCard } from "../components/CustomApiCard";
|
|
98
|
+
|
|
97
99
|
interface AnalyticsPublicKeyRow {
|
|
98
100
|
id: string;
|
|
99
101
|
name: string;
|
|
@@ -2099,6 +2101,8 @@ export default function DataSources() {
|
|
|
2099
2101
|
|
|
2100
2102
|
<GoogleSheetsExportCard statusData={statusData} />
|
|
2101
2103
|
|
|
2104
|
+
<CustomApiCard />
|
|
2105
|
+
|
|
2102
2106
|
{unknownFocusedSourceId && (
|
|
2103
2107
|
<div
|
|
2104
2108
|
role="status"
|
|
@@ -25,6 +25,13 @@ AGENT_CHAT_DURABLE_BACKGROUND = "true"
|
|
|
25
25
|
[functions."*"]
|
|
26
26
|
timeout = 75
|
|
27
27
|
|
|
28
|
+
# Recent durable Analytics runs recorded failed-worker RSS above 4 GB while
|
|
29
|
+
# Netlify Functions default to 1 GB. Give the long-running agent worker the
|
|
30
|
+
# highest supported allocation so memory pressure does not masquerade as a
|
|
31
|
+
# stale heartbeat; query and connection bounds remain the primary safeguards.
|
|
32
|
+
[functions.server-agent-background]
|
|
33
|
+
memory = "4gb"
|
|
34
|
+
|
|
28
35
|
[functions.dashboard-report-sweep-background]
|
|
29
36
|
timeout = 300
|
|
30
37
|
memory = "2gb"
|
|
@@ -83,6 +83,7 @@ function emitBackgroundWorker(token: string) {
|
|
|
83
83
|
rmSync(path.join(dest, "server.mjs"), { force: true });
|
|
84
84
|
|
|
85
85
|
const source = `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
|
|
86
|
+
globalThis.__AGENT_NATIVE_LOW_CONNECTION_BACKGROUND_RUNTIME__ = true;
|
|
86
87
|
globalThis.__AGENT_NATIVE_DASHBOARD_REPORT_SCHEDULED_RUNTIME__ = true;
|
|
87
88
|
|
|
88
89
|
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
@@ -227,6 +228,7 @@ function emitAlertBackgroundWorker(token: string) {
|
|
|
227
228
|
rmSync(path.join(dest, "server.mjs"), { force: true });
|
|
228
229
|
|
|
229
230
|
const source = `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
|
|
231
|
+
globalThis.__AGENT_NATIVE_LOW_CONNECTION_BACKGROUND_RUNTIME__ = true;
|
|
230
232
|
globalThis.__AGENT_NATIVE_ANALYTICS_ALERT_SCHEDULED_RUNTIME__ = true;
|
|
231
233
|
|
|
232
234
|
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
@@ -344,6 +346,7 @@ function emitUptimeBackgroundWorker(token: string) {
|
|
|
344
346
|
rmSync(path.join(dest, "server.mjs"), { force: true });
|
|
345
347
|
|
|
346
348
|
const source = `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
|
|
349
|
+
globalThis.__AGENT_NATIVE_LOW_CONNECTION_BACKGROUND_RUNTIME__ = true;
|
|
347
350
|
globalThis.__AGENT_NATIVE_UPTIME_MONITOR_SCHEDULED_RUNTIME__ = true;
|
|
348
351
|
|
|
349
352
|
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
@@ -443,6 +446,7 @@ function emitRollupBackgroundWorker(token: string) {
|
|
|
443
446
|
rmSync(path.join(dest, "server.mjs"), { force: true });
|
|
444
447
|
|
|
445
448
|
const source = `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
|
|
449
|
+
globalThis.__AGENT_NATIVE_LOW_CONNECTION_BACKGROUND_RUNTIME__ = true;
|
|
446
450
|
globalThis.__AGENT_NATIVE_ANALYTICS_ROLLUP_BACKFILL_SCHEDULED_RUNTIME__ = true;
|
|
447
451
|
|
|
448
452
|
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
@@ -29,6 +29,33 @@ registerShareableResource({
|
|
|
29
29
|
resourceKind: ANALYTICS_DASHBOARD_AGENT_RESOURCE_KIND,
|
|
30
30
|
getContextPath: () => ANALYTICS_DASHBOARD_AGENT_CONTEXT_ENDPOINT,
|
|
31
31
|
},
|
|
32
|
+
persistVisibilityChange: async ({
|
|
33
|
+
resource,
|
|
34
|
+
resourceId,
|
|
35
|
+
visibility,
|
|
36
|
+
update,
|
|
37
|
+
userEmail,
|
|
38
|
+
orgId,
|
|
39
|
+
}) => {
|
|
40
|
+
const { persistDashboardVisibilityChange } =
|
|
41
|
+
await import("../lib/dashboards-store.js");
|
|
42
|
+
await persistDashboardVisibilityChange(
|
|
43
|
+
{
|
|
44
|
+
id: resourceId,
|
|
45
|
+
title: resource.title,
|
|
46
|
+
orgId: resource.orgId ?? null,
|
|
47
|
+
},
|
|
48
|
+
visibility,
|
|
49
|
+
update,
|
|
50
|
+
{
|
|
51
|
+
email: userEmail ?? resource.ownerEmail,
|
|
52
|
+
orgId:
|
|
53
|
+
typeof update.orgId === "string"
|
|
54
|
+
? update.orgId
|
|
55
|
+
: (orgId ?? resource.orgId ?? null),
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
},
|
|
32
59
|
getDb,
|
|
33
60
|
});
|
|
34
61
|
|
|
@@ -43,6 +43,16 @@ export const dashboards = table("dashboards", {
|
|
|
43
43
|
...ownableColumns(),
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Persistent per-name rows serialize concurrent create/rename checks. The row
|
|
48
|
+
* is deliberately independent of dashboard visibility: callers acquire the
|
|
49
|
+
* same lock before applying their access-scoped collision check.
|
|
50
|
+
*/
|
|
51
|
+
export const dashboardNameLocks = table("dashboard_name_locks", {
|
|
52
|
+
nameKey: text("name_key").primaryKey(),
|
|
53
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
54
|
+
});
|
|
55
|
+
|
|
46
56
|
export const dashboardShares = createSharesTable("dashboard_shares");
|
|
47
57
|
|
|
48
58
|
/**
|
|
@@ -138,6 +138,10 @@ const ANALYSIS_PREFIX = "adhoc-analysis-";
|
|
|
138
138
|
const DASHBOARD_REVISION_LIMIT = 50;
|
|
139
139
|
const ANALYSIS_REVISION_LIMIT = 30;
|
|
140
140
|
|
|
141
|
+
export function normalizeDashboardName(value: string): string {
|
|
142
|
+
return value.trim().replace(/\s+/g, " ").toLowerCase();
|
|
143
|
+
}
|
|
144
|
+
|
|
141
145
|
function nowIso(): string {
|
|
142
146
|
return new Date().toISOString();
|
|
143
147
|
}
|
|
@@ -532,9 +536,11 @@ export async function listDashboardSummaries(
|
|
|
532
536
|
archived?: DashboardArchiveFilter;
|
|
533
537
|
hidden?: DashboardHiddenFilter;
|
|
534
538
|
includeCatalogMetadata?: boolean;
|
|
539
|
+
legacyScan?: "best-effort" | "strict";
|
|
535
540
|
},
|
|
541
|
+
dbOverride?: any,
|
|
536
542
|
): Promise<DashboardSummaryRecord[]> {
|
|
537
|
-
const db = getDb() as any;
|
|
543
|
+
const db = (dbOverride ?? getDb()) as any;
|
|
538
544
|
const archived = filter?.archived ?? "active";
|
|
539
545
|
const hidden = filter?.hidden ?? "visible";
|
|
540
546
|
const includeCatalogMetadata = filter?.includeCatalogMetadata === true;
|
|
@@ -663,12 +669,85 @@ export async function listDashboardSummaries(
|
|
|
663
669
|
hiddenBy: null,
|
|
664
670
|
});
|
|
665
671
|
}
|
|
666
|
-
} catch {
|
|
672
|
+
} catch (error) {
|
|
673
|
+
if (filter?.legacyScan === "strict") throw error;
|
|
667
674
|
// Legacy scan is best-effort.
|
|
668
675
|
}
|
|
669
676
|
return out;
|
|
670
677
|
}
|
|
671
678
|
|
|
679
|
+
/**
|
|
680
|
+
* Reject a name that would collide with another dashboard visible to the
|
|
681
|
+
* caller. Archived and hidden dashboards are intentionally excluded because
|
|
682
|
+
* they are not part of the navigation surface this protects.
|
|
683
|
+
*/
|
|
684
|
+
export async function assertDashboardNameIsAvailable(
|
|
685
|
+
name: string,
|
|
686
|
+
ctx: AccessCtx,
|
|
687
|
+
excludeId?: string,
|
|
688
|
+
dbOverride?: any,
|
|
689
|
+
): Promise<void> {
|
|
690
|
+
const normalized = normalizeDashboardName(name);
|
|
691
|
+
if (!normalized) return;
|
|
692
|
+
const conflict = (
|
|
693
|
+
await listDashboardSummaries(ctx, { legacyScan: "strict" }, dbOverride)
|
|
694
|
+
).find(
|
|
695
|
+
(dashboard) =>
|
|
696
|
+
dashboard.id !== excludeId &&
|
|
697
|
+
normalizeDashboardName(dashboard.name) === normalized,
|
|
698
|
+
);
|
|
699
|
+
if (!conflict) return;
|
|
700
|
+
throw new Error(
|
|
701
|
+
`Dashboard name "${name.trim()}" is already used by visible dashboard "${conflict.name}". Choose a different name.`,
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async function lockDashboardNames(db: any, names: string[]): Promise<void> {
|
|
706
|
+
const nameKeys = [
|
|
707
|
+
...new Set(names.map(normalizeDashboardName).filter(Boolean)),
|
|
708
|
+
].sort();
|
|
709
|
+
for (const nameKey of nameKeys) {
|
|
710
|
+
await db
|
|
711
|
+
.insert(schema.dashboardNameLocks)
|
|
712
|
+
.values({ nameKey, createdAt: nowIso() })
|
|
713
|
+
.onConflictDoNothing();
|
|
714
|
+
if (isPostgres()) {
|
|
715
|
+
await db.execute(
|
|
716
|
+
sql`SELECT name_key FROM dashboard_name_locks WHERE name_key = ${nameKey} FOR UPDATE`,
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Persist a visibility change while holding the same name lock used by create
|
|
724
|
+
* and rename. Sharing a private duplicate must not bypass the visible-name
|
|
725
|
+
* invariant by changing visibility after the dashboard was created.
|
|
726
|
+
*/
|
|
727
|
+
export async function persistDashboardVisibilityChange(
|
|
728
|
+
resource: Pick<DashboardRecord, "id" | "title" | "orgId">,
|
|
729
|
+
visibility: DashboardRecord["visibility"],
|
|
730
|
+
update: Record<string, unknown>,
|
|
731
|
+
ctx: AccessCtx,
|
|
732
|
+
): Promise<void> {
|
|
733
|
+
const db = getDb() as any;
|
|
734
|
+
await db.transaction(async (tx: any) => {
|
|
735
|
+
if (visibility !== "private") {
|
|
736
|
+
await lockDashboardNames(tx, [resource.title]);
|
|
737
|
+
await assertDashboardNameIsAvailable(
|
|
738
|
+
resource.title,
|
|
739
|
+
ctx,
|
|
740
|
+
resource.id,
|
|
741
|
+
tx,
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
await tx
|
|
745
|
+
.update(schema.dashboards)
|
|
746
|
+
.set(update)
|
|
747
|
+
.where(eq(schema.dashboards.id, resource.id));
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
|
|
672
751
|
async function pruneDashboardRevisions(
|
|
673
752
|
db: any,
|
|
674
753
|
dashboardId: string,
|
|
@@ -746,58 +825,80 @@ export async function upsertDashboard(
|
|
|
746
825
|
userEmail: ctx.email,
|
|
747
826
|
orgId: ctx.orgId ?? undefined,
|
|
748
827
|
});
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
.
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
828
|
+
}
|
|
829
|
+
const nameChanged =
|
|
830
|
+
!existing ||
|
|
831
|
+
normalizeDashboardName(existing.title) !== normalizeDashboardName(title);
|
|
832
|
+
if (nameChanged) {
|
|
833
|
+
await assertDashboardNameIsAvailable(title, ctx, existing?.id);
|
|
834
|
+
}
|
|
835
|
+
const persist = async (writeDb: any): Promise<void> => {
|
|
836
|
+
if (existing) {
|
|
837
|
+
const changed =
|
|
838
|
+
existing.kind !== kind ||
|
|
839
|
+
existing.title !== title ||
|
|
840
|
+
JSON.stringify(existing.config) !== configJson;
|
|
841
|
+
const setValues = {
|
|
842
|
+
kind,
|
|
843
|
+
title,
|
|
844
|
+
config: configJson,
|
|
845
|
+
updatedAt: nowIso(),
|
|
846
|
+
updatedBy: ctx.email,
|
|
847
|
+
};
|
|
848
|
+
if (expectedUpdatedAt !== undefined) {
|
|
849
|
+
// Fenced write. Snapshot the revision only after we know this exact
|
|
850
|
+
// write actually landed — otherwise a lost race would record a
|
|
851
|
+
// revision for a save that never happened.
|
|
852
|
+
const updateResult = await writeDb
|
|
853
|
+
.update(schema.dashboards)
|
|
854
|
+
.set(setValues)
|
|
855
|
+
.where(
|
|
856
|
+
and(
|
|
857
|
+
eq(schema.dashboards.id, id),
|
|
858
|
+
eq(schema.dashboards.updatedAt, expectedUpdatedAt),
|
|
859
|
+
),
|
|
860
|
+
);
|
|
861
|
+
const affected = affectedRowCount(updateResult);
|
|
862
|
+
if (affected === undefined) {
|
|
863
|
+
throw new Error(
|
|
864
|
+
"The database driver did not report an affected-row count for the fenced dashboard update.",
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
if (affected === 0) {
|
|
868
|
+
throw new DashboardConflictError(id);
|
|
869
|
+
}
|
|
870
|
+
if (changed) await snapshotDashboardRevision(writeDb, existing, ctx);
|
|
871
|
+
} else {
|
|
872
|
+
if (changed) await snapshotDashboardRevision(writeDb, existing, ctx);
|
|
873
|
+
await writeDb
|
|
874
|
+
.update(schema.dashboards)
|
|
875
|
+
.set(setValues)
|
|
876
|
+
.where(eq(schema.dashboards.id, id));
|
|
781
877
|
}
|
|
782
|
-
if (changed) await snapshotDashboardRevision(db, existing, ctx);
|
|
783
878
|
} else {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
.
|
|
879
|
+
await writeDb.insert(schema.dashboards).values({
|
|
880
|
+
id,
|
|
881
|
+
kind,
|
|
882
|
+
title,
|
|
883
|
+
config: JSON.stringify(config),
|
|
884
|
+
ownerEmail: ctx.email,
|
|
885
|
+
orgId: ctx.orgId,
|
|
886
|
+
visibility: "private",
|
|
887
|
+
updatedBy: ctx.email,
|
|
888
|
+
});
|
|
789
889
|
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
updatedBy: ctx.email,
|
|
890
|
+
};
|
|
891
|
+
if (nameChanged) {
|
|
892
|
+
await db.transaction(async (tx: any) => {
|
|
893
|
+
await lockDashboardNames(tx, [
|
|
894
|
+
title,
|
|
895
|
+
...(existing ? [existing.title] : []),
|
|
896
|
+
]);
|
|
897
|
+
await assertDashboardNameIsAvailable(title, ctx, existing?.id, tx);
|
|
898
|
+
await persist(tx);
|
|
800
899
|
});
|
|
900
|
+
} else {
|
|
901
|
+
await persist(db);
|
|
801
902
|
}
|
|
802
903
|
const [row] = await db
|
|
803
904
|
.select()
|
|
@@ -932,7 +1033,23 @@ export async function restoreDashboardRevision(
|
|
|
932
1033
|
if (!revisionRow) return null;
|
|
933
1034
|
const revision = rowToDashboardRevision(revisionRow);
|
|
934
1035
|
const updatedAt = nowIso();
|
|
1036
|
+
const nameChanged =
|
|
1037
|
+
normalizeDashboardName(existing.title) !==
|
|
1038
|
+
normalizeDashboardName(revision.title);
|
|
1039
|
+
const becomesVisible = !existing.archivedAt && !existing.hiddenAt;
|
|
1040
|
+
if (nameChanged && becomesVisible) {
|
|
1041
|
+
await assertDashboardNameIsAvailable(revision.title, ctx, dashboardId);
|
|
1042
|
+
}
|
|
935
1043
|
const restored = await db.transaction(async (tx: any) => {
|
|
1044
|
+
if (nameChanged && becomesVisible) {
|
|
1045
|
+
await lockDashboardNames(tx, [existing.title, revision.title]);
|
|
1046
|
+
await assertDashboardNameIsAvailable(
|
|
1047
|
+
revision.title,
|
|
1048
|
+
ctx,
|
|
1049
|
+
dashboardId,
|
|
1050
|
+
tx,
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
936
1053
|
const updateResult = await tx
|
|
937
1054
|
.update(schema.dashboards)
|
|
938
1055
|
.set({
|
|
@@ -1037,11 +1154,25 @@ export async function unarchiveDashboard(
|
|
|
1037
1154
|
userEmail: ctx.email,
|
|
1038
1155
|
orgId: ctx.orgId ?? undefined,
|
|
1039
1156
|
});
|
|
1157
|
+
if (!existing.hiddenAt) {
|
|
1158
|
+
await assertDashboardNameIsAvailable(existing.title, ctx, id);
|
|
1159
|
+
}
|
|
1040
1160
|
const db = getDb() as any;
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1161
|
+
const persist = async (writeDb: any) => {
|
|
1162
|
+
await writeDb
|
|
1163
|
+
.update(schema.dashboards)
|
|
1164
|
+
.set({ archivedAt: null, updatedAt: nowIso(), updatedBy: ctx.email })
|
|
1165
|
+
.where(eq(schema.dashboards.id, id));
|
|
1166
|
+
};
|
|
1167
|
+
if (!existing.hiddenAt) {
|
|
1168
|
+
await db.transaction(async (tx: any) => {
|
|
1169
|
+
await lockDashboardNames(tx, [existing.title]);
|
|
1170
|
+
await assertDashboardNameIsAvailable(existing.title, ctx, id, tx);
|
|
1171
|
+
await persist(tx);
|
|
1172
|
+
});
|
|
1173
|
+
} else {
|
|
1174
|
+
await persist(db);
|
|
1175
|
+
}
|
|
1045
1176
|
const [row] = await db
|
|
1046
1177
|
.select()
|
|
1047
1178
|
.from(schema.dashboards)
|
|
@@ -1116,6 +1247,9 @@ export async function unhideDashboard(
|
|
|
1116
1247
|
userEmail: ctx.email,
|
|
1117
1248
|
orgId: ctx.orgId ?? undefined,
|
|
1118
1249
|
});
|
|
1250
|
+
if (!existing.archivedAt) {
|
|
1251
|
+
await assertDashboardNameIsAvailable(existing.title, ctx, id);
|
|
1252
|
+
}
|
|
1119
1253
|
const db = getDb() as any;
|
|
1120
1254
|
const now = nowIso();
|
|
1121
1255
|
const patch: Record<string, unknown> = {
|
|
@@ -1127,10 +1261,21 @@ export async function unhideDashboard(
|
|
|
1127
1261
|
if (!existing.ownerEmail) {
|
|
1128
1262
|
patch.ownerEmail = ctx.email;
|
|
1129
1263
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1264
|
+
const persist = async (writeDb: any) => {
|
|
1265
|
+
await writeDb
|
|
1266
|
+
.update(schema.dashboards)
|
|
1267
|
+
.set(patch)
|
|
1268
|
+
.where(eq(schema.dashboards.id, id));
|
|
1269
|
+
};
|
|
1270
|
+
if (!existing.archivedAt) {
|
|
1271
|
+
await db.transaction(async (tx: any) => {
|
|
1272
|
+
await lockDashboardNames(tx, [existing.title]);
|
|
1273
|
+
await assertDashboardNameIsAvailable(existing.title, ctx, id, tx);
|
|
1274
|
+
await persist(tx);
|
|
1275
|
+
});
|
|
1276
|
+
} else {
|
|
1277
|
+
await persist(db);
|
|
1278
|
+
}
|
|
1134
1279
|
const [row] = await db
|
|
1135
1280
|
.select()
|
|
1136
1281
|
.from(schema.dashboards)
|
|
@@ -1922,8 +2067,30 @@ export async function listDashboardViews(
|
|
|
1922
2067
|
ctx: AccessCtx,
|
|
1923
2068
|
): Promise<DashboardViewRecord[]> {
|
|
1924
2069
|
// Parent access gates view visibility.
|
|
1925
|
-
const
|
|
1926
|
-
|
|
2070
|
+
const access = await resolveAccess(
|
|
2071
|
+
"dashboard",
|
|
2072
|
+
dashboardId,
|
|
2073
|
+
{
|
|
2074
|
+
userEmail: ctx.email,
|
|
2075
|
+
orgId: ctx.orgId ?? undefined,
|
|
2076
|
+
},
|
|
2077
|
+
{ skipResourceBody: true },
|
|
2078
|
+
);
|
|
2079
|
+
if (!access) {
|
|
2080
|
+
// Keep the migration-aware legacy fallback for dashboards that predate
|
|
2081
|
+
// SQL materialization while retaining the projected SQL fast path.
|
|
2082
|
+
const legacy = await findLegacyDashboard(dashboardId, ctx);
|
|
2083
|
+
if (!legacy) return [];
|
|
2084
|
+
await migrateDashboardFromSettings(
|
|
2085
|
+
dashboardId,
|
|
2086
|
+
legacy.kind,
|
|
2087
|
+
legacy.data,
|
|
2088
|
+
legacy.ownerEmail,
|
|
2089
|
+
legacy.orgId,
|
|
2090
|
+
legacy.visibility,
|
|
2091
|
+
"owner",
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
1927
2094
|
const db = getDb() as any;
|
|
1928
2095
|
const rows = await db
|
|
1929
2096
|
.select()
|