@agent-native/core 0.90.1 → 0.90.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +14 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +11 -6
- package/corpus/core/src/client/use-action.ts +39 -2
- package/corpus/core/src/client/use-db-sync.ts +44 -18
- package/corpus/core/src/db/create-get-db.ts +32 -2
- package/corpus/core/src/server/framework-request-handler.ts +52 -4
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +34 -6
- package/corpus/templates/assets/AGENTS.md +23 -4
- package/corpus/templates/assets/actions/_generation-preset-settings.ts +48 -0
- package/corpus/templates/assets/actions/_helpers.ts +8 -1
- package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +64 -0
- package/corpus/templates/assets/actions/create-generation-preset.ts +11 -3
- package/corpus/templates/assets/actions/generate-image-batch.ts +7 -2
- package/corpus/templates/assets/actions/generate-image.ts +342 -25
- package/corpus/templates/assets/actions/get-library.ts +4 -3
- package/corpus/templates/assets/actions/navigate.ts +2 -1
- package/corpus/templates/assets/actions/refresh-generation-run.ts +5 -1
- package/corpus/templates/assets/actions/update-asset.ts +1 -0
- package/corpus/templates/assets/actions/update-generation-preset.ts +8 -1
- package/corpus/templates/assets/actions/view-screen.ts +8 -1
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +9 -1
- package/corpus/templates/assets/app/hooks/use-image-model-menu.ts +1 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +11 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +64 -0
- package/corpus/templates/assets/app/i18n-data.ts +650 -0
- package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +44 -33
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1474 -0
- package/corpus/templates/assets/app/routes/library.tsx +43 -1
- package/corpus/templates/assets/server/lib/generation.ts +366 -44
- package/corpus/templates/assets/server/lib/image-processing.ts +252 -0
- package/corpus/templates/assets/server/lib/preset-skeleton.ts +137 -0
- package/corpus/templates/assets/shared/api.ts +47 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -2
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +114 -33
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +27 -1
- package/corpus/templates/clips/app/routes/record.tsx +157 -68
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +5 -5
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +20 -3
- package/corpus/templates/clips/shared/finalize-recovery.ts +23 -3
- package/corpus/templates/content/AGENTS.md +52 -52
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +188 -8
- package/corpus/templates/content/actions/_builder-docs-client.ts +41 -3
- package/corpus/templates/content/actions/_database-source-utils.ts +998 -160
- package/corpus/templates/content/actions/_database-utils.ts +44 -4
- package/corpus/templates/content/actions/_notion-action-utils.ts +6 -2
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +85 -12
- package/corpus/templates/content/actions/change-content-database-source-role.ts +9 -1
- package/corpus/templates/content/actions/delete-content-database.ts +1 -0
- package/corpus/templates/content/actions/get-document.ts +11 -2
- package/corpus/templates/content/actions/list-content-databases.ts +57 -9
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +23 -6
- package/corpus/templates/content/actions/refresh-content-database-source.ts +26 -3
- package/corpus/templates/content/actions/restore-content-database.ts +1 -0
- package/corpus/templates/content/actions/update-document.ts +43 -0
- package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +21 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +0 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +70 -28
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +69 -17
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +4 -4
- package/corpus/templates/content/app/components/editor/body-hydration.ts +112 -0
- package/corpus/templates/content/app/components/editor/builder-body-hydration-pump.ts +52 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +9076 -2876
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +41 -1
- package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +36 -11
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +21 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -1
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +11 -8
- package/corpus/templates/content/app/global.css +41 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +346 -42
- package/corpus/templates/content/app/hooks/use-db-sync.ts +9 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +47 -0
- package/corpus/templates/content/app/hooks/use-notion.ts +12 -10
- package/corpus/templates/content/app/i18n/zh-TW.ts +35 -0
- package/corpus/templates/content/app/i18n-data.ts +355 -0
- package/corpus/templates/content/app/root.tsx +22 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-database-sources-keep-loading-rows-in-the-background.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attach-starts-with-usable-rows.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attachment-now-stays-connected-after-large.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-refreshes-now-show-progress-for-large-docs-blog.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-database-pages-now-delete-to-trash-without-route-errors.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-source-refreshes-recover-from-stalled-background-row.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-sourced-rows-open-with-sync-protection.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-database-rows-and-pages-open-faster-from-recently-loaded-dat.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-preview-panels-close-reliably-narrow-sidebar-row-actions-sta.md +6 -0
- package/corpus/templates/content/changelog/2026-07-06-builder-sync-progress-no-longer-shows-continue.md +6 -0
- package/corpus/templates/content/shared/api.ts +13 -0
- package/corpus/templates/content/shared/builder-mdx.ts +16 -3
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +23 -13
- package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +98 -0
- package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +162 -0
- package/corpus/templates/design/AGENTS.md +9 -2
- package/corpus/templates/design/actions/add-breakpoint.ts +6 -3
- package/corpus/templates/design/actions/apply-a11y-fix.ts +57 -37
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +41 -20
- package/corpus/templates/design/actions/apply-motion-edit.ts +251 -38
- package/corpus/templates/design/actions/apply-shader-fill.ts +90 -66
- package/corpus/templates/design/actions/apply-visual-edit.ts +282 -55
- package/corpus/templates/design/actions/create-component.ts +29 -60
- package/corpus/templates/design/actions/create-file.ts +9 -2
- package/corpus/templates/design/actions/duplicate-design.ts +31 -2
- package/corpus/templates/design/actions/edit-design.ts +36 -38
- package/corpus/templates/design/actions/generate-design-title.ts +87 -0
- package/corpus/templates/design/actions/generate-design.ts +53 -18
- package/corpus/templates/design/actions/generate-screens.ts +108 -4
- package/corpus/templates/design/actions/get-motion-timeline.ts +35 -7
- package/corpus/templates/design/actions/insert-asset.ts +34 -29
- package/corpus/templates/design/actions/insert-design-native-asset.ts +129 -32
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +35 -30
- package/corpus/templates/design/actions/present-design-variants.ts +7 -2
- package/corpus/templates/design/actions/remove-motion-timeline.ts +31 -36
- package/corpus/templates/design/actions/update-file.ts +190 -75
- package/corpus/templates/design/app/components/design/BreakpointBar.tsx +403 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +469 -222
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +708 -53
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +83 -3
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1091 -6948
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +419 -85
- package/corpus/templates/design/app/components/design/MotionDock.tsx +1124 -103
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2610 -1398
- package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +22 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2182 -235
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +187 -11
- package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +376 -1
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +746 -0
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +17 -0
- package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +1 -1
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +1 -3
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +1 -1
- package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +518 -0
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +562 -0
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +763 -0
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +94 -0
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +780 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +446 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +79 -0
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +315 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +344 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +594 -0
- package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +119 -0
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +248 -0
- package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +45 -0
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +693 -0
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +724 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +207 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +628 -0
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +91 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +649 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-change-types.ts +118 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +88 -0
- package/corpus/templates/design/app/components/design/edit-panel/transform-helpers.ts +100 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +117 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +501 -0
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +91 -40
- package/corpus/templates/design/app/components/design/inspector/BreakpointOverrideIndicator.tsx +82 -0
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +189 -87
- package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +1097 -0
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +44 -0
- package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +258 -0
- package/corpus/templates/design/app/components/design/inspector/MotionKeyframeDiamond.tsx +144 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +99 -9
- package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +116 -0
- package/corpus/templates/design/app/components/design/inspector/index.ts +26 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +29 -0
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +171 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +220 -0
- package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +35 -0
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +134 -0
- package/corpus/templates/design/app/components/design/multi-screen/culling.ts +185 -0
- package/corpus/templates/design/app/components/design/multi-screen/gradient-overlay-geometry.ts +120 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +892 -0
- package/corpus/templates/design/app/components/design/multi-screen/vector-edit-geometry.ts +21 -0
- package/corpus/templates/design/app/components/design/types.ts +15 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +109 -5
- package/corpus/templates/design/app/global.css +8 -8
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +259 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +163 -9
- package/corpus/templates/design/app/i18n-breakpoints.ts +205 -0
- package/corpus/templates/design/app/i18n-data.ts +1664 -152
- package/corpus/templates/design/app/i18n-motion.ts +563 -0
- package/corpus/templates/design/app/lib/design-import.ts +73 -0
- package/corpus/templates/design/app/pages/Index.tsx +41 -22
- package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +1 -1
- package/corpus/templates/design/changelog/2026-07-05-designs-get-ai-generated-names-from-your-prompt.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-local-code-screens-keep-their-connection-when-duplicated-and.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-press-a-to-draw-screens-on-the-canvas-inside-a-screen-it-dr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-3d-rotation-and-perspective-controls-on-every-element.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-ai-generated-and-duplicated-screens-now-get-their-editor-sel.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-applying-shaders-and-fills-in-quick-succession-can-no-longer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-frames-in-the-overview-now-support-click-to-selec.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-segments-in-the-inspector-now-show-a-device-icon-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-targeting-now-lives-in-one-compact-control-in-the.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-can-no-longer-be-overwritten-by-stale-collabora.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-inside-screens-save-reliably-again.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-cleaner-inspector-removed-the-ask-ai-box-from-the-design-tab.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-clicking-empty-canvas-space-now-deselects-an-element-inside-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-an-element-onto-a-rectangle-now-nests-it-inside-wit.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-screens-and-objects-on-the-canvas-is-now-much-smoot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-drawing-a-shape-or-text-on-the-canvas-no-longer-flashes-away.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dropping-an-element-between-two-others-inside-a-screen-now-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-duplicating-a-screen-now-places-the-copy-exactly-where-you-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edit-gradients-directly-on-elements-inside-screens-scale-str.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edits-from-collaborators-and-the-agent-now-update-the-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-bug-where-most-style-position-and-text-edits-briefly.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-confusing-raw-error-message-when-a-file-upload-fails.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-rare-case-where-an-edit-could-be-silently-overwritte.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inserted-assets-sometimes-disappearing-reappearing-or-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inspector-value-scrubbing-producing-erratic-numbers-an.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-padding-gap-and-min-max-size-scrubbing-not-updating-th.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-text-stroke-color-turning-black-and-glyphs-disappearin.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-collapsed-effects-and-stroke-inspector-sections-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-new-design-dialog-closing-unexpectedly-when-using-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-typography-section-missing-when-selecting-text-nes.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-full-view-no-longer-flashes-back-to-the-overview-on-entry-no.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-keyframe-animation-timeline-per-property-keyframes-easing-cu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-moving-restyling-and-scrubbing-values-on-elements-in-ai-gene.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-and-corner-radius-value-scrubbing-now-snaps-to-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-handles-now-only-resize-on-the-handle-line-itself-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-preview-and-edit-hover-focus-and-pressed-states-with-real-cs.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-promoting-an-element-to-a-component-now-works-correctly-for-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-reduced-url-history-churn-and-selection-overlay-flicker-whil.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-removed-the-decorative-dot-before-screen-names-in-the-overvi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-responsive-breakpoints-edit-at-any-width-with-cascading-over.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-screen-labels-no-longer-turn-blue-when-you-hover-inside-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-scrolling-a-screen-with-an-element-selected-stays-smooth-on-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selecting-multiple-elements-and-dragging-now-moves-the-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-borders-handles-and-value-readouts-now-stay-the-sa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-handles-and-editing-chrome-now-stay-a-constant-siz.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-shader-fills-and-effects-ai-authored-or-preset-glsl-shaders-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-drawn-on-the-canvas-now-defaults-to-white-and-inter-in-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-dropped-into-a-shape-now-stays-readable-instead-of-disa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-add-tweak-controls-prompt-no-longer-jumps-to-the-corner-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-padding-value-readout-now-stays-visible-while-you-hover-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-selected-element-attachment-now-clears-from-the-chat-com.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-zoom-menu-is-more-compact-with-tight-rows-and-right-alig.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-undo-and-redo-no-longer-flash-the-screen-changes-now-apply-i.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-zoom-presets-like-zoom-to-50-now-stay-on-the-focused-screen-.md +6 -0
- package/corpus/templates/design/server/lib/import-design-files.ts +11 -2
- package/corpus/templates/design/server/source-workspace.ts +139 -59
- package/corpus/templates/design/shared/board-file.ts +11 -2
- package/corpus/templates/design/shared/breakpoint-media.ts +543 -0
- package/corpus/templates/design/shared/canvas-math.ts +354 -35
- package/corpus/templates/design/shared/code-layer.ts +277 -8
- package/corpus/templates/design/shared/design-state.ts +11 -4
- package/corpus/templates/design/shared/interaction-states.ts +548 -0
- package/corpus/templates/design/shared/motion-compiler.ts +186 -23
- package/corpus/templates/design/shared/motion-easing.ts +294 -0
- package/corpus/templates/design/shared/motion-timeline.ts +400 -34
- package/corpus/templates/design/shared/prompt-title.ts +95 -0
- package/corpus/templates/design/shared/responsive-classes.ts +448 -10
- package/corpus/templates/design/shared/screen-annotation.ts +46 -0
- package/corpus/templates/design/shared/shader-fills.ts +1009 -0
- package/corpus/templates/design/shared/shader-presets.ts +852 -4
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +15 -2
- package/corpus/templates/slides/app/components/editor/ImportButton.tsx +10 -1
- package/corpus/templates/slides/app/lib/upload-response.ts +71 -0
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/client/use-action.d.ts +3 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +34 -3
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +37 -18
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/create-get-db.d.ts +25 -0
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +25 -2
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +37 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/package.json +1 -1
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +0 -153
- package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +0 -133
- package/corpus/templates/design/app/pages/DesignEditor.tsx +0 -22924
|
@@ -6,8 +6,10 @@ import type {
|
|
|
6
6
|
BuilderCmsModelsResponse,
|
|
7
7
|
ChangeContentDatabaseSourceRoleRequest,
|
|
8
8
|
ContentDatabaseResponse,
|
|
9
|
+
ContentDatabaseSourceFieldMapping,
|
|
9
10
|
CreateInlineDatabaseRequest,
|
|
10
11
|
CreateInlineDatabaseResponse,
|
|
12
|
+
DocumentPropertyType,
|
|
11
13
|
ListTrashedContentDatabasesResponse,
|
|
12
14
|
ListContentDatabasesResponse,
|
|
13
15
|
ContentDatabaseSourceFieldPropertyResponse,
|
|
@@ -33,17 +35,122 @@ import type {
|
|
|
33
35
|
UpdateContentDatabaseViewRequest,
|
|
34
36
|
ValidateBuilderSourceExecutionRequest,
|
|
35
37
|
} from "@shared/api";
|
|
38
|
+
import type { Query, QueryClient } from "@tanstack/react-query";
|
|
36
39
|
import { useQueryClient } from "@tanstack/react-query";
|
|
37
40
|
|
|
38
41
|
export function contentDatabaseQueryKey(documentId: string) {
|
|
39
42
|
return ["action", "get-content-database", { documentId }] as const;
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
function isContentDatabaseQueryForDocument(
|
|
46
|
+
queryKey: readonly unknown[],
|
|
47
|
+
documentId: string,
|
|
48
|
+
) {
|
|
49
|
+
if (
|
|
50
|
+
queryKey[0] !== "action" ||
|
|
51
|
+
queryKey[1] !== "get-content-database" ||
|
|
52
|
+
!queryKey[2] ||
|
|
53
|
+
typeof queryKey[2] !== "object"
|
|
54
|
+
) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const params = queryKey[2] as { documentId?: unknown };
|
|
58
|
+
return params.documentId === documentId;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function contentDatabaseQueryFilter(documentId: string) {
|
|
62
|
+
return {
|
|
63
|
+
queryKey: ["action", "get-content-database"],
|
|
64
|
+
predicate: (query: Query) =>
|
|
65
|
+
isContentDatabaseQueryForDocument(query.queryKey, documentId),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function writeContentDatabaseResponseToCache(
|
|
70
|
+
queryClient: Pick<QueryClient, "setQueryData" | "setQueriesData">,
|
|
71
|
+
documentId: string,
|
|
72
|
+
data: ContentDatabaseResponse,
|
|
73
|
+
) {
|
|
74
|
+
queryClient.setQueryData<ContentDatabaseResponse>(
|
|
75
|
+
contentDatabaseQueryKey(documentId),
|
|
76
|
+
data,
|
|
77
|
+
);
|
|
78
|
+
queryClient.setQueriesData<ContentDatabaseResponse>(
|
|
79
|
+
contentDatabaseQueryFilter(documentId),
|
|
80
|
+
data,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// `get-content-database` returns a union at runtime: the full response, or an
|
|
85
|
+
// unavailable payload (`{ available: false, reason: "deleted" | "not_found" }`)
|
|
86
|
+
// with no `database` field. Consumers typed against ContentDatabaseResponse
|
|
87
|
+
// must narrow with this guard before touching `data.database`.
|
|
88
|
+
export function isContentDatabaseUnavailable(
|
|
89
|
+
data: unknown,
|
|
90
|
+
): data is { available: false; reason: string } {
|
|
91
|
+
return (
|
|
92
|
+
!!data &&
|
|
93
|
+
typeof data === "object" &&
|
|
94
|
+
(data as { available?: unknown }).available === false
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function readCachedContentDatabaseResponse(
|
|
99
|
+
queryClient: Pick<QueryClient, "getQueryData" | "getQueriesData">,
|
|
100
|
+
documentId: string,
|
|
101
|
+
) {
|
|
102
|
+
const exact = queryClient.getQueryData<ContentDatabaseResponse>(
|
|
103
|
+
contentDatabaseQueryKey(documentId),
|
|
104
|
+
);
|
|
105
|
+
if (exact && !isContentDatabaseUnavailable(exact)) return exact;
|
|
106
|
+
|
|
107
|
+
const cached = queryClient
|
|
108
|
+
.getQueriesData<ContentDatabaseResponse>(
|
|
109
|
+
contentDatabaseQueryFilter(documentId),
|
|
110
|
+
)
|
|
111
|
+
.find(([, data]) => data && !isContentDatabaseUnavailable(data));
|
|
112
|
+
return cached?.[1];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function clearDeletedContentDatabaseFromCache(
|
|
116
|
+
queryClient: Pick<QueryClient, "removeQueries" | "invalidateQueries">,
|
|
117
|
+
documentId: string,
|
|
118
|
+
) {
|
|
119
|
+
queryClient.removeQueries(contentDatabaseQueryFilter(documentId));
|
|
120
|
+
queryClient.removeQueries({
|
|
121
|
+
queryKey: ["action", "get-document", { id: documentId }],
|
|
122
|
+
});
|
|
123
|
+
queryClient.invalidateQueries({
|
|
124
|
+
queryKey: ["action", "get-content-database"],
|
|
125
|
+
});
|
|
126
|
+
queryClient.invalidateQueries({
|
|
127
|
+
queryKey: ["action", "get-document"],
|
|
128
|
+
});
|
|
129
|
+
queryClient.invalidateQueries({
|
|
130
|
+
queryKey: ["action", "list-documents"],
|
|
131
|
+
});
|
|
132
|
+
queryClient.invalidateQueries({
|
|
133
|
+
queryKey: ["action", "list-trashed-content-databases"],
|
|
134
|
+
});
|
|
135
|
+
queryClient.invalidateQueries({
|
|
136
|
+
queryKey: ["action", "list-content-databases"],
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
42
140
|
export function applySourceFieldPropertyToDatabaseResponse(
|
|
43
141
|
current: ContentDatabaseResponse | undefined,
|
|
44
142
|
patch: ContentDatabaseSourceFieldPropertyResponse,
|
|
45
143
|
): ContentDatabaseResponse | undefined {
|
|
46
144
|
if (!current || current.database.id !== patch.databaseId) return current;
|
|
145
|
+
const patchSource = (source: ContentDatabaseResponse["source"]) =>
|
|
146
|
+
source
|
|
147
|
+
? {
|
|
148
|
+
...source,
|
|
149
|
+
fields: source.fields.map((field) =>
|
|
150
|
+
field.id === patch.sourceField.id ? patch.sourceField : field,
|
|
151
|
+
),
|
|
152
|
+
}
|
|
153
|
+
: source;
|
|
47
154
|
|
|
48
155
|
const hasProperty = current.properties.some(
|
|
49
156
|
(property) => property.definition.id === patch.property.definition.id,
|
|
@@ -87,18 +194,141 @@ export function applySourceFieldPropertyToDatabaseResponse(
|
|
|
87
194
|
: [...item.properties, nextProperty],
|
|
88
195
|
};
|
|
89
196
|
}),
|
|
90
|
-
source: current.source
|
|
197
|
+
source: patchSource(current.source),
|
|
198
|
+
sources: current.sources?.map((source) => patchSource(source)!),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function propertyTypeForOptimisticSourceField(
|
|
203
|
+
sourceFieldType: string,
|
|
204
|
+
): DocumentPropertyType {
|
|
205
|
+
if (sourceFieldType === "number") return "number";
|
|
206
|
+
if (sourceFieldType === "datetime" || sourceFieldType === "date") {
|
|
207
|
+
return "date";
|
|
208
|
+
}
|
|
209
|
+
if (sourceFieldType === "url") return "url";
|
|
210
|
+
if (sourceFieldType === "boolean" || sourceFieldType === "checkbox") {
|
|
211
|
+
return "checkbox";
|
|
212
|
+
}
|
|
213
|
+
return "text";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function optimisticSourceFieldPropertyId(sourceFieldId: string) {
|
|
217
|
+
return `optimistic-source-field-property:${sourceFieldId}`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function findSourceFieldById(
|
|
221
|
+
current: ContentDatabaseResponse,
|
|
222
|
+
sourceFieldId: string,
|
|
223
|
+
): ContentDatabaseSourceFieldMapping | null {
|
|
224
|
+
const sources = current.sources ?? (current.source ? [current.source] : []);
|
|
225
|
+
for (const source of sources) {
|
|
226
|
+
const field = source.fields.find(
|
|
227
|
+
(candidate) => candidate.id === sourceFieldId,
|
|
228
|
+
);
|
|
229
|
+
if (field) return field;
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function applyOptimisticSourceFieldPropertyToDatabaseResponse(
|
|
235
|
+
current: ContentDatabaseResponse | undefined,
|
|
236
|
+
variables: AddContentDatabaseSourceFieldPropertyRequest,
|
|
237
|
+
): ContentDatabaseResponse | undefined {
|
|
238
|
+
if (
|
|
239
|
+
!current ||
|
|
240
|
+
(current.database.id !== variables.documentId &&
|
|
241
|
+
current.database.documentId !== variables.documentId)
|
|
242
|
+
) {
|
|
243
|
+
return current;
|
|
244
|
+
}
|
|
245
|
+
const field = findSourceFieldById(current, variables.sourceFieldId);
|
|
246
|
+
if (!field || field.propertyId) return current;
|
|
247
|
+
|
|
248
|
+
const propertyId = optimisticSourceFieldPropertyId(field.id);
|
|
249
|
+
const now = new Date().toISOString();
|
|
250
|
+
const position =
|
|
251
|
+
Math.max(
|
|
252
|
+
-1,
|
|
253
|
+
...current.properties.map((property) => property.definition.position),
|
|
254
|
+
) + 1;
|
|
255
|
+
const property = {
|
|
256
|
+
definition: {
|
|
257
|
+
id: propertyId,
|
|
258
|
+
databaseId: current.database.id,
|
|
259
|
+
name: field.sourceFieldLabel,
|
|
260
|
+
type: propertyTypeForOptimisticSourceField(field.sourceFieldType),
|
|
261
|
+
visibility: "always_show" as const,
|
|
262
|
+
options: {},
|
|
263
|
+
position,
|
|
264
|
+
createdAt: now,
|
|
265
|
+
updatedAt: now,
|
|
266
|
+
},
|
|
267
|
+
value: null,
|
|
268
|
+
editable: false,
|
|
269
|
+
};
|
|
270
|
+
const sourceField = {
|
|
271
|
+
...field,
|
|
272
|
+
propertyId,
|
|
273
|
+
propertyName: field.sourceFieldLabel,
|
|
274
|
+
localFieldKey: propertyId,
|
|
275
|
+
freshness: "unknown" as const,
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
return applySourceFieldPropertyToDatabaseResponse(current, {
|
|
279
|
+
databaseId: current.database.id,
|
|
280
|
+
documentId: variables.documentId,
|
|
281
|
+
property,
|
|
282
|
+
sourceField,
|
|
283
|
+
itemValues: current.items.map((item) => ({
|
|
284
|
+
itemId: item.id,
|
|
285
|
+
documentId: item.document.id,
|
|
286
|
+
value: null,
|
|
287
|
+
})),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function removeOptimisticSourceFieldProperty(
|
|
292
|
+
current: ContentDatabaseResponse | undefined,
|
|
293
|
+
sourceFieldId: string,
|
|
294
|
+
): ContentDatabaseResponse | undefined {
|
|
295
|
+
if (!current) return current;
|
|
296
|
+
const propertyId = optimisticSourceFieldPropertyId(sourceFieldId);
|
|
297
|
+
const removeFromSource = (source: ContentDatabaseResponse["source"]) =>
|
|
298
|
+
source
|
|
91
299
|
? {
|
|
92
|
-
...
|
|
93
|
-
fields:
|
|
94
|
-
field.id ===
|
|
300
|
+
...source,
|
|
301
|
+
fields: source.fields.map((field) =>
|
|
302
|
+
field.id === sourceFieldId && field.propertyId === propertyId
|
|
303
|
+
? {
|
|
304
|
+
...field,
|
|
305
|
+
propertyId: null,
|
|
306
|
+
propertyName: null,
|
|
307
|
+
localFieldKey: field.sourceFieldKey,
|
|
308
|
+
freshness: "fresh" as const,
|
|
309
|
+
}
|
|
310
|
+
: field,
|
|
95
311
|
),
|
|
96
312
|
}
|
|
97
|
-
:
|
|
313
|
+
: source;
|
|
314
|
+
return {
|
|
315
|
+
...current,
|
|
316
|
+
properties: current.properties.filter(
|
|
317
|
+
(property) => property.definition.id !== propertyId,
|
|
318
|
+
),
|
|
319
|
+
items: current.items.map((item) => ({
|
|
320
|
+
...item,
|
|
321
|
+
properties: item.properties.filter(
|
|
322
|
+
(property) => property.definition.id !== propertyId,
|
|
323
|
+
),
|
|
324
|
+
})),
|
|
325
|
+
source: removeFromSource(current.source),
|
|
326
|
+
sources: current.sources?.map((source) => removeFromSource(source)!),
|
|
98
327
|
};
|
|
99
328
|
}
|
|
100
329
|
|
|
101
330
|
export function useContentDatabase(documentId: string | null, limit?: number) {
|
|
331
|
+
const queryClient = useQueryClient();
|
|
102
332
|
return useActionQuery<ContentDatabaseResponse>(
|
|
103
333
|
"get-content-database",
|
|
104
334
|
documentId ? { documentId, limit } : undefined,
|
|
@@ -106,6 +336,13 @@ export function useContentDatabase(documentId: string | null, limit?: number) {
|
|
|
106
336
|
enabled: !!documentId,
|
|
107
337
|
retry: false,
|
|
108
338
|
placeholderData: (previous) => previous,
|
|
339
|
+
initialData: () =>
|
|
340
|
+
documentId
|
|
341
|
+
? readCachedContentDatabaseResponse(queryClient, documentId)
|
|
342
|
+
: undefined,
|
|
343
|
+
// Cross-key seeds (e.g. a differently-paginated cached response) render
|
|
344
|
+
// instantly but must refetch immediately, not sit fresh for staleTime.
|
|
345
|
+
initialDataUpdatedAt: 0,
|
|
109
346
|
},
|
|
110
347
|
);
|
|
111
348
|
}
|
|
@@ -171,22 +408,16 @@ export function useCreateInlineContentDatabase(hostDocumentId: string | null) {
|
|
|
171
408
|
export function useDeleteContentDatabase() {
|
|
172
409
|
const queryClient = useQueryClient();
|
|
173
410
|
return useActionMutation<
|
|
174
|
-
{
|
|
411
|
+
{
|
|
412
|
+
success: boolean;
|
|
413
|
+
databaseId: string;
|
|
414
|
+
documentId: string;
|
|
415
|
+
deletedAt: string;
|
|
416
|
+
},
|
|
175
417
|
{ databaseId: string }
|
|
176
418
|
>("delete-content-database", {
|
|
177
|
-
onSuccess: () => {
|
|
178
|
-
queryClient.
|
|
179
|
-
queryKey: ["action", "get-content-database"],
|
|
180
|
-
});
|
|
181
|
-
queryClient.invalidateQueries({
|
|
182
|
-
queryKey: ["action", "get-document"],
|
|
183
|
-
});
|
|
184
|
-
queryClient.invalidateQueries({
|
|
185
|
-
queryKey: ["action", "list-documents"],
|
|
186
|
-
});
|
|
187
|
-
queryClient.invalidateQueries({
|
|
188
|
-
queryKey: ["action", "list-trashed-content-databases"],
|
|
189
|
-
});
|
|
419
|
+
onSuccess: (data) => {
|
|
420
|
+
clearDeletedContentDatabaseFromCache(queryClient, data.documentId);
|
|
190
421
|
},
|
|
191
422
|
});
|
|
192
423
|
}
|
|
@@ -194,7 +425,12 @@ export function useDeleteContentDatabase() {
|
|
|
194
425
|
export function useRestoreContentDatabase() {
|
|
195
426
|
const queryClient = useQueryClient();
|
|
196
427
|
return useActionMutation<
|
|
197
|
-
{
|
|
428
|
+
{
|
|
429
|
+
success: boolean;
|
|
430
|
+
databaseId: string;
|
|
431
|
+
documentId: string;
|
|
432
|
+
deletedAt: null;
|
|
433
|
+
},
|
|
198
434
|
{ databaseId: string }
|
|
199
435
|
>("restore-content-database", {
|
|
200
436
|
onSuccess: () => {
|
|
@@ -210,6 +446,9 @@ export function useRestoreContentDatabase() {
|
|
|
210
446
|
queryClient.invalidateQueries({
|
|
211
447
|
queryKey: ["action", "list-trashed-content-databases"],
|
|
212
448
|
});
|
|
449
|
+
queryClient.invalidateQueries({
|
|
450
|
+
queryKey: ["action", "list-content-databases"],
|
|
451
|
+
});
|
|
213
452
|
},
|
|
214
453
|
});
|
|
215
454
|
}
|
|
@@ -333,10 +572,14 @@ export function useAttachContentDatabaseSource(documentId: string) {
|
|
|
333
572
|
ContentDatabaseResponse,
|
|
334
573
|
AttachContentDatabaseSourceRequest
|
|
335
574
|
>("attach-content-database-source", {
|
|
336
|
-
onSuccess: () => {
|
|
575
|
+
onSuccess: (data) => {
|
|
576
|
+
writeContentDatabaseResponseToCache(queryClient, documentId, data);
|
|
337
577
|
queryClient.invalidateQueries({
|
|
338
578
|
queryKey: contentDatabaseQueryKey(documentId),
|
|
339
579
|
});
|
|
580
|
+
queryClient.invalidateQueries({
|
|
581
|
+
queryKey: ["action", "get-content-database-source", { documentId }],
|
|
582
|
+
});
|
|
340
583
|
},
|
|
341
584
|
});
|
|
342
585
|
}
|
|
@@ -364,10 +607,46 @@ export function useAddContentDatabaseSourceFieldProperty(documentId: string) {
|
|
|
364
607
|
ContentDatabaseSourceFieldPropertyResponse,
|
|
365
608
|
AddContentDatabaseSourceFieldPropertyRequest
|
|
366
609
|
>("add-content-database-source-field-property", {
|
|
610
|
+
onMutate: async (variables) => {
|
|
611
|
+
await queryClient.cancelQueries({
|
|
612
|
+
queryKey: contentDatabaseQueryKey(documentId),
|
|
613
|
+
});
|
|
614
|
+
// Patch every cached response for this document, not just the exact
|
|
615
|
+
// unpaginated key — the rendered table observes a `{documentId, limit}`
|
|
616
|
+
// key, and setQueryData does not partial-match the way invalidate does.
|
|
617
|
+
const previous = queryClient.getQueriesData<ContentDatabaseResponse>(
|
|
618
|
+
contentDatabaseQueryFilter(documentId),
|
|
619
|
+
);
|
|
620
|
+
queryClient.setQueriesData<ContentDatabaseResponse>(
|
|
621
|
+
contentDatabaseQueryFilter(documentId),
|
|
622
|
+
(current) =>
|
|
623
|
+
applyOptimisticSourceFieldPropertyToDatabaseResponse(
|
|
624
|
+
current,
|
|
625
|
+
variables,
|
|
626
|
+
),
|
|
627
|
+
);
|
|
628
|
+
return { previous };
|
|
629
|
+
},
|
|
630
|
+
onError: (_error, _variables, context) => {
|
|
631
|
+
const rollback = context as
|
|
632
|
+
| {
|
|
633
|
+
previous?: Array<
|
|
634
|
+
[readonly unknown[], ContentDatabaseResponse | undefined]
|
|
635
|
+
>;
|
|
636
|
+
}
|
|
637
|
+
| undefined;
|
|
638
|
+
for (const [queryKey, data] of rollback?.previous ?? []) {
|
|
639
|
+
queryClient.setQueryData(queryKey, data);
|
|
640
|
+
}
|
|
641
|
+
},
|
|
367
642
|
onSuccess: (data) => {
|
|
368
|
-
queryClient.
|
|
369
|
-
|
|
370
|
-
(current) =>
|
|
643
|
+
queryClient.setQueriesData<ContentDatabaseResponse>(
|
|
644
|
+
contentDatabaseQueryFilter(documentId),
|
|
645
|
+
(current) =>
|
|
646
|
+
applySourceFieldPropertyToDatabaseResponse(
|
|
647
|
+
removeOptimisticSourceFieldProperty(current, data.sourceField.id),
|
|
648
|
+
data,
|
|
649
|
+
),
|
|
371
650
|
);
|
|
372
651
|
queryClient.invalidateQueries({
|
|
373
652
|
queryKey: contentDatabaseQueryKey(documentId),
|
|
@@ -395,12 +674,16 @@ export function useBuilderCmsModels(enabled: boolean) {
|
|
|
395
674
|
|
|
396
675
|
export function useContentDatabases(args: {
|
|
397
676
|
excludeDatabaseId?: string;
|
|
677
|
+
excludeDatabaseIds?: string[];
|
|
398
678
|
enabled: boolean;
|
|
399
679
|
}) {
|
|
400
680
|
return useActionQuery<ListContentDatabasesResponse>(
|
|
401
681
|
"list-content-databases",
|
|
402
682
|
args.enabled
|
|
403
|
-
? {
|
|
683
|
+
? {
|
|
684
|
+
excludeDatabaseId: args.excludeDatabaseId ?? undefined,
|
|
685
|
+
excludeDatabaseIds: args.excludeDatabaseIds ?? undefined,
|
|
686
|
+
}
|
|
404
687
|
: undefined,
|
|
405
688
|
{ enabled: args.enabled, retry: false },
|
|
406
689
|
);
|
|
@@ -434,39 +717,60 @@ export function useRefreshContentDatabaseSource(documentId: string) {
|
|
|
434
717
|
ContentDatabaseSourceStatusResponse,
|
|
435
718
|
RefreshContentDatabaseSourceRequest
|
|
436
719
|
>("refresh-content-database-source", {
|
|
720
|
+
skipActionQueryInvalidation: true,
|
|
437
721
|
onSuccess: () => {
|
|
438
|
-
queryClient
|
|
439
|
-
queryKey: contentDatabaseQueryKey(documentId),
|
|
440
|
-
});
|
|
441
|
-
queryClient.invalidateQueries({
|
|
442
|
-
queryKey: ["action", "get-content-database-source", { documentId }],
|
|
443
|
-
});
|
|
722
|
+
invalidateContentDatabaseSourceRefreshQueries(queryClient, documentId);
|
|
444
723
|
},
|
|
445
724
|
});
|
|
446
725
|
}
|
|
447
726
|
|
|
727
|
+
export function invalidateContentDatabaseSourceRefreshQueries(
|
|
728
|
+
queryClient: {
|
|
729
|
+
invalidateQueries: (filters: { queryKey: readonly unknown[] }) => unknown;
|
|
730
|
+
},
|
|
731
|
+
documentId: string,
|
|
732
|
+
) {
|
|
733
|
+
queryClient.invalidateQueries({
|
|
734
|
+
queryKey: contentDatabaseQueryKey(documentId),
|
|
735
|
+
});
|
|
736
|
+
queryClient.invalidateQueries({
|
|
737
|
+
queryKey: ["action", "get-content-database-source", { documentId }],
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
448
741
|
export function useProcessBuilderBodyHydration(documentId: string) {
|
|
449
742
|
const queryClient = useQueryClient();
|
|
450
743
|
return useActionMutation<
|
|
451
744
|
ProcessBuilderBodyHydrationResponse,
|
|
452
745
|
ProcessBuilderBodyHydrationRequest
|
|
453
746
|
>("process-builder-body-hydration", {
|
|
747
|
+
skipActionQueryInvalidation: true,
|
|
454
748
|
onSuccess: (_data, variables) => {
|
|
455
|
-
queryClient
|
|
456
|
-
queryKey: contentDatabaseQueryKey(documentId),
|
|
457
|
-
});
|
|
458
|
-
queryClient.invalidateQueries({
|
|
459
|
-
queryKey: ["action", "get-content-database-source", { documentId }],
|
|
460
|
-
});
|
|
461
|
-
if (variables?.documentId) {
|
|
462
|
-
queryClient.invalidateQueries({
|
|
463
|
-
queryKey: ["action", "get-document", { id: variables.documentId }],
|
|
464
|
-
});
|
|
465
|
-
}
|
|
749
|
+
invalidateBuilderBodyHydrationQueries(queryClient, documentId, variables);
|
|
466
750
|
},
|
|
467
751
|
});
|
|
468
752
|
}
|
|
469
753
|
|
|
754
|
+
export function invalidateBuilderBodyHydrationQueries(
|
|
755
|
+
queryClient: {
|
|
756
|
+
invalidateQueries: (filters: { queryKey: readonly unknown[] }) => unknown;
|
|
757
|
+
},
|
|
758
|
+
documentId: string,
|
|
759
|
+
variables?: Pick<ProcessBuilderBodyHydrationRequest, "documentId"> | null,
|
|
760
|
+
) {
|
|
761
|
+
queryClient.invalidateQueries({
|
|
762
|
+
queryKey: contentDatabaseQueryKey(documentId),
|
|
763
|
+
});
|
|
764
|
+
queryClient.invalidateQueries({
|
|
765
|
+
queryKey: ["action", "get-content-database-source", { documentId }],
|
|
766
|
+
});
|
|
767
|
+
if (variables?.documentId) {
|
|
768
|
+
queryClient.invalidateQueries({
|
|
769
|
+
queryKey: ["action", "get-document", { id: variables.documentId }],
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
470
774
|
export function useDisconnectContentDatabaseSource(documentId: string) {
|
|
471
775
|
const queryClient = useQueryClient();
|
|
472
776
|
return useActionMutation<
|
|
@@ -6,6 +6,15 @@ export function useDbSync() {
|
|
|
6
6
|
|
|
7
7
|
useCoreDbSync({
|
|
8
8
|
queryClient,
|
|
9
|
+
// refresh-notion-sync-status is a POST behind an ["action"]-keyed query
|
|
10
|
+
// (useDocumentSyncStatus). Without suppression its own action-change event
|
|
11
|
+
// invalidates all action queries, which refetches the POST, which emits
|
|
12
|
+
// the next event — a self-sustaining refetch storm on every poll tick.
|
|
13
|
+
suppressActionInvalidationFor: [
|
|
14
|
+
"process-builder-body-hydration",
|
|
15
|
+
"refresh-content-database-source",
|
|
16
|
+
"refresh-notion-sync-status",
|
|
17
|
+
],
|
|
9
18
|
queryKeys: [
|
|
10
19
|
"action",
|
|
11
20
|
"document-sync",
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { useActionQuery, useActionMutation } from "@agent-native/core/client";
|
|
2
2
|
import type {
|
|
3
|
+
ContentDatabaseItem,
|
|
3
4
|
Document,
|
|
4
5
|
DocumentCreateRequest,
|
|
6
|
+
DocumentPropertiesResponse,
|
|
5
7
|
DocumentUpdateRequest,
|
|
6
8
|
DocumentUpdateResponse,
|
|
7
9
|
DocumentMoveRequest,
|
|
8
10
|
DocumentTreeNode,
|
|
9
11
|
} from "@shared/api";
|
|
12
|
+
import type { QueryClient } from "@tanstack/react-query";
|
|
10
13
|
import { useQueryClient } from "@tanstack/react-query";
|
|
11
14
|
import { toast } from "sonner";
|
|
12
15
|
|
|
16
|
+
import { databaseItemBodyHydrationIsPending } from "@/components/editor/body-hydration";
|
|
17
|
+
|
|
13
18
|
import type { DocumentUpdateConflictResponse } from "../../actions/update-document";
|
|
14
19
|
import { useRestoreContentDatabase } from "./use-content-database";
|
|
15
20
|
|
|
@@ -17,6 +22,14 @@ export type { DocumentUpdateConflictResponse };
|
|
|
17
22
|
|
|
18
23
|
const LIST_DOCUMENTS_QUERY_KEY = ["action", "list-documents", undefined];
|
|
19
24
|
|
|
25
|
+
export function documentQueryKey(documentId: string) {
|
|
26
|
+
return ["action", "get-document", { id: documentId }] as const;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function documentPropertiesQueryKey(documentId: string) {
|
|
30
|
+
return ["action", "list-document-properties", { documentId }] as const;
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
// Extends the shared request/response shapes with the optional
|
|
21
34
|
// compare-and-swap fields the action supports but shared/api.ts does not
|
|
22
35
|
// (yet) declare. See actions/update-document.ts for the CAS contract.
|
|
@@ -68,6 +81,40 @@ export function mergeDocumentIntoListDocumentsCache(
|
|
|
68
81
|
return { ...(old as object), documents: nextDocuments };
|
|
69
82
|
}
|
|
70
83
|
|
|
84
|
+
export function seedDatabaseItemDocumentCaches(
|
|
85
|
+
queryClient: Pick<QueryClient, "getQueryData" | "setQueryData">,
|
|
86
|
+
item: ContentDatabaseItem,
|
|
87
|
+
) {
|
|
88
|
+
// Seed only cold caches. Overwriting an existing entry would bump its
|
|
89
|
+
// freshness with possibly older table-snapshot data (a background database
|
|
90
|
+
// refetch can lag a just-saved document edit) and suppress the correcting
|
|
91
|
+
// refetch for the whole staleTime window. Rows whose Builder body has not
|
|
92
|
+
// hydrated yet are never seeded: their empty table-snapshot `content` would
|
|
93
|
+
// render as an authoritative empty document.
|
|
94
|
+
if (
|
|
95
|
+
!databaseItemBodyHydrationIsPending(item) &&
|
|
96
|
+
queryClient.getQueryData(documentQueryKey(item.document.id)) === undefined
|
|
97
|
+
) {
|
|
98
|
+
queryClient.setQueryData<Document>(documentQueryKey(item.document.id), {
|
|
99
|
+
...item.document,
|
|
100
|
+
properties: item.properties,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (
|
|
104
|
+
queryClient.getQueryData(documentPropertiesQueryKey(item.document.id)) ===
|
|
105
|
+
undefined
|
|
106
|
+
) {
|
|
107
|
+
queryClient.setQueryData<DocumentPropertiesResponse>(
|
|
108
|
+
documentPropertiesQueryKey(item.document.id),
|
|
109
|
+
{
|
|
110
|
+
documentId: item.document.id,
|
|
111
|
+
databaseId: item.databaseId,
|
|
112
|
+
properties: item.properties,
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
71
118
|
export function useDocuments() {
|
|
72
119
|
return useActionQuery<Document[]>("list-documents", undefined, {
|
|
73
120
|
select: (data: any) => {
|
|
@@ -73,10 +73,11 @@ export function documentSyncStatusQueryKey(
|
|
|
73
73
|
documentId: string,
|
|
74
74
|
options?: { autoSync?: boolean },
|
|
75
75
|
) {
|
|
76
|
+
const normalizedDocumentId = documentId.trim();
|
|
76
77
|
return [
|
|
77
78
|
"action",
|
|
78
79
|
"refresh-notion-sync-status",
|
|
79
|
-
{ documentId, autoSync: !!options?.autoSync },
|
|
80
|
+
{ documentId: normalizedDocumentId, autoSync: !!options?.autoSync },
|
|
80
81
|
] as const;
|
|
81
82
|
}
|
|
82
83
|
|
|
@@ -124,19 +125,20 @@ export function useDocumentSyncStatus(
|
|
|
124
125
|
) {
|
|
125
126
|
const queryClient = useQueryClient();
|
|
126
127
|
const lastObservedSyncedAtRef = useRef<string | null>(null);
|
|
128
|
+
const normalizedDocumentId = documentId?.trim() || null;
|
|
127
129
|
const autoSync = !!options?.autoSync;
|
|
128
130
|
const query = useQuery<DocumentSyncStatus>({
|
|
129
|
-
queryKey:
|
|
130
|
-
? documentSyncStatusQueryKey(
|
|
131
|
+
queryKey: normalizedDocumentId
|
|
132
|
+
? documentSyncStatusQueryKey(normalizedDocumentId, options)
|
|
131
133
|
: ["action", "refresh-notion-sync-status", null],
|
|
132
134
|
queryFn: () => {
|
|
133
|
-
if (!
|
|
135
|
+
if (!normalizedDocumentId) throw new Error("documentId is required");
|
|
134
136
|
return callAction<DocumentSyncStatus>("refresh-notion-sync-status", {
|
|
135
|
-
documentId,
|
|
137
|
+
documentId: normalizedDocumentId,
|
|
136
138
|
autoSync,
|
|
137
139
|
});
|
|
138
140
|
},
|
|
139
|
-
enabled: !!
|
|
141
|
+
enabled: !!normalizedDocumentId,
|
|
140
142
|
// Poll Notion aggressively when auto-sync is on so remote changes appear
|
|
141
143
|
// within ~2s. Server throttles match (see REFRESH_THROTTLE_AUTO_SYNC_MS in
|
|
142
144
|
// notion-sync.ts) so we make at most one real Notion request per 2s per doc.
|
|
@@ -148,7 +150,7 @@ export function useDocumentSyncStatus(
|
|
|
148
150
|
});
|
|
149
151
|
|
|
150
152
|
useEffect(() => {
|
|
151
|
-
if (!
|
|
153
|
+
if (!normalizedDocumentId || !query.data?.lastSyncedAt) return;
|
|
152
154
|
if (lastObservedSyncedAtRef.current === query.data.lastSyncedAt) return;
|
|
153
155
|
|
|
154
156
|
lastObservedSyncedAtRef.current = query.data.lastSyncedAt;
|
|
@@ -156,7 +158,7 @@ export function useDocumentSyncStatus(
|
|
|
156
158
|
const cachedDocument = queryClient.getQueryData<Document>([
|
|
157
159
|
"action",
|
|
158
160
|
"get-document",
|
|
159
|
-
{ id:
|
|
161
|
+
{ id: normalizedDocumentId },
|
|
160
162
|
]);
|
|
161
163
|
const syncedLocalUpdatedAt = query.data.lastPushedLocalUpdatedAt;
|
|
162
164
|
|
|
@@ -166,12 +168,12 @@ export function useDocumentSyncStatus(
|
|
|
166
168
|
syncedLocalUpdatedAt > cachedDocument.updatedAt
|
|
167
169
|
) {
|
|
168
170
|
queryClient.invalidateQueries({
|
|
169
|
-
queryKey: ["action", "get-document", { id:
|
|
171
|
+
queryKey: ["action", "get-document", { id: normalizedDocumentId }],
|
|
170
172
|
});
|
|
171
173
|
queryClient.invalidateQueries({ queryKey: ["action", "list-documents"] });
|
|
172
174
|
}
|
|
173
175
|
}, [
|
|
174
|
-
|
|
176
|
+
normalizedDocumentId,
|
|
175
177
|
query.data?.lastPushedLocalUpdatedAt,
|
|
176
178
|
query.data?.lastSyncedAt,
|
|
177
179
|
queryClient,
|