@agent-native/core 0.85.6 → 0.86.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +130 -1
- package/corpus/core/README.md +0 -11
- package/corpus/core/docs/content/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ar-SA/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ar-SA/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ar-SA/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/workspace-connections.mdx +11 -11
- package/corpus/core/docs/content/locales/de-DE/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/de-DE/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/de-DE/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/es-ES/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/es-ES/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/fr-FR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/fr-FR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/hi-IN/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/hi-IN/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ja-JP/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ja-JP/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ko-KR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ko-KR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/pt-BR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/pt-BR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/zh-CN/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/zh-CN/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/zh-TW/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/zh-TW/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/plan-plugin.mdx +12 -11
- package/corpus/core/docs/content/sharing.mdx +1 -2
- package/corpus/core/docs/content/skills-guide.mdx +4 -3
- package/corpus/core/docs/content/template-plan.mdx +37 -6
- package/corpus/core/docs/content/tracking.mdx +1 -1
- package/corpus/core/docs/content/workspace-connections.mdx +1 -1
- package/corpus/core/package.json +6 -6
- package/corpus/core/src/agent/run-store.ts +1 -1
- package/corpus/core/src/chat-threads/store.ts +73 -11
- package/corpus/core/src/checkpoints/store.ts +13 -2
- package/corpus/core/src/cli/create.ts +3 -4
- package/corpus/core/src/cli/design-connect.ts +469 -9
- package/corpus/core/src/cli/index.ts +13 -0
- package/corpus/core/src/cli/plan-local.ts +281 -24
- package/corpus/core/src/cli/skills.ts +177 -21
- package/corpus/core/src/cli/templates-meta.ts +0 -13
- package/corpus/core/src/cli/visualize-repo.ts +715 -0
- package/corpus/core/src/client/AssistantChat.tsx +126 -17
- package/corpus/core/src/client/agent-chat-adapter.ts +6 -5
- package/corpus/core/src/client/app-providers.tsx +2 -2
- package/corpus/core/src/client/collab/index.ts +31 -0
- package/corpus/core/src/client/components/LiveCursorOverlay.tsx +16 -1
- package/corpus/core/src/client/components/PresenceBar.tsx +14 -1
- package/corpus/core/src/client/components/RecentEditHighlights.tsx +219 -0
- package/corpus/core/src/client/components/RemoteSelectionRings.tsx +40 -6
- package/corpus/core/src/client/index.ts +48 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +0 -4
- package/corpus/core/src/client/rich-markdown-editor/SharedRichEditor.tsx +49 -32
- package/corpus/core/src/client/rich-markdown-editor/index.ts +6 -0
- package/corpus/core/src/client/rich-markdown-editor/surgical-apply.ts +192 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +59 -8
- package/corpus/core/src/client/session-replay.ts +181 -15
- package/corpus/core/src/client/sse-event-processor.ts +90 -1
- package/corpus/core/src/client/use-action.ts +123 -25
- package/corpus/core/src/client/use-agent-engine-configured.ts +7 -1
- package/corpus/core/src/client/use-chat-threads.ts +18 -7
- package/corpus/core/src/client/use-db-sync.ts +104 -19
- package/corpus/core/src/client/use-pinch-zoom.ts +76 -11
- package/corpus/core/src/client/visual-style-controls.tsx +475 -0
- package/corpus/core/src/collab/agent-presence.ts +191 -62
- package/corpus/core/src/collab/awareness.ts +83 -6
- package/corpus/core/src/collab/client.ts +89 -146
- package/corpus/core/src/collab/index.ts +34 -0
- package/corpus/core/src/collab/presence.ts +63 -3
- package/corpus/core/src/collab/recent-edits.ts +171 -0
- package/corpus/core/src/collab/undo.ts +432 -0
- package/corpus/core/src/collab/ydoc-manager.ts +68 -0
- package/corpus/core/src/connections/catalog.ts +2 -3
- package/corpus/core/src/db/create-get-db.ts +86 -1
- package/corpus/core/src/db/ensure-additive-columns.ts +430 -0
- package/corpus/core/src/db/index.ts +6 -0
- package/corpus/core/src/db/migrations.ts +236 -35
- package/corpus/core/src/jobs/scheduler.ts +17 -14
- package/corpus/core/src/observability/traces.ts +182 -1
- package/corpus/core/src/org/context.ts +79 -2
- package/corpus/core/src/server/agent-chat-plugin.ts +10 -6
- package/corpus/core/src/server/auth-marketing.ts +0 -11
- package/corpus/core/src/server/auth.ts +11 -4
- package/corpus/core/src/server/collab-plugin.ts +56 -13
- package/corpus/core/src/server/design-token-utils.ts +1 -1
- package/corpus/core/src/server/fusion-app.ts +447 -0
- package/corpus/core/src/server/index.ts +13 -0
- package/corpus/core/src/server/onboarding-html.ts +3 -4
- package/corpus/core/src/server/poll-events.ts +14 -2
- package/corpus/core/src/server/poll.ts +219 -12
- package/corpus/core/src/server/schema-prompt.ts +28 -9
- package/corpus/core/src/settings/store.ts +33 -2
- package/corpus/core/src/sharing/actions/set-resource-visibility.ts +2 -0
- package/corpus/core/src/sharing/actions/share-resource.ts +3 -0
- package/corpus/core/src/sharing/actions/unshare-resource.ts +2 -0
- package/corpus/core/src/styles/agent-native.css +0 -5
- package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/core/src/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/core/src/templates/default/package.json +3 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/corpus/core/src/tracking/providers.ts +22 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +20 -5
- package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/analytics/AGENTS.md +33 -6
- package/corpus/templates/analytics/actions/navigate.ts +14 -4
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/actions/view-screen.ts +57 -0
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +23 -1
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +21 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +7 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +15 -1
- package/corpus/templates/analytics/app/i18n-data.ts +151 -10
- package/corpus/templates/analytics/app/pages/Agents.tsx +118 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +11 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +76 -40
- package/corpus/templates/analytics/app/pages/sessions/session-replay-devtools.ts +5 -0
- package/corpus/templates/analytics/app/routes/agents.tsx +10 -0
- package/corpus/templates/analytics/changelog/2026-07-03-agent-admin-tools-page.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-03-agent-llm-observability-dashboard.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-03-session-recordings-now-include-response-bodies-for-5xx-error.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +34 -0
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +6 -0
- package/corpus/templates/analytics/package.json +3 -3
- package/corpus/templates/analytics/seeds/dashboards/agent-observability-llm.json +173 -0
- package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +23 -5
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +58 -13
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +23 -0
- package/corpus/templates/analytics/server/lib/dashboard-seeds.ts +5 -0
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +120 -8
- package/corpus/templates/analytics/server/lib/session-replay.ts +3 -2
- package/corpus/templates/analytics/server/plugins/db.ts +93 -2
- package/corpus/templates/analytics/server/routes/api/session-replay/agent-diagnostics.json.get.ts +45 -1
- package/corpus/templates/analytics/shared/session-replay-diagnostics.ts +10 -0
- package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/assets/package.json +3 -3
- package/corpus/templates/assets/server/plugins/db.ts +63 -2
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/brain/package.json +3 -3
- package/corpus/templates/brain/server/plugins/db.ts +75 -2
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/calendar/package.json +3 -3
- package/corpus/templates/calendar/server/plugins/db.ts +64 -2
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/chat/package.json +3 -3
- package/corpus/templates/clips/actions/finalize-recording.ts +50 -40
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +8 -6
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +3 -3
- package/corpus/templates/clips/changelog/2026-07-03-mobile-recording-pages-keep-videos-in-a-16-9-player-with-act.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +245 -77
- package/corpus/templates/clips/package.json +3 -3
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +56 -0
- package/corpus/templates/clips/server/plugins/db.ts +68 -1
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +27 -3
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/content/actions/edit-document.ts +48 -1
- package/corpus/templates/content/actions/list-documents.ts +101 -94
- package/corpus/templates/content/actions/search-documents.ts +19 -3
- package/corpus/templates/content/actions/update-document.ts +54 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +127 -7
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +97 -2
- package/corpus/templates/content/changelog/2026-07-03-agent-document-edits-now-appear-as-a-live-collaborator-prese.md +6 -0
- package/corpus/templates/content/changelog/2026-07-03-document-search-and-list-views-load-faster-on-large-workspac.md +6 -0
- package/corpus/templates/content/package.json +3 -3
- package/corpus/templates/content/server/plugins/db.ts +57 -1
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +190 -13
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +16 -4
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +46 -3
- package/corpus/templates/design/.agents/skills/full-app-build/SKILL.md +140 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +20 -0
- package/corpus/templates/design/AGENTS.md +83 -13
- package/corpus/templates/design/actions/add-fusion-screens.ts +91 -0
- package/corpus/templates/design/actions/apply-a11y-fix.ts +5 -1
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +24 -69
- package/corpus/templates/design/actions/apply-fusion-edits.ts +161 -0
- package/corpus/templates/design/actions/apply-motion-edit.ts +29 -2
- package/corpus/templates/design/actions/apply-visual-edit.ts +38 -3
- package/corpus/templates/design/actions/connect-localhost.ts +25 -18
- package/corpus/templates/design/actions/create-component.ts +5 -1
- package/corpus/templates/design/actions/create-fusion-app.ts +202 -0
- package/corpus/templates/design/actions/deploy-fusion-app.ts +123 -0
- package/corpus/templates/design/actions/edit-design.ts +13 -16
- package/corpus/templates/design/actions/export-pdf.ts +8 -1
- package/corpus/templates/design/actions/export-zip.ts +10 -1
- package/corpus/templates/design/actions/get-fusion-deploy-status.ts +86 -0
- package/corpus/templates/design/actions/get-motion-timeline.ts +26 -20
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +10 -0
- package/corpus/templates/design/actions/insert-asset.ts +190 -7
- package/corpus/templates/design/actions/list-fusion-edits.ts +96 -0
- package/corpus/templates/design/actions/list-local-files.ts +133 -0
- package/corpus/templates/design/actions/open-visual-edit.ts +27 -5
- package/corpus/templates/design/actions/present-design-variants.ts +2 -2
- package/corpus/templates/design/actions/push-fusion-app.ts +62 -0
- package/corpus/templates/design/actions/queue-fusion-edit.ts +112 -0
- package/corpus/templates/design/actions/read-local-file.ts +139 -0
- package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +18 -14
- package/corpus/templates/design/actions/run-design-audit.ts +7 -4
- package/corpus/templates/design/actions/send-fusion-message.ts +69 -0
- package/corpus/templates/design/actions/sync-fusion-app.ts +196 -0
- package/corpus/templates/design/actions/write-local-file.ts +162 -36
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +12 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +600 -66
- package/corpus/templates/design/app/components/design/EditPanel.tsx +793 -304
- package/corpus/templates/design/app/components/design/FusionAppBanner.tsx +328 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +671 -154
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +1 -1
- package/corpus/templates/design/app/components/design/MotionDock.tsx +234 -46
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2070 -420
- package/corpus/templates/design/app/components/design/StatesPanel.tsx +25 -2
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -98
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +640 -72
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +605 -0
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +50 -26
- package/corpus/templates/design/app/components/design/code-workbench/ActivityBar.tsx +85 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +466 -0
- package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +53 -0
- package/corpus/templates/design/app/components/design/code-workbench/commands.ts +339 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/Breadcrumbs.tsx +42 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/BufferSync.tsx +128 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/EditorTabs.tsx +363 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +268 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/StatusBar.tsx +208 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-setup.ts +61 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-theme-palette.ts +191 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-theme.ts +29 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/status-bar-lang.ts +21 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/tab-drag.ts +27 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +155 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +551 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/file-icons.tsx +115 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +65 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/prettier-format.ts +182 -0
- package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +133 -0
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +563 -0
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/fuzzy.ts +170 -0
- package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +508 -0
- package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +280 -0
- package/corpus/templates/design/app/components/design/code-workbench/store.tsx +734 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +39 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/inline-provider.ts +196 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +177 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/tree.ts +110 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/types.ts +103 -0
- package/corpus/templates/design/app/components/design/code-workbench-theme.ts +68 -0
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +16 -4
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +217 -113
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +111 -5
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -2
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +79 -16
- package/corpus/templates/design/app/components/design/inspector/index.ts +9 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +67 -2
- package/corpus/templates/design/app/components/design/types.ts +16 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +80 -1
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +24 -6
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +15 -1
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +6 -16
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +77 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/design/app/i18n-data.ts +31 -0
- package/corpus/templates/design/app/lib/design-import.ts +95 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +5586 -1112
- package/corpus/templates/design/app/pages/Index.tsx +90 -17
- package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-inspector-fixes-mixed-selections-show-mixed-instead-of-wrong.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-keyframe-timeline-works-reliably-drag-keyframes-smoothly-pic.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-much-faster-editor-smooth-dragging-zooming-and-panel-updates.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-pen-tool-refinements-click-the-first-point-to-close-with-a-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-text-editing-enter-adds-a-line-break-international-ime-typin.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-the-ai-now-edits-like-a-collaborator-on-canvas-its-cursor-gl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-the-code-panel-is-now-a-full-vs-code-style-editor-with-a-fil.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-undo-and-redo-are-dependable-across-agent-edits-screen-switc.md +6 -0
- package/corpus/templates/design/package.json +4 -3
- package/corpus/templates/design/server/db/schema.ts +31 -0
- package/corpus/templates/design/server/lib/design-export.ts +43 -1
- package/corpus/templates/design/server/lib/fusion-screens.ts +246 -0
- package/corpus/templates/design/server/plugins/db.ts +89 -2
- package/corpus/templates/design/shared/board-file.ts +25 -5
- package/corpus/templates/design/shared/canvas-math.ts +754 -9
- package/corpus/templates/design/shared/code-layer.ts +304 -26
- package/corpus/templates/design/shared/collab-selection.ts +52 -0
- package/corpus/templates/design/shared/color-utils.ts +84 -0
- package/corpus/templates/design/shared/design-source-capabilities.ts +16 -7
- package/corpus/templates/design/shared/full-app.ts +126 -0
- package/corpus/templates/design/shared/motion-compiler.ts +75 -31
- package/corpus/templates/design/shared/motion-timeline.ts +335 -0
- package/corpus/templates/design/shared/pen-path.ts +496 -23
- package/corpus/templates/dispatch/package.json +3 -3
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/forms/package.json +3 -3
- package/corpus/templates/forms/server/plugins/db.ts +62 -2
- package/corpus/templates/macros/package.json +3 -3
- package/corpus/templates/macros/server/plugins/db.ts +63 -2
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/mail/package.json +3 -3
- package/corpus/templates/mail/server/lib/contact-frequency.ts +42 -15
- package/corpus/templates/mail/server/plugins/db.ts +63 -2
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +9 -3
- package/corpus/templates/plan/.agents/skills/visualize-repo/SKILL.md +92 -0
- package/corpus/templates/plan/actions/export-visual-plan.ts +5 -0
- package/corpus/templates/plan/actions/get-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/get-plan-version.ts +6 -16
- package/corpus/templates/plan/actions/list-plan-versions.ts +48 -20
- package/corpus/templates/plan/actions/patch-visual-plan-source.ts +41 -1
- package/corpus/templates/plan/actions/promote-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/update-local-plan-comments.ts +4 -2
- package/corpus/templates/plan/actions/update-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/update-visual-plan.ts +60 -1
- package/corpus/templates/plan/agent-native.app-skill.json +10 -0
- package/corpus/templates/plan/app/components/editor/PlanDocumentEditor.tsx +138 -39
- package/corpus/templates/plan/app/components/editor/usePlanUndoStack.ts +165 -23
- package/corpus/templates/plan/app/components/plan/PlanContentRenderer.tsx +80 -4
- package/corpus/templates/plan/app/global.css +11 -9
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +10 -1
- package/corpus/templates/plan/app/hooks/use-plan-presence.ts +66 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +215 -63
- package/corpus/templates/plan/changelog/2026-07-03-local-visual-plans-and-recaps-can-save-comments-without-sign.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plan-tabs-render-nested-text-instead-of-raw-json.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plans-are-now-fully-real-time-collaborative-multiple-people-.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plans-open-and-refresh-faster-especially-long-lived-plans-wi.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-undo-now-survives-agent-edits-cmd-z-keeps-working-on-your-ow.md +6 -0
- package/corpus/templates/plan/package.json +5 -3
- package/corpus/templates/plan/server/db/schema.ts +12 -0
- package/corpus/templates/plan/server/lib/local-plan-kind.ts +25 -0
- package/corpus/templates/plan/server/lib/plan-versions.ts +83 -1
- package/corpus/templates/plan/server/lib/public-action-paths.ts +0 -2
- package/corpus/templates/plan/server/plans.ts +26 -3
- package/corpus/templates/plan/server/plugins/db.ts +105 -2
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +8 -4
- package/corpus/templates/slides/AGENTS.md +4 -0
- package/corpus/templates/slides/actions/_agent-presence.ts +48 -0
- package/corpus/templates/slides/actions/add-slide.ts +16 -18
- package/corpus/templates/slides/actions/patch-deck.ts +4 -2
- package/corpus/templates/slides/actions/update-slide.ts +114 -77
- package/corpus/templates/slides/actions/view-screen.ts +39 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +47 -3
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +32 -35
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +625 -199
- package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +342 -0
- package/corpus/templates/slides/app/components/editor/TweaksPanel.tsx +46 -96
- package/corpus/templates/slides/app/components/visual-editor/SaveStatusIndicator.tsx +8 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +589 -176
- package/corpus/templates/slides/app/hooks/use-deck-presence.ts +84 -42
- package/corpus/templates/slides/app/i18n/ar-SA.ts +46 -0
- package/corpus/templates/slides/app/i18n/de-DE.ts +46 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +46 -0
- package/corpus/templates/slides/app/i18n/es-ES.ts +46 -0
- package/corpus/templates/slides/app/i18n/fr-FR.ts +46 -0
- package/corpus/templates/slides/app/i18n/hi-IN.ts +46 -0
- package/corpus/templates/slides/app/i18n/ja-JP.ts +46 -0
- package/corpus/templates/slides/app/i18n/ko-KR.ts +46 -0
- package/corpus/templates/slides/app/i18n/pt-BR.ts +46 -0
- package/corpus/templates/slides/app/i18n/zh-CN.ts +46 -0
- package/corpus/templates/slides/app/i18n/zh-TW.ts +46 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +25 -13
- package/corpus/templates/slides/changelog/2026-07-03-figma-style-slide-editing.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-03-see-the-ai-working-with-you-when-the-agent-edits-a-slide-it-.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-03-undo-redo-is-now-precise-and-safe-with-collaborators-it-only.md +6 -0
- package/corpus/templates/slides/package.json +3 -3
- package/corpus/templates/slides/server/handlers/decks.ts +31 -3
- package/corpus/templates/slides/server/plugins/db.ts +65 -2
- package/corpus/templates/videos/netlify.toml +1 -12
- package/dist/agent/run-store.js +1 -1
- package/dist/agent/run-store.js.map +1 -1
- package/dist/chat-threads/store.d.ts +9 -1
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +63 -11
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/checkpoints/store.d.ts.map +1 -1
- package/dist/checkpoints/store.js +10 -2
- package/dist/checkpoints/store.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +3 -5
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/design-connect.d.ts +49 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +414 -9
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/index.js +12 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/plan-local.d.ts +24 -0
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +188 -20
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +173 -21
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +0 -14
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/cli/visualize-repo.d.ts +49 -0
- package/dist/cli/visualize-repo.d.ts.map +1 -0
- package/dist/cli/visualize-repo.js +561 -0
- package/dist/cli/visualize-repo.js.map +1 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +120 -15
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +6 -5
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/app-providers.d.ts +2 -2
- package/dist/client/app-providers.js.map +1 -1
- package/dist/client/collab/index.d.ts +4 -1
- package/dist/client/collab/index.d.ts.map +1 -1
- package/dist/client/collab/index.js +3 -0
- package/dist/client/collab/index.js.map +1 -1
- package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
- package/dist/client/components/LiveCursorOverlay.js +11 -3
- package/dist/client/components/LiveCursorOverlay.js.map +1 -1
- package/dist/client/components/PresenceBar.d.ts.map +1 -1
- package/dist/client/components/PresenceBar.js +6 -1
- package/dist/client/components/PresenceBar.js.map +1 -1
- package/dist/client/components/RecentEditHighlights.d.ts +43 -0
- package/dist/client/components/RecentEditHighlights.d.ts.map +1 -0
- package/dist/client/components/RecentEditHighlights.js +146 -0
- package/dist/client/components/RecentEditHighlights.js.map +1 -0
- package/dist/client/components/RemoteSelectionRings.d.ts +9 -0
- package/dist/client/components/RemoteSelectionRings.d.ts.map +1 -1
- package/dist/client/components/RemoteSelectionRings.js +22 -8
- package/dist/client/components/RemoteSelectionRings.js.map +1 -1
- package/dist/client/index.d.ts +6 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +7 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +1 -3
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +8 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +8 -2
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/index.d.ts +1 -0
- package/dist/client/rich-markdown-editor/index.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/index.js +1 -0
- package/dist/client/rich-markdown-editor/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/surgical-apply.d.ts +66 -0
- package/dist/client/rich-markdown-editor/surgical-apply.d.ts.map +1 -0
- package/dist/client/rich-markdown-editor/surgical-apply.js +147 -0
- package/dist/client/rich-markdown-editor/surgical-apply.js.map +1 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts +18 -2
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +39 -8
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/client/session-replay.d.ts +10 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +134 -7
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +81 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-action.d.ts +24 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +109 -27
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +7 -1
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +11 -3
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +36 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +68 -12
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/use-pinch-zoom.d.ts.map +1 -1
- package/dist/client/use-pinch-zoom.js +76 -11
- package/dist/client/use-pinch-zoom.js.map +1 -1
- package/dist/client/visual-style-controls.d.ts +79 -0
- package/dist/client/visual-style-controls.d.ts.map +1 -0
- package/dist/client/visual-style-controls.js +150 -0
- package/dist/client/visual-style-controls.js.map +1 -0
- package/dist/collab/agent-presence.d.ts +51 -5
- package/dist/collab/agent-presence.d.ts.map +1 -1
- package/dist/collab/agent-presence.js +144 -58
- package/dist/collab/agent-presence.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +32 -0
- package/dist/collab/awareness-store.d.ts.map +1 -0
- package/dist/collab/awareness-store.js +0 -0
- package/dist/collab/awareness-store.js.map +1 -0
- package/dist/collab/awareness.d.ts +14 -3
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/awareness.js +53 -5
- package/dist/collab/awareness.js.map +1 -1
- package/dist/collab/client.d.ts +2 -0
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +79 -119
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/index.d.ts +3 -1
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +5 -1
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/presence.d.ts.map +1 -1
- package/dist/collab/presence.js +54 -3
- package/dist/collab/presence.js.map +1 -1
- package/dist/collab/recent-edits.d.ts +87 -0
- package/dist/collab/recent-edits.d.ts.map +1 -0
- package/dist/collab/recent-edits.js +116 -0
- package/dist/collab/recent-edits.js.map +1 -0
- package/dist/collab/undo.d.ts +121 -0
- package/dist/collab/undo.d.ts.map +1 -0
- package/dist/collab/undo.js +244 -0
- package/dist/collab/undo.js.map +1 -0
- package/dist/collab/ydoc-manager.d.ts +10 -0
- package/dist/collab/ydoc-manager.d.ts.map +1 -1
- package/dist/collab/ydoc-manager.js +57 -0
- package/dist/collab/ydoc-manager.js.map +1 -1
- package/dist/connections/catalog.d.ts +2 -2
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +1 -1
- package/dist/connections/catalog.js.map +1 -1
- package/dist/db/create-get-db.d.ts +22 -0
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +73 -1
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/db/ensure-additive-columns.d.ts +93 -0
- package/dist/db/ensure-additive-columns.d.ts.map +1 -0
- package/dist/db/ensure-additive-columns.js +355 -0
- package/dist/db/ensure-additive-columns.js.map +1 -0
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +70 -0
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +196 -33
- package/dist/db/migrations.js.map +1 -1
- package/dist/jobs/scheduler.js +17 -10
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +5 -5
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +155 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/org/context.d.ts +7 -0
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +54 -2
- package/dist/org/context.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +10 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth-marketing.d.ts.map +1 -1
- package/dist/server/auth-marketing.js +0 -10
- package/dist/server/auth-marketing.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +6 -4
- package/dist/server/auth.js.map +1 -1
- package/dist/server/collab-plugin.d.ts.map +1 -1
- package/dist/server/collab-plugin.js +45 -13
- package/dist/server/collab-plugin.js.map +1 -1
- package/dist/server/design-token-utils.d.ts +1 -1
- package/dist/server/design-token-utils.js +1 -1
- package/dist/server/design-token-utils.js.map +1 -1
- package/dist/server/fusion-app.d.ts +107 -0
- package/dist/server/fusion-app.d.ts.map +1 -0
- package/dist/server/fusion-app.js +371 -0
- package/dist/server/fusion-app.js.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +3 -4
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/poll-events.d.ts +2 -0
- package/dist/server/poll-events.d.ts.map +1 -1
- package/dist/server/poll-events.js +7 -2
- package/dist/server/poll-events.js.map +1 -1
- package/dist/server/poll.d.ts +47 -3
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +176 -10
- package/dist/server/poll.js.map +1 -1
- package/dist/server/schema-prompt.d.ts.map +1 -1
- package/dist/server/schema-prompt.js +24 -7
- package/dist/server/schema-prompt.js.map +1 -1
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +32 -3
- package/dist/settings/store.js.map +1 -1
- package/dist/sharing/actions/set-resource-visibility.js +2 -0
- package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
- package/dist/sharing/actions/share-resource.d.ts.map +1 -1
- package/dist/sharing/actions/share-resource.js +3 -0
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/sharing/actions/unshare-resource.js +2 -0
- package/dist/sharing/actions/unshare-resource.js.map +1 -1
- package/dist/styles/agent-native.css +0 -5
- package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/dist/templates/default/package.json +3 -3
- package/dist/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/dist/tracking/providers.d.ts.map +1 -1
- package/dist/tracking/providers.js +17 -1
- package/dist/tracking/providers.js.map +1 -1
- package/docs/content/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ar-SA/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ar-SA/plan-plugin.mdx +10 -9
- package/docs/content/locales/ar-SA/sharing.mdx +1 -2
- package/docs/content/locales/ar-SA/skills-guide.mdx +2 -3
- package/docs/content/locales/ar-SA/template-plan.mdx +23 -7
- package/docs/content/locales/ar-SA/tracking.mdx +1 -1
- package/docs/content/locales/ar-SA/workspace-connections.mdx +11 -11
- package/docs/content/locales/de-DE/cloneable-saas.mdx +0 -1
- package/docs/content/locales/de-DE/plan-plugin.mdx +10 -9
- package/docs/content/locales/de-DE/sharing.mdx +1 -2
- package/docs/content/locales/de-DE/skills-guide.mdx +2 -3
- package/docs/content/locales/de-DE/template-plan.mdx +23 -7
- package/docs/content/locales/de-DE/tracking.mdx +1 -1
- package/docs/content/locales/de-DE/workspace-connections.mdx +1 -1
- package/docs/content/locales/es-ES/cloneable-saas.mdx +0 -1
- package/docs/content/locales/es-ES/plan-plugin.mdx +10 -9
- package/docs/content/locales/es-ES/sharing.mdx +1 -2
- package/docs/content/locales/es-ES/skills-guide.mdx +2 -3
- package/docs/content/locales/es-ES/template-plan.mdx +23 -7
- package/docs/content/locales/es-ES/tracking.mdx +1 -1
- package/docs/content/locales/es-ES/workspace-connections.mdx +1 -1
- package/docs/content/locales/fr-FR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/fr-FR/plan-plugin.mdx +10 -9
- package/docs/content/locales/fr-FR/sharing.mdx +1 -2
- package/docs/content/locales/fr-FR/skills-guide.mdx +2 -3
- package/docs/content/locales/fr-FR/template-plan.mdx +23 -7
- package/docs/content/locales/fr-FR/tracking.mdx +1 -1
- package/docs/content/locales/fr-FR/workspace-connections.mdx +1 -1
- package/docs/content/locales/hi-IN/cloneable-saas.mdx +0 -1
- package/docs/content/locales/hi-IN/plan-plugin.mdx +10 -9
- package/docs/content/locales/hi-IN/sharing.mdx +1 -2
- package/docs/content/locales/hi-IN/skills-guide.mdx +2 -3
- package/docs/content/locales/hi-IN/template-plan.mdx +23 -7
- package/docs/content/locales/hi-IN/tracking.mdx +1 -1
- package/docs/content/locales/hi-IN/workspace-connections.mdx +1 -1
- package/docs/content/locales/ja-JP/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ja-JP/plan-plugin.mdx +10 -9
- package/docs/content/locales/ja-JP/sharing.mdx +1 -2
- package/docs/content/locales/ja-JP/skills-guide.mdx +2 -3
- package/docs/content/locales/ja-JP/template-plan.mdx +23 -7
- package/docs/content/locales/ja-JP/tracking.mdx +1 -1
- package/docs/content/locales/ja-JP/workspace-connections.mdx +1 -1
- package/docs/content/locales/ko-KR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ko-KR/plan-plugin.mdx +10 -9
- package/docs/content/locales/ko-KR/sharing.mdx +1 -2
- package/docs/content/locales/ko-KR/skills-guide.mdx +2 -3
- package/docs/content/locales/ko-KR/template-plan.mdx +23 -7
- package/docs/content/locales/ko-KR/tracking.mdx +1 -1
- package/docs/content/locales/ko-KR/workspace-connections.mdx +1 -1
- package/docs/content/locales/pt-BR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/pt-BR/plan-plugin.mdx +10 -9
- package/docs/content/locales/pt-BR/sharing.mdx +1 -2
- package/docs/content/locales/pt-BR/skills-guide.mdx +2 -3
- package/docs/content/locales/pt-BR/template-plan.mdx +23 -7
- package/docs/content/locales/pt-BR/tracking.mdx +1 -1
- package/docs/content/locales/pt-BR/workspace-connections.mdx +1 -1
- package/docs/content/locales/zh-CN/cloneable-saas.mdx +0 -1
- package/docs/content/locales/zh-CN/plan-plugin.mdx +10 -9
- package/docs/content/locales/zh-CN/sharing.mdx +1 -2
- package/docs/content/locales/zh-CN/skills-guide.mdx +2 -3
- package/docs/content/locales/zh-CN/template-plan.mdx +23 -7
- package/docs/content/locales/zh-CN/tracking.mdx +1 -1
- package/docs/content/locales/zh-CN/workspace-connections.mdx +1 -1
- package/docs/content/locales/zh-TW/cloneable-saas.mdx +0 -1
- package/docs/content/locales/zh-TW/plan-plugin.mdx +10 -9
- package/docs/content/locales/zh-TW/sharing.mdx +1 -2
- package/docs/content/locales/zh-TW/skills-guide.mdx +2 -3
- package/docs/content/locales/zh-TW/template-plan.mdx +23 -7
- package/docs/content/locales/zh-TW/tracking.mdx +1 -1
- package/docs/content/locales/zh-TW/workspace-connections.mdx +1 -1
- package/docs/content/plan-plugin.mdx +12 -11
- package/docs/content/sharing.mdx +1 -2
- package/docs/content/skills-guide.mdx +4 -3
- package/docs/content/template-plan.mdx +37 -6
- package/docs/content/tracking.mdx +1 -1
- package/docs/content/workspace-connections.mdx +1 -1
- package/package.json +6 -6
- package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/src/templates/default/package.json +3 -3
- package/src/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/corpus/core/docs/content/locales/ar-SA/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/de-DE/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/es-ES/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/fr-FR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/hi-IN/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/ja-JP/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/ko-KR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/pt-BR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/zh-CN/template-videos.mdx +0 -334
- package/corpus/core/docs/content/locales/zh-TW/template-videos.mdx +0 -334
- package/corpus/core/docs/content/template-videos.mdx +0 -332
- package/corpus/templates/design/app/components/design/CodeWorkbenchHost.tsx +0 -697
- package/corpus/templates/slides/app/components/editor/CodeEditor.tsx +0 -49
- package/corpus/templates/videos/.agents/skills/actions/SKILL.md +0 -432
- package/corpus/templates/videos/.agents/skills/animation-tracks/SKILL.md +0 -99
- package/corpus/templates/videos/.agents/skills/capture-learnings/SKILL.md +0 -76
- package/corpus/templates/videos/.agents/skills/composition-management/SKILL.md +0 -106
- package/corpus/templates/videos/.agents/skills/create-skill/SKILL.md +0 -221
- package/corpus/templates/videos/.agents/skills/delegate-to-agent/SKILL.md +0 -263
- package/corpus/templates/videos/.agents/skills/frontend-design/SKILL.md +0 -112
- package/corpus/templates/videos/.agents/skills/security/SKILL.md +0 -263
- package/corpus/templates/videos/.agents/skills/self-modifying-code/SKILL.md +0 -88
- package/corpus/templates/videos/.agents/skills/shadcn-ui/SKILL.md +0 -95
- package/corpus/templates/videos/.builder/ANIMATED_PROPERTIES.md +0 -335
- package/corpus/templates/videos/.builder/KEYFRAME_SYNC.md +0 -166
- package/corpus/templates/videos/.builder/SEAMLESS_SYNC.md +0 -211
- package/corpus/templates/videos/.builder/rules/deploy-app.mdc +0 -22
- package/corpus/templates/videos/.builder/rules/organize-ui.mdc +0 -9
- package/corpus/templates/videos/.builder/skills/remotion/SKILL.md +0 -29
- package/corpus/templates/videos/.builder/skills/remotion/rules/animations.md +0 -27
- package/corpus/templates/videos/.builder/skills/remotion/rules/assets.md +0 -43
- package/corpus/templates/videos/.builder/skills/remotion/rules/audio.md +0 -58
- package/corpus/templates/videos/.builder/skills/remotion/rules/compositions.md +0 -129
- package/corpus/templates/videos/.builder/skills/remotion/rules/fonts.md +0 -47
- package/corpus/templates/videos/.builder/skills/remotion/rules/images.md +0 -41
- package/corpus/templates/videos/.builder/skills/remotion/rules/parameters.md +0 -59
- package/corpus/templates/videos/.builder/skills/remotion/rules/sequencing.md +0 -54
- package/corpus/templates/videos/.builder/skills/remotion/rules/tailwind.md +0 -11
- package/corpus/templates/videos/.builder/skills/remotion/rules/text-animations.md +0 -18
- package/corpus/templates/videos/.builder/skills/remotion/rules/timing.md +0 -103
- package/corpus/templates/videos/.builder/skills/remotion/rules/transparent-videos.md +0 -35
- package/corpus/templates/videos/.builder/skills/remotion/rules/trimming.md +0 -38
- package/corpus/templates/videos/.builder/skills/remotion/rules/videos.md +0 -54
- package/corpus/templates/videos/.dockerignore +0 -62
- package/corpus/templates/videos/.env.example +0 -4
- package/corpus/templates/videos/.oxfmtrc.json +0 -8
- package/corpus/templates/videos/AGENTS.md +0 -46
- package/corpus/templates/videos/CHANGELOG.md +0 -10
- package/corpus/templates/videos/DEVELOPING.md +0 -143
- package/corpus/templates/videos/README.md +0 -33
- package/corpus/templates/videos/actions/analyze-brand-assets.ts +0 -151
- package/corpus/templates/videos/actions/apply-design-system.ts +0 -35
- package/corpus/templates/videos/actions/create-design-system.ts +0 -84
- package/corpus/templates/videos/actions/create-folder.ts +0 -48
- package/corpus/templates/videos/actions/db-connect.ts +0 -45
- package/corpus/templates/videos/actions/db-health.ts +0 -24
- package/corpus/templates/videos/actions/db-status.ts +0 -28
- package/corpus/templates/videos/actions/delete-composition.ts +0 -272
- package/corpus/templates/videos/actions/delete-folder.ts +0 -27
- package/corpus/templates/videos/actions/generate-animated-component.ts +0 -470
- package/corpus/templates/videos/actions/get-composition.ts +0 -36
- package/corpus/templates/videos/actions/get-design-system.ts +0 -35
- package/corpus/templates/videos/actions/import-code.ts +0 -67
- package/corpus/templates/videos/actions/import-design-project.ts +0 -42
- package/corpus/templates/videos/actions/import-document.ts +0 -125
- package/corpus/templates/videos/actions/import-from-url.ts +0 -18
- package/corpus/templates/videos/actions/import-github.ts +0 -182
- package/corpus/templates/videos/actions/list-compositions.ts +0 -32
- package/corpus/templates/videos/actions/list-design-systems.ts +0 -66
- package/corpus/templates/videos/actions/list-folders.ts +0 -61
- package/corpus/templates/videos/actions/move-composition-to-folder.ts +0 -59
- package/corpus/templates/videos/actions/navigate.ts +0 -40
- package/corpus/templates/videos/actions/rename-folder.ts +0 -41
- package/corpus/templates/videos/actions/run.ts +0 -2
- package/corpus/templates/videos/actions/save-composition.ts +0 -114
- package/corpus/templates/videos/actions/set-default-design-system.ts +0 -40
- package/corpus/templates/videos/actions/update-composition.ts +0 -81
- package/corpus/templates/videos/actions/update-design-system.ts +0 -68
- package/corpus/templates/videos/actions/validate-compositions.ts +0 -502
- package/corpus/templates/videos/actions/view-screen.ts +0 -48
- package/corpus/templates/videos/app/components/CameraControls.tsx +0 -442
- package/corpus/templates/videos/app/components/CameraToolbar.tsx +0 -437
- package/corpus/templates/videos/app/components/CloudUpgrade.tsx +0 -287
- package/corpus/templates/videos/app/components/CollabPresenceBar.tsx +0 -81
- package/corpus/templates/videos/app/components/CompSettingsEditor.tsx +0 -107
- package/corpus/templates/videos/app/components/ComponentLibrarySidebar.tsx +0 -457
- package/corpus/templates/videos/app/components/ComponentPropsPanel.tsx +0 -227
- package/corpus/templates/videos/app/components/ComponentsSidebar.tsx +0 -70
- package/corpus/templates/videos/app/components/CompositionCard.tsx +0 -147
- package/corpus/templates/videos/app/components/CurrentElementPanel.tsx +0 -835
- package/corpus/templates/videos/app/components/CursorControls.tsx +0 -664
- package/corpus/templates/videos/app/components/CursorPositioningOverlay.tsx +0 -238
- package/corpus/templates/videos/app/components/LibraryFolderRow.tsx +0 -235
- package/corpus/templates/videos/app/components/MotionCurveSelect.tsx +0 -61
- package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +0 -192
- package/corpus/templates/videos/app/components/PropsEditor.tsx +0 -210
- package/corpus/templates/videos/app/components/QuestionFlow.tsx +0 -40
- package/corpus/templates/videos/app/components/Sidebar.tsx +0 -609
- package/corpus/templates/videos/app/components/StudioHeader.tsx +0 -109
- package/corpus/templates/videos/app/components/Timeline.tsx +0 -2067
- package/corpus/templates/videos/app/components/TrackPropertiesPanel.tsx +0 -922
- package/corpus/templates/videos/app/components/TweaksPanel.tsx +0 -277
- package/corpus/templates/videos/app/components/VideoPlayer.tsx +0 -487
- package/corpus/templates/videos/app/components/design-system/DesignSystemCard.tsx +0 -134
- package/corpus/templates/videos/app/components/design-system/DesignSystemPreview.tsx +0 -176
- package/corpus/templates/videos/app/components/design-system/DesignSystemSetup.tsx +0 -707
- package/corpus/templates/videos/app/components/keyframes/KeyframeActionButtons.tsx +0 -78
- package/corpus/templates/videos/app/components/keyframes/KeyframeNavigation.tsx +0 -59
- package/corpus/templates/videos/app/components/keyframes/PropertyNumberInput.tsx +0 -56
- package/corpus/templates/videos/app/components/layout/Header.tsx +0 -64
- package/corpus/templates/videos/app/components/layout/HeaderActions.tsx +0 -84
- package/corpus/templates/videos/app/components/layout/Layout.tsx +0 -132
- package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +0 -180
- package/corpus/templates/videos/app/components/ui/accordion.tsx +0 -56
- package/corpus/templates/videos/app/components/ui/alert-dialog.tsx +0 -139
- package/corpus/templates/videos/app/components/ui/alert.tsx +0 -59
- package/corpus/templates/videos/app/components/ui/aspect-ratio.tsx +0 -5
- package/corpus/templates/videos/app/components/ui/avatar.tsx +0 -48
- package/corpus/templates/videos/app/components/ui/badge.tsx +0 -37
- package/corpus/templates/videos/app/components/ui/breadcrumb.tsx +0 -115
- package/corpus/templates/videos/app/components/ui/button.tsx +0 -57
- package/corpus/templates/videos/app/components/ui/calendar.tsx +0 -68
- package/corpus/templates/videos/app/components/ui/card.tsx +0 -86
- package/corpus/templates/videos/app/components/ui/carousel.tsx +0 -260
- package/corpus/templates/videos/app/components/ui/chart.tsx +0 -375
- package/corpus/templates/videos/app/components/ui/checkbox.tsx +0 -28
- package/corpus/templates/videos/app/components/ui/collapsible.tsx +0 -9
- package/corpus/templates/videos/app/components/ui/command.tsx +0 -154
- package/corpus/templates/videos/app/components/ui/context-menu.tsx +0 -202
- package/corpus/templates/videos/app/components/ui/dialog.tsx +0 -130
- package/corpus/templates/videos/app/components/ui/drawer.tsx +0 -116
- package/corpus/templates/videos/app/components/ui/dropdown-menu.tsx +0 -212
- package/corpus/templates/videos/app/components/ui/form.tsx +0 -177
- package/corpus/templates/videos/app/components/ui/hover-card.tsx +0 -27
- package/corpus/templates/videos/app/components/ui/input-otp.tsx +0 -69
- package/corpus/templates/videos/app/components/ui/input.tsx +0 -22
- package/corpus/templates/videos/app/components/ui/label.tsx +0 -24
- package/corpus/templates/videos/app/components/ui/menubar.tsx +0 -234
- package/corpus/templates/videos/app/components/ui/navigation-menu.tsx +0 -128
- package/corpus/templates/videos/app/components/ui/pagination.tsx +0 -121
- package/corpus/templates/videos/app/components/ui/popover.tsx +0 -44
- package/corpus/templates/videos/app/components/ui/progress.tsx +0 -26
- package/corpus/templates/videos/app/components/ui/radio-group.tsx +0 -42
- package/corpus/templates/videos/app/components/ui/resizable.tsx +0 -43
- package/corpus/templates/videos/app/components/ui/scroll-area.tsx +0 -46
- package/corpus/templates/videos/app/components/ui/select.tsx +0 -158
- package/corpus/templates/videos/app/components/ui/separator.tsx +0 -29
- package/corpus/templates/videos/app/components/ui/sheet.tsx +0 -160
- package/corpus/templates/videos/app/components/ui/sidebar.tsx +0 -782
- package/corpus/templates/videos/app/components/ui/skeleton.tsx +0 -15
- package/corpus/templates/videos/app/components/ui/slider.tsx +0 -26
- package/corpus/templates/videos/app/components/ui/sonner.tsx +0 -58
- package/corpus/templates/videos/app/components/ui/spinner.tsx +0 -17
- package/corpus/templates/videos/app/components/ui/switch.tsx +0 -27
- package/corpus/templates/videos/app/components/ui/table.tsx +0 -117
- package/corpus/templates/videos/app/components/ui/tabs.tsx +0 -53
- package/corpus/templates/videos/app/components/ui/textarea.tsx +0 -23
- package/corpus/templates/videos/app/components/ui/toast.tsx +0 -127
- package/corpus/templates/videos/app/components/ui/toaster.tsx +0 -33
- package/corpus/templates/videos/app/components/ui/toggle-group.tsx +0 -59
- package/corpus/templates/videos/app/components/ui/toggle.tsx +0 -43
- package/corpus/templates/videos/app/components/ui/tooltip.tsx +0 -30
- package/corpus/templates/videos/app/components/ui/use-toast.ts +0 -3
- package/corpus/templates/videos/app/config/constants.ts +0 -204
- package/corpus/templates/videos/app/contexts/CompositionContext.tsx +0 -437
- package/corpus/templates/videos/app/contexts/CurrentElementContext.tsx +0 -247
- package/corpus/templates/videos/app/contexts/PlaybackContext.tsx +0 -65
- package/corpus/templates/videos/app/contexts/TimelineContext.tsx +0 -433
- package/corpus/templates/videos/app/entry.client.tsx +0 -19
- package/corpus/templates/videos/app/entry.server.tsx +0 -10
- package/corpus/templates/videos/app/global.css +0 -171
- package/corpus/templates/videos/app/hooks/use-composition-collab.ts +0 -269
- package/corpus/templates/videos/app/hooks/use-composition-design-system.ts +0 -47
- package/corpus/templates/videos/app/hooks/use-database-compositions.ts +0 -144
- package/corpus/templates/videos/app/hooks/use-db-status.ts +0 -30
- package/corpus/templates/videos/app/hooks/use-design-systems.ts +0 -21
- package/corpus/templates/videos/app/hooks/use-folders.ts +0 -199
- package/corpus/templates/videos/app/hooks/use-mobile.tsx +0 -21
- package/corpus/templates/videos/app/hooks/use-navigation-state.ts +0 -52
- package/corpus/templates/videos/app/hooks/use-question-flow.ts +0 -14
- package/corpus/templates/videos/app/hooks/use-toast.ts +0 -188
- package/corpus/templates/videos/app/hooks/useUnsavedChanges.ts +0 -48
- package/corpus/templates/videos/app/i18n/ar-SA.ts +0 -446
- package/corpus/templates/videos/app/i18n/de-DE.ts +0 -470
- package/corpus/templates/videos/app/i18n/en-US.ts +0 -452
- package/corpus/templates/videos/app/i18n/es-ES.ts +0 -468
- package/corpus/templates/videos/app/i18n/fr-FR.ts +0 -469
- package/corpus/templates/videos/app/i18n/hi-IN.ts +0 -446
- package/corpus/templates/videos/app/i18n/index.ts +0 -34
- package/corpus/templates/videos/app/i18n/ja-JP.ts +0 -460
- package/corpus/templates/videos/app/i18n/ko-KR.ts +0 -453
- package/corpus/templates/videos/app/i18n/pt-BR.ts +0 -461
- package/corpus/templates/videos/app/i18n/zh-CN.ts +0 -437
- package/corpus/templates/videos/app/i18n/zh-TW.ts +0 -437
- package/corpus/templates/videos/app/lib/database-compositions.ts +0 -67
- package/corpus/templates/videos/app/lib/design-systems.ts +0 -234
- package/corpus/templates/videos/app/lib/tab-id.ts +0 -1
- package/corpus/templates/videos/app/lib/utils.ts +0 -1
- package/corpus/templates/videos/app/pages/ComponentLibrary.tsx +0 -134
- package/corpus/templates/videos/app/pages/ComponentLibraryView.tsx +0 -362
- package/corpus/templates/videos/app/pages/CompositionView.tsx +0 -715
- package/corpus/templates/videos/app/pages/DesignSystems.tsx +0 -180
- package/corpus/templates/videos/app/pages/Index.tsx +0 -258
- package/corpus/templates/videos/app/pages/NewComposition.tsx +0 -95
- package/corpus/templates/videos/app/pages/NotFound.tsx +0 -36
- package/corpus/templates/videos/app/remotion/CameraHost.tsx +0 -223
- package/corpus/templates/videos/app/remotion/animations/useElementAnimations.ts +0 -231
- package/corpus/templates/videos/app/remotion/componentRegistry.ts +0 -473
- package/corpus/templates/videos/app/remotion/components/AnimatedElement.tsx +0 -436
- package/corpus/templates/videos/app/remotion/components/InteractiveElement.tsx +0 -159
- package/corpus/templates/videos/app/remotion/components/InteractiveZoneEditor.tsx +0 -273
- package/corpus/templates/videos/app/remotion/compositions/BlankComposition.tsx +0 -204
- package/corpus/templates/videos/app/remotion/compositions/index.ts +0 -2
- package/corpus/templates/videos/app/remotion/createComponentCursorTrack.ts +0 -132
- package/corpus/templates/videos/app/remotion/docs/CURSOR_TRACKS.md +0 -285
- package/corpus/templates/videos/app/remotion/easingFunctions.ts +0 -255
- package/corpus/templates/videos/app/remotion/hooks/createInteractiveComposition.tsx +0 -283
- package/corpus/templates/videos/app/remotion/hooks/useCursorHistory.ts +0 -72
- package/corpus/templates/videos/app/remotion/hooks/useCursorTypeFromHover.ts +0 -35
- package/corpus/templates/videos/app/remotion/hooks/useEditableZones.tsx +0 -267
- package/corpus/templates/videos/app/remotion/hooks/useHoverAnimation.ts +0 -90
- package/corpus/templates/videos/app/remotion/hooks/useHoverAnimationSmooth.ts +0 -146
- package/corpus/templates/videos/app/remotion/hooks/useInteractiveComponent.ts +0 -711
- package/corpus/templates/videos/app/remotion/hooks/useRegisterInteractiveElement.ts +0 -56
- package/corpus/templates/videos/app/remotion/library-components/Button.tsx +0 -252
- package/corpus/templates/videos/app/remotion/library-components/Card.tsx +0 -241
- package/corpus/templates/videos/app/remotion/library-components/CodePanel.tsx +0 -1005
- package/corpus/templates/videos/app/remotion/library-components/FileItem.tsx +0 -196
- package/corpus/templates/videos/app/remotion/library-components/FolderItem.tsx +0 -199
- package/corpus/templates/videos/app/remotion/library-components/PrimaryButton.tsx +0 -177
- package/corpus/templates/videos/app/remotion/library-components/SecondaryButton.tsx +0 -167
- package/corpus/templates/videos/app/remotion/library-components/SectionHeader.tsx +0 -108
- package/corpus/templates/videos/app/remotion/library-components/TEMPLATE.tsx +0 -211
- package/corpus/templates/videos/app/remotion/library-components/index.ts +0 -10
- package/corpus/templates/videos/app/remotion/registry.ts +0 -91
- package/corpus/templates/videos/app/remotion/testing/animationTestUtils.ts +0 -366
- package/corpus/templates/videos/app/remotion/trackAnimation.ts +0 -179
- package/corpus/templates/videos/app/remotion/trackHelpers.ts +0 -110
- package/corpus/templates/videos/app/remotion/ui-components/Cursor.tsx +0 -182
- package/corpus/templates/videos/app/remotion/ui-components/InteractiveButton.tsx +0 -116
- package/corpus/templates/videos/app/remotion/ui-components/InteractiveCard.tsx +0 -126
- package/corpus/templates/videos/app/remotion/ui-components/index.ts +0 -16
- package/corpus/templates/videos/app/remotion/utils/animationHelpers.ts +0 -444
- package/corpus/templates/videos/app/remotion/utils/interactiveElements.ts +0 -235
- package/corpus/templates/videos/app/remotion/utils/springAnimation.ts +0 -76
- package/corpus/templates/videos/app/root.tsx +0 -165
- package/corpus/templates/videos/app/routes/$.tsx +0 -10
- package/corpus/templates/videos/app/routes/_index.tsx +0 -25
- package/corpus/templates/videos/app/routes/c.$compositionId.tsx +0 -10
- package/corpus/templates/videos/app/routes/components.tsx +0 -10
- package/corpus/templates/videos/app/routes/design-systems.tsx +0 -10
- package/corpus/templates/videos/app/routes/extensions.$id.$slug.tsx +0 -2
- package/corpus/templates/videos/app/routes/extensions.$id.tsx +0 -5
- package/corpus/templates/videos/app/routes/extensions._index.tsx +0 -5
- package/corpus/templates/videos/app/routes/extensions.tsx +0 -5
- package/corpus/templates/videos/app/routes/settings.tsx +0 -88
- package/corpus/templates/videos/app/routes/team.tsx +0 -11
- package/corpus/templates/videos/app/routes.ts +0 -4
- package/corpus/templates/videos/app/state.ts +0 -77
- package/corpus/templates/videos/app/types/elementAnimations.ts +0 -121
- package/corpus/templates/videos/app/types.ts +0 -200
- package/corpus/templates/videos/app/utils/compositionHelpers.ts +0 -445
- package/corpus/templates/videos/app/utils/debug.ts +0 -63
- package/corpus/templates/videos/app/utils/keyframeUtils.ts +0 -331
- package/corpus/templates/videos/app/utils/timelineCoordinates.ts +0 -79
- package/corpus/templates/videos/app/vite-env.d.ts +0 -6
- package/corpus/templates/videos/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-29-video-layouts-adapt-when-the-agent-sidebar-is-open.md +0 -6
- package/corpus/templates/videos/components.json +0 -20
- package/corpus/templates/videos/data/sync-config.json +0 -3
- package/corpus/templates/videos/docs/examples/create-composition.example.ts +0 -128
- package/corpus/templates/videos/drizzle.config.ts +0 -3
- package/corpus/templates/videos/learnings.defaults.md +0 -5
- package/corpus/templates/videos/package.json +0 -114
- package/corpus/templates/videos/public/agent-native-icon-dark.svg +0 -10
- package/corpus/templates/videos/public/agent-native-icon-light.svg +0 -10
- package/corpus/templates/videos/public/agent-native-logo-dark.svg +0 -21
- package/corpus/templates/videos/public/agent-native-logo-light.svg +0 -21
- package/corpus/templates/videos/public/favicon.svg +0 -1
- package/corpus/templates/videos/public/icon-180.svg +0 -1
- package/corpus/templates/videos/public/icon-192.svg +0 -1
- package/corpus/templates/videos/public/icon-512.svg +0 -1
- package/corpus/templates/videos/public/manifest.json +0 -21
- package/corpus/templates/videos/public/placeholder.svg +0 -1
- package/corpus/templates/videos/public/robots.txt +0 -14
- package/corpus/templates/videos/react-router.config.ts +0 -7
- package/corpus/templates/videos/server/db/index.ts +0 -37
- package/corpus/templates/videos/server/db/schema.ts +0 -55
- package/corpus/templates/videos/server/middleware/auth.ts +0 -15
- package/corpus/templates/videos/server/plugins/agent-chat.ts +0 -29
- package/corpus/templates/videos/server/plugins/auth.ts +0 -14
- package/corpus/templates/videos/server/plugins/collab.ts +0 -11
- package/corpus/templates/videos/server/plugins/core-routes.ts +0 -22
- package/corpus/templates/videos/server/plugins/db.ts +0 -160
- package/corpus/templates/videos/server/routes/[...page].get.ts +0 -5
- package/corpus/templates/videos/server/routes/[...page].head.ts +0 -1
- package/corpus/templates/videos/server/routes/api/save-composition-defaults.post.ts +0 -274
- package/corpus/templates/videos/shared/api.ts +0 -75
- package/corpus/templates/videos/ssr-entry.ts +0 -15
- package/corpus/templates/videos/tsconfig.json +0 -21
- package/corpus/templates/videos/vite.config.ts +0 -19
- package/corpus/templates/videos/vitest.config.ts +0 -16
- package/docs/content/locales/ar-SA/template-videos.mdx +0 -336
- package/docs/content/locales/de-DE/template-videos.mdx +0 -336
- package/docs/content/locales/es-ES/template-videos.mdx +0 -336
- package/docs/content/locales/fr-FR/template-videos.mdx +0 -336
- package/docs/content/locales/hi-IN/template-videos.mdx +0 -336
- package/docs/content/locales/ja-JP/template-videos.mdx +0 -336
- package/docs/content/locales/ko-KR/template-videos.mdx +0 -336
- package/docs/content/locales/pt-BR/template-videos.mdx +0 -336
- package/docs/content/locales/zh-CN/template-videos.mdx +0 -334
- package/docs/content/locales/zh-TW/template-videos.mdx +0 -334
- package/docs/content/template-videos.mdx +0 -332
|
@@ -118,19 +118,36 @@ async function introspectSqlite(db) {
|
|
|
118
118
|
return tables;
|
|
119
119
|
}
|
|
120
120
|
// ─── Cached entry point ─────────────────────────────────────────────────────
|
|
121
|
+
// Coalesces concurrent cache-miss introspections (same pattern as poll.ts's
|
|
122
|
+
// _checkPromise): several chat turns starting inside one TTL window would
|
|
123
|
+
// otherwise each run the full multi-query DB introspection in parallel.
|
|
124
|
+
let _inflight = null;
|
|
121
125
|
async function getSchema() {
|
|
122
126
|
const key = cacheKey();
|
|
123
127
|
const now = Date.now();
|
|
124
128
|
if (_cache && _cache.key === key && _cache.expires > now) {
|
|
125
129
|
return { tables: _cache.tables, dialect: _cache.dialect };
|
|
126
130
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
if (_inflight && _inflight.key === key) {
|
|
132
|
+
return _inflight.promise;
|
|
133
|
+
}
|
|
134
|
+
const promise = (async () => {
|
|
135
|
+
const db = getDbExec();
|
|
136
|
+
const dialect = isPostgres() ? "postgres" : "sqlite";
|
|
137
|
+
const tables = dialect === "postgres"
|
|
138
|
+
? await introspectPostgres(db)
|
|
139
|
+
: await introspectSqlite(db);
|
|
140
|
+
_cache = { key, expires: Date.now() + CACHE_TTL_MS, tables, dialect };
|
|
141
|
+
return { tables, dialect };
|
|
142
|
+
})();
|
|
143
|
+
_inflight = { key, promise };
|
|
144
|
+
try {
|
|
145
|
+
return await promise;
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
if (_inflight?.promise === promise)
|
|
149
|
+
_inflight = null;
|
|
150
|
+
}
|
|
134
151
|
}
|
|
135
152
|
/** Manually drop the cache — useful from tests or after running a migration. */
|
|
136
153
|
export function invalidateSchemaPromptCache() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-prompt.js","sourceRoot":"","sources":["../../src/server/schema-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Auto-introspected SQL schema context block for the agent's system prompt.\n *\n * On every chat turn, the framework appends a compact, always-fresh summary\n * of the app's SQL database — every table, every column, every foreign key —\n * so the agent knows exactly what data model it's working with. The schema\n * is pulled live from `information_schema` (Postgres) or `PRAGMA table_info`\n * (SQLite), cached briefly to keep latency down but never hard-coded.\n *\n * The block also:\n * - points at the enabled db-* tools for runtime access\n * - lists Postgres column descriptions (`COMMENT ON COLUMN ...`) if present\n * - explains the current user/org data scoping so the agent doesn't re-filter\n * by hand (which would be redundant and easy to get wrong)\n */\nimport {\n getDbExec,\n getDatabaseUrl,\n isPostgres,\n type DbExec,\n} from \"../db/client.js\";\nimport {\n normalizeDatabaseToolsMode,\n type DatabaseToolsOption,\n} from \"../scripts/db/tool-mode.js\";\n\ninterface ColumnSchema {\n name: string;\n type: string;\n notnull: boolean;\n pk: boolean;\n comment: string | null;\n}\n\ninterface ForeignKey {\n from: string;\n table: string;\n to: string;\n}\n\ninterface TableSchema {\n name: string;\n columns: ColumnSchema[];\n foreignKeys: ForeignKey[];\n comment: string | null;\n}\n\n// Short-lived in-memory cache — schema rarely changes between messages, but\n// we want new tables to show up within a few seconds during active dev.\nconst CACHE_TTL_MS = 15_000;\nlet _cache: {\n key: string;\n expires: number;\n tables: TableSchema[];\n dialect: \"postgres\" | \"sqlite\";\n} | null = null;\n\nfunction cacheKey(): string {\n return (isPostgres() ? \"pg:\" : \"lite:\") + (getDatabaseUrl() || \"\");\n}\n\n// ─── Postgres introspection ─────────────────────────────────────────────────\n\nasync function introspectPostgres(db: DbExec): Promise<TableSchema[]> {\n const tablesRes = await db.execute({\n sql: `SELECT table_name AS name,\n obj_description((quote_ident(table_schema) || '.' || quote_ident(table_name))::regclass, 'pg_class') AS comment\n FROM information_schema.tables\n WHERE table_schema = 'public' AND table_type = 'BASE TABLE'\n ORDER BY table_name`,\n args: [],\n });\n\n const tables: TableSchema[] = [];\n\n for (const t of tablesRes.rows as any[]) {\n const name = t.name as string;\n\n const colsRes = await db.execute({\n sql: `SELECT c.column_name AS name,\n c.data_type AS type,\n CASE WHEN c.is_nullable = 'NO' THEN 1 ELSE 0 END AS notnull,\n col_description((quote_ident(c.table_schema) || '.' || quote_ident(c.table_name))::regclass, c.ordinal_position) AS comment\n FROM information_schema.columns c\n WHERE c.table_name = ? AND c.table_schema = 'public'\n ORDER BY c.ordinal_position`,\n args: [name],\n });\n\n const pksRes = await db.execute({\n sql: `SELECT kcu.column_name AS name\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 = ? AND tc.constraint_type = 'PRIMARY KEY'`,\n args: [name],\n });\n const pkSet = new Set((pksRes.rows as any[]).map((r) => r.name as string));\n\n const fksRes = await db.execute({\n sql: `SELECT kcu.column_name AS col_from,\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 JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n WHERE tc.table_name = ? AND tc.constraint_type = 'FOREIGN KEY'`,\n args: [name],\n });\n\n tables.push({\n name,\n comment: (t.comment as string | null) ?? null,\n columns: (colsRes.rows as any[]).map((c) => ({\n name: c.name as string,\n type: (c.type as string) || \"any\",\n notnull: Number(c.notnull) === 1,\n pk: pkSet.has(c.name as string),\n comment: (c.comment as string | null) ?? null,\n })),\n foreignKeys: (fksRes.rows as any[]).map((f) => ({\n from: f.col_from as string,\n table: f.ref_table as string,\n to: f.ref_col as string,\n })),\n });\n }\n\n return tables;\n}\n\n// ─── SQLite / libSQL / D1 introspection ────────────────────────────────────\n\nasync function introspectSqlite(db: DbExec): Promise<TableSchema[]> {\n const tablesRes = await db.execute(\n `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`,\n );\n\n const tables: TableSchema[] = [];\n\n for (const row of tablesRes.rows as any[]) {\n const name = row.name as string;\n if (!name) continue;\n // Quote the identifier for PRAGMA calls; SQLite requires doubling embedded quotes.\n const escaped = name.replace(/\"/g, '\"\"');\n\n const colsRes = await db.execute(`PRAGMA table_info(\"${escaped}\")`);\n const fksRes = await db.execute(`PRAGMA foreign_key_list(\"${escaped}\")`);\n\n tables.push({\n name,\n comment: null, // SQLite has no column/table comments\n columns: (colsRes.rows as any[]).map((c) => ({\n name: c.name as string,\n type: ((c.type as string) || \"\").toLowerCase() || \"any\",\n notnull: Number(c.notnull) === 1,\n pk: Number(c.pk) === 1,\n comment: null,\n })),\n foreignKeys: (fksRes.rows as any[]).map((f) => ({\n from: f.from as string,\n table: f.table as string,\n to: f.to as string,\n })),\n });\n }\n\n return tables;\n}\n\n// ─── Cached entry point ─────────────────────────────────────────────────────\n\nasync function getSchema(): Promise<{\n tables: TableSchema[];\n dialect: \"postgres\" | \"sqlite\";\n}> {\n const key = cacheKey();\n const now = Date.now();\n if (_cache && _cache.key === key && _cache.expires > now) {\n return { tables: _cache.tables, dialect: _cache.dialect };\n }\n\n const db = getDbExec();\n const dialect: \"postgres\" | \"sqlite\" = isPostgres() ? \"postgres\" : \"sqlite\";\n const tables =\n dialect === \"postgres\"\n ? await introspectPostgres(db)\n : await introspectSqlite(db);\n\n _cache = { key, expires: now + CACHE_TTL_MS, tables, dialect };\n return { tables, dialect };\n}\n\n/** Manually drop the cache — useful from tests or after running a migration. */\nexport function invalidateSchemaPromptCache(): void {\n _cache = null;\n}\n\n// ─── Formatting ─────────────────────────────────────────────────────────────\n\nfunction shortType(type: string): string {\n // Trim verbose Postgres type names for compactness in the prompt.\n const t = type.toLowerCase();\n if (t === \"character varying\") return \"varchar\";\n if (t === \"timestamp without time zone\") return \"timestamp\";\n if (t === \"timestamp with time zone\") return \"timestamptz\";\n if (t === \"double precision\") return \"double\";\n return t;\n}\n\nfunction formatTable(table: TableSchema): string {\n const fkByCol = new Map<string, string>();\n for (const fk of table.foreignKeys) {\n fkByCol.set(fk.from, `${fk.table}.${fk.to}`);\n }\n\n const cols = table.columns.map((c) => {\n const flags: string[] = [];\n if (c.pk) flags.push(\"pk\");\n if (!c.notnull && !c.pk) flags.push(\"null\");\n const fk = fkByCol.get(c.name);\n if (fk) flags.push(`→${fk}`);\n\n // Flag scoping columns so the agent understands per-user/per-org filtering.\n if (c.name === \"owner_email\") flags.push(\"user-scope\");\n if (c.name === \"org_id\") flags.push(\"org-scope\");\n\n const flagStr = flags.length ? ` [${flags.join(\", \")}]` : \"\";\n const commentStr = c.comment ? ` -- ${c.comment.replace(/\\s+/g, \" \")}` : \"\";\n return ` ${c.name} ${shortType(c.type)}${flagStr}${commentStr}`;\n });\n\n const header = table.comment\n ? ` ${table.name} -- ${table.comment.replace(/\\s+/g, \" \")}`\n : ` ${table.name}`;\n\n return [header, ...cols].join(\"\\n\");\n}\n\n// ─── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Build the `<sql-database>` block appended to the system prompt on every turn.\n *\n * `owner` and `orgId` come from the per-request context (AGENT_USER_EMAIL /\n * AGENT_ORG_ID) and are surfaced so the agent knows who it is acting on behalf\n * of — and understands that rows are already filtered for that identity.\n */\nexport async function loadSchemaPromptBlock(opts: {\n owner?: string | null;\n orgId?: string | null;\n /** Controls which raw db-* tools are available to the agent. */\n databaseTools?: DatabaseToolsOption;\n /** @deprecated Use databaseTools instead. */\n hasRawDbTools?: boolean;\n}): Promise<string> {\n let tables: TableSchema[];\n let dialect: \"postgres\" | \"sqlite\";\n try {\n const res = await getSchema();\n tables = res.tables;\n dialect = res.dialect;\n } catch {\n // DB not ready, or introspection blew up — don't take the chat down.\n return \"\";\n }\n\n if (tables.length === 0) return \"\";\n\n // Partition framework-internal tables from template tables so the agent\n // focuses on the data model it's most likely to touch.\n const CORE_TABLES = new Set([\n \"application_state\",\n \"settings\",\n \"oauth_tokens\",\n \"sessions\",\n \"resources\",\n \"chat_threads\",\n \"_collab_docs\",\n \"usage_events\",\n \"usage_totals\",\n \"user\",\n \"account\",\n \"verification\",\n \"organization\",\n \"member\",\n \"invitation\",\n ]);\n\n const templateTables = tables.filter((t) => !CORE_TABLES.has(t.name));\n const coreTables = tables.filter((t) => CORE_TABLES.has(t.name));\n\n const lines: string[] = [];\n lines.push(\"<sql-database>\");\n lines.push(\n `The app's state lives in a SQL database (${dialect}). The schema below is auto-introspected fresh each turn — treat it as authoritative.`,\n );\n lines.push(\"\");\n\n if (templateTables.length > 0) {\n lines.push(\"## Template tables\");\n lines.push(\"\");\n for (const t of templateTables) {\n lines.push(formatTable(t));\n lines.push(\"\");\n }\n }\n\n if (coreTables.length > 0) {\n lines.push(\n \"## Framework tables (auth, resources, chat threads, app-state, etc.) — usually read/written via dedicated tools, not raw SQL\",\n );\n lines.push(\"\");\n for (const t of coreTables) {\n lines.push(formatTable(t));\n lines.push(\"\");\n }\n }\n\n const databaseToolsMode =\n opts.databaseTools === undefined && opts.hasRawDbTools !== undefined\n ? normalizeDatabaseToolsMode(opts.hasRawDbTools)\n : normalizeDatabaseToolsMode(opts.databaseTools);\n const hasRawDbTools = databaseToolsMode !== \"off\";\n const hasRawDbWriteTools = databaseToolsMode === \"write\";\n\n // Tooling references.\n if (hasRawDbTools) {\n lines.push(\"## SQL tools\");\n lines.push(\n \"- `db-schema` — refresh the full schema with indexes and foreign keys\",\n );\n lines.push(\n \"- `db-query` — run a SELECT (read-only; results already filtered to the current user/org)\",\n );\n if (hasRawDbWriteTools) {\n lines.push(\n \"- `db-exec` — run INSERT / UPDATE / DELETE / REPLACE (writes already scoped; owner_email and org_id are auto-injected on INSERT). For multiple related writes, pass `statements` so they run in one transaction instead of separate tool calls. Schema changes are blocked.\",\n );\n lines.push(\n \"- `db-patch` — surgical search-and-replace on a large text column. Send `{find, replace}` pairs instead of the full new value. Use this for edits to large fields (documents, slide HTML, dashboard/form JSON) — it avoids re-sending multi-kilobyte strings and saves tokens. Targets exactly one row (narrow `--where` by primary key). Uses the same per-user/per-org scoping as db-exec.\",\n );\n }\n lines.push(\"\");\n lines.push(\"### When to pick which SQL tool\");\n if (hasRawDbWriteTools) {\n lines.push(\n \"- Set a short column outright, update multiple columns, or do computed updates (`calories = calories + 50`) → `db-exec UPDATE`.\",\n );\n lines.push(\n '- Insert/update several rows as one logical operation → `db-exec` with `statements: \\'[{\"sql\":\"...\",\"args\":[...]}]\\'` so the batch commits or rolls back together.',\n );\n lines.push(\n \"- Change a small slice of a large text/JSON column → `db-patch`. Much cheaper token-wise than re-sending the whole column.\",\n );\n } else {\n lines.push(\n \"- Read data and inspect shape → `db-query` / `db-schema`. Raw SQL write tools are not available on this surface.\",\n );\n }\n lines.push(\n \"- A template-specific action exists for the table (`edit-document`, `update-slide`, etc.) → use that action. It encodes business rules and pushes live Yjs updates to any open collaborative editor; raw SQL does neither.\",\n );\n lines.push(\n \"- Read data → `db-query`. Never re-add `WHERE owner_email = ...` — scoping already applies it.\",\n );\n lines.push(\"\");\n lines.push(\"### External data sources vs the app database\");\n lines.push(\n \"The `db-*` tools ONLY query the app's own SQL database (the tables listed above). They do NOT reach external data warehouses, analytics platforms, or third-party services.\",\n );\n lines.push(\n \"If the user asks about tables that are NOT in the schema above, use the relevant provider, warehouse, MCP, or template action listed in your available tools. When provider-api-catalog/provider-api-docs/provider-api-request are available, use them for provider endpoints or filters that no first-class shortcut models.\",\n );\n lines.push(\n \"**Never use `db-query` for external data.** It will fail because those tables don't exist in the app database.\",\n );\n lines.push(\"\");\n } else {\n lines.push(\n \"SQL is accessed through the template actions listed above. The schema is shown for context — so you understand the data model those actions operate on.\",\n );\n lines.push(\"\");\n }\n\n // Data scoping context.\n const ownerLine = opts.owner ? opts.owner : \"(unresolved)\";\n const orgLine = opts.orgId ? opts.orgId : \"(none)\";\n lines.push(\"## Data scoping (enforced at the SQL layer)\");\n lines.push(`- Current user: \\`${ownerLine}\\``);\n lines.push(`- Current org: \\`${orgLine}\\``);\n lines.push(\n \"- Tables with an `owner_email` column are automatically filtered to the current user via temporary views before every query.\",\n );\n lines.push(\n \"- Tables with an `org_id` column are automatically filtered to the current org as well.\",\n );\n lines.push(\n \"- On INSERT, `owner_email` and `org_id` are auto-injected — do NOT set them manually.\",\n );\n lines.push(\n \"- Do NOT add `WHERE owner_email = ...` or `WHERE org_id = ...` to your queries — the filter is already applied, and re-adding it will confuse the scoped view.\",\n );\n lines.push(\"</sql-database>\");\n\n return \"\\n\\n\" + lines.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"schema-prompt.js","sourceRoot":"","sources":["../../src/server/schema-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Auto-introspected SQL schema context block for the agent's system prompt.\n *\n * On every chat turn, the framework appends a compact, always-fresh summary\n * of the app's SQL database — every table, every column, every foreign key —\n * so the agent knows exactly what data model it's working with. The schema\n * is pulled live from `information_schema` (Postgres) or `PRAGMA table_info`\n * (SQLite), cached briefly to keep latency down but never hard-coded.\n *\n * The block also:\n * - points at the enabled db-* tools for runtime access\n * - lists Postgres column descriptions (`COMMENT ON COLUMN ...`) if present\n * - explains the current user/org data scoping so the agent doesn't re-filter\n * by hand (which would be redundant and easy to get wrong)\n */\nimport {\n getDbExec,\n getDatabaseUrl,\n isPostgres,\n type DbExec,\n} from \"../db/client.js\";\nimport {\n normalizeDatabaseToolsMode,\n type DatabaseToolsOption,\n} from \"../scripts/db/tool-mode.js\";\n\ninterface ColumnSchema {\n name: string;\n type: string;\n notnull: boolean;\n pk: boolean;\n comment: string | null;\n}\n\ninterface ForeignKey {\n from: string;\n table: string;\n to: string;\n}\n\ninterface TableSchema {\n name: string;\n columns: ColumnSchema[];\n foreignKeys: ForeignKey[];\n comment: string | null;\n}\n\n// Short-lived in-memory cache — schema rarely changes between messages, but\n// we want new tables to show up within a few seconds during active dev.\nconst CACHE_TTL_MS = 15_000;\nlet _cache: {\n key: string;\n expires: number;\n tables: TableSchema[];\n dialect: \"postgres\" | \"sqlite\";\n} | null = null;\n\nfunction cacheKey(): string {\n return (isPostgres() ? \"pg:\" : \"lite:\") + (getDatabaseUrl() || \"\");\n}\n\n// ─── Postgres introspection ─────────────────────────────────────────────────\n\nasync function introspectPostgres(db: DbExec): Promise<TableSchema[]> {\n const tablesRes = await db.execute({\n sql: `SELECT table_name AS name,\n obj_description((quote_ident(table_schema) || '.' || quote_ident(table_name))::regclass, 'pg_class') AS comment\n FROM information_schema.tables\n WHERE table_schema = 'public' AND table_type = 'BASE TABLE'\n ORDER BY table_name`,\n args: [],\n });\n\n const tables: TableSchema[] = [];\n\n for (const t of tablesRes.rows as any[]) {\n const name = t.name as string;\n\n const colsRes = await db.execute({\n sql: `SELECT c.column_name AS name,\n c.data_type AS type,\n CASE WHEN c.is_nullable = 'NO' THEN 1 ELSE 0 END AS notnull,\n col_description((quote_ident(c.table_schema) || '.' || quote_ident(c.table_name))::regclass, c.ordinal_position) AS comment\n FROM information_schema.columns c\n WHERE c.table_name = ? AND c.table_schema = 'public'\n ORDER BY c.ordinal_position`,\n args: [name],\n });\n\n const pksRes = await db.execute({\n sql: `SELECT kcu.column_name AS name\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 = ? AND tc.constraint_type = 'PRIMARY KEY'`,\n args: [name],\n });\n const pkSet = new Set((pksRes.rows as any[]).map((r) => r.name as string));\n\n const fksRes = await db.execute({\n sql: `SELECT kcu.column_name AS col_from,\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 JOIN information_schema.constraint_column_usage ccu\n ON tc.constraint_name = ccu.constraint_name\n WHERE tc.table_name = ? AND tc.constraint_type = 'FOREIGN KEY'`,\n args: [name],\n });\n\n tables.push({\n name,\n comment: (t.comment as string | null) ?? null,\n columns: (colsRes.rows as any[]).map((c) => ({\n name: c.name as string,\n type: (c.type as string) || \"any\",\n notnull: Number(c.notnull) === 1,\n pk: pkSet.has(c.name as string),\n comment: (c.comment as string | null) ?? null,\n })),\n foreignKeys: (fksRes.rows as any[]).map((f) => ({\n from: f.col_from as string,\n table: f.ref_table as string,\n to: f.ref_col as string,\n })),\n });\n }\n\n return tables;\n}\n\n// ─── SQLite / libSQL / D1 introspection ────────────────────────────────────\n\nasync function introspectSqlite(db: DbExec): Promise<TableSchema[]> {\n const tablesRes = await db.execute(\n `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`,\n );\n\n const tables: TableSchema[] = [];\n\n for (const row of tablesRes.rows as any[]) {\n const name = row.name as string;\n if (!name) continue;\n // Quote the identifier for PRAGMA calls; SQLite requires doubling embedded quotes.\n const escaped = name.replace(/\"/g, '\"\"');\n\n const colsRes = await db.execute(`PRAGMA table_info(\"${escaped}\")`);\n const fksRes = await db.execute(`PRAGMA foreign_key_list(\"${escaped}\")`);\n\n tables.push({\n name,\n comment: null, // SQLite has no column/table comments\n columns: (colsRes.rows as any[]).map((c) => ({\n name: c.name as string,\n type: ((c.type as string) || \"\").toLowerCase() || \"any\",\n notnull: Number(c.notnull) === 1,\n pk: Number(c.pk) === 1,\n comment: null,\n })),\n foreignKeys: (fksRes.rows as any[]).map((f) => ({\n from: f.from as string,\n table: f.table as string,\n to: f.to as string,\n })),\n });\n }\n\n return tables;\n}\n\n// ─── Cached entry point ─────────────────────────────────────────────────────\n\n// Coalesces concurrent cache-miss introspections (same pattern as poll.ts's\n// _checkPromise): several chat turns starting inside one TTL window would\n// otherwise each run the full multi-query DB introspection in parallel.\nlet _inflight: {\n key: string;\n promise: Promise<{ tables: TableSchema[]; dialect: \"postgres\" | \"sqlite\" }>;\n} | null = null;\n\nasync function getSchema(): Promise<{\n tables: TableSchema[];\n dialect: \"postgres\" | \"sqlite\";\n}> {\n const key = cacheKey();\n const now = Date.now();\n if (_cache && _cache.key === key && _cache.expires > now) {\n return { tables: _cache.tables, dialect: _cache.dialect };\n }\n if (_inflight && _inflight.key === key) {\n return _inflight.promise;\n }\n\n const promise = (async () => {\n const db = getDbExec();\n const dialect: \"postgres\" | \"sqlite\" = isPostgres() ? \"postgres\" : \"sqlite\";\n const tables =\n dialect === \"postgres\"\n ? await introspectPostgres(db)\n : await introspectSqlite(db);\n\n _cache = { key, expires: Date.now() + CACHE_TTL_MS, tables, dialect };\n return { tables, dialect };\n })();\n _inflight = { key, promise };\n try {\n return await promise;\n } finally {\n if (_inflight?.promise === promise) _inflight = null;\n }\n}\n\n/** Manually drop the cache — useful from tests or after running a migration. */\nexport function invalidateSchemaPromptCache(): void {\n _cache = null;\n}\n\n// ─── Formatting ─────────────────────────────────────────────────────────────\n\nfunction shortType(type: string): string {\n // Trim verbose Postgres type names for compactness in the prompt.\n const t = type.toLowerCase();\n if (t === \"character varying\") return \"varchar\";\n if (t === \"timestamp without time zone\") return \"timestamp\";\n if (t === \"timestamp with time zone\") return \"timestamptz\";\n if (t === \"double precision\") return \"double\";\n return t;\n}\n\nfunction formatTable(table: TableSchema): string {\n const fkByCol = new Map<string, string>();\n for (const fk of table.foreignKeys) {\n fkByCol.set(fk.from, `${fk.table}.${fk.to}`);\n }\n\n const cols = table.columns.map((c) => {\n const flags: string[] = [];\n if (c.pk) flags.push(\"pk\");\n if (!c.notnull && !c.pk) flags.push(\"null\");\n const fk = fkByCol.get(c.name);\n if (fk) flags.push(`→${fk}`);\n\n // Flag scoping columns so the agent understands per-user/per-org filtering.\n if (c.name === \"owner_email\") flags.push(\"user-scope\");\n if (c.name === \"org_id\") flags.push(\"org-scope\");\n\n const flagStr = flags.length ? ` [${flags.join(\", \")}]` : \"\";\n const commentStr = c.comment ? ` -- ${c.comment.replace(/\\s+/g, \" \")}` : \"\";\n return ` ${c.name} ${shortType(c.type)}${flagStr}${commentStr}`;\n });\n\n const header = table.comment\n ? ` ${table.name} -- ${table.comment.replace(/\\s+/g, \" \")}`\n : ` ${table.name}`;\n\n return [header, ...cols].join(\"\\n\");\n}\n\n// ─── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Build the `<sql-database>` block appended to the system prompt on every turn.\n *\n * `owner` and `orgId` come from the per-request context (AGENT_USER_EMAIL /\n * AGENT_ORG_ID) and are surfaced so the agent knows who it is acting on behalf\n * of — and understands that rows are already filtered for that identity.\n */\nexport async function loadSchemaPromptBlock(opts: {\n owner?: string | null;\n orgId?: string | null;\n /** Controls which raw db-* tools are available to the agent. */\n databaseTools?: DatabaseToolsOption;\n /** @deprecated Use databaseTools instead. */\n hasRawDbTools?: boolean;\n}): Promise<string> {\n let tables: TableSchema[];\n let dialect: \"postgres\" | \"sqlite\";\n try {\n const res = await getSchema();\n tables = res.tables;\n dialect = res.dialect;\n } catch {\n // DB not ready, or introspection blew up — don't take the chat down.\n return \"\";\n }\n\n if (tables.length === 0) return \"\";\n\n // Partition framework-internal tables from template tables so the agent\n // focuses on the data model it's most likely to touch.\n const CORE_TABLES = new Set([\n \"application_state\",\n \"settings\",\n \"oauth_tokens\",\n \"sessions\",\n \"resources\",\n \"chat_threads\",\n \"_collab_docs\",\n \"usage_events\",\n \"usage_totals\",\n \"user\",\n \"account\",\n \"verification\",\n \"organization\",\n \"member\",\n \"invitation\",\n ]);\n\n const templateTables = tables.filter((t) => !CORE_TABLES.has(t.name));\n const coreTables = tables.filter((t) => CORE_TABLES.has(t.name));\n\n const lines: string[] = [];\n lines.push(\"<sql-database>\");\n lines.push(\n `The app's state lives in a SQL database (${dialect}). The schema below is auto-introspected fresh each turn — treat it as authoritative.`,\n );\n lines.push(\"\");\n\n if (templateTables.length > 0) {\n lines.push(\"## Template tables\");\n lines.push(\"\");\n for (const t of templateTables) {\n lines.push(formatTable(t));\n lines.push(\"\");\n }\n }\n\n if (coreTables.length > 0) {\n lines.push(\n \"## Framework tables (auth, resources, chat threads, app-state, etc.) — usually read/written via dedicated tools, not raw SQL\",\n );\n lines.push(\"\");\n for (const t of coreTables) {\n lines.push(formatTable(t));\n lines.push(\"\");\n }\n }\n\n const databaseToolsMode =\n opts.databaseTools === undefined && opts.hasRawDbTools !== undefined\n ? normalizeDatabaseToolsMode(opts.hasRawDbTools)\n : normalizeDatabaseToolsMode(opts.databaseTools);\n const hasRawDbTools = databaseToolsMode !== \"off\";\n const hasRawDbWriteTools = databaseToolsMode === \"write\";\n\n // Tooling references.\n if (hasRawDbTools) {\n lines.push(\"## SQL tools\");\n lines.push(\n \"- `db-schema` — refresh the full schema with indexes and foreign keys\",\n );\n lines.push(\n \"- `db-query` — run a SELECT (read-only; results already filtered to the current user/org)\",\n );\n if (hasRawDbWriteTools) {\n lines.push(\n \"- `db-exec` — run INSERT / UPDATE / DELETE / REPLACE (writes already scoped; owner_email and org_id are auto-injected on INSERT). For multiple related writes, pass `statements` so they run in one transaction instead of separate tool calls. Schema changes are blocked.\",\n );\n lines.push(\n \"- `db-patch` — surgical search-and-replace on a large text column. Send `{find, replace}` pairs instead of the full new value. Use this for edits to large fields (documents, slide HTML, dashboard/form JSON) — it avoids re-sending multi-kilobyte strings and saves tokens. Targets exactly one row (narrow `--where` by primary key). Uses the same per-user/per-org scoping as db-exec.\",\n );\n }\n lines.push(\"\");\n lines.push(\"### When to pick which SQL tool\");\n if (hasRawDbWriteTools) {\n lines.push(\n \"- Set a short column outright, update multiple columns, or do computed updates (`calories = calories + 50`) → `db-exec UPDATE`.\",\n );\n lines.push(\n '- Insert/update several rows as one logical operation → `db-exec` with `statements: \\'[{\"sql\":\"...\",\"args\":[...]}]\\'` so the batch commits or rolls back together.',\n );\n lines.push(\n \"- Change a small slice of a large text/JSON column → `db-patch`. Much cheaper token-wise than re-sending the whole column.\",\n );\n } else {\n lines.push(\n \"- Read data and inspect shape → `db-query` / `db-schema`. Raw SQL write tools are not available on this surface.\",\n );\n }\n lines.push(\n \"- A template-specific action exists for the table (`edit-document`, `update-slide`, etc.) → use that action. It encodes business rules and pushes live Yjs updates to any open collaborative editor; raw SQL does neither.\",\n );\n lines.push(\n \"- Read data → `db-query`. Never re-add `WHERE owner_email = ...` — scoping already applies it.\",\n );\n lines.push(\"\");\n lines.push(\"### External data sources vs the app database\");\n lines.push(\n \"The `db-*` tools ONLY query the app's own SQL database (the tables listed above). They do NOT reach external data warehouses, analytics platforms, or third-party services.\",\n );\n lines.push(\n \"If the user asks about tables that are NOT in the schema above, use the relevant provider, warehouse, MCP, or template action listed in your available tools. When provider-api-catalog/provider-api-docs/provider-api-request are available, use them for provider endpoints or filters that no first-class shortcut models.\",\n );\n lines.push(\n \"**Never use `db-query` for external data.** It will fail because those tables don't exist in the app database.\",\n );\n lines.push(\"\");\n } else {\n lines.push(\n \"SQL is accessed through the template actions listed above. The schema is shown for context — so you understand the data model those actions operate on.\",\n );\n lines.push(\"\");\n }\n\n // Data scoping context.\n const ownerLine = opts.owner ? opts.owner : \"(unresolved)\";\n const orgLine = opts.orgId ? opts.orgId : \"(none)\";\n lines.push(\"## Data scoping (enforced at the SQL layer)\");\n lines.push(`- Current user: \\`${ownerLine}\\``);\n lines.push(`- Current org: \\`${orgLine}\\``);\n lines.push(\n \"- Tables with an `owner_email` column are automatically filtered to the current user via temporary views before every query.\",\n );\n lines.push(\n \"- Tables with an `org_id` column are automatically filtered to the current org as well.\",\n );\n lines.push(\n \"- On INSERT, `owner_email` and `org_id` are auto-injected — do NOT set them manually.\",\n );\n lines.push(\n \"- Do NOT add `WHERE owner_email = ...` or `WHERE org_id = ...` to your queries — the filter is already applied, and re-adding it will confuse the scoped view.\",\n );\n lines.push(\"</sql-database>\");\n\n return \"\\n\\n\" + lines.join(\"\\n\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/settings/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/settings/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAiCtC,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAsED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAgBzC;AAED,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAmBlB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CACxC,CAUA"}
|
package/dist/settings/store.js
CHANGED
|
@@ -2,7 +2,29 @@ import { EventEmitter } from "events";
|
|
|
2
2
|
import { getDbExec, isPostgres, intType } from "../db/client.js";
|
|
3
3
|
import { ensureIndexExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
4
4
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
5
|
+
import { getRequestContext } from "../server/request-context.js";
|
|
5
6
|
let _initPromise;
|
|
7
|
+
// Per-request memoization of settings reads, keyed on the active
|
|
8
|
+
// AsyncLocalStorage RequestContext (WeakMap → freed with the request). One
|
|
9
|
+
// action request can read the same setting several times (org resolution,
|
|
10
|
+
// guards, the action body), and each read is a network round trip on
|
|
11
|
+
// serverless Postgres. Mirrors the per-request session/org caches on
|
|
12
|
+
// event.context. The cache holds the raw JSON string and re-parses per hit
|
|
13
|
+
// so callers can't mutate a shared object; writes in the same request are
|
|
14
|
+
// written through, while other in-flight requests keep their snapshot for
|
|
15
|
+
// their own (short) lifetime.
|
|
16
|
+
const _requestSettingsCache = new WeakMap();
|
|
17
|
+
function requestSettingsCache() {
|
|
18
|
+
const ctx = getRequestContext();
|
|
19
|
+
if (!ctx || typeof ctx !== "object")
|
|
20
|
+
return null;
|
|
21
|
+
let cache = _requestSettingsCache.get(ctx);
|
|
22
|
+
if (!cache) {
|
|
23
|
+
cache = new Map();
|
|
24
|
+
_requestSettingsCache.set(ctx, cache);
|
|
25
|
+
}
|
|
26
|
+
return cache;
|
|
27
|
+
}
|
|
6
28
|
const _emitter = new EventEmitter();
|
|
7
29
|
export function getSettingsEmitter() {
|
|
8
30
|
return _emitter;
|
|
@@ -68,6 +90,11 @@ async function ensureTable() {
|
|
|
68
90
|
return _initPromise;
|
|
69
91
|
}
|
|
70
92
|
export async function getSetting(key) {
|
|
93
|
+
const cache = requestSettingsCache();
|
|
94
|
+
if (cache?.has(key)) {
|
|
95
|
+
const cached = cache.get(key);
|
|
96
|
+
return cached == null ? null : JSON.parse(cached);
|
|
97
|
+
}
|
|
71
98
|
await ensureTable();
|
|
72
99
|
const client = getDbExec();
|
|
73
100
|
const table = settingsTable();
|
|
@@ -75,9 +102,9 @@ export async function getSetting(key) {
|
|
|
75
102
|
sql: `SELECT value FROM ${table} WHERE key = ?`,
|
|
76
103
|
args: [key],
|
|
77
104
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return JSON.parse(
|
|
105
|
+
const raw = rows.length === 0 ? null : rows[0].value;
|
|
106
|
+
cache?.set(key, raw);
|
|
107
|
+
return raw == null ? null : JSON.parse(raw);
|
|
81
108
|
}
|
|
82
109
|
export async function putSetting(key, value, options) {
|
|
83
110
|
await ensureTable();
|
|
@@ -89,6 +116,7 @@ export async function putSetting(key, value, options) {
|
|
|
89
116
|
: `INSERT OR REPLACE INTO ${table} (key, value, updated_at) VALUES (?, ?, ?)`,
|
|
90
117
|
args: [key, JSON.stringify(value), Date.now()],
|
|
91
118
|
});
|
|
119
|
+
requestSettingsCache()?.set(key, JSON.stringify(value));
|
|
92
120
|
_emitter.emit("settings", {
|
|
93
121
|
source: "settings",
|
|
94
122
|
type: "change",
|
|
@@ -104,6 +132,7 @@ export async function deleteSetting(key, options) {
|
|
|
104
132
|
sql: `DELETE FROM ${table} WHERE key = ?`,
|
|
105
133
|
args: [key],
|
|
106
134
|
});
|
|
135
|
+
requestSettingsCache()?.set(key, null);
|
|
107
136
|
if (result.rowsAffected > 0) {
|
|
108
137
|
_emitter.emit("settings", {
|
|
109
138
|
source: "settings",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/settings/store.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"events\";\n\nimport { getDbExec, isPostgres, intType } from \"../db/client.js\";\nimport { ensureIndexExists, ensureTableExists } from \"../db/ddl-guard.js\";\nimport { widenIntColumnsToBigInt } from \"../db/widen-columns.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\nconst _emitter = new EventEmitter();\n\nexport function getSettingsEmitter(): EventEmitter {\n return _emitter;\n}\n\nfunction settingsTable(): string {\n return isPostgres() ? \"public.settings\" : \"settings\";\n}\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const table = settingsTable();\n const createSql = `\n CREATE TABLE IF NOT EXISTS ${table} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n `;\n\n if (isPostgres()) {\n // Hot path: the `settings` table and its poll index are virtually\n // always already present in production. Issuing `CREATE TABLE`/\n // `CREATE INDEX` still takes a lock that, in a fresh background-worker\n // process behind a concurrent connection on the shared Neon DB, can\n // block ~indefinitely (ACCESS EXCLUSIVE for CREATE TABLE; a write-\n // blocking SHARE lock for CREATE INDEX). `ensureTableExists` /\n // `ensureIndexExists` probe `information_schema`/`pg_indexes` first\n // (plain reads, no lock) and run DDL ONLY for what is actually missing,\n // bounding any DDL with a transaction-scoped `lock_timeout`. They also\n // re-probe after a swallowed lock-timeout and THROW if the schema is\n // still missing, so a timed-out DDL never poisons this init memo with\n // missing schema. `settingsTable()` is `public.settings` on Postgres;\n // the existence checks use the unqualified table name.\n await ensureTableExists(\"settings\", createSql);\n // Older deployments (pre BIGINT-compat) have a 32-bit `updated_at`; on\n // Postgres the `Date.now()` written on every setSetting overflows int4.\n // widenIntColumnsToBigInt already probes information_schema and only\n // ALTERs columns that are still int4 — a no-op on fresh/widened DBs.\n await widenIntColumnsToBigInt(\"settings\", [\"updated_at\"]);\n // Index for the poll watermark query: `SELECT MAX(updated_at)`.\n await ensureIndexExists(\n \"settings_updated_at_idx\",\n `CREATE INDEX IF NOT EXISTS settings_updated_at_idx ON ${table} (updated_at)`,\n );\n return;\n }\n\n // SQLite (local dev): no lock problem — keep the original behaviour.\n await client.execute(createSql);\n // No-op on SQLite (INTEGER is already 64-bit).\n await widenIntColumnsToBigInt(\"settings\", [\"updated_at\"]);\n // Index for the poll watermark query: `SELECT MAX(updated_at) FROM settings`.\n // MAX on an indexed column avoids a full-table scan on every poll cycle.\n // IF NOT EXISTS makes it idempotent on existing databases.\n try {\n await client.execute(\n `CREATE INDEX IF NOT EXISTS settings_updated_at_idx ON ${table} (updated_at)`,\n );\n } catch {\n // Index already exists or the dialect rejected a duplicate.\n }\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nexport async function getSetting(\n key: string,\n): Promise<Record<string, unknown> | null> {\n await ensureTable();\n const client = getDbExec();\n const table = settingsTable();\n const { rows } = await client.execute({\n sql: `SELECT value FROM ${table} WHERE key = ?`,\n args: [key],\n });\n if (rows.length === 0) return null;\n return JSON.parse(rows[0].value as string);\n}\n\nexport interface StoreWriteOptions {\n /** Tag identifying who initiated this write (e.g. a tab ID). */\n requestSource?: string;\n}\n\nexport async function putSetting(\n key: string,\n value: Record<string, unknown>,\n options?: StoreWriteOptions,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const table = settingsTable();\n await client.execute({\n sql: isPostgres()\n ? `INSERT INTO ${table} (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT (key) DO UPDATE SET value=EXCLUDED.value, updated_at=EXCLUDED.updated_at`\n : `INSERT OR REPLACE INTO ${table} (key, value, updated_at) VALUES (?, ?, ?)`,\n args: [key, JSON.stringify(value), Date.now()],\n });\n _emitter.emit(\"settings\", {\n source: \"settings\",\n type: \"change\",\n key,\n ...(options?.requestSource && { requestSource: options.requestSource }),\n });\n}\n\nexport async function deleteSetting(\n key: string,\n options?: StoreWriteOptions,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const table = settingsTable();\n const result = await client.execute({\n sql: `DELETE FROM ${table} WHERE key = ?`,\n args: [key],\n });\n if (result.rowsAffected > 0) {\n _emitter.emit(\"settings\", {\n source: \"settings\",\n type: \"delete\",\n key,\n ...(options?.requestSource && { requestSource: options.requestSource }),\n });\n return true;\n }\n return false;\n}\n\nexport async function getAllSettings(): Promise<\n Record<string, Record<string, unknown>>\n> {\n await ensureTable();\n const client = getDbExec();\n const table = settingsTable();\n const { rows } = await client.execute(`SELECT key, value FROM ${table}`);\n const result: Record<string, Record<string, unknown>> = {};\n for (const row of rows) {\n result[row.key as string] = JSON.parse(row.value as string);\n }\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/settings/store.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"events\";\n\nimport { getDbExec, isPostgres, intType } from \"../db/client.js\";\nimport { ensureIndexExists, ensureTableExists } from \"../db/ddl-guard.js\";\nimport { widenIntColumnsToBigInt } from \"../db/widen-columns.js\";\nimport { getRequestContext } from \"../server/request-context.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\n// Per-request memoization of settings reads, keyed on the active\n// AsyncLocalStorage RequestContext (WeakMap → freed with the request). One\n// action request can read the same setting several times (org resolution,\n// guards, the action body), and each read is a network round trip on\n// serverless Postgres. Mirrors the per-request session/org caches on\n// event.context. The cache holds the raw JSON string and re-parses per hit\n// so callers can't mutate a shared object; writes in the same request are\n// written through, while other in-flight requests keep their snapshot for\n// their own (short) lifetime.\nconst _requestSettingsCache = new WeakMap<object, Map<string, string | null>>();\n\nfunction requestSettingsCache(): Map<string, string | null> | null {\n const ctx = getRequestContext();\n if (!ctx || typeof ctx !== \"object\") return null;\n let cache = _requestSettingsCache.get(ctx);\n if (!cache) {\n cache = new Map();\n _requestSettingsCache.set(ctx, cache);\n }\n return cache;\n}\n\nconst _emitter = new EventEmitter();\n\nexport function getSettingsEmitter(): EventEmitter {\n return _emitter;\n}\n\nfunction settingsTable(): string {\n return isPostgres() ? \"public.settings\" : \"settings\";\n}\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const table = settingsTable();\n const createSql = `\n CREATE TABLE IF NOT EXISTS ${table} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n `;\n\n if (isPostgres()) {\n // Hot path: the `settings` table and its poll index are virtually\n // always already present in production. Issuing `CREATE TABLE`/\n // `CREATE INDEX` still takes a lock that, in a fresh background-worker\n // process behind a concurrent connection on the shared Neon DB, can\n // block ~indefinitely (ACCESS EXCLUSIVE for CREATE TABLE; a write-\n // blocking SHARE lock for CREATE INDEX). `ensureTableExists` /\n // `ensureIndexExists` probe `information_schema`/`pg_indexes` first\n // (plain reads, no lock) and run DDL ONLY for what is actually missing,\n // bounding any DDL with a transaction-scoped `lock_timeout`. They also\n // re-probe after a swallowed lock-timeout and THROW if the schema is\n // still missing, so a timed-out DDL never poisons this init memo with\n // missing schema. `settingsTable()` is `public.settings` on Postgres;\n // the existence checks use the unqualified table name.\n await ensureTableExists(\"settings\", createSql);\n // Older deployments (pre BIGINT-compat) have a 32-bit `updated_at`; on\n // Postgres the `Date.now()` written on every setSetting overflows int4.\n // widenIntColumnsToBigInt already probes information_schema and only\n // ALTERs columns that are still int4 — a no-op on fresh/widened DBs.\n await widenIntColumnsToBigInt(\"settings\", [\"updated_at\"]);\n // Index for the poll watermark query: `SELECT MAX(updated_at)`.\n await ensureIndexExists(\n \"settings_updated_at_idx\",\n `CREATE INDEX IF NOT EXISTS settings_updated_at_idx ON ${table} (updated_at)`,\n );\n return;\n }\n\n // SQLite (local dev): no lock problem — keep the original behaviour.\n await client.execute(createSql);\n // No-op on SQLite (INTEGER is already 64-bit).\n await widenIntColumnsToBigInt(\"settings\", [\"updated_at\"]);\n // Index for the poll watermark query: `SELECT MAX(updated_at) FROM settings`.\n // MAX on an indexed column avoids a full-table scan on every poll cycle.\n // IF NOT EXISTS makes it idempotent on existing databases.\n try {\n await client.execute(\n `CREATE INDEX IF NOT EXISTS settings_updated_at_idx ON ${table} (updated_at)`,\n );\n } catch {\n // Index already exists or the dialect rejected a duplicate.\n }\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nexport async function getSetting(\n key: string,\n): Promise<Record<string, unknown> | null> {\n const cache = requestSettingsCache();\n if (cache?.has(key)) {\n const cached = cache.get(key);\n return cached == null ? null : JSON.parse(cached);\n }\n await ensureTable();\n const client = getDbExec();\n const table = settingsTable();\n const { rows } = await client.execute({\n sql: `SELECT value FROM ${table} WHERE key = ?`,\n args: [key],\n });\n const raw = rows.length === 0 ? null : (rows[0].value as string);\n cache?.set(key, raw);\n return raw == null ? null : JSON.parse(raw);\n}\n\nexport interface StoreWriteOptions {\n /** Tag identifying who initiated this write (e.g. a tab ID). */\n requestSource?: string;\n}\n\nexport async function putSetting(\n key: string,\n value: Record<string, unknown>,\n options?: StoreWriteOptions,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const table = settingsTable();\n await client.execute({\n sql: isPostgres()\n ? `INSERT INTO ${table} (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT (key) DO UPDATE SET value=EXCLUDED.value, updated_at=EXCLUDED.updated_at`\n : `INSERT OR REPLACE INTO ${table} (key, value, updated_at) VALUES (?, ?, ?)`,\n args: [key, JSON.stringify(value), Date.now()],\n });\n requestSettingsCache()?.set(key, JSON.stringify(value));\n _emitter.emit(\"settings\", {\n source: \"settings\",\n type: \"change\",\n key,\n ...(options?.requestSource && { requestSource: options.requestSource }),\n });\n}\n\nexport async function deleteSetting(\n key: string,\n options?: StoreWriteOptions,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const table = settingsTable();\n const result = await client.execute({\n sql: `DELETE FROM ${table} WHERE key = ?`,\n args: [key],\n });\n requestSettingsCache()?.set(key, null);\n if (result.rowsAffected > 0) {\n _emitter.emit(\"settings\", {\n source: \"settings\",\n type: \"delete\",\n key,\n ...(options?.requestSource && { requestSource: options.requestSource }),\n });\n return true;\n }\n return false;\n}\n\nexport async function getAllSettings(): Promise<\n Record<string, Record<string, unknown>>\n> {\n await ensureTable();\n const client = getDbExec();\n const table = settingsTable();\n const { rows } = await client.execute(`SELECT key, value FROM ${table}`);\n const result: Record<string, Record<string, unknown>> = {};\n for (const row of rows) {\n result[row.key as string] = JSON.parse(row.value as string);\n }\n return result;\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { eq } from "drizzle-orm";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { defineAction } from "../../action.js";
|
|
4
|
+
import { invalidateCollabAccessCache } from "../../server/poll.js";
|
|
4
5
|
import { assertAccess, currentAccess, ForbiddenError, resolveRegisteredAccessContext, } from "../access.js";
|
|
5
6
|
import { requireShareableResource } from "../registry.js";
|
|
6
7
|
import { getExtensionShareChangeTargets, notifyExtensionShareChanged, } from "./extension-change.js";
|
|
@@ -55,6 +56,7 @@ export default defineAction({
|
|
|
55
56
|
.update(reg.resourceTable)
|
|
56
57
|
.set(update)
|
|
57
58
|
.where(eq(reg.resourceTable.id, args.resourceId));
|
|
59
|
+
invalidateCollabAccessCache(args.resourceType, args.resourceId);
|
|
58
60
|
await notifyExtensionShareChanged(args.resourceType, args.resourceId, beforeExtensionTargets);
|
|
59
61
|
return { ok: true, visibility: args.visibility };
|
|
60
62
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set-resource-visibility.js","sourceRoot":"","sources":["../../../src/sharing/actions/set-resource-visibility.ts"],"names":[],"mappings":"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","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport {\n assertAccess,\n currentAccess,\n ForbiddenError,\n resolveRegisteredAccessContext,\n} from \"../access.js\";\nimport { requireShareableResource } from \"../registry.js\";\nimport {\n getExtensionShareChangeTargets,\n notifyExtensionShareChanged,\n} from \"./extension-change.js\";\n\nexport default defineAction({\n description:\n \"Change the coarse visibility of a shareable resource: 'private' keeps it owner-only, 'org' shares it with all members of the owner's organization, 'public' makes it accessible to anyone with the link. Visibility changes require owner or admin role.\",\n // (audit H5) Visibility changes can flip a private resource org-wide or\n // public. Refuse from the tools iframe bridge.\n toolCallable: false,\n mcpApp: {\n compactCatalog: true,\n },\n schema: z.object({\n resourceType: z.string(),\n resourceId: z.string(),\n visibility: z.enum([\"private\", \"org\", \"public\"]),\n }),\n run: async (args) => {\n const reg = requireShareableResource(args.resourceType);\n if (args.visibility === \"public\" && reg.allowPublic === false) {\n throw new ForbiddenError(\n `${reg.displayName} cannot be made public — share with specific people or your organization instead.`,\n );\n }\n const access = await assertAccess(\n args.resourceType,\n args.resourceId,\n \"admin\",\n );\n const db = reg.getDb() as any;\n const update: Record<string, unknown> = { visibility: args.visibility };\n const rawAccess = currentAccess();\n const currentOrgId = resolveRegisteredAccessContext(reg, rawAccess).orgId;\n if (args.visibility === \"org\" && !access.resource?.orgId) {\n if (!currentOrgId) {\n const canKeepResourceUnscoped =\n !!rawAccess.orgId &&\n !!reg.resolveAccessContext &&\n access.role === \"owner\";\n // Some templates intentionally normalize local single-user resources\n // out of request org scope. In that mode, keep the row unbound while\n // still allowing the owner to persist the visibility preference.\n if (!canKeepResourceUnscoped) {\n throw new ForbiddenError(\n `${reg.displayName} cannot be shared with your organization because no active organization is selected.`,\n );\n }\n } else {\n // Only the resource owner may bind an org to a previously unscoped resource.\n // If a non-owner admin did this, the resource would adopt the admin's org\n // and ownerMatchesActiveScope would then lock the real owner out of their\n // own resource. Non-owner admins can still flip visibility once orgId is set.\n if (access.role !== \"owner\") {\n throw new ForbiddenError(\n `${reg.displayName} can only be attached to an organization by its owner.`,\n );\n }\n update.orgId = currentOrgId;\n }\n }\n const beforeExtensionTargets = await getExtensionShareChangeTargets(\n args.resourceType,\n args.resourceId,\n );\n await db\n .update(reg.resourceTable)\n .set(update)\n .where(eq(reg.resourceTable.id, args.resourceId));\n await notifyExtensionShareChanged(\n args.resourceType,\n args.resourceId,\n beforeExtensionTargets,\n );\n return { ok: true, visibility: args.visibility };\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"set-resource-visibility.js","sourceRoot":"","sources":["../../../src/sharing/actions/set-resource-visibility.ts"],"names":[],"mappings":"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","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport { invalidateCollabAccessCache } from \"../../server/poll.js\";\nimport {\n assertAccess,\n currentAccess,\n ForbiddenError,\n resolveRegisteredAccessContext,\n} from \"../access.js\";\nimport { requireShareableResource } from \"../registry.js\";\nimport {\n getExtensionShareChangeTargets,\n notifyExtensionShareChanged,\n} from \"./extension-change.js\";\n\nexport default defineAction({\n description:\n \"Change the coarse visibility of a shareable resource: 'private' keeps it owner-only, 'org' shares it with all members of the owner's organization, 'public' makes it accessible to anyone with the link. Visibility changes require owner or admin role.\",\n // (audit H5) Visibility changes can flip a private resource org-wide or\n // public. Refuse from the tools iframe bridge.\n toolCallable: false,\n mcpApp: {\n compactCatalog: true,\n },\n schema: z.object({\n resourceType: z.string(),\n resourceId: z.string(),\n visibility: z.enum([\"private\", \"org\", \"public\"]),\n }),\n run: async (args) => {\n const reg = requireShareableResource(args.resourceType);\n if (args.visibility === \"public\" && reg.allowPublic === false) {\n throw new ForbiddenError(\n `${reg.displayName} cannot be made public — share with specific people or your organization instead.`,\n );\n }\n const access = await assertAccess(\n args.resourceType,\n args.resourceId,\n \"admin\",\n );\n const db = reg.getDb() as any;\n const update: Record<string, unknown> = { visibility: args.visibility };\n const rawAccess = currentAccess();\n const currentOrgId = resolveRegisteredAccessContext(reg, rawAccess).orgId;\n if (args.visibility === \"org\" && !access.resource?.orgId) {\n if (!currentOrgId) {\n const canKeepResourceUnscoped =\n !!rawAccess.orgId &&\n !!reg.resolveAccessContext &&\n access.role === \"owner\";\n // Some templates intentionally normalize local single-user resources\n // out of request org scope. In that mode, keep the row unbound while\n // still allowing the owner to persist the visibility preference.\n if (!canKeepResourceUnscoped) {\n throw new ForbiddenError(\n `${reg.displayName} cannot be shared with your organization because no active organization is selected.`,\n );\n }\n } else {\n // Only the resource owner may bind an org to a previously unscoped resource.\n // If a non-owner admin did this, the resource would adopt the admin's org\n // and ownerMatchesActiveScope would then lock the real owner out of their\n // own resource. Non-owner admins can still flip visibility once orgId is set.\n if (access.role !== \"owner\") {\n throw new ForbiddenError(\n `${reg.displayName} can only be attached to an organization by its owner.`,\n );\n }\n update.orgId = currentOrgId;\n }\n }\n const beforeExtensionTargets = await getExtensionShareChangeTargets(\n args.resourceType,\n args.resourceId,\n );\n await db\n .update(reg.resourceTable)\n .set(update)\n .where(eq(reg.resourceTable.id, args.resourceId));\n invalidateCollabAccessCache(args.resourceType, args.resourceId);\n await notifyExtensionShareChanged(\n args.resourceType,\n args.resourceId,\n beforeExtensionTargets,\n );\n return { ok: true, visibility: args.visibility };\n },\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"share-resource.d.ts","sourceRoot":"","sources":["../../../src/sharing/actions/share-resource.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"share-resource.d.ts","sourceRoot":"","sources":["../../../src/sharing/actions/share-resource.ts"],"names":[],"mappings":"AAiBA,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAazD;AAwCD,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,MAAM,SAAwB,GAC7B,MAAM,CAOR"}
|
|
@@ -5,6 +5,7 @@ import { getDbExec } from "../../db/client.js";
|
|
|
5
5
|
import { getAppProductionUrl } from "../../server/app-url.js";
|
|
6
6
|
import { renderEmail, emailStrong } from "../../server/email-template.js";
|
|
7
7
|
import { sendEmail, isEmailConfigured } from "../../server/email.js";
|
|
8
|
+
import { invalidateCollabAccessCache } from "../../server/poll.js";
|
|
8
9
|
import { getRequestUserEmail } from "../../server/request-context.js";
|
|
9
10
|
import { assertAccess, ForbiddenError } from "../access.js";
|
|
10
11
|
import { requireShareableResource } from "../registry.js";
|
|
@@ -186,6 +187,7 @@ export default defineAction({
|
|
|
186
187
|
.update(reg.sharesTable)
|
|
187
188
|
.set({ role: args.role })
|
|
188
189
|
.where(eq(reg.sharesTable.id, existing.id));
|
|
190
|
+
invalidateCollabAccessCache(args.resourceType, args.resourceId);
|
|
189
191
|
await notifyExtensionShareChanged(args.resourceType, args.resourceId, beforeExtensionTargets);
|
|
190
192
|
return { id: existing.id, updated: true };
|
|
191
193
|
}
|
|
@@ -199,6 +201,7 @@ export default defineAction({
|
|
|
199
201
|
createdBy: actor,
|
|
200
202
|
createdAt: new Date().toISOString(),
|
|
201
203
|
});
|
|
204
|
+
invalidateCollabAccessCache(args.resourceType, args.resourceId);
|
|
202
205
|
await notifyExtensionShareChanged(args.resourceType, args.resourceId, beforeExtensionTargets);
|
|
203
206
|
if (args.notify !== false &&
|
|
204
207
|
args.principalType === "user" &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"share-resource.js","sourceRoot":"","sources":["../../../src/sharing/actions/share-resource.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, sql, type SQL } from \"drizzle-orm\";\nimport { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport { getDbExec } from \"../../db/client.js\";\nimport { getAppProductionUrl } from \"../../server/app-url.js\";\nimport { renderEmail, emailStrong } from \"../../server/email-template.js\";\nimport { sendEmail, isEmailConfigured } from \"../../server/email.js\";\nimport { getRequestUserEmail } from \"../../server/request-context.js\";\nimport { assertAccess, ForbiddenError } from \"../access.js\";\nimport { requireShareableResource } from \"../registry.js\";\nimport {\n getExtensionShareChangeTargets,\n notifyExtensionShareChanged,\n} from \"./extension-change.js\";\n\nexport function isSyntheticQaEmail(email: string): boolean {\n const trimmed = email.trim().toLowerCase();\n const at = trimmed.lastIndexOf(\"@\");\n if (at <= 0) return false;\n const local = trimmed.slice(0, at);\n const domain = trimmed.slice(at + 1);\n return (\n local.includes(\"+qa\") &&\n (domain === \"example.test\" ||\n domain.endsWith(\".test\") ||\n domain === \"example.invalid\" ||\n domain.endsWith(\".invalid\"))\n );\n}\n\nfunction appPath(path: string): string {\n if (!path.startsWith(\"/\")) return path;\n const raw = process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || \"\";\n const base = raw.trim().replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (!base) return path;\n const normalizedBase = `/${base}`;\n if (path === normalizedBase || path.startsWith(`${normalizedBase}/`)) {\n return path;\n }\n return `${normalizedBase}${path}`;\n}\n\nfunction safeNotificationUrl(value: string, appUrl: string): string | null {\n const trimmed = value.trim();\n if (!trimmed) return null;\n\n try {\n const base = new URL(appUrl);\n if (trimmed.startsWith(\"/\")) {\n const path = appPath(trimmed);\n const basePath = base.pathname.replace(/\\/+$/, \"\");\n const alreadyIncludesBase =\n basePath && basePath !== \"/\" && path.startsWith(`${basePath}/`);\n const joined = alreadyIncludesBase\n ? `${base.origin}${path}`\n : `${appUrl.replace(/\\/+$/, \"\")}${path}`;\n return new URL(joined).toString();\n }\n\n const url = new URL(trimmed);\n if (![\"http:\", \"https:\"].includes(url.protocol)) return null;\n if (url.origin !== base.origin) return null;\n return url.toString();\n } catch {\n return null;\n }\n}\n\nexport function resolveShareNotificationUrl(\n explicitUrl: string | undefined,\n fallbackPath: string | undefined,\n appUrl = getAppProductionUrl(),\n): string {\n for (const candidate of [explicitUrl, fallbackPath]) {\n if (!candidate) continue;\n const url = safeNotificationUrl(candidate, appUrl);\n if (url) return url;\n }\n return appUrl;\n}\n\nfunction nanoid(size = 12): string {\n const chars =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n let id = \"\";\n const bytes = crypto.getRandomValues(new Uint8Array(size));\n for (const byte of bytes) id += chars[byte % chars.length];\n return id;\n}\n\nfunction normalizePrincipalId(\n principalType: \"user\" | \"org\",\n principalId: string,\n): string {\n return principalType === \"user\"\n ? principalId.trim().toLowerCase()\n : principalId;\n}\n\nfunction principalIdMatches(\n sharesTable: any,\n principalType: \"user\" | \"org\",\n principalId: string,\n): SQL {\n return principalType === \"user\"\n ? sql`lower(${sharesTable.principalId}) = ${principalId}`\n : eq(sharesTable.principalId, principalId);\n}\n\n/**\n * Returns true if the given email is either an active member of `orgId` or\n * has a pending invitation to `orgId`. Used by resources whose registration\n * sets `requireOrgMemberForUserShares` (currently extensions) to refuse\n * cross-org user shares.\n *\n * Both `org_members` and `org_invitations` store email case-insensitively\n * via `LOWER()` in the rest of the framework, so we follow the same\n * convention here.\n */\nasync function isOrgMemberOrInvited(\n orgId: string,\n email: string,\n): Promise<boolean> {\n const lower = email.trim().toLowerCase();\n if (!lower || !orgId) return false;\n const client = getDbExec();\n const member = await client.execute({\n sql: `SELECT 1 FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n args: [orgId, lower],\n });\n if (member.rows.length > 0) return true;\n const invited = await client.execute({\n sql: `SELECT 1 FROM org_invitations WHERE org_id = ? AND LOWER(email) = ? AND status = 'pending' LIMIT 1`,\n args: [orgId, lower],\n });\n return invited.rows.length > 0;\n}\n\nexport default defineAction({\n description:\n \"Grant a user or org access to a shareable resource. Owner or admin role required.\",\n // (audit H5) Sharing-grant operations are admin-tier and let a caller\n // expand who can read/write a resource. Refuse from the tools iframe\n // bridge so a malicious shared tool can't silently re-share its\n // viewer's resources to an attacker-controlled email.\n toolCallable: false,\n schema: z.object({\n resourceType: z\n .string()\n .describe(\"Registered resource type, e.g. 'document', 'form'.\"),\n resourceId: z.string().describe(\"Id of the resource to share.\"),\n principalType: z\n .enum([\"user\", \"org\"])\n .describe(\"'user' for an individual, 'org' for a whole organization.\"),\n principalId: z\n .string()\n .describe(\"Email (user) or org id (org) of the principal.\"),\n role: z\n .enum([\"viewer\", \"editor\", \"admin\"])\n .default(\"viewer\")\n .describe(\"Role to grant.\"),\n notify: z\n .boolean()\n .default(true)\n .describe(\n \"Whether to email the user about a new individual share. Defaults to true.\",\n ),\n resourceUrl: z\n .string()\n .optional()\n .describe(\n \"Optional app-relative or same-origin URL recipients should open. External origins are ignored.\",\n ),\n }),\n run: async (args) => {\n const reg = requireShareableResource(args.resourceType);\n const access = await assertAccess(\n args.resourceType,\n args.resourceId,\n \"admin\",\n );\n const actor = getRequestUserEmail();\n if (!actor) throw new ForbiddenError(\"Not signed in\");\n const principalId = normalizePrincipalId(\n args.principalType,\n args.principalId,\n );\n const beforeExtensionTargets = await getExtensionShareChangeTargets(\n args.resourceType,\n args.resourceId,\n );\n\n if (reg.requireOrgMemberForUserShares) {\n const resourceOrgId = access.resource?.orgId as string | undefined | null;\n if (!resourceOrgId) {\n throw new ForbiddenError(\n `${reg.displayName} can only be shared from within an organization. Create or join an organization first.`,\n );\n }\n if (args.principalType === \"user\") {\n const ok = await isOrgMemberOrInvited(resourceOrgId, principalId);\n if (!ok) {\n throw new ForbiddenError(\n `${principalId} is not in your organization. Invite them to the organization first, then share.`,\n );\n }\n } else if (args.principalType === \"org\") {\n // Cross-org org shares would let an outside org's members run\n // extension code in the viewer's auth context — the same threat\n // model that blocks public + cross-org user shares. Pin org-\n // principal shares to the resource's own org.\n if (principalId !== resourceOrgId) {\n throw new ForbiddenError(\n `${reg.displayName} can only be shared with its own organization, not a different one.`,\n );\n }\n }\n }\n\n const db = reg.getDb() as any;\n const [existing] = await db\n .select()\n .from(reg.sharesTable)\n .where(\n and(\n eq(reg.sharesTable.resourceId, args.resourceId),\n eq(reg.sharesTable.principalType, args.principalType),\n principalIdMatches(reg.sharesTable, args.principalType, principalId),\n ),\n );\n\n if (existing) {\n await db\n .update(reg.sharesTable)\n .set({ role: args.role })\n .where(eq(reg.sharesTable.id, existing.id));\n await notifyExtensionShareChanged(\n args.resourceType,\n args.resourceId,\n beforeExtensionTargets,\n );\n return { id: existing.id, updated: true };\n }\n\n const id = nanoid();\n await db.insert(reg.sharesTable).values({\n id,\n resourceId: args.resourceId,\n principalType: args.principalType,\n principalId,\n role: args.role,\n createdBy: actor,\n createdAt: new Date().toISOString(),\n });\n await notifyExtensionShareChanged(\n args.resourceType,\n args.resourceId,\n beforeExtensionTargets,\n );\n\n if (\n args.notify !== false &&\n args.principalType === \"user\" &&\n (await isEmailConfigured()) &&\n !isSyntheticQaEmail(principalId)\n ) {\n try {\n const titleCol = reg.titleColumn ?? \"title\";\n const [resource] = await db\n .select()\n .from(reg.resourceTable)\n .where(eq(reg.resourceTable.id, args.resourceId));\n const resourceTitle: string =\n (resource?.[titleCol] as string | undefined) ?? args.resourceType;\n const appUrl = getAppProductionUrl();\n const resourcePath =\n resource && reg.getResourcePath\n ? reg.getResourcePath(resource)\n : undefined;\n const notificationUrl = resolveShareNotificationUrl(\n args.resourceUrl,\n resourcePath,\n appUrl,\n );\n const appName =\n process.env.APP_NAME || process.env.VITE_APP_NAME || \"Agent Native\";\n const subject = `${actor} shared \"${resourceTitle}\" with you on ${appName}`;\n const { html, text } = renderEmail({\n preheader: subject,\n heading: \"You've been given access\",\n paragraphs: [\n `${emailStrong(actor)} has shared the ${reg.displayName} ${emailStrong(resourceTitle)} with you as a ${emailStrong(args.role)}.`,\n `Use the button below to open it. If prompted, sign in with ${emailStrong(principalId)}.`,\n ],\n cta: { label: `Open ${reg.displayName}`, url: notificationUrl },\n footer: `You received this because ${actor} granted you ${args.role} access.`,\n });\n await sendEmail({ to: principalId, subject, html, text });\n } catch (err) {\n console.error(\n \"[share-resource] failed to send share notification:\",\n err,\n );\n }\n }\n\n return { id, updated: false };\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"share-resource.js","sourceRoot":"","sources":["../../../src/sharing/actions/share-resource.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, sql, type SQL } from \"drizzle-orm\";\nimport { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport { getDbExec } from \"../../db/client.js\";\nimport { getAppProductionUrl } from \"../../server/app-url.js\";\nimport { renderEmail, emailStrong } from \"../../server/email-template.js\";\nimport { sendEmail, isEmailConfigured } from \"../../server/email.js\";\nimport { invalidateCollabAccessCache } from \"../../server/poll.js\";\nimport { getRequestUserEmail } from \"../../server/request-context.js\";\nimport { assertAccess, ForbiddenError } from \"../access.js\";\nimport { requireShareableResource } from \"../registry.js\";\nimport {\n getExtensionShareChangeTargets,\n notifyExtensionShareChanged,\n} from \"./extension-change.js\";\n\nexport function isSyntheticQaEmail(email: string): boolean {\n const trimmed = email.trim().toLowerCase();\n const at = trimmed.lastIndexOf(\"@\");\n if (at <= 0) return false;\n const local = trimmed.slice(0, at);\n const domain = trimmed.slice(at + 1);\n return (\n local.includes(\"+qa\") &&\n (domain === \"example.test\" ||\n domain.endsWith(\".test\") ||\n domain === \"example.invalid\" ||\n domain.endsWith(\".invalid\"))\n );\n}\n\nfunction appPath(path: string): string {\n if (!path.startsWith(\"/\")) return path;\n const raw = process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || \"\";\n const base = raw.trim().replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (!base) return path;\n const normalizedBase = `/${base}`;\n if (path === normalizedBase || path.startsWith(`${normalizedBase}/`)) {\n return path;\n }\n return `${normalizedBase}${path}`;\n}\n\nfunction safeNotificationUrl(value: string, appUrl: string): string | null {\n const trimmed = value.trim();\n if (!trimmed) return null;\n\n try {\n const base = new URL(appUrl);\n if (trimmed.startsWith(\"/\")) {\n const path = appPath(trimmed);\n const basePath = base.pathname.replace(/\\/+$/, \"\");\n const alreadyIncludesBase =\n basePath && basePath !== \"/\" && path.startsWith(`${basePath}/`);\n const joined = alreadyIncludesBase\n ? `${base.origin}${path}`\n : `${appUrl.replace(/\\/+$/, \"\")}${path}`;\n return new URL(joined).toString();\n }\n\n const url = new URL(trimmed);\n if (![\"http:\", \"https:\"].includes(url.protocol)) return null;\n if (url.origin !== base.origin) return null;\n return url.toString();\n } catch {\n return null;\n }\n}\n\nexport function resolveShareNotificationUrl(\n explicitUrl: string | undefined,\n fallbackPath: string | undefined,\n appUrl = getAppProductionUrl(),\n): string {\n for (const candidate of [explicitUrl, fallbackPath]) {\n if (!candidate) continue;\n const url = safeNotificationUrl(candidate, appUrl);\n if (url) return url;\n }\n return appUrl;\n}\n\nfunction nanoid(size = 12): string {\n const chars =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n let id = \"\";\n const bytes = crypto.getRandomValues(new Uint8Array(size));\n for (const byte of bytes) id += chars[byte % chars.length];\n return id;\n}\n\nfunction normalizePrincipalId(\n principalType: \"user\" | \"org\",\n principalId: string,\n): string {\n return principalType === \"user\"\n ? principalId.trim().toLowerCase()\n : principalId;\n}\n\nfunction principalIdMatches(\n sharesTable: any,\n principalType: \"user\" | \"org\",\n principalId: string,\n): SQL {\n return principalType === \"user\"\n ? sql`lower(${sharesTable.principalId}) = ${principalId}`\n : eq(sharesTable.principalId, principalId);\n}\n\n/**\n * Returns true if the given email is either an active member of `orgId` or\n * has a pending invitation to `orgId`. Used by resources whose registration\n * sets `requireOrgMemberForUserShares` (currently extensions) to refuse\n * cross-org user shares.\n *\n * Both `org_members` and `org_invitations` store email case-insensitively\n * via `LOWER()` in the rest of the framework, so we follow the same\n * convention here.\n */\nasync function isOrgMemberOrInvited(\n orgId: string,\n email: string,\n): Promise<boolean> {\n const lower = email.trim().toLowerCase();\n if (!lower || !orgId) return false;\n const client = getDbExec();\n const member = await client.execute({\n sql: `SELECT 1 FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n args: [orgId, lower],\n });\n if (member.rows.length > 0) return true;\n const invited = await client.execute({\n sql: `SELECT 1 FROM org_invitations WHERE org_id = ? AND LOWER(email) = ? AND status = 'pending' LIMIT 1`,\n args: [orgId, lower],\n });\n return invited.rows.length > 0;\n}\n\nexport default defineAction({\n description:\n \"Grant a user or org access to a shareable resource. Owner or admin role required.\",\n // (audit H5) Sharing-grant operations are admin-tier and let a caller\n // expand who can read/write a resource. Refuse from the tools iframe\n // bridge so a malicious shared tool can't silently re-share its\n // viewer's resources to an attacker-controlled email.\n toolCallable: false,\n schema: z.object({\n resourceType: z\n .string()\n .describe(\"Registered resource type, e.g. 'document', 'form'.\"),\n resourceId: z.string().describe(\"Id of the resource to share.\"),\n principalType: z\n .enum([\"user\", \"org\"])\n .describe(\"'user' for an individual, 'org' for a whole organization.\"),\n principalId: z\n .string()\n .describe(\"Email (user) or org id (org) of the principal.\"),\n role: z\n .enum([\"viewer\", \"editor\", \"admin\"])\n .default(\"viewer\")\n .describe(\"Role to grant.\"),\n notify: z\n .boolean()\n .default(true)\n .describe(\n \"Whether to email the user about a new individual share. Defaults to true.\",\n ),\n resourceUrl: z\n .string()\n .optional()\n .describe(\n \"Optional app-relative or same-origin URL recipients should open. External origins are ignored.\",\n ),\n }),\n run: async (args) => {\n const reg = requireShareableResource(args.resourceType);\n const access = await assertAccess(\n args.resourceType,\n args.resourceId,\n \"admin\",\n );\n const actor = getRequestUserEmail();\n if (!actor) throw new ForbiddenError(\"Not signed in\");\n const principalId = normalizePrincipalId(\n args.principalType,\n args.principalId,\n );\n const beforeExtensionTargets = await getExtensionShareChangeTargets(\n args.resourceType,\n args.resourceId,\n );\n\n if (reg.requireOrgMemberForUserShares) {\n const resourceOrgId = access.resource?.orgId as string | undefined | null;\n if (!resourceOrgId) {\n throw new ForbiddenError(\n `${reg.displayName} can only be shared from within an organization. Create or join an organization first.`,\n );\n }\n if (args.principalType === \"user\") {\n const ok = await isOrgMemberOrInvited(resourceOrgId, principalId);\n if (!ok) {\n throw new ForbiddenError(\n `${principalId} is not in your organization. Invite them to the organization first, then share.`,\n );\n }\n } else if (args.principalType === \"org\") {\n // Cross-org org shares would let an outside org's members run\n // extension code in the viewer's auth context — the same threat\n // model that blocks public + cross-org user shares. Pin org-\n // principal shares to the resource's own org.\n if (principalId !== resourceOrgId) {\n throw new ForbiddenError(\n `${reg.displayName} can only be shared with its own organization, not a different one.`,\n );\n }\n }\n }\n\n const db = reg.getDb() as any;\n const [existing] = await db\n .select()\n .from(reg.sharesTable)\n .where(\n and(\n eq(reg.sharesTable.resourceId, args.resourceId),\n eq(reg.sharesTable.principalType, args.principalType),\n principalIdMatches(reg.sharesTable, args.principalType, principalId),\n ),\n );\n\n if (existing) {\n await db\n .update(reg.sharesTable)\n .set({ role: args.role })\n .where(eq(reg.sharesTable.id, existing.id));\n invalidateCollabAccessCache(args.resourceType, args.resourceId);\n await notifyExtensionShareChanged(\n args.resourceType,\n args.resourceId,\n beforeExtensionTargets,\n );\n return { id: existing.id, updated: true };\n }\n\n const id = nanoid();\n await db.insert(reg.sharesTable).values({\n id,\n resourceId: args.resourceId,\n principalType: args.principalType,\n principalId,\n role: args.role,\n createdBy: actor,\n createdAt: new Date().toISOString(),\n });\n invalidateCollabAccessCache(args.resourceType, args.resourceId);\n await notifyExtensionShareChanged(\n args.resourceType,\n args.resourceId,\n beforeExtensionTargets,\n );\n\n if (\n args.notify !== false &&\n args.principalType === \"user\" &&\n (await isEmailConfigured()) &&\n !isSyntheticQaEmail(principalId)\n ) {\n try {\n const titleCol = reg.titleColumn ?? \"title\";\n const [resource] = await db\n .select()\n .from(reg.resourceTable)\n .where(eq(reg.resourceTable.id, args.resourceId));\n const resourceTitle: string =\n (resource?.[titleCol] as string | undefined) ?? args.resourceType;\n const appUrl = getAppProductionUrl();\n const resourcePath =\n resource && reg.getResourcePath\n ? reg.getResourcePath(resource)\n : undefined;\n const notificationUrl = resolveShareNotificationUrl(\n args.resourceUrl,\n resourcePath,\n appUrl,\n );\n const appName =\n process.env.APP_NAME || process.env.VITE_APP_NAME || \"Agent Native\";\n const subject = `${actor} shared \"${resourceTitle}\" with you on ${appName}`;\n const { html, text } = renderEmail({\n preheader: subject,\n heading: \"You've been given access\",\n paragraphs: [\n `${emailStrong(actor)} has shared the ${reg.displayName} ${emailStrong(resourceTitle)} with you as a ${emailStrong(args.role)}.`,\n `Use the button below to open it. If prompted, sign in with ${emailStrong(principalId)}.`,\n ],\n cta: { label: `Open ${reg.displayName}`, url: notificationUrl },\n footer: `You received this because ${actor} granted you ${args.role} access.`,\n });\n await sendEmail({ to: principalId, subject, html, text });\n } catch (err) {\n console.error(\n \"[share-resource] failed to send share notification:\",\n err,\n );\n }\n }\n\n return { id, updated: false };\n },\n});\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { and, eq, sql } from "drizzle-orm";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { defineAction } from "../../action.js";
|
|
4
|
+
import { invalidateCollabAccessCache } from "../../server/poll.js";
|
|
4
5
|
import { assertAccess } from "../access.js";
|
|
5
6
|
import { requireShareableResource } from "../registry.js";
|
|
6
7
|
import { getExtensionShareChangeTargets, notifyExtensionShareChanged, } from "./extension-change.js";
|
|
@@ -33,6 +34,7 @@ export default defineAction({
|
|
|
33
34
|
await db
|
|
34
35
|
.delete(reg.sharesTable)
|
|
35
36
|
.where(and(eq(reg.sharesTable.resourceId, args.resourceId), eq(reg.sharesTable.principalType, args.principalType), principalIdMatches(reg.sharesTable, args.principalType, principalId)));
|
|
37
|
+
invalidateCollabAccessCache(args.resourceType, args.resourceId);
|
|
36
38
|
await notifyExtensionShareChanged(args.resourceType, args.resourceId, beforeExtensionTargets);
|
|
37
39
|
return { ok: true };
|
|
38
40
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unshare-resource.js","sourceRoot":"","sources":["../../../src/sharing/actions/unshare-resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAY,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAE/B,SAAS,oBAAoB,CAC3B,aAA6B,EAC7B,WAAmB;IAEnB,OAAO,aAAa,KAAK,MAAM;QAC7B,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;QAClC,CAAC,CAAC,WAAW,CAAC;AAClB,CAAC;AAED,SAAS,kBAAkB,CACzB,WAAgB,EAChB,aAA6B,EAC7B,WAAmB;IAEnB,OAAO,aAAa,KAAK,MAAM;QAC7B,CAAC,CAAC,GAAG,CAAA,SAAS,WAAW,CAAC,WAAW,OAAO,WAAW,EAAE;QACzD,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,kEAAkE;IACpE,yEAAyE;IACzE,YAAY,EAAE,KAAK;IACnB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;QACxB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;QACtB,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACtC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;KACxB,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAClB,MAAM,GAAG,GAAG,wBAAwB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,sBAAsB,GAAG,MAAM,8BAA8B,CACjE,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,UAAU,CAChB,CAAC;QACF,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,EAAS,CAAC;QAC9B,MAAM,WAAW,GAAG,oBAAoB,CACtC,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,WAAW,CACjB,CAAC;QACF,MAAM,EAAE;aACL,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;aACvB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,EAC/C,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,EACrD,kBAAkB,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CACrE,CACF,CAAC;QACJ,MAAM,2BAA2B,CAC/B,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,UAAU,EACf,sBAAsB,CACvB,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { and, eq, sql, type SQL } from \"drizzle-orm\";\nimport { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport { assertAccess } from \"../access.js\";\nimport { requireShareableResource } from \"../registry.js\";\nimport {\n getExtensionShareChangeTargets,\n notifyExtensionShareChanged,\n} from \"./extension-change.js\";\n\nfunction normalizePrincipalId(\n principalType: \"user\" | \"org\",\n principalId: string,\n): string {\n return principalType === \"user\"\n ? principalId.trim().toLowerCase()\n : principalId;\n}\n\nfunction principalIdMatches(\n sharesTable: any,\n principalType: \"user\" | \"org\",\n principalId: string,\n): SQL {\n return principalType === \"user\"\n ? sql`lower(${sharesTable.principalId}) = ${principalId}`\n : eq(sharesTable.principalId, principalId);\n}\n\nexport default defineAction({\n description:\n \"Revoke a previously granted share. Owner or admin role required.\",\n // (audit H5) Mirror share-resource: refuse from the tools iframe bridge.\n toolCallable: false,\n schema: z.object({\n resourceType: z.string(),\n resourceId: z.string(),\n principalType: z.enum([\"user\", \"org\"]),\n principalId: z.string(),\n }),\n run: async (args) => {\n const reg = requireShareableResource(args.resourceType);\n await assertAccess(args.resourceType, args.resourceId, \"admin\");\n const beforeExtensionTargets = await getExtensionShareChangeTargets(\n args.resourceType,\n args.resourceId,\n );\n const db = reg.getDb() as any;\n const principalId = normalizePrincipalId(\n args.principalType,\n args.principalId,\n );\n await db\n .delete(reg.sharesTable)\n .where(\n and(\n eq(reg.sharesTable.resourceId, args.resourceId),\n eq(reg.sharesTable.principalType, args.principalType),\n principalIdMatches(reg.sharesTable, args.principalType, principalId),\n ),\n );\n await notifyExtensionShareChanged(\n args.resourceType,\n args.resourceId,\n beforeExtensionTargets,\n );\n return { ok: true };\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"unshare-resource.js","sourceRoot":"","sources":["../../../src/sharing/actions/unshare-resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAY,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAE/B,SAAS,oBAAoB,CAC3B,aAA6B,EAC7B,WAAmB;IAEnB,OAAO,aAAa,KAAK,MAAM;QAC7B,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;QAClC,CAAC,CAAC,WAAW,CAAC;AAClB,CAAC;AAED,SAAS,kBAAkB,CACzB,WAAgB,EAChB,aAA6B,EAC7B,WAAmB;IAEnB,OAAO,aAAa,KAAK,MAAM;QAC7B,CAAC,CAAC,GAAG,CAAA,SAAS,WAAW,CAAC,WAAW,OAAO,WAAW,EAAE;QACzD,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,kEAAkE;IACpE,yEAAyE;IACzE,YAAY,EAAE,KAAK;IACnB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;QACxB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;QACtB,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACtC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;KACxB,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAClB,MAAM,GAAG,GAAG,wBAAwB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,sBAAsB,GAAG,MAAM,8BAA8B,CACjE,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,UAAU,CAChB,CAAC;QACF,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,EAAS,CAAC;QAC9B,MAAM,WAAW,GAAG,oBAAoB,CACtC,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,WAAW,CACjB,CAAC;QACF,MAAM,EAAE;aACL,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;aACvB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,EAC/C,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,EACrD,kBAAkB,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CACrE,CACF,CAAC;QACJ,2BAA2B,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,MAAM,2BAA2B,CAC/B,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,UAAU,EACf,sBAAsB,CACvB,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { and, eq, sql, type SQL } from \"drizzle-orm\";\nimport { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport { invalidateCollabAccessCache } from \"../../server/poll.js\";\nimport { assertAccess } from \"../access.js\";\nimport { requireShareableResource } from \"../registry.js\";\nimport {\n getExtensionShareChangeTargets,\n notifyExtensionShareChanged,\n} from \"./extension-change.js\";\n\nfunction normalizePrincipalId(\n principalType: \"user\" | \"org\",\n principalId: string,\n): string {\n return principalType === \"user\"\n ? principalId.trim().toLowerCase()\n : principalId;\n}\n\nfunction principalIdMatches(\n sharesTable: any,\n principalType: \"user\" | \"org\",\n principalId: string,\n): SQL {\n return principalType === \"user\"\n ? sql`lower(${sharesTable.principalId}) = ${principalId}`\n : eq(sharesTable.principalId, principalId);\n}\n\nexport default defineAction({\n description:\n \"Revoke a previously granted share. Owner or admin role required.\",\n // (audit H5) Mirror share-resource: refuse from the tools iframe bridge.\n toolCallable: false,\n schema: z.object({\n resourceType: z.string(),\n resourceId: z.string(),\n principalType: z.enum([\"user\", \"org\"]),\n principalId: z.string(),\n }),\n run: async (args) => {\n const reg = requireShareableResource(args.resourceType);\n await assertAccess(args.resourceType, args.resourceId, \"admin\");\n const beforeExtensionTargets = await getExtensionShareChangeTargets(\n args.resourceType,\n args.resourceId,\n );\n const db = reg.getDb() as any;\n const principalId = normalizePrincipalId(\n args.principalType,\n args.principalId,\n );\n await db\n .delete(reg.sharesTable)\n .where(\n and(\n eq(reg.sharesTable.resourceId, args.resourceId),\n eq(reg.sharesTable.principalType, args.principalType),\n principalIdMatches(reg.sharesTable, args.principalType, principalId),\n ),\n );\n invalidateCollabAccessCache(args.resourceType, args.resourceId);\n await notifyExtensionShareChanged(\n args.resourceType,\n args.resourceId,\n beforeExtensionTargets,\n );\n return { ok: true };\n },\n});\n"]}
|
|
@@ -735,11 +735,6 @@
|
|
|
735
735
|
top: calc(100% + 0.5rem);
|
|
736
736
|
}
|
|
737
737
|
|
|
738
|
-
[data-agent-empty-state="compact-setup"] > .agent-chat-scroll {
|
|
739
|
-
flex: 0 0 auto;
|
|
740
|
-
overflow: visible;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
738
|
[data-agent-empty-state="compact-setup"] .agent-empty-state {
|
|
744
739
|
height: auto;
|
|
745
740
|
min-height: 5rem;
|