@agent-native/core 0.85.7 → 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 +124 -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/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/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/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/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 +50 -12
- 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 +10 -2
- package/corpus/templates/design/actions/apply-fusion-edits.ts +161 -0
- package/corpus/templates/design/actions/apply-visual-edit.ts +34 -1
- 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/get-fusion-deploy-status.ts +86 -0
- 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/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/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 +115 -14
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +12 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +379 -0
- package/corpus/templates/design/app/components/design/EditPanel.tsx +149 -73
- package/corpus/templates/design/app/components/design/FusionAppBanner.tsx +328 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +148 -30
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +1 -1
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +567 -6
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -98
- 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/DesignColorPicker.tsx +127 -10
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +52 -29
- package/corpus/templates/design/app/components/design/inspector/index.ts +9 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +56 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +80 -1
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +6 -16
- package/corpus/templates/design/app/i18n/zh-TW.ts +2 -1
- package/corpus/templates/design/app/i18n-data.ts +31 -18
- package/corpus/templates/design/app/pages/DesignEditor.tsx +1474 -175
- package/corpus/templates/design/app/pages/Index.tsx +90 -17
- 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/package.json +4 -3
- package/corpus/templates/design/server/db/schema.ts +31 -0
- 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/collab-selection.ts +52 -0
- package/corpus/templates/design/shared/full-app.ts +126 -0
- package/corpus/templates/design/shared/pen-path.ts +296 -0
- 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/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 +12 -1
- 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/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/routes.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- 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 +2 -2
- 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/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- 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/server/transcribe-voice.d.ts +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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.js","sourceRoot":"","sources":["../../src/collab/undo.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared per-user undo/redo for collaborative surfaces.\n *\n * Two primitives, one rule: undo NEVER reverts another participant's (human\n * or agent) work, and never restores whole-document snapshots that would\n * clobber concurrent edits.\n *\n * - `useCollabUndo` — Y.UndoManager lifecycle wrapper for Yjs-backed surfaces.\n * Tracks only transactions tagged with the local origin, coalesces rapid\n * edits, and is recreated/destroyed when the document changes (stale\n * managers hold Y.Doc references and grow unboundedly).\n *\n * - `useLocalOpUndo` / `createLocalOpUndoController` — inverse-operation undo\n * for op-based apps (slides decks, forms). Each local mutation registers\n * the granular ops that redo and undo it; Cmd+Z replays the inverse ops\n * through the app's normal granular mutation path, so concurrent edits by\n * other participants to OTHER items are never touched.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport * as Y from \"yjs\";\n\n// ---------------------------------------------------------------------------\n// Keyboard shortcut helper (shared by both hooks)\n// ---------------------------------------------------------------------------\n\nexport interface UndoKeyboardOptions {\n /** Bind Mod+Z / Shift+Mod+Z / Mod+Y on window while mounted. */\n enableKeyboardShortcuts?: boolean;\n /**\n * Skip the shortcut when the event target is an input, textarea, or\n * contentEditable (those own their own undo). Default true.\n */\n ignoreInputTargets?: boolean;\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null;\n if (!el) return false;\n const tag = el.tagName;\n return (\n tag === \"INPUT\" ||\n tag === \"TEXTAREA\" ||\n tag === \"SELECT\" ||\n !!el.isContentEditable\n );\n}\n\nfunction useUndoKeyboard(\n undo: () => void,\n redo: () => void,\n options: UndoKeyboardOptions | undefined,\n): void {\n const enabled = options?.enableKeyboardShortcuts ?? false;\n const ignoreInputs = options?.ignoreInputTargets ?? true;\n\n useEffect(() => {\n if (!enabled || typeof window === \"undefined\") return;\n\n function onKeyDown(e: KeyboardEvent) {\n if (!(e.metaKey || e.ctrlKey)) return;\n if (ignoreInputs && isEditableTarget(e.target)) return;\n const key = e.key.toLowerCase();\n if (key === \"z\") {\n e.preventDefault();\n if (e.shiftKey) redo();\n else undo();\n } else if (key === \"y\") {\n e.preventDefault();\n redo();\n }\n }\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [enabled, ignoreInputs, undo, redo]);\n}\n\n// ---------------------------------------------------------------------------\n// Yjs-backed undo — useCollabUndo\n// ---------------------------------------------------------------------------\n\nexport type CollabUndoScope =\n | Y.AbstractType<any>\n | Y.AbstractType<any>[]\n | ((doc: Y.Doc) => Y.AbstractType<any> | Y.AbstractType<any>[]);\n\nexport interface UseCollabUndoOptions extends UndoKeyboardOptions {\n /** The collaborative document. Null/undefined while loading. */\n ydoc: Y.Doc | null | undefined;\n /**\n * Shared type(s) to track, or a factory receiving the doc (evaluated when\n * the doc changes) — e.g. `(doc) => doc.getText(\"content\")`.\n */\n scope: CollabUndoScope;\n /**\n * Origins captured as undoable. Defaults to the hook's own `localOrigin`.\n * Transactions from remote peers (\"remote\") and the agent (\"agent\"/\n * \"server\") are never captured.\n */\n trackedOrigins?: unknown[];\n /** Coalesce rapid edits into one undo step. Default 500ms. */\n captureTimeout?: number;\n}\n\nexport interface UseCollabUndoResult {\n /** Undo the local user's most recent edit. Returns true if applied. */\n undo: () => boolean;\n /** Redo the local user's most recently undone edit. */\n redo: () => boolean;\n canUndo: boolean;\n canRedo: boolean;\n /**\n * Tag local transactions with this origin so they're captured:\n * `ydoc.transact(() => { ... }, localOrigin)` — or use `transactLocal`.\n */\n localOrigin: unknown;\n /** Run a mutation in a transaction tagged with the local origin. */\n transactLocal: <T>(fn: () => T) => T;\n /** The underlying manager (null while the doc is loading). */\n undoManager: Y.UndoManager | null;\n}\n\nexport function useCollabUndo(\n options: UseCollabUndoOptions,\n): UseCollabUndoResult {\n const { ydoc, scope, trackedOrigins, captureTimeout = 500 } = options;\n\n // Stable per-hook local origin (an object identity — never collides).\n const localOrigin = useMemo<unknown>(\n () => ({ collabUndoLocalOrigin: true }),\n [],\n );\n\n const managerRef = useRef<Y.UndoManager | null>(null);\n const [canUndo, setCanUndo] = useState(false);\n const [canRedo, setCanRedo] = useState(false);\n\n // Keep latest scope/origins in refs so the effect only re-runs on doc change.\n const scopeRef = useRef(scope);\n scopeRef.current = scope;\n const trackedRef = useRef(trackedOrigins);\n trackedRef.current = trackedOrigins;\n\n useEffect(() => {\n if (!ydoc) {\n managerRef.current = null;\n setCanUndo(false);\n setCanRedo(false);\n return;\n }\n\n const rawScope = scopeRef.current;\n const resolved = typeof rawScope === \"function\" ? rawScope(ydoc) : rawScope;\n const scopes = Array.isArray(resolved) ? resolved : [resolved];\n\n const origins = new Set<unknown>(trackedRef.current ?? [localOrigin]);\n const manager = new Y.UndoManager(scopes, {\n trackedOrigins: origins,\n captureTimeout,\n });\n // The manager applies undo/redo transactions with itself as origin;\n // track it so redo of an undone step is capturable.\n origins.add(manager);\n managerRef.current = manager;\n\n function refresh() {\n setCanUndo(manager.undoStack.length > 0);\n setCanRedo(manager.redoStack.length > 0);\n }\n refresh();\n\n manager.on(\"stack-item-added\", refresh);\n manager.on(\"stack-item-popped\", refresh);\n manager.on(\"stack-cleared\", refresh);\n\n return () => {\n manager.off(\"stack-item-added\", refresh);\n manager.off(\"stack-item-popped\", refresh);\n manager.off(\"stack-cleared\", refresh);\n manager.destroy();\n if (managerRef.current === manager) {\n managerRef.current = null;\n }\n };\n }, [ydoc, captureTimeout, localOrigin]);\n\n const undo = useCallback((): boolean => {\n const m = managerRef.current;\n if (!m || m.undoStack.length === 0) return false;\n m.undo();\n return true;\n }, []);\n\n const redo = useCallback((): boolean => {\n const m = managerRef.current;\n if (!m || m.redoStack.length === 0) return false;\n m.redo();\n return true;\n }, []);\n\n const transactLocal = useCallback(\n <T>(fn: () => T): T => {\n if (!ydoc) return fn();\n let result!: T;\n ydoc.transact(() => {\n result = fn();\n }, localOrigin);\n return result;\n },\n [ydoc, localOrigin],\n );\n\n useUndoKeyboard(undo, redo, options);\n\n return {\n undo,\n redo,\n canUndo,\n canRedo,\n localOrigin,\n transactLocal,\n undoManager: managerRef.current,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Inverse-op undo — createLocalOpUndoController / useLocalOpUndo\n// ---------------------------------------------------------------------------\n\nexport interface LocalOpUndoEntry<TOp> {\n /** Granular ops that reverse the mutation. */\n undo: TOp[];\n /** Granular ops that re-apply the mutation. */\n redo: TOp[];\n /** Optional label for UI (\"Delete slide 3\"). */\n label?: string;\n /**\n * Coalescing key: consecutive pushes with the same non-empty key within\n * `coalesceMs` merge into one entry (keeps the FIRST undo ops and the\n * LATEST redo ops) — e.g. per-keystroke text patches on one field.\n */\n coalesceKey?: string;\n}\n\nexport interface LocalOpUndoController<TOp> {\n /** Record a local mutation. Clears the redo stack. */\n push(entry: LocalOpUndoEntry<TOp>): void;\n /** Apply the inverse ops of the most recent entry. */\n undo(): Promise<boolean>;\n /** Re-apply the most recently undone entry. */\n redo(): Promise<boolean>;\n canUndo(): boolean;\n canRedo(): boolean;\n clear(): void;\n /** Peek labels for UI (undo tooltip). */\n peekUndoLabel(): string | undefined;\n peekRedoLabel(): string | undefined;\n}\n\nexport interface CreateLocalOpUndoOptions<TOp> {\n /**\n * Apply granular ops through the app's normal mutation path. MUST NOT\n * push back into this controller (re-entrant pushes are ignored).\n */\n apply: (\n ops: TOp[],\n direction: \"undo\" | \"redo\",\n entry: LocalOpUndoEntry<TOp>,\n ) => void | Promise<void>;\n /** Max retained entries. Default 200. */\n maxDepth?: number;\n /** Window for coalescing same-key pushes. Default 800ms. */\n coalesceMs?: number;\n /** Called after any stack change (for canUndo/canRedo UI updates). */\n onChange?: () => void;\n /** Clock override for tests. */\n now?: () => number;\n}\n\ninterface StampedEntry<TOp> extends LocalOpUndoEntry<TOp> {\n at: number;\n}\n\nexport function createLocalOpUndoController<TOp>(\n options: CreateLocalOpUndoOptions<TOp>,\n): LocalOpUndoController<TOp> {\n const {\n apply,\n maxDepth = 200,\n coalesceMs = 800,\n onChange,\n now = () => Date.now(),\n } = options;\n\n const undoStack: StampedEntry<TOp>[] = [];\n const redoStack: StampedEntry<TOp>[] = [];\n let applying = false;\n\n function notify() {\n onChange?.();\n }\n\n return {\n push(entry) {\n // Ignore pushes triggered by our own undo/redo application.\n if (applying) return;\n\n const at = now();\n const top = undoStack[undoStack.length - 1];\n if (\n top &&\n entry.coalesceKey &&\n top.coalesceKey === entry.coalesceKey &&\n at - top.at <= coalesceMs\n ) {\n // Merge: first undo wins (restores the pre-burst state), latest redo\n // wins (re-applies the final state).\n top.redo = entry.redo;\n top.at = at;\n } else {\n undoStack.push({ ...entry, at });\n if (undoStack.length > maxDepth) {\n undoStack.splice(0, undoStack.length - maxDepth);\n }\n }\n redoStack.length = 0;\n notify();\n },\n\n async undo() {\n const entry = undoStack.pop();\n if (!entry) return false;\n redoStack.push(entry);\n notify();\n applying = true;\n try {\n await apply(entry.undo, \"undo\", entry);\n } finally {\n applying = false;\n }\n return true;\n },\n\n async redo() {\n const entry = redoStack.pop();\n if (!entry) return false;\n undoStack.push(entry);\n notify();\n applying = true;\n try {\n await apply(entry.redo, \"redo\", entry);\n } finally {\n applying = false;\n }\n return true;\n },\n\n canUndo: () => undoStack.length > 0,\n canRedo: () => redoStack.length > 0,\n\n clear() {\n undoStack.length = 0;\n redoStack.length = 0;\n notify();\n },\n\n peekUndoLabel: () => undoStack[undoStack.length - 1]?.label,\n peekRedoLabel: () => redoStack[redoStack.length - 1]?.label,\n };\n}\n\nexport interface UseLocalOpUndoOptions<TOp>\n extends\n Omit<CreateLocalOpUndoOptions<TOp>, \"onChange\">,\n UndoKeyboardOptions {}\n\nexport interface UseLocalOpUndoResult<TOp> {\n push: (entry: LocalOpUndoEntry<TOp>) => void;\n undo: () => Promise<boolean>;\n redo: () => Promise<boolean>;\n canUndo: boolean;\n canRedo: boolean;\n clear: () => void;\n controller: LocalOpUndoController<TOp>;\n}\n\nexport function useLocalOpUndo<TOp>(\n options: UseLocalOpUndoOptions<TOp>,\n): UseLocalOpUndoResult<TOp> {\n const [, setTick] = useState(0);\n const applyRef = useRef(options.apply);\n applyRef.current = options.apply;\n\n const controller = useMemo(\n () =>\n createLocalOpUndoController<TOp>({\n apply: (ops, direction, entry) =>\n applyRef.current(ops, direction, entry),\n maxDepth: options.maxDepth,\n coalesceMs: options.coalesceMs,\n now: options.now,\n onChange: () => setTick((n) => n + 1),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n\n const undo = useCallback(() => controller.undo(), [controller]);\n const redo = useCallback(() => controller.redo(), [controller]);\n const push = useCallback(\n (entry: LocalOpUndoEntry<TOp>) => controller.push(entry),\n [controller],\n );\n const clear = useCallback(() => controller.clear(), [controller]);\n\n useUndoKeyboard(\n () => void controller.undo(),\n () => void controller.redo(),\n options,\n );\n\n return {\n push,\n undo,\n redo,\n canUndo: controller.canUndo(),\n canRedo: controller.canRedo(),\n clear,\n controller,\n };\n}\n"]}
|
|
@@ -16,6 +16,16 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import * as Y from "yjs";
|
|
18
18
|
import { type PatchOp } from "./json-to-yjs.js";
|
|
19
|
+
/**
|
|
20
|
+
* Compute a small "what changed" descriptor from a text diff by trimming the
|
|
21
|
+
* common prefix/suffix. Used for lingering edit highlights client-side.
|
|
22
|
+
*/
|
|
23
|
+
export declare function computeTextEditDescriptor(oldText: string, newText: string): {
|
|
24
|
+
kind: "text";
|
|
25
|
+
quote: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "doc";
|
|
28
|
+
};
|
|
19
29
|
/**
|
|
20
30
|
* Get or load a Yjs document by ID. Creates a new empty doc if none exists.
|
|
21
31
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ydoc-manager.d.ts","sourceRoot":"","sources":["../../src/collab/ydoc-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAGzB,OAAO,EAKL,KAAK,OAAO,EACb,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ydoc-manager.d.ts","sourceRoot":"","sources":["../../src/collab/ydoc-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAGzB,OAAO,EAKL,KAAK,OAAO,EACb,MAAM,kBAAkB,CAAC;AAmC1B;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAqBnD;AAuHD;;GAEG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAoC1D;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,UAAU,EAClB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,MAAsB,EACjC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,CAkCjD;AAED;;GAEG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAsB,GAChC,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAGjE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,iBAAiB,EAAE,UAAU,GAC5B,OAAO,CAAC,UAAU,CAAC,CAGrB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAsB,GAChC,OAAO,CAAC,IAAI,CAAC,CAYf;AAID;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,GAAG,EACZ,SAAS,GAAE,MAAe,EAC1B,KAAK,GAAE,KAAK,GAAG,OAAe,EAC9B,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EAAE,EACd,SAAS,GAAE,MAAe,EAC1B,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;GAEG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAe,GACzB,OAAO,CAAC,GAAG,CAAC,CAGd;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,GAAG,EACT,SAAS,GAAE,MAAe,EAC1B,IAAI,GAAE,KAAK,GAAG,OAAe,GAC5B,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAM9C"}
|
|
@@ -23,6 +23,46 @@ import { applyTextToYDoc, initYDocWithText } from "./text-to-yjs.js";
|
|
|
23
23
|
import { searchAndReplaceInYXml, extractTextFromYXml } from "./xml-ops.js";
|
|
24
24
|
const DEFAULT_FIELD = "content";
|
|
25
25
|
const MAX_CACHE = 50;
|
|
26
|
+
/**
|
|
27
|
+
* Auto-presence: any agent-sourced write produces visible presence and
|
|
28
|
+
* lingering edit attribution without the calling action having to wire
|
|
29
|
+
* agentEnterDocument/agentLeaveDocument itself. Dynamic import avoids a
|
|
30
|
+
* static cycle (agent-presence.ts imports searchAndReplace from this module).
|
|
31
|
+
*/
|
|
32
|
+
function touchAgentPresence(docId, requestSource, edit) {
|
|
33
|
+
if (requestSource !== "agent")
|
|
34
|
+
return;
|
|
35
|
+
import("./agent-presence.js")
|
|
36
|
+
.then((mod) => {
|
|
37
|
+
mod.agentTouchDocument(docId, edit ? { edit: edit } : undefined);
|
|
38
|
+
})
|
|
39
|
+
.catch(() => {
|
|
40
|
+
// Presence is best-effort; never fail the write for it.
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Compute a small "what changed" descriptor from a text diff by trimming the
|
|
45
|
+
* common prefix/suffix. Used for lingering edit highlights client-side.
|
|
46
|
+
*/
|
|
47
|
+
export function computeTextEditDescriptor(oldText, newText) {
|
|
48
|
+
let start = 0;
|
|
49
|
+
const maxStart = Math.min(oldText.length, newText.length);
|
|
50
|
+
while (start < maxStart && oldText[start] === newText[start])
|
|
51
|
+
start++;
|
|
52
|
+
let endOld = oldText.length;
|
|
53
|
+
let endNew = newText.length;
|
|
54
|
+
while (endOld > start &&
|
|
55
|
+
endNew > start &&
|
|
56
|
+
oldText[endOld - 1] === newText[endNew - 1]) {
|
|
57
|
+
endOld--;
|
|
58
|
+
endNew--;
|
|
59
|
+
}
|
|
60
|
+
const inserted = newText.slice(start, endNew).trim();
|
|
61
|
+
if (inserted.length > 0) {
|
|
62
|
+
return { kind: "text", quote: inserted.slice(0, 120) };
|
|
63
|
+
}
|
|
64
|
+
return { kind: "doc" };
|
|
65
|
+
}
|
|
26
66
|
/**
|
|
27
67
|
* Compaction ratio threshold. When the stored state byte count exceeds
|
|
28
68
|
* COMPACTION_RATIO × the freshly encoded state, write the compact form
|
|
@@ -176,12 +216,16 @@ export async function applyUpdate(docId, update, requestSource) {
|
|
|
176
216
|
export async function applyText(docId, newText, fieldName = DEFAULT_FIELD, requestSource) {
|
|
177
217
|
return withDocWriteLock(docId, async () => {
|
|
178
218
|
const doc = await getDoc(docId);
|
|
219
|
+
const oldText = doc.getText(fieldName).toString();
|
|
179
220
|
const update = applyTextToYDoc(doc, fieldName, newText, "server");
|
|
180
221
|
if (update.length === 0) {
|
|
181
222
|
return doc.getText(fieldName).toString();
|
|
182
223
|
}
|
|
183
224
|
await persistMergedState(docId, doc, () => doc.getText(fieldName).toString());
|
|
184
225
|
emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);
|
|
226
|
+
touchAgentPresence(docId, requestSource, {
|
|
227
|
+
descriptor: computeTextEditDescriptor(oldText, newText),
|
|
228
|
+
});
|
|
185
229
|
return doc.getText(fieldName).toString();
|
|
186
230
|
});
|
|
187
231
|
}
|
|
@@ -211,6 +255,12 @@ export async function searchAndReplace(docId, find, replace, requestSource) {
|
|
|
211
255
|
}
|
|
212
256
|
await persistMergedState(docId, doc, () => extractTextFromYXml(fragment));
|
|
213
257
|
emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);
|
|
258
|
+
touchAgentPresence(docId, requestSource, {
|
|
259
|
+
descriptor: {
|
|
260
|
+
kind: "text",
|
|
261
|
+
quote: (replace || find).slice(0, 120),
|
|
262
|
+
},
|
|
263
|
+
});
|
|
214
264
|
return { found: true, update };
|
|
215
265
|
});
|
|
216
266
|
}
|
|
@@ -267,6 +317,7 @@ export async function applyJson(docId, newJson, fieldName = "data", _type = "map
|
|
|
267
317
|
// concurrent writes, so `newJson` can be stale. Matches applyPatchOps.
|
|
268
318
|
await persistMergedState(docId, doc, () => JSON.stringify(yDocToJson(doc, fieldName)));
|
|
269
319
|
emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);
|
|
320
|
+
touchAgentPresence(docId, requestSource, { descriptor: { kind: "doc" } });
|
|
270
321
|
});
|
|
271
322
|
}
|
|
272
323
|
/**
|
|
@@ -280,6 +331,12 @@ export async function applyPatchOps(docId, ops, fieldName = "data", requestSourc
|
|
|
280
331
|
return;
|
|
281
332
|
await persistMergedState(docId, doc, () => JSON.stringify(yDocToJson(doc, fieldName)));
|
|
282
333
|
emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);
|
|
334
|
+
touchAgentPresence(docId, requestSource, {
|
|
335
|
+
descriptor: {
|
|
336
|
+
kind: "paths",
|
|
337
|
+
paths: ops.slice(0, 5).map((op) => op.path),
|
|
338
|
+
},
|
|
339
|
+
});
|
|
283
340
|
});
|
|
284
341
|
}
|
|
285
342
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ydoc-manager.js","sourceRoot":"","sources":["../../src/collab/ydoc-manager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Server-side Yjs document manager with LRU caching and SQL persistence.\n *\n * Performance notes:\n * - `getDoc()` loads from the DB once on cache miss; subsequent calls return\n * the cached Y.Doc directly with no DB I/O.\n * - Mutations no longer call `applyStoredState()` unconditionally on every\n * write. The defensive re-read from the DB happens only inside\n * `persistMergedState` (needed for the CAS version read), not as a\n * separate SELECT before applying the new update. This removes the\n * redundant double-read that the previous implementation performed on\n * every write even on a hot cache.\n * - Compaction: when the stored blob is >4x the freshly encoded state, the\n * GC'd encoding is stored instead (removes accumulated Yjs tombstones,\n * preventing unbounded blob growth without any background jobs).\n */\n\nimport * as Y from \"yjs\";\n\nimport { emitCollabUpdate } from \"./emitter.js\";\nimport {\n applyJsonDiff,\n applyJsonPatch,\n yDocToJson,\n initYDocWithJson,\n type PatchOp,\n} from \"./json-to-yjs.js\";\nimport {\n loadYDocRecord,\n loadYDocState,\n saveYDocState,\n trySaveYDocState,\n} from \"./storage.js\";\nimport { uint8ArrayToBase64 } from \"./storage.js\";\nimport { applyTextToYDoc, initYDocWithText } from \"./text-to-yjs.js\";\nimport { searchAndReplaceInYXml, extractTextFromYXml } from \"./xml-ops.js\";\n\nconst DEFAULT_FIELD = \"content\";\nconst MAX_CACHE = 50;\n\n/**\n * Compaction ratio threshold. When the stored state byte count exceeds\n * COMPACTION_RATIO × the freshly encoded state, write the compact form\n * (strips accumulated tombstones). A value of 4 means: compact when the\n * stored blob is 4× larger than necessary.\n */\nconst COMPACTION_RATIO = 4;\n\ninterface CacheEntry {\n doc: Y.Doc;\n lastAccess: number;\n}\n\nconst _cache = new Map<string, CacheEntry>();\nconst _writeLocks = new Map<string, Promise<void>>();\n// Coalesces concurrent cache-miss loads for the same docId. Without this, two\n// simultaneous getDoc() callers both miss the cache, both build a Y.Doc and\n// apply stored state, and the second _cache.set silently orphans the first\n// doc (a memory leak that grows with concurrent read traffic).\nconst _loadLocks = new Map<string, Promise<Y.Doc>>();\n\nfunction evictIfNeeded(): void {\n if (_cache.size <= MAX_CACHE) return;\n // Evict least-recently-accessed entry\n let oldest: string | null = null;\n let oldestTime = Infinity;\n for (const [id, entry] of _cache) {\n if (entry.lastAccess < oldestTime) {\n oldestTime = entry.lastAccess;\n oldest = id;\n }\n }\n if (oldest) {\n const entry = _cache.get(oldest);\n entry?.doc.destroy();\n _cache.delete(oldest);\n }\n}\n\nasync function withDocWriteLock<T>(\n docId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const previous = _writeLocks.get(docId) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const chained = previous.catch(() => {}).then(() => current);\n _writeLocks.set(docId, chained);\n\n await previous.catch(() => {});\n try {\n return await fn();\n } finally {\n release();\n if (_writeLocks.get(docId) === chained) {\n _writeLocks.delete(docId);\n }\n }\n}\n\n/**\n * Build state to persist. If the stored blob is significantly larger than\n * the freshly encoded state, store the compact (GC'd) form instead to\n * prevent unbounded blob growth from accumulated tombstones.\n */\nfunction buildStateToStore(doc: Y.Doc, storedByteCount: number): Uint8Array {\n const encoded = Y.encodeStateAsUpdate(doc);\n if (\n storedByteCount > 0 &&\n storedByteCount > encoded.length * COMPACTION_RATIO\n ) {\n // Stored blob is much larger than needed — return the GC'd encoding.\n return encoded;\n }\n return encoded;\n}\n\n/**\n * Persist the merged doc state with CAS retry on conflict.\n *\n * REMOVED: the unconditional `applyStoredState()` that was called on every\n * write path before this function. The only DB read is the `loadYDocRecord`\n * call here — needed to get the CAS version and merge any concurrent writes\n * from OTHER processes. Within this process, the in-memory doc is already\n * up-to-date because mutations are serialized by withDocWriteLock.\n */\nasync function persistMergedState(\n docId: string,\n doc: Y.Doc,\n getTextSnapshot: () => string,\n): Promise<void> {\n for (let attempt = 0; attempt < 5; attempt++) {\n // One DB read per persist attempt. On first attempt this is the only read\n // on the write path (previously there was an unconditional second read\n // before the update was applied). On retry attempts it re-reads to get the\n // latest version after a CAS conflict.\n const latest = await loadYDocRecord(docId);\n if (latest?.state && latest.state.length > 0) {\n Y.applyUpdate(doc, latest.state);\n }\n\n const stateToStore = buildStateToStore(doc, latest?.state?.length ?? 0);\n const saved = await trySaveYDocState(\n docId,\n stateToStore,\n getTextSnapshot(),\n latest?.version ?? null,\n );\n if (saved) return;\n }\n\n // All CAS attempts failed — fall back to unconditional save.\n await saveYDocState(docId, Y.encodeStateAsUpdate(doc), getTextSnapshot());\n}\n\n/**\n * Get or load a Yjs document by ID. Creates a new empty doc if none exists.\n */\nexport async function getDoc(docId: string): Promise<Y.Doc> {\n const cached = _cache.get(docId);\n if (cached) {\n cached.lastAccess = Date.now();\n return cached.doc;\n }\n\n const inFlight = _loadLocks.get(docId);\n if (inFlight) return inFlight;\n\n const load = (async () => {\n // Re-check the cache: a concurrent writer (or loader) may have populated it\n // between our miss above and acquiring this load slot.\n const reCached = _cache.get(docId);\n if (reCached) {\n reCached.lastAccess = Date.now();\n return reCached.doc;\n }\n\n const doc = new Y.Doc();\n const stored = await loadYDocState(docId);\n if (stored && stored.length > 0) {\n Y.applyUpdate(doc, stored);\n }\n\n evictIfNeeded();\n _cache.set(docId, { doc, lastAccess: Date.now() });\n return doc;\n })();\n\n _loadLocks.set(docId, load);\n try {\n return await load;\n } finally {\n _loadLocks.delete(docId);\n }\n}\n\n/**\n * Apply a binary Yjs update (from a client) to a document.\n * Persists the result and emits a change event.\n */\nexport async function applyUpdate(\n docId: string,\n update: Uint8Array,\n requestSource?: string,\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n // The cached doc is already up-to-date from the initial load or a previous\n // write in this process. No redundant applyStoredState() here — cross-\n // process writes are merged inside persistMergedState when needed.\n Y.applyUpdate(doc, update);\n\n await persistMergedState(docId, doc, () =>\n doc.getText(DEFAULT_FIELD).toString(),\n );\n\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n });\n}\n\n/**\n * Apply a text change to a document. Computes the minimal diff and\n * converts it to Yjs operations.\n *\n * Returns the text snapshot after the update.\n */\nexport async function applyText(\n docId: string,\n newText: string,\n fieldName: string = DEFAULT_FIELD,\n requestSource?: string,\n): Promise<string> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n const update = applyTextToYDoc(doc, fieldName, newText, \"server\");\n\n if (update.length === 0) {\n return doc.getText(fieldName).toString();\n }\n\n await persistMergedState(docId, doc, () =>\n doc.getText(fieldName).toString(),\n );\n\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n return doc.getText(fieldName).toString();\n });\n}\n\n/**\n * Search-and-replace text within a Y.XmlFragment (ProseMirror tree).\n * Produces minimal Yjs operations for cursor-preserving updates.\n *\n * Returns whether the text was found and the binary update.\n */\nexport async function searchAndReplace(\n docId: string,\n find: string,\n replace: string,\n requestSource?: string,\n): Promise<{ found: boolean; update: Uint8Array }> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n const fragment = doc.getXmlFragment(\"default\");\n\n // Capture the update produced by the transaction\n let update: Uint8Array = new Uint8Array(0);\n const handler = (u: Uint8Array) => {\n update = u;\n };\n doc.on(\"update\", handler);\n\n let found = false;\n doc.transact(() => {\n found = searchAndReplaceInYXml(fragment, find, replace);\n }, \"agent\");\n\n doc.off(\"update\", handler);\n\n if (!found || update.length === 0) {\n return { found: false, update: new Uint8Array(0) };\n }\n\n await persistMergedState(docId, doc, () => extractTextFromYXml(fragment));\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n\n return { found: true, update };\n });\n}\n\n/**\n * Get the current text content of a document field.\n */\nexport async function getText(\n docId: string,\n fieldName: string = DEFAULT_FIELD,\n): Promise<string> {\n const doc = await getDoc(docId);\n return doc.getText(fieldName).toString();\n}\n\n/**\n * Get the full document state as a Uint8Array.\n */\nexport async function getState(docId: string): Promise<Uint8Array> {\n const doc = await getDoc(docId);\n return Y.encodeStateAsUpdate(doc);\n}\n\n/**\n * Get an incremental update relative to a client's state vector.\n */\nexport async function getIncUpdate(\n docId: string,\n clientStateVector: Uint8Array,\n): Promise<Uint8Array> {\n const doc = await getDoc(docId);\n return Y.encodeStateAsUpdate(doc, clientStateVector);\n}\n\n/**\n * Seed a document from existing text content (for migration).\n * Only seeds if no collab state exists yet.\n */\nexport async function seedFromText(\n docId: string,\n text: string,\n fieldName: string = DEFAULT_FIELD,\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const existing = await loadYDocState(docId);\n if (existing && existing.length > 0) return; // Already seeded\n\n const { doc, state } = initYDocWithText(fieldName, text);\n await saveYDocState(docId, state, text);\n\n // Cache the doc\n evictIfNeeded();\n _cache.set(docId, { doc, lastAccess: Date.now() });\n });\n}\n\n// ─── Structured JSON Operations ─────────────────────────────────────\n\n/**\n * Apply a full JSON update to a document. Computes the minimal diff\n * and converts it to Yjs operations on Y.Map/Y.Array.\n */\nexport async function applyJson(\n docId: string,\n newJson: any,\n fieldName: string = \"data\",\n _type: \"map\" | \"array\" = \"map\",\n requestSource?: string,\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n const update = applyJsonDiff(doc, fieldName, newJson, \"server\");\n\n if (update.length === 0) return;\n\n // Snapshot the doc's actual post-merge state, not the caller-supplied\n // `newJson` — persistMergedState may re-apply newer DB state to resolve\n // concurrent writes, so `newJson` can be stale. Matches applyPatchOps.\n await persistMergedState(docId, doc, () =>\n JSON.stringify(yDocToJson(doc, fieldName)),\n );\n\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n });\n}\n\n/**\n * Apply surgical JSON patch operations to a document.\n */\nexport async function applyPatchOps(\n docId: string,\n ops: PatchOp[],\n fieldName: string = \"data\",\n requestSource?: string,\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n const update = applyJsonPatch(doc, fieldName, ops, \"server\");\n\n if (update.length === 0) return;\n\n await persistMergedState(docId, doc, () =>\n JSON.stringify(yDocToJson(doc, fieldName)),\n );\n\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n });\n}\n\n/**\n * Get the current JSON state of a document field.\n */\nexport async function getJson(\n docId: string,\n fieldName: string = \"data\",\n): Promise<any> {\n const doc = await getDoc(docId);\n return yDocToJson(doc, fieldName);\n}\n\n/**\n * Seed a document from existing JSON content (for migration).\n * Only seeds if no collab state exists yet.\n */\nexport async function seedFromJson(\n docId: string,\n json: any,\n fieldName: string = \"data\",\n type: \"map\" | \"array\" = \"map\",\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const existing = await loadYDocState(docId);\n if (existing && existing.length > 0) return; // Already seeded\n\n const { doc, state } = initYDocWithJson(fieldName, json, type);\n await saveYDocState(docId, state, JSON.stringify(json));\n\n // Cache the doc\n evictIfNeeded();\n _cache.set(docId, { doc, lastAccess: Date.now() });\n });\n}\n\n/**\n * Release a document from the in-memory cache.\n */\nexport function releaseDoc(docId: string): void {\n const entry = _cache.get(docId);\n if (entry) {\n entry.doc.destroy();\n _cache.delete(docId);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ydoc-manager.js","sourceRoot":"","sources":["../../src/collab/ydoc-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,aAAa,EACb,cAAc,EACd,UAAU,EACV,gBAAgB,GAEjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAE3E,MAAM,aAAa,GAAG,SAAS,CAAC;AAChC,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB;;;;;GAKG;AACH,SAAS,kBAAkB,CACzB,KAAa,EACb,aAAiC,EACjC,IAAoE;IAEpE,IAAI,aAAa,KAAK,OAAO;QAAE,OAAO;IACtC,MAAM,CAAC,qBAAqB,CAAC;SAC1B,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QACZ,GAAG,CAAC,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1E,CAAC,CAAC;SACD,KAAK,CAAC,GAAG,EAAE;QACV,wDAAwD;IAC1D,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAe,EACf,OAAe;IAEf,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,OAAO,KAAK,GAAG,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,CAAC;IAEtE,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC5B,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC5B,OACE,MAAM,GAAG,KAAK;QACd,MAAM,GAAG,KAAK;QACd,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EAC3C,CAAC;QACD,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACzD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAO3B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;AAC7C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAyB,CAAC;AACrD,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,+DAA+D;AAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,EAA0B,CAAC;AAErD,SAAS,aAAa;IACpB,IAAI,MAAM,CAAC,IAAI,IAAI,SAAS;QAAE,OAAO;IACrC,sCAAsC;IACtC,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,UAAU,GAAG,QAAQ,CAAC;IAC1B,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC;YAClC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;YAC9B,MAAM,GAAG,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,KAAa,EACb,EAAoB;IAEpB,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7D,IAAI,OAAoB,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC5C,OAAO,GAAG,OAAO,CAAC;IACpB,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;IAC7D,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAEhC,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC/B,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,OAAO,EAAE,CAAC;QACV,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC;YACvC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,GAAU,EAAE,eAAuB;IAC5D,MAAM,OAAO,GAAG,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC3C,IACE,eAAe,GAAG,CAAC;QACnB,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,gBAAgB,EACnD,CAAC;QACD,qEAAqE;QACrE,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,kBAAkB,CAC/B,KAAa,EACb,GAAU,EACV,eAA6B;IAE7B,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,0EAA0E;QAC1E,uEAAuE;QACvE,2EAA2E;QAC3E,uCAAuC;QACvC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,MAAM,EAAE,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7C,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,MAAM,YAAY,GAAG,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAClC,KAAK,EACL,YAAY,EACZ,eAAe,EAAE,EACjB,MAAM,EAAE,OAAO,IAAI,IAAI,CACxB,CAAC;QACF,IAAI,KAAK;YAAE,OAAO;IACpB,CAAC;IAED,6DAA6D;IAC7D,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAAa;IACxC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC,GAAG,CAAC;IACpB,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE;QACvB,4EAA4E;QAC5E,uDAAuD;QACvD,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,OAAO,QAAQ,CAAC,GAAG,CAAC;QACtB,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC;QAED,aAAa,EAAE,CAAC;QAChB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,EAAE,CAAC;IAEL,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,MAAkB,EAClB,aAAsB;IAEtB,OAAO,gBAAgB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,2EAA2E;QAC3E,uEAAuE;QACvE,mEAAmE;QACnE,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAE3B,MAAM,kBAAkB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CACxC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,CACtC,CAAC;QAEF,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,KAAa,EACb,OAAe,EACf,SAAS,GAAW,aAAa,EACjC,aAAsB;IAEtB,OAAO,gBAAgB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAElE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC3C,CAAC;QAED,MAAM,kBAAkB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CACxC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAClC,CAAC;QAEF,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;QACnE,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE;YACvC,UAAU,EAAE,yBAAyB,CAAC,OAAO,EAAE,OAAO,CAAC;SACxD,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,IAAY,EACZ,OAAe,EACf,aAAsB;IAEtB,OAAO,gBAAgB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAE/C,iDAAiD;QACjD,IAAI,MAAM,GAAe,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,CAAC,CAAa,EAAE,EAAE;YAChC,MAAM,GAAG,CAAC,CAAC;QACb,CAAC,CAAC;QACF,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE1B,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE;YAChB,KAAK,GAAG,sBAAsB,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1D,CAAC,EAAE,OAAO,CAAC,CAAC;QAEZ,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE3B,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,CAAC;QAED,MAAM,kBAAkB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC1E,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;QACnE,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE;YACvC,UAAU,EAAE;gBACV,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;aACvC;SACF,CAAC,CAAC;QAEH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAAa,EACb,SAAS,GAAW,aAAa;IAEjC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,KAAa;IAC1C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,iBAA6B;IAE7B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,CAAC,CAAC,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,IAAY,EACZ,SAAS,GAAW,aAAa;IAEjC,OAAO,gBAAgB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,iBAAiB;QAE9D,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACzD,MAAM,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAExC,gBAAgB;QAChB,aAAa,EAAE,CAAC;QAChB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uEAAuE;AAEvE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,KAAa,EACb,OAAY,EACZ,SAAS,GAAW,MAAM,EAC1B,KAAK,GAAoB,KAAK,EAC9B,aAAsB;IAEtB,OAAO,gBAAgB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEhE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEhC,sEAAsE;QACtE,wEAAwE;QACxE,uEAAuE;QACvE,MAAM,kBAAkB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CACxC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAC3C,CAAC;QAEF,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;QACnE,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAa,EACb,GAAc,EACd,SAAS,GAAW,MAAM,EAC1B,aAAsB;IAEtB,OAAO,gBAAgB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAE7D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEhC,MAAM,kBAAkB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CACxC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAC3C,CAAC;QAEF,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;QACnE,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE;YACvC,UAAU,EAAE;gBACV,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;aAC5C;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAAa,EACb,SAAS,GAAW,MAAM;IAE1B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,IAAS,EACT,SAAS,GAAW,MAAM,EAC1B,IAAI,GAAoB,KAAK;IAE7B,OAAO,gBAAgB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,iBAAiB;QAE9D,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/D,MAAM,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAExD,gBAAgB;QAChB,aAAa,EAAE,CAAC;QAChB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,KAAK,EAAE,CAAC;QACV,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC","sourcesContent":["/**\n * Server-side Yjs document manager with LRU caching and SQL persistence.\n *\n * Performance notes:\n * - `getDoc()` loads from the DB once on cache miss; subsequent calls return\n * the cached Y.Doc directly with no DB I/O.\n * - Mutations no longer call `applyStoredState()` unconditionally on every\n * write. The defensive re-read from the DB happens only inside\n * `persistMergedState` (needed for the CAS version read), not as a\n * separate SELECT before applying the new update. This removes the\n * redundant double-read that the previous implementation performed on\n * every write even on a hot cache.\n * - Compaction: when the stored blob is >4x the freshly encoded state, the\n * GC'd encoding is stored instead (removes accumulated Yjs tombstones,\n * preventing unbounded blob growth without any background jobs).\n */\n\nimport * as Y from \"yjs\";\n\nimport { emitCollabUpdate } from \"./emitter.js\";\nimport {\n applyJsonDiff,\n applyJsonPatch,\n yDocToJson,\n initYDocWithJson,\n type PatchOp,\n} from \"./json-to-yjs.js\";\nimport {\n loadYDocRecord,\n loadYDocState,\n saveYDocState,\n trySaveYDocState,\n} from \"./storage.js\";\nimport { uint8ArrayToBase64 } from \"./storage.js\";\nimport { applyTextToYDoc, initYDocWithText } from \"./text-to-yjs.js\";\nimport { searchAndReplaceInYXml, extractTextFromYXml } from \"./xml-ops.js\";\n\nconst DEFAULT_FIELD = \"content\";\nconst MAX_CACHE = 50;\n\n/**\n * Auto-presence: any agent-sourced write produces visible presence and\n * lingering edit attribution without the calling action having to wire\n * agentEnterDocument/agentLeaveDocument itself. Dynamic import avoids a\n * static cycle (agent-presence.ts imports searchAndReplace from this module).\n */\nfunction touchAgentPresence(\n docId: string,\n requestSource: string | undefined,\n edit: { descriptor: Record<string, unknown>; label?: string } | null,\n): void {\n if (requestSource !== \"agent\") return;\n import(\"./agent-presence.js\")\n .then((mod) => {\n mod.agentTouchDocument(docId, edit ? { edit: edit as any } : undefined);\n })\n .catch(() => {\n // Presence is best-effort; never fail the write for it.\n });\n}\n\n/**\n * Compute a small \"what changed\" descriptor from a text diff by trimming the\n * common prefix/suffix. Used for lingering edit highlights client-side.\n */\nexport function computeTextEditDescriptor(\n oldText: string,\n newText: string,\n): { kind: \"text\"; quote: string } | { kind: \"doc\" } {\n let start = 0;\n const maxStart = Math.min(oldText.length, newText.length);\n while (start < maxStart && oldText[start] === newText[start]) start++;\n\n let endOld = oldText.length;\n let endNew = newText.length;\n while (\n endOld > start &&\n endNew > start &&\n oldText[endOld - 1] === newText[endNew - 1]\n ) {\n endOld--;\n endNew--;\n }\n\n const inserted = newText.slice(start, endNew).trim();\n if (inserted.length > 0) {\n return { kind: \"text\", quote: inserted.slice(0, 120) };\n }\n return { kind: \"doc\" };\n}\n\n/**\n * Compaction ratio threshold. When the stored state byte count exceeds\n * COMPACTION_RATIO × the freshly encoded state, write the compact form\n * (strips accumulated tombstones). A value of 4 means: compact when the\n * stored blob is 4× larger than necessary.\n */\nconst COMPACTION_RATIO = 4;\n\ninterface CacheEntry {\n doc: Y.Doc;\n lastAccess: number;\n}\n\nconst _cache = new Map<string, CacheEntry>();\nconst _writeLocks = new Map<string, Promise<void>>();\n// Coalesces concurrent cache-miss loads for the same docId. Without this, two\n// simultaneous getDoc() callers both miss the cache, both build a Y.Doc and\n// apply stored state, and the second _cache.set silently orphans the first\n// doc (a memory leak that grows with concurrent read traffic).\nconst _loadLocks = new Map<string, Promise<Y.Doc>>();\n\nfunction evictIfNeeded(): void {\n if (_cache.size <= MAX_CACHE) return;\n // Evict least-recently-accessed entry\n let oldest: string | null = null;\n let oldestTime = Infinity;\n for (const [id, entry] of _cache) {\n if (entry.lastAccess < oldestTime) {\n oldestTime = entry.lastAccess;\n oldest = id;\n }\n }\n if (oldest) {\n const entry = _cache.get(oldest);\n entry?.doc.destroy();\n _cache.delete(oldest);\n }\n}\n\nasync function withDocWriteLock<T>(\n docId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const previous = _writeLocks.get(docId) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const chained = previous.catch(() => {}).then(() => current);\n _writeLocks.set(docId, chained);\n\n await previous.catch(() => {});\n try {\n return await fn();\n } finally {\n release();\n if (_writeLocks.get(docId) === chained) {\n _writeLocks.delete(docId);\n }\n }\n}\n\n/**\n * Build state to persist. If the stored blob is significantly larger than\n * the freshly encoded state, store the compact (GC'd) form instead to\n * prevent unbounded blob growth from accumulated tombstones.\n */\nfunction buildStateToStore(doc: Y.Doc, storedByteCount: number): Uint8Array {\n const encoded = Y.encodeStateAsUpdate(doc);\n if (\n storedByteCount > 0 &&\n storedByteCount > encoded.length * COMPACTION_RATIO\n ) {\n // Stored blob is much larger than needed — return the GC'd encoding.\n return encoded;\n }\n return encoded;\n}\n\n/**\n * Persist the merged doc state with CAS retry on conflict.\n *\n * REMOVED: the unconditional `applyStoredState()` that was called on every\n * write path before this function. The only DB read is the `loadYDocRecord`\n * call here — needed to get the CAS version and merge any concurrent writes\n * from OTHER processes. Within this process, the in-memory doc is already\n * up-to-date because mutations are serialized by withDocWriteLock.\n */\nasync function persistMergedState(\n docId: string,\n doc: Y.Doc,\n getTextSnapshot: () => string,\n): Promise<void> {\n for (let attempt = 0; attempt < 5; attempt++) {\n // One DB read per persist attempt. On first attempt this is the only read\n // on the write path (previously there was an unconditional second read\n // before the update was applied). On retry attempts it re-reads to get the\n // latest version after a CAS conflict.\n const latest = await loadYDocRecord(docId);\n if (latest?.state && latest.state.length > 0) {\n Y.applyUpdate(doc, latest.state);\n }\n\n const stateToStore = buildStateToStore(doc, latest?.state?.length ?? 0);\n const saved = await trySaveYDocState(\n docId,\n stateToStore,\n getTextSnapshot(),\n latest?.version ?? null,\n );\n if (saved) return;\n }\n\n // All CAS attempts failed — fall back to unconditional save.\n await saveYDocState(docId, Y.encodeStateAsUpdate(doc), getTextSnapshot());\n}\n\n/**\n * Get or load a Yjs document by ID. Creates a new empty doc if none exists.\n */\nexport async function getDoc(docId: string): Promise<Y.Doc> {\n const cached = _cache.get(docId);\n if (cached) {\n cached.lastAccess = Date.now();\n return cached.doc;\n }\n\n const inFlight = _loadLocks.get(docId);\n if (inFlight) return inFlight;\n\n const load = (async () => {\n // Re-check the cache: a concurrent writer (or loader) may have populated it\n // between our miss above and acquiring this load slot.\n const reCached = _cache.get(docId);\n if (reCached) {\n reCached.lastAccess = Date.now();\n return reCached.doc;\n }\n\n const doc = new Y.Doc();\n const stored = await loadYDocState(docId);\n if (stored && stored.length > 0) {\n Y.applyUpdate(doc, stored);\n }\n\n evictIfNeeded();\n _cache.set(docId, { doc, lastAccess: Date.now() });\n return doc;\n })();\n\n _loadLocks.set(docId, load);\n try {\n return await load;\n } finally {\n _loadLocks.delete(docId);\n }\n}\n\n/**\n * Apply a binary Yjs update (from a client) to a document.\n * Persists the result and emits a change event.\n */\nexport async function applyUpdate(\n docId: string,\n update: Uint8Array,\n requestSource?: string,\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n // The cached doc is already up-to-date from the initial load or a previous\n // write in this process. No redundant applyStoredState() here — cross-\n // process writes are merged inside persistMergedState when needed.\n Y.applyUpdate(doc, update);\n\n await persistMergedState(docId, doc, () =>\n doc.getText(DEFAULT_FIELD).toString(),\n );\n\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n });\n}\n\n/**\n * Apply a text change to a document. Computes the minimal diff and\n * converts it to Yjs operations.\n *\n * Returns the text snapshot after the update.\n */\nexport async function applyText(\n docId: string,\n newText: string,\n fieldName: string = DEFAULT_FIELD,\n requestSource?: string,\n): Promise<string> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n const oldText = doc.getText(fieldName).toString();\n const update = applyTextToYDoc(doc, fieldName, newText, \"server\");\n\n if (update.length === 0) {\n return doc.getText(fieldName).toString();\n }\n\n await persistMergedState(docId, doc, () =>\n doc.getText(fieldName).toString(),\n );\n\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n touchAgentPresence(docId, requestSource, {\n descriptor: computeTextEditDescriptor(oldText, newText),\n });\n return doc.getText(fieldName).toString();\n });\n}\n\n/**\n * Search-and-replace text within a Y.XmlFragment (ProseMirror tree).\n * Produces minimal Yjs operations for cursor-preserving updates.\n *\n * Returns whether the text was found and the binary update.\n */\nexport async function searchAndReplace(\n docId: string,\n find: string,\n replace: string,\n requestSource?: string,\n): Promise<{ found: boolean; update: Uint8Array }> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n const fragment = doc.getXmlFragment(\"default\");\n\n // Capture the update produced by the transaction\n let update: Uint8Array = new Uint8Array(0);\n const handler = (u: Uint8Array) => {\n update = u;\n };\n doc.on(\"update\", handler);\n\n let found = false;\n doc.transact(() => {\n found = searchAndReplaceInYXml(fragment, find, replace);\n }, \"agent\");\n\n doc.off(\"update\", handler);\n\n if (!found || update.length === 0) {\n return { found: false, update: new Uint8Array(0) };\n }\n\n await persistMergedState(docId, doc, () => extractTextFromYXml(fragment));\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n touchAgentPresence(docId, requestSource, {\n descriptor: {\n kind: \"text\",\n quote: (replace || find).slice(0, 120),\n },\n });\n\n return { found: true, update };\n });\n}\n\n/**\n * Get the current text content of a document field.\n */\nexport async function getText(\n docId: string,\n fieldName: string = DEFAULT_FIELD,\n): Promise<string> {\n const doc = await getDoc(docId);\n return doc.getText(fieldName).toString();\n}\n\n/**\n * Get the full document state as a Uint8Array.\n */\nexport async function getState(docId: string): Promise<Uint8Array> {\n const doc = await getDoc(docId);\n return Y.encodeStateAsUpdate(doc);\n}\n\n/**\n * Get an incremental update relative to a client's state vector.\n */\nexport async function getIncUpdate(\n docId: string,\n clientStateVector: Uint8Array,\n): Promise<Uint8Array> {\n const doc = await getDoc(docId);\n return Y.encodeStateAsUpdate(doc, clientStateVector);\n}\n\n/**\n * Seed a document from existing text content (for migration).\n * Only seeds if no collab state exists yet.\n */\nexport async function seedFromText(\n docId: string,\n text: string,\n fieldName: string = DEFAULT_FIELD,\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const existing = await loadYDocState(docId);\n if (existing && existing.length > 0) return; // Already seeded\n\n const { doc, state } = initYDocWithText(fieldName, text);\n await saveYDocState(docId, state, text);\n\n // Cache the doc\n evictIfNeeded();\n _cache.set(docId, { doc, lastAccess: Date.now() });\n });\n}\n\n// ─── Structured JSON Operations ─────────────────────────────────────\n\n/**\n * Apply a full JSON update to a document. Computes the minimal diff\n * and converts it to Yjs operations on Y.Map/Y.Array.\n */\nexport async function applyJson(\n docId: string,\n newJson: any,\n fieldName: string = \"data\",\n _type: \"map\" | \"array\" = \"map\",\n requestSource?: string,\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n const update = applyJsonDiff(doc, fieldName, newJson, \"server\");\n\n if (update.length === 0) return;\n\n // Snapshot the doc's actual post-merge state, not the caller-supplied\n // `newJson` — persistMergedState may re-apply newer DB state to resolve\n // concurrent writes, so `newJson` can be stale. Matches applyPatchOps.\n await persistMergedState(docId, doc, () =>\n JSON.stringify(yDocToJson(doc, fieldName)),\n );\n\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n touchAgentPresence(docId, requestSource, { descriptor: { kind: \"doc\" } });\n });\n}\n\n/**\n * Apply surgical JSON patch operations to a document.\n */\nexport async function applyPatchOps(\n docId: string,\n ops: PatchOp[],\n fieldName: string = \"data\",\n requestSource?: string,\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const doc = await getDoc(docId);\n const update = applyJsonPatch(doc, fieldName, ops, \"server\");\n\n if (update.length === 0) return;\n\n await persistMergedState(docId, doc, () =>\n JSON.stringify(yDocToJson(doc, fieldName)),\n );\n\n emitCollabUpdate(docId, uint8ArrayToBase64(update), requestSource);\n touchAgentPresence(docId, requestSource, {\n descriptor: {\n kind: \"paths\",\n paths: ops.slice(0, 5).map((op) => op.path),\n },\n });\n });\n}\n\n/**\n * Get the current JSON state of a document field.\n */\nexport async function getJson(\n docId: string,\n fieldName: string = \"data\",\n): Promise<any> {\n const doc = await getDoc(docId);\n return yDocToJson(doc, fieldName);\n}\n\n/**\n * Seed a document from existing JSON content (for migration).\n * Only seeds if no collab state exists yet.\n */\nexport async function seedFromJson(\n docId: string,\n json: any,\n fieldName: string = \"data\",\n type: \"map\" | \"array\" = \"map\",\n): Promise<void> {\n return withDocWriteLock(docId, async () => {\n const existing = await loadYDocState(docId);\n if (existing && existing.length > 0) return; // Already seeded\n\n const { doc, state } = initYDocWithJson(fieldName, json, type);\n await saveYDocState(docId, state, JSON.stringify(json));\n\n // Cache the doc\n evictIfNeeded();\n _cache.set(docId, { doc, lastAccess: Date.now() });\n });\n}\n\n/**\n * Release a document from the in-memory cache.\n */\nexport function releaseDoc(docId: string): void {\n const entry = _cache.get(docId);\n if (entry) {\n entry.doc.destroy();\n _cache.delete(docId);\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type WorkspaceConnectionCapability = "search" | "import" | "messages" | "meetings" | "crm" | "code" | "docs";
|
|
2
|
-
export type WorkspaceConnectionTemplateUse = "analytics" | "brain" | "calendar" | "clips" | "content" | "design" | "dispatch" | "forms" | "mail" | "slides"
|
|
2
|
+
export type WorkspaceConnectionTemplateUse = "analytics" | "brain" | "calendar" | "clips" | "content" | "design" | "dispatch" | "forms" | "mail" | "slides";
|
|
3
3
|
export type WorkspaceConnectionProviderId = "slack" | "github" | "notion" | "gmail" | "google_drive" | "hubspot" | "granola" | "clips" | "generic";
|
|
4
4
|
export interface WorkspaceConnectionCredentialKey {
|
|
5
5
|
key: string;
|
|
@@ -116,7 +116,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
|
|
|
116
116
|
readonly description: "Agent-native Clips exports and recordings for transcript import and searchable meeting context.";
|
|
117
117
|
readonly credentialKeys: readonly [];
|
|
118
118
|
readonly capabilities: readonly ["search", "import", "meetings"];
|
|
119
|
-
readonly recommendedTemplateUses: readonly ["brain", "clips"
|
|
119
|
+
readonly recommendedTemplateUses: readonly ["brain", "clips"];
|
|
120
120
|
}, {
|
|
121
121
|
readonly id: "generic";
|
|
122
122
|
readonly label: "Generic";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/connections/catalog.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,6BAA6B,GACrC,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,UAAU,GACV,KAAK,GACL,MAAM,GACN,MAAM,CAAC;AAEX,MAAM,MAAM,8BAA8B,GACtC,WAAW,GACX,OAAO,GACP,UAAU,GACV,OAAO,GACP,SAAS,GACT,QAAQ,GACR,UAAU,GACV,OAAO,GACP,MAAM,GACN,QAAQ,
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/connections/catalog.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,6BAA6B,GACrC,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,UAAU,GACV,KAAK,GACL,MAAM,GACN,MAAM,CAAC;AAEX,MAAM,MAAM,8BAA8B,GACtC,WAAW,GACX,OAAO,GACP,UAAU,GACV,OAAO,GACP,SAAS,GACT,QAAQ,GACR,UAAU,GACV,OAAO,GACP,MAAM,GACN,QAAQ,CAAC;AAEb,MAAM,MAAM,6BAA6B,GACrC,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,cAAc,GACd,SAAS,GACT,SAAS,GACT,OAAO,GACP,SAAS,CAAC;AAEd,MAAM,WAAW,gCAAgC;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,6BAA6B,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,SAAS,gCAAgC,EAAE,CAAC;IAC5D,YAAY,EAAE,SAAS,6BAA6B,EAAE,CAAC;IACvD,uBAAuB,EAAE,SAAS,8BAA8B,EAAE,CAAC;CACpE;AAED,MAAM,WAAW,uCAAuC;IACtD,UAAU,CAAC,EAAE,6BAA6B,CAAC;IAC3C,WAAW,CAAC,EAAE,8BAA8B,CAAC;CAC9C;AAED,wBAAgB,iCAAiC,CAC/C,KAAK,CAAC,CAAC,SAAS,2BAA2B,EAC3C,QAAQ,EAAE,CAAC,GAAG,CAAC,CAEhB;AAED,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsJgB,CAAC;AAO5D,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,uCAA4C,GACpD,2BAA2B,EAAE,CAsB/B;AAED,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,MAAM,GACT,2BAA2B,GAAG,SAAS,CAGzC;AAED,wBAAgB,+BAA+B,CAC7C,EAAE,EAAE,MAAM,GACT,EAAE,IAAI,6BAA6B,CAErC;AAED,wBAAgB,2CAA2C,CACzD,WAAW,EAAE,8BAA8B,GAC1C,2BAA2B,EAAE,CAE/B;AAED,wBAAgB,6CAA6C,CAC3D,UAAU,EAAE,6BAA6B,GACxC,2BAA2B,EAAE,CAE/B;AAED,wBAAgB,mCAAmC,CACjD,YAAY,EAAE,2BAA2B,GAAG,MAAM,EAClD,UAAU,EAAE,6BAA6B,GACxC,OAAO,CAMT"}
|
|
@@ -121,7 +121,7 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
|
|
|
121
121
|
description: "Agent-native Clips exports and recordings for transcript import and searchable meeting context.",
|
|
122
122
|
credentialKeys: [],
|
|
123
123
|
capabilities: ["search", "import", "meetings"],
|
|
124
|
-
recommendedTemplateUses: ["brain", "clips"
|
|
124
|
+
recommendedTemplateUses: ["brain", "clips"],
|
|
125
125
|
}),
|
|
126
126
|
defineWorkspaceConnectionProvider({
|
|
127
127
|
id: "generic",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/connections/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["export type WorkspaceConnectionCapability =\n | \"search\"\n | \"import\"\n | \"messages\"\n | \"meetings\"\n | \"crm\"\n | \"code\"\n | \"docs\";\n\nexport type WorkspaceConnectionTemplateUse =\n | \"analytics\"\n | \"brain\"\n | \"calendar\"\n | \"clips\"\n | \"content\"\n | \"design\"\n | \"dispatch\"\n | \"forms\"\n | \"mail\"\n | \"slides\"\n | \"videos\";\n\nexport type WorkspaceConnectionProviderId =\n | \"slack\"\n | \"github\"\n | \"notion\"\n | \"gmail\"\n | \"google_drive\"\n | \"hubspot\"\n | \"granola\"\n | \"clips\"\n | \"generic\";\n\nexport interface WorkspaceConnectionCredentialKey {\n key: string;\n label: string;\n description?: string;\n required?: boolean;\n}\n\nexport interface WorkspaceConnectionProvider {\n id: WorkspaceConnectionProviderId;\n label: string;\n description: string;\n credentialKeys: readonly WorkspaceConnectionCredentialKey[];\n capabilities: readonly WorkspaceConnectionCapability[];\n recommendedTemplateUses: readonly WorkspaceConnectionTemplateUse[];\n}\n\nexport interface ListWorkspaceConnectionProvidersOptions {\n capability?: WorkspaceConnectionCapability;\n templateUse?: WorkspaceConnectionTemplateUse;\n}\n\nexport function defineWorkspaceConnectionProvider<\n const T extends WorkspaceConnectionProvider,\n>(provider: T): T {\n return provider;\n}\n\nexport const WORKSPACE_CONNECTION_PROVIDERS = [\n defineWorkspaceConnectionProvider({\n id: \"slack\",\n label: \"Slack\",\n description:\n \"Workspace conversations and channel history for company memory, support workflows, and messaging automations.\",\n credentialKeys: [\n {\n key: \"SLACK_BOT_TOKEN\",\n label: \"Slack bot token\",\n description:\n \"Bot token with the smallest channel and history scopes needed by the template.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"messages\"],\n recommendedTemplateUses: [\"brain\", \"dispatch\", \"analytics\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"github\",\n label: \"GitHub\",\n description:\n \"Repository, issue, pull request, and code context for product memory, engineering workflows, and analytics.\",\n credentialKeys: [\n {\n key: \"GITHUB_TOKEN\",\n label: \"GitHub token\",\n description:\n \"Fine-grained token or app credential scoped to the repositories the workspace should access.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"code\", \"docs\"],\n recommendedTemplateUses: [\"brain\", \"analytics\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"notion\",\n label: \"Notion\",\n description:\n \"Workspace docs, wikis, pages, and databases for knowledge capture and search.\",\n credentialKeys: [\n {\n key: \"NOTION_API_KEY\",\n label: \"Notion API key\",\n description:\n \"Integration secret with access to the pages or databases shared with the integration.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"docs\"],\n recommendedTemplateUses: [\"brain\", \"content\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"gmail\",\n label: \"Gmail\",\n description:\n \"Mailbox messages and threads for search, triage, customer context, and agent replies.\",\n credentialKeys: [\n {\n key: \"GOOGLE_CLIENT_ID\",\n label: \"Google OAuth client ID\",\n required: true,\n },\n {\n key: \"GOOGLE_CLIENT_SECRET\",\n label: \"Google OAuth client secret\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"messages\"],\n recommendedTemplateUses: [\"mail\", \"brain\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"google_drive\",\n label: \"Google Drive\",\n description:\n \"Drive files, Docs, Sheets, and Slides for document search and import workflows.\",\n credentialKeys: [\n {\n key: \"GOOGLE_CLIENT_ID\",\n label: \"Google OAuth client ID\",\n required: true,\n },\n {\n key: \"GOOGLE_CLIENT_SECRET\",\n label: \"Google OAuth client secret\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"docs\"],\n recommendedTemplateUses: [\"brain\", \"content\", \"slides\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"hubspot\",\n label: \"HubSpot\",\n description:\n \"CRM records, companies, contacts, deals, and engagement history for customer-aware apps.\",\n credentialKeys: [\n {\n key: \"HUBSPOT_PRIVATE_APP_TOKEN\",\n label: \"HubSpot private app token\",\n description:\n \"Private app token scoped to the CRM objects the workspace needs.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"crm\"],\n recommendedTemplateUses: [\"analytics\", \"brain\", \"mail\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"granola\",\n label: \"Granola\",\n description:\n \"Meeting notes and transcripts for company memory and follow-up workflows.\",\n credentialKeys: [\n {\n key: \"GRANOLA_API_KEY\",\n label: \"Granola API key\",\n description:\n \"API key for accessible team notes; templates should respect Granola's workspace visibility.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"meetings\", \"docs\"],\n recommendedTemplateUses: [\"brain\", \"calendar\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"clips\",\n label: \"Clips\",\n description:\n \"Agent-native Clips exports and recordings for transcript import and searchable meeting context.\",\n credentialKeys: [],\n capabilities: [\"search\", \"import\", \"meetings\"],\n recommendedTemplateUses: [\"brain\", \"clips\", \"videos\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"generic\",\n label: \"Generic\",\n description:\n \"Custom webhooks, CSV exports, transcript drops, and one-off sources that do not need a first-class provider yet.\",\n credentialKeys: [],\n capabilities: [\"search\", \"import\", \"docs\"],\n recommendedTemplateUses: [\n \"brain\",\n \"analytics\",\n \"content\",\n \"dispatch\",\n \"forms\",\n ],\n }),\n] as const satisfies readonly WorkspaceConnectionProvider[];\n\nconst PROVIDERS_BY_ID = new Map<\n WorkspaceConnectionProviderId,\n WorkspaceConnectionProvider\n>(WORKSPACE_CONNECTION_PROVIDERS.map((provider) => [provider.id, provider]));\n\nexport function listWorkspaceConnectionProviders(\n options: ListWorkspaceConnectionProvidersOptions = {},\n): WorkspaceConnectionProvider[] {\n return WORKSPACE_CONNECTION_PROVIDERS.filter((provider) => {\n if (\n options.capability &&\n !includesWorkspaceConnectionCapability(\n provider.capabilities,\n options.capability,\n )\n ) {\n return false;\n }\n if (\n options.templateUse &&\n !includesWorkspaceConnectionTemplateUse(\n provider.recommendedTemplateUses,\n options.templateUse,\n )\n ) {\n return false;\n }\n return true;\n }).map((provider) => ({ ...provider }));\n}\n\nexport function getWorkspaceConnectionProvider(\n id: string,\n): WorkspaceConnectionProvider | undefined {\n const provider = PROVIDERS_BY_ID.get(id as WorkspaceConnectionProviderId);\n return provider ? { ...provider } : undefined;\n}\n\nexport function isWorkspaceConnectionProviderId(\n id: string,\n): id is WorkspaceConnectionProviderId {\n return PROVIDERS_BY_ID.has(id as WorkspaceConnectionProviderId);\n}\n\nexport function listWorkspaceConnectionProvidersForTemplate(\n templateUse: WorkspaceConnectionTemplateUse,\n): WorkspaceConnectionProvider[] {\n return listWorkspaceConnectionProviders({ templateUse });\n}\n\nexport function listWorkspaceConnectionProvidersForCapability(\n capability: WorkspaceConnectionCapability,\n): WorkspaceConnectionProvider[] {\n return listWorkspaceConnectionProviders({ capability });\n}\n\nexport function workspaceConnectionProviderSupports(\n providerOrId: WorkspaceConnectionProvider | string,\n capability: WorkspaceConnectionCapability,\n): boolean {\n const provider =\n typeof providerOrId === \"string\"\n ? getWorkspaceConnectionProvider(providerOrId)\n : providerOrId;\n return provider?.capabilities.includes(capability) ?? false;\n}\n\nfunction includesWorkspaceConnectionCapability(\n capabilities: readonly WorkspaceConnectionCapability[],\n capability: WorkspaceConnectionCapability,\n): boolean {\n return capabilities.includes(capability);\n}\n\nfunction includesWorkspaceConnectionTemplateUse(\n templateUses: readonly WorkspaceConnectionTemplateUse[],\n templateUse: WorkspaceConnectionTemplateUse,\n): boolean {\n return templateUses.includes(templateUse);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/connections/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["export type WorkspaceConnectionCapability =\n | \"search\"\n | \"import\"\n | \"messages\"\n | \"meetings\"\n | \"crm\"\n | \"code\"\n | \"docs\";\n\nexport type WorkspaceConnectionTemplateUse =\n | \"analytics\"\n | \"brain\"\n | \"calendar\"\n | \"clips\"\n | \"content\"\n | \"design\"\n | \"dispatch\"\n | \"forms\"\n | \"mail\"\n | \"slides\";\n\nexport type WorkspaceConnectionProviderId =\n | \"slack\"\n | \"github\"\n | \"notion\"\n | \"gmail\"\n | \"google_drive\"\n | \"hubspot\"\n | \"granola\"\n | \"clips\"\n | \"generic\";\n\nexport interface WorkspaceConnectionCredentialKey {\n key: string;\n label: string;\n description?: string;\n required?: boolean;\n}\n\nexport interface WorkspaceConnectionProvider {\n id: WorkspaceConnectionProviderId;\n label: string;\n description: string;\n credentialKeys: readonly WorkspaceConnectionCredentialKey[];\n capabilities: readonly WorkspaceConnectionCapability[];\n recommendedTemplateUses: readonly WorkspaceConnectionTemplateUse[];\n}\n\nexport interface ListWorkspaceConnectionProvidersOptions {\n capability?: WorkspaceConnectionCapability;\n templateUse?: WorkspaceConnectionTemplateUse;\n}\n\nexport function defineWorkspaceConnectionProvider<\n const T extends WorkspaceConnectionProvider,\n>(provider: T): T {\n return provider;\n}\n\nexport const WORKSPACE_CONNECTION_PROVIDERS = [\n defineWorkspaceConnectionProvider({\n id: \"slack\",\n label: \"Slack\",\n description:\n \"Workspace conversations and channel history for company memory, support workflows, and messaging automations.\",\n credentialKeys: [\n {\n key: \"SLACK_BOT_TOKEN\",\n label: \"Slack bot token\",\n description:\n \"Bot token with the smallest channel and history scopes needed by the template.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"messages\"],\n recommendedTemplateUses: [\"brain\", \"dispatch\", \"analytics\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"github\",\n label: \"GitHub\",\n description:\n \"Repository, issue, pull request, and code context for product memory, engineering workflows, and analytics.\",\n credentialKeys: [\n {\n key: \"GITHUB_TOKEN\",\n label: \"GitHub token\",\n description:\n \"Fine-grained token or app credential scoped to the repositories the workspace should access.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"code\", \"docs\"],\n recommendedTemplateUses: [\"brain\", \"analytics\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"notion\",\n label: \"Notion\",\n description:\n \"Workspace docs, wikis, pages, and databases for knowledge capture and search.\",\n credentialKeys: [\n {\n key: \"NOTION_API_KEY\",\n label: \"Notion API key\",\n description:\n \"Integration secret with access to the pages or databases shared with the integration.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"docs\"],\n recommendedTemplateUses: [\"brain\", \"content\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"gmail\",\n label: \"Gmail\",\n description:\n \"Mailbox messages and threads for search, triage, customer context, and agent replies.\",\n credentialKeys: [\n {\n key: \"GOOGLE_CLIENT_ID\",\n label: \"Google OAuth client ID\",\n required: true,\n },\n {\n key: \"GOOGLE_CLIENT_SECRET\",\n label: \"Google OAuth client secret\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"messages\"],\n recommendedTemplateUses: [\"mail\", \"brain\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"google_drive\",\n label: \"Google Drive\",\n description:\n \"Drive files, Docs, Sheets, and Slides for document search and import workflows.\",\n credentialKeys: [\n {\n key: \"GOOGLE_CLIENT_ID\",\n label: \"Google OAuth client ID\",\n required: true,\n },\n {\n key: \"GOOGLE_CLIENT_SECRET\",\n label: \"Google OAuth client secret\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"docs\"],\n recommendedTemplateUses: [\"brain\", \"content\", \"slides\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"hubspot\",\n label: \"HubSpot\",\n description:\n \"CRM records, companies, contacts, deals, and engagement history for customer-aware apps.\",\n credentialKeys: [\n {\n key: \"HUBSPOT_PRIVATE_APP_TOKEN\",\n label: \"HubSpot private app token\",\n description:\n \"Private app token scoped to the CRM objects the workspace needs.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"crm\"],\n recommendedTemplateUses: [\"analytics\", \"brain\", \"mail\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"granola\",\n label: \"Granola\",\n description:\n \"Meeting notes and transcripts for company memory and follow-up workflows.\",\n credentialKeys: [\n {\n key: \"GRANOLA_API_KEY\",\n label: \"Granola API key\",\n description:\n \"API key for accessible team notes; templates should respect Granola's workspace visibility.\",\n required: true,\n },\n ],\n capabilities: [\"search\", \"import\", \"meetings\", \"docs\"],\n recommendedTemplateUses: [\"brain\", \"calendar\", \"dispatch\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"clips\",\n label: \"Clips\",\n description:\n \"Agent-native Clips exports and recordings for transcript import and searchable meeting context.\",\n credentialKeys: [],\n capabilities: [\"search\", \"import\", \"meetings\"],\n recommendedTemplateUses: [\"brain\", \"clips\"],\n }),\n defineWorkspaceConnectionProvider({\n id: \"generic\",\n label: \"Generic\",\n description:\n \"Custom webhooks, CSV exports, transcript drops, and one-off sources that do not need a first-class provider yet.\",\n credentialKeys: [],\n capabilities: [\"search\", \"import\", \"docs\"],\n recommendedTemplateUses: [\n \"brain\",\n \"analytics\",\n \"content\",\n \"dispatch\",\n \"forms\",\n ],\n }),\n] as const satisfies readonly WorkspaceConnectionProvider[];\n\nconst PROVIDERS_BY_ID = new Map<\n WorkspaceConnectionProviderId,\n WorkspaceConnectionProvider\n>(WORKSPACE_CONNECTION_PROVIDERS.map((provider) => [provider.id, provider]));\n\nexport function listWorkspaceConnectionProviders(\n options: ListWorkspaceConnectionProvidersOptions = {},\n): WorkspaceConnectionProvider[] {\n return WORKSPACE_CONNECTION_PROVIDERS.filter((provider) => {\n if (\n options.capability &&\n !includesWorkspaceConnectionCapability(\n provider.capabilities,\n options.capability,\n )\n ) {\n return false;\n }\n if (\n options.templateUse &&\n !includesWorkspaceConnectionTemplateUse(\n provider.recommendedTemplateUses,\n options.templateUse,\n )\n ) {\n return false;\n }\n return true;\n }).map((provider) => ({ ...provider }));\n}\n\nexport function getWorkspaceConnectionProvider(\n id: string,\n): WorkspaceConnectionProvider | undefined {\n const provider = PROVIDERS_BY_ID.get(id as WorkspaceConnectionProviderId);\n return provider ? { ...provider } : undefined;\n}\n\nexport function isWorkspaceConnectionProviderId(\n id: string,\n): id is WorkspaceConnectionProviderId {\n return PROVIDERS_BY_ID.has(id as WorkspaceConnectionProviderId);\n}\n\nexport function listWorkspaceConnectionProvidersForTemplate(\n templateUse: WorkspaceConnectionTemplateUse,\n): WorkspaceConnectionProvider[] {\n return listWorkspaceConnectionProviders({ templateUse });\n}\n\nexport function listWorkspaceConnectionProvidersForCapability(\n capability: WorkspaceConnectionCapability,\n): WorkspaceConnectionProvider[] {\n return listWorkspaceConnectionProviders({ capability });\n}\n\nexport function workspaceConnectionProviderSupports(\n providerOrId: WorkspaceConnectionProvider | string,\n capability: WorkspaceConnectionCapability,\n): boolean {\n const provider =\n typeof providerOrId === \"string\"\n ? getWorkspaceConnectionProvider(providerOrId)\n : providerOrId;\n return provider?.capabilities.includes(capability) ?? false;\n}\n\nfunction includesWorkspaceConnectionCapability(\n capabilities: readonly WorkspaceConnectionCapability[],\n capability: WorkspaceConnectionCapability,\n): boolean {\n return capabilities.includes(capability);\n}\n\nfunction includesWorkspaceConnectionTemplateUse(\n templateUses: readonly WorkspaceConnectionTemplateUse[],\n templateUse: WorkspaceConnectionTemplateUse,\n): boolean {\n return templateUses.includes(templateUse);\n}\n"]}
|
|
@@ -37,6 +37,28 @@ export declare function buildResilientNeonPool(pool: {
|
|
|
37
37
|
end(): Promise<void>;
|
|
38
38
|
on(event: string, listener: (...args: any[]) => void): unknown;
|
|
39
39
|
}): typeof pool;
|
|
40
|
+
/**
|
|
41
|
+
* Wraps a postgres.js client so Drizzle queries on the non-Neon Postgres
|
|
42
|
+
* path get the same withDbTimeout + retryOnConnectionError protection as
|
|
43
|
+
* every other Postgres path (raw DbExec postgres.js, raw DbExec Neon, and
|
|
44
|
+
* the Drizzle Neon pool above). Without this, one hung query on a BYO
|
|
45
|
+
* Postgres deployment stalls its request forever.
|
|
46
|
+
*
|
|
47
|
+
* Drizzle's postgres-js session only calls `client.unsafe(query, params)` —
|
|
48
|
+
* awaited directly for row-object results or via `.values()` for row-array
|
|
49
|
+
* results — plus `client.begin(...)` for transactions. We interpose on
|
|
50
|
+
* `unsafe` with a lazy thenable that re-issues the query per retry attempt,
|
|
51
|
+
* and leave transactions unwrapped (same rule as the Neon wrapper: the
|
|
52
|
+
* driver manages the sticky connection inside `begin`).
|
|
53
|
+
*
|
|
54
|
+
* Retry-safety mirrors buildResilientNeonPool: reads retry freely on
|
|
55
|
+
* connection-class errors; writes retry only on CONNECT_TIMEOUT (postgres.js
|
|
56
|
+
* raises it before the statement is ever sent), so writes can't
|
|
57
|
+
* double-execute.
|
|
58
|
+
*/
|
|
59
|
+
export declare function buildResilientPostgresJsClient<T extends {
|
|
60
|
+
unsafe(query: string, params?: any[], options?: any): any;
|
|
61
|
+
}>(client: T): T;
|
|
40
62
|
/**
|
|
41
63
|
* Neon's pooler endpoints cold-start in 5–10s. Serverless environments
|
|
42
64
|
* (Netlify Functions, Vercel Edge, CF Workers) have short cold-start
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-get-db.d.ts","sourceRoot":"","sources":["../../src/db/create-get-db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAkDzD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IACxB,KAAK,CACH,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,GAAG,EAAE,GACX,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC;CAChE,GAAG,OAAO,IAAI,CAyFd;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAK9C;AA6HD,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"create-get-db.d.ts","sourceRoot":"","sources":["../../src/db/create-get-db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAkDzD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IACxB,KAAK,CACH,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,GAAG,EAAE,GACX,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC;CAChE,GAAG,OAAO,IAAI,CAyFd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAC5C,CAAC,SAAS;IACR,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;CAC3D,EACD,MAAM,EAAE,CAAC,GAAG,CAAC,CAyDd;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAK9C;AA6HD,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,SA6HpD,cAAc,CAAC,CAAC,CAAC,CASpC"}
|
package/dist/db/create-get-db.js
CHANGED
|
@@ -126,6 +126,75 @@ export function buildResilientNeonPool(pool) {
|
|
|
126
126
|
},
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Wraps a postgres.js client so Drizzle queries on the non-Neon Postgres
|
|
131
|
+
* path get the same withDbTimeout + retryOnConnectionError protection as
|
|
132
|
+
* every other Postgres path (raw DbExec postgres.js, raw DbExec Neon, and
|
|
133
|
+
* the Drizzle Neon pool above). Without this, one hung query on a BYO
|
|
134
|
+
* Postgres deployment stalls its request forever.
|
|
135
|
+
*
|
|
136
|
+
* Drizzle's postgres-js session only calls `client.unsafe(query, params)` —
|
|
137
|
+
* awaited directly for row-object results or via `.values()` for row-array
|
|
138
|
+
* results — plus `client.begin(...)` for transactions. We interpose on
|
|
139
|
+
* `unsafe` with a lazy thenable that re-issues the query per retry attempt,
|
|
140
|
+
* and leave transactions unwrapped (same rule as the Neon wrapper: the
|
|
141
|
+
* driver manages the sticky connection inside `begin`).
|
|
142
|
+
*
|
|
143
|
+
* Retry-safety mirrors buildResilientNeonPool: reads retry freely on
|
|
144
|
+
* connection-class errors; writes retry only on CONNECT_TIMEOUT (postgres.js
|
|
145
|
+
* raises it before the statement is ever sent), so writes can't
|
|
146
|
+
* double-execute.
|
|
147
|
+
*/
|
|
148
|
+
export function buildResilientPostgresJsClient(client) {
|
|
149
|
+
const wrapUnsafe = (query, params, options) => {
|
|
150
|
+
const isRead = isSqlRead(query);
|
|
151
|
+
const runAttempt = (mode) => async () => {
|
|
152
|
+
const pending = client.unsafe(query, params, options);
|
|
153
|
+
return withDbTimeout("query", async () => (mode === "values" ? pending.values() : pending), dbOpTimeoutMs(), () => {
|
|
154
|
+
// Best-effort cancel so the timed-out statement doesn't keep
|
|
155
|
+
// occupying one of the (small, serverless-capped) pool slots.
|
|
156
|
+
try {
|
|
157
|
+
pending.cancel?.();
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// ignore — cancellation is advisory
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
const execute = async (mode) => {
|
|
165
|
+
if (isRead)
|
|
166
|
+
return retryOnConnectionError(runAttempt(mode));
|
|
167
|
+
try {
|
|
168
|
+
return await runAttempt(mode)();
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
// Connect timeout fires before the statement is sent → one retry is
|
|
172
|
+
// safe even for writes.
|
|
173
|
+
if (isConnectionError(err) &&
|
|
174
|
+
err?.code === "CONNECT_TIMEOUT") {
|
|
175
|
+
return runAttempt(mode)();
|
|
176
|
+
}
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
// Lazy thenable mirroring the slice of postgres.js's PendingQuery
|
|
181
|
+
// surface that Drizzle uses: `await q` or `await q.values()`.
|
|
182
|
+
return {
|
|
183
|
+
then: (onFulfilled, onRejected) => execute("rows").then(onFulfilled, onRejected),
|
|
184
|
+
catch: (onRejected) => execute("rows").catch(onRejected),
|
|
185
|
+
finally: (onFinally) => execute("rows").finally(onFinally),
|
|
186
|
+
values: () => execute("values"),
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
return new Proxy(client, {
|
|
190
|
+
get(target, prop) {
|
|
191
|
+
if (prop === "unsafe")
|
|
192
|
+
return wrapUnsafe;
|
|
193
|
+
const val = target[prop];
|
|
194
|
+
return typeof val === "function" ? val.bind(target) : val;
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}
|
|
129
198
|
/**
|
|
130
199
|
* Neon's pooler endpoints cold-start in 5–10s. Serverless environments
|
|
131
200
|
* (Netlify Functions, Vercel Edge, CF Workers) have short cold-start
|
|
@@ -302,7 +371,7 @@ export function createGetDb(schema) {
|
|
|
302
371
|
// concurrent frozen instances don't exhaust Neon/Postgres'
|
|
303
372
|
// connection limit ("Max client connections reached").
|
|
304
373
|
const client = postgres(url, pgPoolOptions(url));
|
|
305
|
-
_db = drizzle(client, { schema });
|
|
374
|
+
_db = drizzle(buildResilientPostgresJsClient(client), { schema });
|
|
306
375
|
});
|
|
307
376
|
}
|
|
308
377
|
}
|
|
@@ -312,6 +381,9 @@ export function createGetDb(schema) {
|
|
|
312
381
|
getBetterSqliteDrizzle(),
|
|
313
382
|
]).then(([sqliteUrl, { drizzle, Database }]) => {
|
|
314
383
|
const sqlite = new Database(sqliteFilenameFromUrl(sqliteUrl));
|
|
384
|
+
// Wait up to 10s for a concurrent writer instead of failing fast
|
|
385
|
+
// with SQLITE_BUSY — mirrors the raw DbExec SQLite path in client.ts.
|
|
386
|
+
sqlite.pragma("busy_timeout = 10000");
|
|
315
387
|
sqlite.pragma("journal_mode = WAL");
|
|
316
388
|
const db = drizzle(sqlite, { schema });
|
|
317
389
|
_db = patchBetterSqliteTransactions(db, sqlite);
|