@agent-native/core 0.137.7 → 0.138.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +2 -0
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +15 -0
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/analytics/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/analytics/AGENTS.md +2 -2
- package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +65 -0
- package/corpus/templates/analytics/actions/provider-api-catalog.ts +3 -6
- package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -6
- package/corpus/templates/analytics/actions/provider-api-request.ts +3 -6
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +3 -3
- package/corpus/templates/analytics/agent-native.json +12 -0
- package/corpus/templates/analytics/app/i18n-data.ts +162 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +126 -1
- package/corpus/templates/analytics/changelog/2026-08-05-analytics-now-flags-neon-pressure-and-guides-high-volume-tra.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-05-first-party-analytics-uses-compact-rollups-for-faster-usage-.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +52 -0
- package/corpus/templates/analytics/server/lib/credential-keys.ts +3 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +397 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +182 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +86 -15
- package/corpus/templates/analytics/server/lib/provider-api.ts +20 -1
- package/corpus/templates/analytics/server/lib/replay-storage.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/analytics/server/plugins/db.ts +60 -0
- package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/assets/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/assets/agent-native.json +12 -0
- package/corpus/templates/assets/server/lib/generation.ts +8 -8
- package/corpus/templates/assets/server/lib/storage.ts +1 -1
- package/corpus/templates/assets/server/plugins/onboarding.ts +1 -1
- package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/brain/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/brain/agent-native.json +12 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/calendar/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/calendar/agent-native.json +12 -0
- package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/chat/AGENTS.md +3 -0
- package/corpus/templates/chat/DESIGN.md +28 -0
- package/corpus/templates/chat/agent-native.json +12 -0
- package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/clips/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/clips/actions/cleanup-transcript.ts +2 -2
- package/corpus/templates/clips/actions/delete-recording-permanent.ts +3 -0
- package/corpus/templates/clips/actions/get-playback-position.ts +68 -0
- package/corpus/templates/clips/actions/import-loom-recording.ts +2 -2
- package/corpus/templates/clips/actions/save-playback-position.ts +80 -0
- package/corpus/templates/clips/actions/set-thumbnail.ts +1 -1
- package/corpus/templates/clips/agent-native.json +12 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +54 -5
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +65 -18
- package/corpus/templates/clips/app/hooks/use-playback-position.ts +188 -0
- package/corpus/templates/clips/app/hooks/use-view-tracking.ts +6 -24
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
- package/corpus/templates/clips/app/lib/playback-position.ts +99 -0
- package/corpus/templates/clips/app/lib/viewer-session.ts +29 -0
- package/corpus/templates/clips/changelog/2026-08-05-clip-buffering-now-uses-buffering-copy-after-playback.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-05-clips-remembers-your-playback-position-when-you-reopen-a-cli.md +6 -0
- package/corpus/templates/clips/desktop/package.json +1 -0
- package/corpus/templates/clips/desktop/src/app.tsx +70 -6
- package/corpus/templates/clips/desktop/src/components/AlertDialog.tsx +131 -0
- package/corpus/templates/clips/desktop/src/styles.css +129 -0
- package/corpus/templates/clips/learnings.defaults.md +1 -1
- package/corpus/templates/clips/server/db/schema.ts +18 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +1 -1
- package/corpus/templates/clips/server/lib/video-storage.ts +1 -1
- package/corpus/templates/clips/server/plugins/db.ts +15 -0
- package/corpus/templates/clips/server/routes/api/media/index.post.ts +1 -1
- package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +13 -0
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/content/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/content/AGENTS.md +1 -0
- package/corpus/templates/content/actions/_content-database-mutation-lock.ts +41 -0
- package/corpus/templates/content/actions/_content-database-row-migration.ts +569 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +82 -36
- package/corpus/templates/content/actions/_database-utils.ts +5 -0
- package/corpus/templates/content/actions/_delete-content-space.ts +25 -11
- package/corpus/templates/content/actions/add-database-item.ts +60 -42
- package/corpus/templates/content/actions/attach-content-database-source.ts +2 -0
- package/corpus/templates/content/actions/configure-document-property.ts +99 -104
- package/corpus/templates/content/actions/delete-content-database.ts +19 -7
- package/corpus/templates/content/actions/delete-document-property.ts +47 -58
- package/corpus/templates/content/actions/delete-document.ts +390 -167
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +41 -24
- package/corpus/templates/content/actions/duplicate-database-item.ts +63 -31
- package/corpus/templates/content/actions/duplicate-database-items.ts +86 -43
- package/corpus/templates/content/actions/duplicate-document-property.ts +37 -14
- package/corpus/templates/content/actions/migrate-content-database-rows.ts +830 -0
- package/corpus/templates/content/actions/move-database-item.ts +14 -0
- package/corpus/templates/content/actions/permanently-delete-document.ts +27 -6
- package/corpus/templates/content/actions/remove-database-items.ts +13 -0
- package/corpus/templates/content/actions/reorder-document-property.ts +45 -46
- package/corpus/templates/content/actions/set-document-property.ts +68 -28
- package/corpus/templates/content/actions/submit-content-database-form.ts +49 -0
- package/corpus/templates/content/actions/transcribe-media.ts +1 -1
- package/corpus/templates/content/agent-native.json +12 -0
- package/corpus/templates/content/app/components/editor/image-upload.ts +2 -2
- package/corpus/templates/content/app/i18n-data.ts +1 -1
- package/corpus/templates/content/changelog/2026-08-01-content-can-reorganize-every-row-in-an-existing-database-as-.md +6 -0
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +4 -2
- package/corpus/templates/content/server/db/schema.ts +30 -0
- package/corpus/templates/content/server/plugins/db.ts +24 -0
- package/corpus/templates/content/server/plugins/onboarding.ts +2 -2
- package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/crm/agent-native.json +12 -0
- package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -0
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/design/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +2 -2
- package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +2 -2
- package/corpus/templates/design/actions/apply-design-token-edit.ts +1 -1
- package/corpus/templates/design/actions/capture-design-state.ts +1 -1
- package/corpus/templates/design/actions/connect-builder-app.ts +2 -2
- package/corpus/templates/design/actions/create-design-branch.ts +1 -1
- package/corpus/templates/design/actions/create-fusion-app.ts +3 -3
- package/corpus/templates/design/actions/deploy-design-preview.ts +1 -1
- package/corpus/templates/design/actions/generate-design.ts +3 -2
- package/corpus/templates/design/actions/get-component-details.ts +1 -1
- package/corpus/templates/design/actions/get-design-branch-diff.ts +1 -1
- package/corpus/templates/design/actions/index-components.ts +3 -3
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/design/actions/migrate-inline-design-to-app.ts +3 -3
- package/corpus/templates/design/actions/open-component-source.ts +1 -1
- package/corpus/templates/design/actions/update-design.ts +96 -14
- package/corpus/templates/design/agent-native.json +12 -0
- package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +7 -2
- package/corpus/templates/design/app/components/design/FigmaHydrationDialog.tsx +11 -2
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +1 -1
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +8 -1
- package/corpus/templates/design/app/i18n-data.ts +53 -22
- package/corpus/templates/design/app/lib/design-file-upload.ts +2 -3
- package/corpus/templates/design/app/lib/upload-limits.ts +4 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/design/changelog/2026-08-05-chat-attachments-now-warn-before-upload-when-they-exceed-the.md +6 -0
- package/corpus/templates/design/changelog/2026-08-05-figma-fig-uploads-now-show-a-clear-4-mb-limit-up-front-inste.md +6 -0
- package/corpus/templates/design/scripts/qa-figma-stress-import.ts +1 -1
- package/corpus/templates/design/server/handlers/import-design-file.ts +9 -5
- package/corpus/templates/design/server/handlers/uploads.ts +13 -9
- package/corpus/templates/design/server/lib/fig-file-limits.ts +2 -1
- package/corpus/templates/design/server/lib/figma-image-hydration.ts +1 -1
- package/corpus/templates/design/server/lib/figma-node-import.ts +1 -1
- package/corpus/templates/design/server/lib/request-body-limits.ts +11 -0
- package/corpus/templates/design/shared/canvas-frames.ts +81 -0
- package/corpus/templates/design/shared/design-source-capabilities.ts +25 -9
- package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/dispatch/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/dispatch/agent-native.json +12 -0
- package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/factory/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/factory/agent-native.json +12 -0
- package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/forms/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/forms/actions/export-responses.ts +1 -1
- package/corpus/templates/forms/agent-native.json +12 -0
- package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/macros/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/macros/agent-native.json +12 -0
- package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/mail/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/mail/agent-native.json +12 -0
- package/corpus/templates/mail/app/i18n/en-US.ts +1 -1
- package/corpus/templates/mail/server/lib/media-upload.ts +1 -1
- package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/plan/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/plan/agent-native.json +12 -0
- package/corpus/templates/plan/server/lib/plan-assets.ts +1 -1
- package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/slides/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
- package/corpus/templates/slides/actions/generate-slides-ai.ts +1 -1
- package/corpus/templates/slides/actions/import-file.ts +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/slides/agent-native.json +12 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +2 -2
- package/corpus/templates/slides/app/lib/deck-sorting.ts +19 -0
- package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +1 -1
- package/corpus/templates/slides/app/pages/Index.tsx +7 -2
- package/corpus/templates/slides/changelog/2026-08-05-decks-are-now-sorted-by-most-recently-updated.md +6 -0
- package/corpus/templates/slides/server/handlers/assets.ts +1 -1
- package/corpus/templates/slides/server/handlers/uploads.ts +1 -1
- package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/tasks/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/tasks/agent-native.json +12 -0
- package/dist/action.d.ts +6 -0
- package/dist/agent/engine/builder-engine.js +2 -2
- package/dist/agent/engine/credential-errors.d.ts +1 -1
- package/dist/agent/engine/credential-errors.js +2 -2
- package/dist/agent/production-agent.js +3 -2
- package/dist/brand-kit/fig/index.js +1 -1
- package/dist/cli/agent.js +45 -3
- package/dist/cli/code-agent-executor.js +2 -1
- package/dist/cli/create.d.ts +9 -1
- package/dist/cli/create.js +94 -1
- package/dist/cli/doctor.d.ts +8 -11
- package/dist/cli/doctor.js +92 -24
- package/dist/cli/index.js +6 -5
- package/dist/client/AgentAskPopover.d.ts +3 -1
- package/dist/client/AgentAskPopover.js +2 -2
- package/dist/client/AgentPanel.js +9 -3
- package/dist/client/AssistantChat.js +54 -33
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/RouteTransitionIndicator.d.ts +7 -0
- package/dist/client/RouteTransitionIndicator.js +31 -0
- package/dist/client/agent-engine-key.js +1 -1
- package/dist/client/app-providers.js +11 -2
- package/dist/client/chat/message-components.js +1 -1
- package/dist/client/chat/run-recovery.js +1 -1
- package/dist/client/chat/tool-call-display.d.ts +3 -1
- package/dist/client/chat/tool-call-display.js +4 -3
- package/dist/client/chat-model-groups.d.ts +6 -0
- package/dist/client/chat-model-groups.js +11 -0
- package/dist/client/error-format.js +1 -1
- package/dist/client/i18n.js +1 -1
- package/dist/client/onboarding/FirstRunOnboarding.d.ts +5 -1
- package/dist/client/onboarding/FirstRunOnboarding.js +29 -13
- package/dist/client/onboarding/first-run-enabled.d.ts +6 -1
- package/dist/client/onboarding/first-run-enabled.js +33 -3
- package/dist/client/onboarding/use-onboarding.js +16 -11
- package/dist/client/require-session.js +13 -4
- package/dist/client/resources/mcp-integration-catalog.js +26 -0
- package/dist/client/resources/mcp-integration-logos.js +4 -0
- package/dist/client/route-warmup.js +56 -10
- package/dist/client/settings/AccountSettingsCard.js +78 -3
- package/dist/client/settings/SettingsPanel.js +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.js +2 -2
- package/dist/client/settings/useBuilderStatus.js +1 -1
- package/dist/client/setup-connections/useBuilderConnectCardController.js +1 -1
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/client/uploads/upload-editor-image.js +1 -1
- package/dist/client/use-chat-threads.js +3 -0
- package/dist/client/use-session.d.ts +11 -0
- package/dist/client/use-session.js +34 -6
- package/dist/collab/routes.d.ts +2 -2
- package/dist/config.d.ts +48 -0
- package/dist/config.js +111 -0
- package/dist/db/migrations.js +5 -0
- package/dist/eject/provider-api-definitions.d.ts +1 -1
- package/dist/eject/provider-api-definitions.js +1 -0
- package/dist/eject/remote-mcp-presets.js +1 -0
- package/dist/extensions/web-search-tool.js +2 -2
- package/dist/file-upload/actions/upload-image.js +1 -1
- package/dist/file-upload/registry.js +1 -1
- package/dist/guards/index.d.ts +3 -0
- package/dist/guards/index.js +2 -0
- package/dist/guards/no-empty-migrations.d.ts +14 -0
- package/dist/guards/no-empty-migrations.js +126 -0
- package/dist/index.browser.d.ts +1 -0
- package/dist/index.browser.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/localization/default-messages.d.ts +24 -0
- package/dist/localization/default-messages.js +26 -2
- package/dist/notifications/routes.d.ts +6 -6
- package/dist/onboarding/app-profile.js +1 -1
- package/dist/onboarding/plugin.d.ts +2 -0
- package/dist/onboarding/plugin.js +29 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/provider-api/index.d.ts +4 -4
- package/dist/provider-api/index.js +35 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/handlers.js +1 -1
- package/dist/scripts/docs/framework-search.d.ts +9 -0
- package/dist/scripts/docs/framework-search.js +239 -0
- package/dist/scripts/docs/index.js +1 -0
- package/dist/scripts/docs/search.d.ts +10 -0
- package/dist/scripts/docs/search.js +1 -1
- package/dist/scripts/docs/source-search.d.ts +10 -2
- package/dist/scripts/docs/source-search.js +108 -41
- package/dist/search-utils/index.d.ts +11 -0
- package/dist/search-utils/index.js +72 -0
- package/dist/server/action-change.d.ts +6 -0
- package/dist/server/action-change.js +28 -14
- package/dist/server/action-discovery.js +9 -0
- package/dist/server/action-routes.js +1 -0
- package/dist/server/agent-chat/browser-team-tools.js +1 -1
- package/dist/server/agent-chat/script-entries.js +43 -2
- package/dist/server/auth-login-mode.d.ts +8 -0
- package/dist/server/auth-login-mode.js +17 -0
- package/dist/server/auth.js +100 -15
- package/dist/server/better-auth-instance.d.ts +36 -0
- package/dist/server/better-auth-instance.js +25 -3
- package/dist/server/builder-design-systems.js +1 -1
- package/dist/server/core-routes-plugin.js +17 -14
- package/dist/server/credential-provider.js +3 -3
- package/dist/server/email-templates.d.ts +7 -0
- package/dist/server/email-templates.js +24 -0
- package/dist/server/email.d.ts +17 -0
- package/dist/server/email.js +22 -1
- package/dist/server/framework-request-handler.js +6 -0
- package/dist/server/onboarding-html.d.ts +2 -0
- package/dist/server/onboarding-html.js +169 -8
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/realtime-voice.js +1 -1
- package/dist/server/sentry.d.ts +1 -1
- package/dist/server/transcribe-voice.js +3 -3
- package/dist/shared/first-run-onboarding.d.ts +1 -0
- package/dist/shared/first-run-onboarding.js +1 -0
- package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/chat/AGENTS.md +3 -0
- package/dist/templates/chat/DESIGN.md +28 -0
- package/dist/templates/chat/agent-native.json +12 -0
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/default/AGENTS.md +4 -0
- package/dist/templates/default/DESIGN.md +30 -0
- package/dist/templates/default/agent-native.json +9 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +2 -2
- package/dist/templates/default/app/i18n/de-DE.ts +2 -2
- package/dist/templates/default/app/i18n/en-US.ts +2 -2
- package/dist/templates/default/app/i18n/es-ES.ts +2 -2
- package/dist/templates/default/app/i18n/fr-FR.ts +2 -2
- package/dist/templates/default/app/i18n/hi-IN.ts +2 -2
- package/dist/templates/default/app/i18n/ja-JP.ts +2 -2
- package/dist/templates/default/app/i18n/ko-KR.ts +2 -2
- package/dist/templates/default/app/i18n/pt-BR.ts +2 -2
- package/dist/templates/default/app/i18n/zh-CN.ts +2 -2
- package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
- package/dist/templates/default/package.json +1 -0
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/headless/agent-native.json +9 -0
- package/dist/templates/headless/package.json +2 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/workspace-core/AGENTS.md +3 -0
- package/dist/templates/workspace-core/DESIGN.md +35 -0
- package/dist/templates/workspace-root/AGENTS.md +3 -0
- package/dist/templates/workspace-root/DESIGN.md +35 -0
- package/dist/templates/workspace-root/agent-native.json +9 -0
- package/dist/templates/workspace-root/package.json +3 -0
- package/dist/transcription/builder-transcription.js +1 -1
- package/dist/user-profile/actions/change-password.d.ts +8 -0
- package/dist/user-profile/actions/change-password.js +24 -0
- package/dist/user-profile/actions/get-auth-methods.d.ts +6 -0
- package/dist/user-profile/actions/get-auth-methods.js +23 -0
- package/dist/user-profile/actions/set-password.d.ts +7 -0
- package/dist/user-profile/actions/set-password.js +23 -0
- package/dist/vite/client.d.ts +8 -1
- package/dist/vite/client.js +63 -12
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.js +1 -0
- package/docs/AGENTS.md +7 -2
- package/docs/SKILL.md +7 -5
- package/docs/content/agent-native-config.mdx +165 -0
- package/docs/content/agent-native-toolkit.mdx +1 -1
- package/docs/content/deployment.mdx +7 -2
- package/docs/content/doctor.mdx +21 -13
- package/docs/content/environment-variables.mdx +158 -0
- package/docs/content/file-uploads.mdx +1 -1
- package/docs/content/getting-started.mdx +1 -1
- package/docs/content/key-concepts.mdx +1 -1
- package/docs/content/multi-app-workspace.mdx +1 -1
- package/docs/content/template-clips-ai-and-editing.mdx +6 -6
- package/docs/content/template-clips-developers.mdx +3 -3
- package/docs/content/toolkit-settings.mdx +1 -1
- package/docs/content/voice-input.mdx +4 -4
- package/package.json +6 -2
- package/src/eject/provider-api-definitions.ts +1 -0
- package/src/eject/remote-mcp-presets.ts +1 -0
- package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/chat/AGENTS.md +3 -0
- package/src/templates/chat/DESIGN.md +28 -0
- package/src/templates/chat/agent-native.json +12 -0
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/default/AGENTS.md +4 -0
- package/src/templates/default/DESIGN.md +30 -0
- package/src/templates/default/agent-native.json +9 -0
- package/src/templates/default/app/i18n/ar-SA.ts +2 -2
- package/src/templates/default/app/i18n/de-DE.ts +2 -2
- package/src/templates/default/app/i18n/en-US.ts +2 -2
- package/src/templates/default/app/i18n/es-ES.ts +2 -2
- package/src/templates/default/app/i18n/fr-FR.ts +2 -2
- package/src/templates/default/app/i18n/hi-IN.ts +2 -2
- package/src/templates/default/app/i18n/ja-JP.ts +2 -2
- package/src/templates/default/app/i18n/ko-KR.ts +2 -2
- package/src/templates/default/app/i18n/pt-BR.ts +2 -2
- package/src/templates/default/app/i18n/zh-CN.ts +2 -2
- package/src/templates/default/app/i18n/zh-TW.ts +1 -1
- package/src/templates/default/package.json +1 -0
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/headless/agent-native.json +9 -0
- package/src/templates/headless/package.json +2 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/workspace-core/AGENTS.md +3 -0
- package/src/templates/workspace-core/DESIGN.md +35 -0
- package/src/templates/workspace-root/AGENTS.md +3 -0
- package/src/templates/workspace-root/DESIGN.md +35 -0
- package/src/templates/workspace-root/agent-native.json +9 -0
- package/src/templates/workspace-root/package.json +3 -0
|
@@ -1,16 +1,38 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { writeAppState } from "@agent-native/core/application-state";
|
|
3
3
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
4
|
-
import { and, eq, inArray, isNotNull, isNull, ne, or
|
|
4
|
+
import { and, eq, inArray, isNotNull, isNull, ne, or } from "drizzle-orm";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
|
|
7
7
|
import { getDb, schema } from "../server/db/index.js";
|
|
8
8
|
import { chunks } from "./_batch-utils.js";
|
|
9
|
+
import {
|
|
10
|
+
lockContentDatabaseMutation,
|
|
11
|
+
touchContentDatabase,
|
|
12
|
+
} from "./_content-database-mutation-lock.js";
|
|
9
13
|
import { assertNotWorkspaceCatalogDocuments } from "./_content-space-catalog-guards.js";
|
|
14
|
+
import { lockDatabaseMemberships } from "./_database-membership-lock.js";
|
|
10
15
|
import { renumberDatabaseRows } from "./_database-row-batch.js";
|
|
11
16
|
|
|
12
17
|
const DELETE_BATCH_SIZE = 90;
|
|
13
18
|
|
|
19
|
+
export class PermanentDeleteScopeChangedError extends Error {
|
|
20
|
+
constructor() {
|
|
21
|
+
super("Document deletion scope changed; retry deletion.");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type PermanentDeleteScope = {
|
|
26
|
+
documentIds: string[];
|
|
27
|
+
ownedDatabaseIds: string[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function hasSameIds(left: string[], right: string[]) {
|
|
31
|
+
if (left.length !== right.length) return false;
|
|
32
|
+
const rightIds = new Set(right);
|
|
33
|
+
return left.every((id) => rightIds.has(id));
|
|
34
|
+
}
|
|
35
|
+
|
|
14
36
|
async function selectDocumentChildren(
|
|
15
37
|
db: ReturnType<typeof getDb>,
|
|
16
38
|
parentIds: string[],
|
|
@@ -97,26 +119,75 @@ async function selectDatabaseItemDocuments(
|
|
|
97
119
|
return ownedRows.map((row) => ({ documentId: row.id }));
|
|
98
120
|
}
|
|
99
121
|
|
|
100
|
-
async function
|
|
122
|
+
async function selectDatabaseItemDocumentTrashState(
|
|
101
123
|
db: ReturnType<typeof getDb>,
|
|
102
|
-
|
|
124
|
+
databaseIds: string[],
|
|
103
125
|
ownerEmail: string,
|
|
104
126
|
) {
|
|
105
|
-
const
|
|
106
|
-
|
|
127
|
+
const itemDocuments = await selectDatabaseItemDocuments(
|
|
128
|
+
db,
|
|
129
|
+
databaseIds,
|
|
130
|
+
ownerEmail,
|
|
131
|
+
);
|
|
132
|
+
const rows: Array<{
|
|
133
|
+
id: string;
|
|
134
|
+
trashedAt: string | null;
|
|
135
|
+
}> = [];
|
|
136
|
+
for (const batch of chunks(
|
|
137
|
+
itemDocuments.map((item) => item.documentId),
|
|
138
|
+
DELETE_BATCH_SIZE,
|
|
139
|
+
)) {
|
|
107
140
|
rows.push(
|
|
108
141
|
...(await db
|
|
109
|
-
.select({
|
|
110
|
-
|
|
142
|
+
.select({
|
|
143
|
+
id: schema.documents.id,
|
|
144
|
+
trashedAt: schema.documents.trashedAt,
|
|
145
|
+
})
|
|
146
|
+
.from(schema.documents)
|
|
111
147
|
.where(
|
|
112
148
|
and(
|
|
113
|
-
inArray(schema.
|
|
114
|
-
eq(schema.
|
|
149
|
+
inArray(schema.documents.id, batch),
|
|
150
|
+
eq(schema.documents.ownerEmail, ownerEmail),
|
|
115
151
|
),
|
|
116
152
|
)),
|
|
117
153
|
);
|
|
118
154
|
}
|
|
119
|
-
return
|
|
155
|
+
return rows;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function selectMembershipsForDocuments(
|
|
159
|
+
db: ReturnType<typeof getDb>,
|
|
160
|
+
documentIds: string[],
|
|
161
|
+
) {
|
|
162
|
+
const rows: Array<{ id: string; databaseId: string }> = [];
|
|
163
|
+
for (const batch of chunks(documentIds, DELETE_BATCH_SIZE)) {
|
|
164
|
+
rows.push(
|
|
165
|
+
...(await db
|
|
166
|
+
.select({
|
|
167
|
+
id: schema.contentDatabaseItems.id,
|
|
168
|
+
databaseId: schema.contentDatabaseItems.databaseId,
|
|
169
|
+
})
|
|
170
|
+
.from(schema.contentDatabaseItems)
|
|
171
|
+
.where(inArray(schema.contentDatabaseItems.documentId, batch))),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
return rows;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function selectMembershipIdsForDatabases(
|
|
178
|
+
db: ReturnType<typeof getDb>,
|
|
179
|
+
databaseIds: string[],
|
|
180
|
+
) {
|
|
181
|
+
const rows: Array<{ id: string }> = [];
|
|
182
|
+
for (const batch of chunks(databaseIds, DELETE_BATCH_SIZE)) {
|
|
183
|
+
rows.push(
|
|
184
|
+
...(await db
|
|
185
|
+
.select({ id: schema.contentDatabaseItems.id })
|
|
186
|
+
.from(schema.contentDatabaseItems)
|
|
187
|
+
.where(inArray(schema.contentDatabaseItems.databaseId, batch))),
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return rows.map((row) => row.id);
|
|
120
191
|
}
|
|
121
192
|
|
|
122
193
|
async function collectDocumentSubtreeForDelete(
|
|
@@ -172,84 +243,117 @@ async function collectDocumentSubtreeForDelete(
|
|
|
172
243
|
frontier = [...next];
|
|
173
244
|
}
|
|
174
245
|
|
|
175
|
-
const collectedDocumentIds = [...documentIds];
|
|
176
|
-
const collectedOwnedDatabaseIds = [...ownedDatabaseIds];
|
|
177
246
|
return {
|
|
178
|
-
documentIds:
|
|
179
|
-
ownedDatabaseIds:
|
|
180
|
-
lockDatabaseIds: [
|
|
181
|
-
...new Set([
|
|
182
|
-
...collectedOwnedDatabaseIds,
|
|
183
|
-
...(await selectMembershipDatabaseIds(
|
|
184
|
-
db,
|
|
185
|
-
collectedDocumentIds,
|
|
186
|
-
ownerEmail,
|
|
187
|
-
)),
|
|
188
|
-
]),
|
|
189
|
-
],
|
|
247
|
+
documentIds: [...documentIds],
|
|
248
|
+
ownedDatabaseIds: [...ownedDatabaseIds],
|
|
190
249
|
};
|
|
191
250
|
}
|
|
192
251
|
|
|
193
|
-
async function
|
|
194
|
-
T extends { lockDatabaseIds: string[] },
|
|
195
|
-
>(
|
|
252
|
+
async function lockPermanentDeleteScope(
|
|
196
253
|
db: ReturnType<typeof getDb>,
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
254
|
+
collectScope: () => Promise<PermanentDeleteScope>,
|
|
255
|
+
) {
|
|
256
|
+
const initialScope = await collectScope();
|
|
257
|
+
const initialMemberships = await selectMembershipsForDocuments(
|
|
258
|
+
db,
|
|
259
|
+
initialScope.documentIds,
|
|
260
|
+
);
|
|
261
|
+
const lockedDatabaseIds = [
|
|
262
|
+
...new Set([
|
|
263
|
+
...initialScope.ownedDatabaseIds,
|
|
264
|
+
...initialMemberships.map((membership) => membership.databaseId),
|
|
265
|
+
]),
|
|
266
|
+
].sort();
|
|
267
|
+
for (const databaseId of lockedDatabaseIds) {
|
|
268
|
+
await lockContentDatabaseMutation(db, databaseId);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const reloadedScope = await collectScope();
|
|
272
|
+
const reloadedMemberships = await selectMembershipsForDocuments(
|
|
273
|
+
db,
|
|
274
|
+
reloadedScope.documentIds,
|
|
275
|
+
);
|
|
276
|
+
const lockedDatabaseIdSet = new Set(lockedDatabaseIds);
|
|
277
|
+
const uncoveredDatabaseId = [
|
|
278
|
+
...reloadedScope.ownedDatabaseIds,
|
|
279
|
+
...reloadedMemberships.map((membership) => membership.databaseId),
|
|
280
|
+
].find((databaseId) => !lockedDatabaseIdSet.has(databaseId));
|
|
281
|
+
if (uncoveredDatabaseId) {
|
|
282
|
+
throw new PermanentDeleteScopeChangedError();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const membershipIds = await selectMembershipIdsForDatabases(
|
|
286
|
+
db,
|
|
287
|
+
lockedDatabaseIds,
|
|
288
|
+
);
|
|
289
|
+
await lockDatabaseMemberships(db, membershipIds);
|
|
290
|
+
|
|
291
|
+
const lockedScope = await collectScope();
|
|
292
|
+
const lockedMemberships = await selectMembershipsForDocuments(
|
|
293
|
+
db,
|
|
294
|
+
lockedScope.documentIds,
|
|
295
|
+
);
|
|
296
|
+
const lockedMembershipIds = await selectMembershipIdsForDatabases(
|
|
297
|
+
db,
|
|
298
|
+
lockedDatabaseIds,
|
|
299
|
+
);
|
|
300
|
+
if (
|
|
301
|
+
!hasSameIds(reloadedScope.documentIds, lockedScope.documentIds) ||
|
|
302
|
+
!hasSameIds(reloadedScope.ownedDatabaseIds, lockedScope.ownedDatabaseIds) ||
|
|
303
|
+
!hasSameIds(membershipIds, lockedMembershipIds) ||
|
|
304
|
+
[
|
|
305
|
+
...lockedScope.ownedDatabaseIds,
|
|
306
|
+
...lockedMemberships.map((membership) => membership.databaseId),
|
|
307
|
+
].some((databaseId) => !lockedDatabaseIdSet.has(databaseId))
|
|
308
|
+
) {
|
|
309
|
+
throw new PermanentDeleteScopeChangedError();
|
|
220
310
|
}
|
|
311
|
+
return lockedScope;
|
|
221
312
|
}
|
|
222
313
|
|
|
223
|
-
export async function
|
|
314
|
+
export async function lockDatabasesForTrash(
|
|
224
315
|
db: ReturnType<typeof getDb>,
|
|
225
316
|
id: string,
|
|
226
317
|
ownerEmail: string,
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
id,
|
|
233
|
-
ownerEmail,
|
|
234
|
-
trashedAt,
|
|
235
|
-
),
|
|
318
|
+
) {
|
|
319
|
+
const subtree = await collectDocumentSubtreeForDelete(db, id, ownerEmail);
|
|
320
|
+
const memberships = await selectMembershipsForDocuments(
|
|
321
|
+
db,
|
|
322
|
+
subtree.documentIds,
|
|
236
323
|
);
|
|
324
|
+
const databaseIds = [
|
|
325
|
+
...new Set([
|
|
326
|
+
...memberships.map((membership) => membership.databaseId),
|
|
327
|
+
...subtree.ownedDatabaseIds,
|
|
328
|
+
]),
|
|
329
|
+
].sort();
|
|
330
|
+
for (const databaseId of databaseIds) {
|
|
331
|
+
await lockContentDatabaseMutation(db, databaseId);
|
|
332
|
+
}
|
|
333
|
+
return new Set(databaseIds);
|
|
237
334
|
}
|
|
238
335
|
|
|
239
|
-
async function
|
|
336
|
+
export async function trashDocumentSubtree(
|
|
240
337
|
db: ReturnType<typeof getDb>,
|
|
241
338
|
id: string,
|
|
242
339
|
ownerEmail: string,
|
|
243
|
-
trashedAt
|
|
340
|
+
trashedAt = new Date().toISOString(),
|
|
341
|
+
lockedDatabaseIds?: ReadonlySet<string>,
|
|
244
342
|
): Promise<string[]> {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
343
|
+
const { documentIds, ownedDatabaseIds } =
|
|
344
|
+
await collectDocumentSubtreeForDelete(db, id, ownerEmail);
|
|
345
|
+
if (lockedDatabaseIds) {
|
|
346
|
+
const memberships = await selectMembershipsForDocuments(db, documentIds);
|
|
347
|
+
const unlockedDatabaseId = [
|
|
348
|
+
...new Set([
|
|
349
|
+
...ownedDatabaseIds,
|
|
350
|
+
...memberships.map((membership) => membership.databaseId),
|
|
351
|
+
]),
|
|
352
|
+
].find((databaseId) => !lockedDatabaseIds.has(databaseId));
|
|
353
|
+
if (unlockedDatabaseId) {
|
|
354
|
+
throw new Error("Document subtree changed; retry deletion.");
|
|
355
|
+
}
|
|
356
|
+
}
|
|
253
357
|
await assertNotWorkspaceCatalogDocuments(db, documentIds, "deleted");
|
|
254
358
|
|
|
255
359
|
const independentlyTrashedDatabaseDocumentIds = new Set<string>();
|
|
@@ -291,6 +395,39 @@ async function trashDocumentSubtreeInTransaction(
|
|
|
291
395
|
);
|
|
292
396
|
}
|
|
293
397
|
|
|
398
|
+
const activeMemberships = await selectMembershipsForDocuments(
|
|
399
|
+
db,
|
|
400
|
+
activeDocumentIds,
|
|
401
|
+
);
|
|
402
|
+
const transitioningOwnedDatabases: Array<{ id: string }> = [];
|
|
403
|
+
for (const batch of chunks(activeDocumentIds, DELETE_BATCH_SIZE)) {
|
|
404
|
+
transitioningOwnedDatabases.push(
|
|
405
|
+
...(await db
|
|
406
|
+
.select({ id: schema.contentDatabases.id })
|
|
407
|
+
.from(schema.contentDatabases)
|
|
408
|
+
.where(
|
|
409
|
+
and(
|
|
410
|
+
inArray(schema.contentDatabases.documentId, batch),
|
|
411
|
+
eq(schema.contentDatabases.ownerEmail, ownerEmail),
|
|
412
|
+
isNull(schema.contentDatabases.deletedAt),
|
|
413
|
+
),
|
|
414
|
+
)),
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
const transitioningOwnedDatabaseIds = new Set(
|
|
418
|
+
transitioningOwnedDatabases.map((database) => database.id),
|
|
419
|
+
);
|
|
420
|
+
const externalDatabaseIds = [
|
|
421
|
+
...new Set(
|
|
422
|
+
activeMemberships
|
|
423
|
+
.map((membership) => membership.databaseId)
|
|
424
|
+
.filter((databaseId) => !transitioningOwnedDatabaseIds.has(databaseId)),
|
|
425
|
+
),
|
|
426
|
+
].sort();
|
|
427
|
+
for (const databaseId of externalDatabaseIds) {
|
|
428
|
+
await touchContentDatabase(db, databaseId, trashedAt);
|
|
429
|
+
}
|
|
430
|
+
|
|
294
431
|
for (const batch of chunks(activeDocumentIds, DELETE_BATCH_SIZE)) {
|
|
295
432
|
await db
|
|
296
433
|
.update(schema.documents)
|
|
@@ -322,19 +459,55 @@ export async function restoreDocumentSubtree(
|
|
|
322
459
|
rootId: string,
|
|
323
460
|
ownerEmail: string,
|
|
324
461
|
): Promise<string[]> {
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
462
|
+
const collectRestoreScope = async () => {
|
|
463
|
+
const documentIds = (
|
|
464
|
+
await db
|
|
465
|
+
.select({ id: schema.documents.id })
|
|
466
|
+
.from(schema.documents)
|
|
467
|
+
.where(
|
|
468
|
+
and(
|
|
469
|
+
eq(schema.documents.trashRootId, rootId),
|
|
470
|
+
eq(schema.documents.ownerEmail, ownerEmail),
|
|
471
|
+
),
|
|
472
|
+
)
|
|
473
|
+
).map((document) => document.id);
|
|
474
|
+
const memberships = await selectMembershipsForDocuments(db, documentIds);
|
|
475
|
+
const ownedDatabaseIds = (
|
|
476
|
+
await selectOwnedDatabaseIds(db, documentIds, ownerEmail)
|
|
477
|
+
).map((database) => database.id);
|
|
478
|
+
return { documentIds, memberships, ownedDatabaseIds };
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
const initialScope = await collectRestoreScope();
|
|
482
|
+
if (initialScope.documentIds.length === 0) return [];
|
|
483
|
+
const lockedDatabaseIds = [
|
|
484
|
+
...new Set([
|
|
485
|
+
...initialScope.ownedDatabaseIds,
|
|
486
|
+
...initialScope.memberships.map((membership) => membership.databaseId),
|
|
487
|
+
]),
|
|
488
|
+
].sort();
|
|
489
|
+
for (const databaseId of lockedDatabaseIds) {
|
|
490
|
+
await lockContentDatabaseMutation(db, databaseId);
|
|
491
|
+
}
|
|
337
492
|
|
|
493
|
+
const restoreScope = await collectRestoreScope();
|
|
494
|
+
const lockedDatabaseIdSet = new Set(lockedDatabaseIds);
|
|
495
|
+
const unlockedDatabaseId = [
|
|
496
|
+
...new Set([
|
|
497
|
+
...restoreScope.ownedDatabaseIds,
|
|
498
|
+
...restoreScope.memberships.map((membership) => membership.databaseId),
|
|
499
|
+
]),
|
|
500
|
+
].find((databaseId) => !lockedDatabaseIdSet.has(databaseId));
|
|
501
|
+
if (unlockedDatabaseId) {
|
|
502
|
+
throw new Error("Document restore scope changed; retry restoration.");
|
|
503
|
+
}
|
|
504
|
+
await lockDatabaseMemberships(
|
|
505
|
+
db,
|
|
506
|
+
await selectMembershipIdsForDatabases(db, lockedDatabaseIds),
|
|
507
|
+
);
|
|
508
|
+
|
|
509
|
+
const documentIds = restoreScope.documentIds;
|
|
510
|
+
if (documentIds.length === 0) return [];
|
|
338
511
|
const now = new Date().toISOString();
|
|
339
512
|
for (const batch of chunks(documentIds, DELETE_BATCH_SIZE)) {
|
|
340
513
|
await db
|
|
@@ -399,20 +572,49 @@ export async function deleteDocumentRecursive(
|
|
|
399
572
|
id: string,
|
|
400
573
|
ownerEmail: string,
|
|
401
574
|
): Promise<string[]> {
|
|
402
|
-
return db.transaction(
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
ownerEmail,
|
|
407
|
-
() => collectDocumentSubtreeForDelete(scopedDb, id, ownerEmail),
|
|
408
|
-
);
|
|
409
|
-
return deleteCollectedDocuments(
|
|
410
|
-
scopedDb,
|
|
411
|
-
documentIds,
|
|
412
|
-
ownedDatabaseIds,
|
|
575
|
+
return db.transaction((tx) =>
|
|
576
|
+
deleteDocumentRootsRecursive(
|
|
577
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
578
|
+
[id],
|
|
413
579
|
ownerEmail,
|
|
414
|
-
)
|
|
415
|
-
|
|
580
|
+
),
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export async function deleteDocumentRootsRecursive(
|
|
585
|
+
db: ReturnType<typeof getDb>,
|
|
586
|
+
rootIds: string[],
|
|
587
|
+
ownerEmail: string,
|
|
588
|
+
): Promise<string[]> {
|
|
589
|
+
const collectScope = async () => {
|
|
590
|
+
const documentIds = new Set<string>();
|
|
591
|
+
const ownedDatabaseIds = new Set<string>();
|
|
592
|
+
for (const rootId of rootIds) {
|
|
593
|
+
const scope = await collectDocumentSubtreeForDelete(
|
|
594
|
+
db,
|
|
595
|
+
rootId,
|
|
596
|
+
ownerEmail,
|
|
597
|
+
);
|
|
598
|
+
for (const documentId of scope.documentIds) documentIds.add(documentId);
|
|
599
|
+
for (const databaseId of scope.ownedDatabaseIds) {
|
|
600
|
+
ownedDatabaseIds.add(databaseId);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
documentIds: [...documentIds],
|
|
605
|
+
ownedDatabaseIds: [...ownedDatabaseIds],
|
|
606
|
+
};
|
|
607
|
+
};
|
|
608
|
+
const { documentIds, ownedDatabaseIds } = await lockPermanentDeleteScope(
|
|
609
|
+
db,
|
|
610
|
+
collectScope,
|
|
611
|
+
);
|
|
612
|
+
return deleteCollectedDocuments(
|
|
613
|
+
db,
|
|
614
|
+
documentIds,
|
|
615
|
+
ownedDatabaseIds,
|
|
616
|
+
ownerEmail,
|
|
617
|
+
);
|
|
416
618
|
}
|
|
417
619
|
|
|
418
620
|
async function deleteCollectedDocuments(
|
|
@@ -515,6 +717,7 @@ async function deleteCollectedDocuments(
|
|
|
515
717
|
),
|
|
516
718
|
);
|
|
517
719
|
});
|
|
720
|
+
|
|
518
721
|
await deleteWhereIn(documentIds, async (documentIdBatch) => {
|
|
519
722
|
await db
|
|
520
723
|
.delete(schema.contentDatabaseItemKeyClaims)
|
|
@@ -570,6 +773,17 @@ async function deleteCollectedDocuments(
|
|
|
570
773
|
await db
|
|
571
774
|
.delete(schema.contentDatabases)
|
|
572
775
|
.where(inArray(schema.contentDatabases.id, databaseIdBatch));
|
|
776
|
+
// Receipts deliberately have no database foreign key. Removing them after
|
|
777
|
+
// the database row closes the race with a migration that already holds the
|
|
778
|
+
// row lock and commits its receipt before this deletion can continue.
|
|
779
|
+
await db
|
|
780
|
+
.delete(schema.contentDatabaseMigrationReceipts)
|
|
781
|
+
.where(
|
|
782
|
+
inArray(
|
|
783
|
+
schema.contentDatabaseMigrationReceipts.databaseId,
|
|
784
|
+
databaseIdBatch,
|
|
785
|
+
),
|
|
786
|
+
);
|
|
573
787
|
});
|
|
574
788
|
|
|
575
789
|
await deleteWhereIn(documentIds, async (documentIdBatch) => {
|
|
@@ -629,74 +843,63 @@ export async function deleteTrashedDocumentSubtree(
|
|
|
629
843
|
id: string,
|
|
630
844
|
ownerEmail: string,
|
|
631
845
|
): Promise<string[]> {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
846
|
+
const collectScope = async () => {
|
|
847
|
+
const [root] = await db
|
|
848
|
+
.select({ id: schema.documents.id })
|
|
849
|
+
.from(schema.documents)
|
|
850
|
+
.where(
|
|
851
|
+
and(
|
|
852
|
+
eq(schema.documents.id, id),
|
|
853
|
+
eq(schema.documents.ownerEmail, ownerEmail),
|
|
854
|
+
eq(schema.documents.trashRootId, id),
|
|
855
|
+
isNotNull(schema.documents.trashedAt),
|
|
856
|
+
),
|
|
857
|
+
)
|
|
858
|
+
.limit(1);
|
|
859
|
+
if (!root) {
|
|
860
|
+
throw new Error(
|
|
861
|
+
"Document must be in Trash and be a Trash root before permanent deletion",
|
|
862
|
+
);
|
|
863
|
+
}
|
|
640
864
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
.
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
865
|
+
const documentIds = (
|
|
866
|
+
await db
|
|
867
|
+
.select({ id: schema.documents.id })
|
|
868
|
+
.from(schema.documents)
|
|
869
|
+
.where(
|
|
870
|
+
and(
|
|
871
|
+
eq(schema.documents.ownerEmail, ownerEmail),
|
|
872
|
+
eq(schema.documents.trashRootId, id),
|
|
873
|
+
isNotNull(schema.documents.trashedAt),
|
|
874
|
+
),
|
|
875
|
+
)
|
|
876
|
+
).map((document) => document.id);
|
|
877
|
+
const ownedDatabaseIds = await selectOwnedDatabaseIds(
|
|
878
|
+
db,
|
|
879
|
+
documentIds,
|
|
880
|
+
ownerEmail,
|
|
881
|
+
).then((rows) => rows.map((database) => database.id));
|
|
882
|
+
const documentIdSet = new Set(documentIds);
|
|
883
|
+
const activeOutsideScope = (
|
|
884
|
+
await selectDatabaseItemDocumentTrashState(
|
|
885
|
+
db,
|
|
886
|
+
ownedDatabaseIds,
|
|
887
|
+
ownerEmail,
|
|
888
|
+
)
|
|
889
|
+
).find(
|
|
890
|
+
(document) => !documentIdSet.has(document.id) && !document.trashedAt,
|
|
661
891
|
);
|
|
662
|
-
|
|
892
|
+
if (activeOutsideScope) {
|
|
893
|
+
throw new Error(
|
|
894
|
+
"Database contains an active row outside this Trash item",
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
return { documentIds, ownedDatabaseIds };
|
|
898
|
+
};
|
|
663
899
|
|
|
664
|
-
const { documentIds, ownedDatabaseIds } = await
|
|
900
|
+
const { documentIds, ownedDatabaseIds } = await lockPermanentDeleteScope(
|
|
665
901
|
db,
|
|
666
|
-
|
|
667
|
-
async () => {
|
|
668
|
-
const collectedDocumentIds = (
|
|
669
|
-
await db
|
|
670
|
-
.select({ id: schema.documents.id })
|
|
671
|
-
.from(schema.documents)
|
|
672
|
-
.where(
|
|
673
|
-
and(
|
|
674
|
-
eq(schema.documents.ownerEmail, ownerEmail),
|
|
675
|
-
eq(schema.documents.trashRootId, id),
|
|
676
|
-
isNotNull(schema.documents.trashedAt),
|
|
677
|
-
),
|
|
678
|
-
)
|
|
679
|
-
).map((document) => document.id);
|
|
680
|
-
const collectedDatabaseIds = await selectOwnedDatabaseIds(
|
|
681
|
-
db,
|
|
682
|
-
collectedDocumentIds,
|
|
683
|
-
ownerEmail,
|
|
684
|
-
).then((rows) => rows.map((database) => database.id));
|
|
685
|
-
return {
|
|
686
|
-
documentIds: collectedDocumentIds,
|
|
687
|
-
ownedDatabaseIds: collectedDatabaseIds,
|
|
688
|
-
lockDatabaseIds: [
|
|
689
|
-
...new Set([
|
|
690
|
-
...collectedDatabaseIds,
|
|
691
|
-
...(await selectMembershipDatabaseIds(
|
|
692
|
-
db,
|
|
693
|
-
collectedDocumentIds,
|
|
694
|
-
ownerEmail,
|
|
695
|
-
)),
|
|
696
|
-
]),
|
|
697
|
-
],
|
|
698
|
-
};
|
|
699
|
-
},
|
|
902
|
+
collectScope,
|
|
700
903
|
);
|
|
701
904
|
|
|
702
905
|
await db
|
|
@@ -760,9 +963,19 @@ export default defineAction({
|
|
|
760
963
|
if (!membership) {
|
|
761
964
|
throw new Error("Document is not part of Favorites");
|
|
762
965
|
}
|
|
763
|
-
await db
|
|
764
|
-
|
|
765
|
-
|
|
966
|
+
await db.transaction(async (tx) => {
|
|
967
|
+
await lockContentDatabaseMutation(
|
|
968
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
969
|
+
contextDatabase.id,
|
|
970
|
+
);
|
|
971
|
+
await touchContentDatabase(
|
|
972
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
973
|
+
contextDatabase.id,
|
|
974
|
+
);
|
|
975
|
+
await tx
|
|
976
|
+
.delete(schema.contentDatabaseItems)
|
|
977
|
+
.where(eq(schema.contentDatabaseItems.id, membership.id));
|
|
978
|
+
});
|
|
766
979
|
await writeAppState("refresh-signal", { ts: Date.now() });
|
|
767
980
|
return { success: true, deleted: 0, removed: 1 };
|
|
768
981
|
}
|
|
@@ -777,11 +990,21 @@ export default defineAction({
|
|
|
777
990
|
if (systemDatabase?.systemRole) {
|
|
778
991
|
throw new Error("System Content database documents cannot be deleted");
|
|
779
992
|
}
|
|
780
|
-
const deleted = await
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
993
|
+
const deleted = await db.transaction(async (tx) => {
|
|
994
|
+
const transactionDb = tx as unknown as ReturnType<typeof getDb>;
|
|
995
|
+
const lockedDatabaseIds = await lockDatabasesForTrash(
|
|
996
|
+
transactionDb,
|
|
997
|
+
id,
|
|
998
|
+
existing.ownerEmail as string,
|
|
999
|
+
);
|
|
1000
|
+
return trashDocumentSubtree(
|
|
1001
|
+
transactionDb,
|
|
1002
|
+
id,
|
|
1003
|
+
existing.ownerEmail as string,
|
|
1004
|
+
undefined,
|
|
1005
|
+
lockedDatabaseIds,
|
|
1006
|
+
);
|
|
1007
|
+
});
|
|
785
1008
|
|
|
786
1009
|
await writeAppState("refresh-signal", { ts: Date.now() });
|
|
787
1010
|
|