@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
|
@@ -30,10 +30,12 @@ type DatabaseMembershipRow = {
|
|
|
30
30
|
item: typeof schema.contentDatabaseItems.$inferSelect;
|
|
31
31
|
database: typeof schema.contentDatabases.$inferSelect;
|
|
32
32
|
sourceId?: string | null;
|
|
33
|
+
bodyHydrationQueueId?: string | null;
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
export function serializeBodyHydration(
|
|
36
37
|
item: typeof schema.contentDatabaseItems.$inferSelect,
|
|
38
|
+
options: { queued?: boolean } = {},
|
|
37
39
|
): ContentDatabaseBodyHydration {
|
|
38
40
|
const status = item.bodyHydrationStatus;
|
|
39
41
|
return {
|
|
@@ -43,7 +45,9 @@ export function serializeBodyHydration(
|
|
|
43
45
|
status === "hydrated" ||
|
|
44
46
|
status === "error"
|
|
45
47
|
? status
|
|
46
|
-
:
|
|
48
|
+
: options.queued
|
|
49
|
+
? "pending"
|
|
50
|
+
: "hydrated",
|
|
47
51
|
attemptedAt: item.bodyHydrationAttemptedAt,
|
|
48
52
|
error: item.bodyHydrationError,
|
|
49
53
|
version: item.bodyHydrationVersion,
|
|
@@ -59,7 +63,9 @@ export function serializeDatabaseMembership(
|
|
|
59
63
|
databaseTitle: row.database.title || "Untitled database",
|
|
60
64
|
position: row.item.position,
|
|
61
65
|
sourceId: row.sourceId ?? null,
|
|
62
|
-
bodyHydration: serializeBodyHydration(row.item
|
|
66
|
+
bodyHydration: serializeBodyHydration(row.item, {
|
|
67
|
+
queued: !!row.bodyHydrationQueueId,
|
|
68
|
+
}),
|
|
63
69
|
};
|
|
64
70
|
}
|
|
65
71
|
|
|
@@ -190,17 +196,43 @@ export async function getContentDatabaseResponse(
|
|
|
190
196
|
)
|
|
191
197
|
: [];
|
|
192
198
|
const documentById = new Map(documents.map((doc) => [doc.id, doc]));
|
|
199
|
+
const queuedBodyHydrationItemIds =
|
|
200
|
+
items.length > 0
|
|
201
|
+
? new Set(
|
|
202
|
+
(
|
|
203
|
+
await db
|
|
204
|
+
.select({
|
|
205
|
+
databaseItemId:
|
|
206
|
+
schema.contentDatabaseBodyHydrationQueue.databaseItemId,
|
|
207
|
+
})
|
|
208
|
+
.from(schema.contentDatabaseBodyHydrationQueue)
|
|
209
|
+
.where(
|
|
210
|
+
inArray(
|
|
211
|
+
schema.contentDatabaseBodyHydrationQueue.databaseItemId,
|
|
212
|
+
items.map((item) => item.id),
|
|
213
|
+
),
|
|
214
|
+
)
|
|
215
|
+
).map((row) => row.databaseItemId),
|
|
216
|
+
)
|
|
217
|
+
: new Set<string>();
|
|
193
218
|
|
|
194
219
|
const serializedItems = [];
|
|
195
220
|
for (const item of items) {
|
|
196
221
|
const document = documentById.get(item.documentId);
|
|
197
222
|
if (!document) continue;
|
|
223
|
+
const bodyHydrationQueued = queuedBodyHydrationItemIds.has(item.id);
|
|
198
224
|
serializedItems.push({
|
|
199
225
|
id: item.id,
|
|
200
226
|
databaseId: item.databaseId,
|
|
201
|
-
document: serializeDocument(document, {
|
|
227
|
+
document: serializeDocument(document, {
|
|
228
|
+
item,
|
|
229
|
+
database,
|
|
230
|
+
bodyHydrationQueueId: bodyHydrationQueued ? item.id : null,
|
|
231
|
+
}),
|
|
202
232
|
position: item.position,
|
|
203
|
-
bodyHydration: serializeBodyHydration(item
|
|
233
|
+
bodyHydration: serializeBodyHydration(item, {
|
|
234
|
+
queued: bodyHydrationQueued,
|
|
235
|
+
}),
|
|
204
236
|
properties: await listPropertiesForDatabase(databaseId, document),
|
|
205
237
|
});
|
|
206
238
|
}
|
|
@@ -312,6 +344,7 @@ export async function getDatabaseItemByDocumentId(
|
|
|
312
344
|
item: schema.contentDatabaseItems,
|
|
313
345
|
database: schema.contentDatabases,
|
|
314
346
|
sourceId: schema.contentDatabaseSourceRows.sourceId,
|
|
347
|
+
bodyHydrationQueueId: schema.contentDatabaseBodyHydrationQueue.id,
|
|
315
348
|
})
|
|
316
349
|
.from(schema.contentDatabaseItems)
|
|
317
350
|
.innerJoin(
|
|
@@ -325,6 +358,13 @@ export async function getDatabaseItemByDocumentId(
|
|
|
325
358
|
schema.contentDatabaseItems.id,
|
|
326
359
|
),
|
|
327
360
|
)
|
|
361
|
+
.leftJoin(
|
|
362
|
+
schema.contentDatabaseBodyHydrationQueue,
|
|
363
|
+
eq(
|
|
364
|
+
schema.contentDatabaseBodyHydrationQueue.databaseItemId,
|
|
365
|
+
schema.contentDatabaseItems.id,
|
|
366
|
+
),
|
|
367
|
+
)
|
|
328
368
|
.where(and(...clauses));
|
|
329
369
|
return row ?? null;
|
|
330
370
|
}
|
|
@@ -24,7 +24,11 @@ export async function getNotionDocumentOwner(documentId: string) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function resolveDocumentId(args: { documentId?: string; id?: string }) {
|
|
27
|
-
const documentId = args.documentId || args.id;
|
|
28
|
-
if (!documentId)
|
|
27
|
+
const documentId = args.documentId?.trim() || args.id?.trim();
|
|
28
|
+
if (!documentId) {
|
|
29
|
+
throw Object.assign(new Error("documentId is required"), {
|
|
30
|
+
statusCode: 400,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
29
33
|
return documentId;
|
|
30
34
|
}
|
|
@@ -80,6 +80,14 @@ export default defineAction({
|
|
|
80
80
|
databaseId: z.string().optional().describe("Database ID"),
|
|
81
81
|
documentId: z.string().optional().describe("Database document/page ID"),
|
|
82
82
|
sourceFieldId: z.string().describe("Source field mapping ID"),
|
|
83
|
+
sourceId: z
|
|
84
|
+
.string()
|
|
85
|
+
.optional()
|
|
86
|
+
.describe("Source ID for stale field ID fallback"),
|
|
87
|
+
sourceFieldKey: z
|
|
88
|
+
.string()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe("Stable source field key for stale field ID fallback"),
|
|
83
91
|
}),
|
|
84
92
|
run: async (
|
|
85
93
|
args: AddContentDatabaseSourceFieldPropertyRequest,
|
|
@@ -89,10 +97,24 @@ export default defineAction({
|
|
|
89
97
|
await assertAccess("document", database.documentId, "editor");
|
|
90
98
|
|
|
91
99
|
const db = getDb();
|
|
92
|
-
|
|
100
|
+
let [field] = await db
|
|
93
101
|
.select()
|
|
94
102
|
.from(schema.contentDatabaseSourceFields)
|
|
95
103
|
.where(eq(schema.contentDatabaseSourceFields.id, args.sourceFieldId));
|
|
104
|
+
if (!field && args.sourceId && args.sourceFieldKey) {
|
|
105
|
+
[field] = await db
|
|
106
|
+
.select()
|
|
107
|
+
.from(schema.contentDatabaseSourceFields)
|
|
108
|
+
.where(
|
|
109
|
+
and(
|
|
110
|
+
eq(schema.contentDatabaseSourceFields.sourceId, args.sourceId),
|
|
111
|
+
eq(
|
|
112
|
+
schema.contentDatabaseSourceFields.sourceFieldKey,
|
|
113
|
+
args.sourceFieldKey,
|
|
114
|
+
),
|
|
115
|
+
),
|
|
116
|
+
);
|
|
117
|
+
}
|
|
96
118
|
if (!field) throw new Error("Source field not found.");
|
|
97
119
|
|
|
98
120
|
const [source] = await db
|
|
@@ -12,6 +12,7 @@ import { sanitizeNormalizationFormula } from "../shared/properties.js";
|
|
|
12
12
|
import {
|
|
13
13
|
readBuilderCmsContentEntries,
|
|
14
14
|
readBuilderCmsModelFields,
|
|
15
|
+
type BuilderCmsReadResult,
|
|
15
16
|
} from "./_builder-cms-read-client.js";
|
|
16
17
|
import type { BuilderCmsSourceEntry } from "./_builder-cms-source-adapter.js";
|
|
17
18
|
import {
|
|
@@ -42,6 +43,54 @@ import {
|
|
|
42
43
|
const sourceTypeSchema = z
|
|
43
44
|
.enum(["mock-local", "builder-cms", "local-table"])
|
|
44
45
|
.default("mock-local");
|
|
46
|
+
const BUILDER_CMS_ATTACH_INITIAL_PAGES = 1;
|
|
47
|
+
|
|
48
|
+
export async function readInitialBuilderCmsAttachEntries(
|
|
49
|
+
sourceTable: string,
|
|
50
|
+
readEntries: typeof readBuilderCmsContentEntries = readBuilderCmsContentEntries,
|
|
51
|
+
) {
|
|
52
|
+
return readEntries({
|
|
53
|
+
model: sourceTable,
|
|
54
|
+
maxPages: BUILDER_CMS_ATTACH_INITIAL_PAGES,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function builderReadHasMore(read: BuilderCmsReadResult | null | undefined) {
|
|
59
|
+
return read?.state === "live" && read.progress?.hasMore === true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function builderReadActiveSourceRowIds(
|
|
63
|
+
read: BuilderCmsReadResult | null | undefined,
|
|
64
|
+
) {
|
|
65
|
+
if (read?.state !== "live" || read.progress?.hasMore !== true) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
return read.entries.map((entry) => entry.id);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function builderReadSyncState(read: BuilderCmsReadResult) {
|
|
72
|
+
if (read.state === "error") return "error";
|
|
73
|
+
return builderReadHasMore(read) ? "refreshing" : "linked";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function builderCmsAttachReadMetadata(read: BuilderCmsReadResult) {
|
|
77
|
+
const sourceFetchState: "idle" | "fetching" | "error" = builderReadHasMore(
|
|
78
|
+
read,
|
|
79
|
+
)
|
|
80
|
+
? "fetching"
|
|
81
|
+
: read.state === "error"
|
|
82
|
+
? "error"
|
|
83
|
+
: "idle";
|
|
84
|
+
const syncState: "linked" | "refreshing" | "error" =
|
|
85
|
+
builderReadSyncState(read);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
progress: read.progress,
|
|
89
|
+
sourceFetchState,
|
|
90
|
+
activeReadSourceRowIds: builderReadActiveSourceRowIds(read),
|
|
91
|
+
syncState,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
45
94
|
|
|
46
95
|
// Per-source key mapping the UI commits after the canonical-key confirm step.
|
|
47
96
|
const normalizationFormulaSchema = z
|
|
@@ -187,9 +236,10 @@ export default defineAction({
|
|
|
187
236
|
}
|
|
188
237
|
let entries: BuilderCmsSourceEntry[];
|
|
189
238
|
let modelFields: BuilderCmsModelFieldSummary[];
|
|
239
|
+
let builderRead: BuilderCmsReadResult | null = null;
|
|
190
240
|
if (sourceType === "builder-cms") {
|
|
191
|
-
|
|
192
|
-
entries =
|
|
241
|
+
builderRead = await readInitialBuilderCmsAttachEntries(sourceTable);
|
|
242
|
+
entries = builderRead.state === "live" ? builderRead.entries : [];
|
|
193
243
|
modelFields = await readBuilderCmsModelFields({ model: sourceTable });
|
|
194
244
|
} else if (sourceType === "local-table") {
|
|
195
245
|
// sourceTable carries the target database id for a local-table source.
|
|
@@ -224,6 +274,19 @@ export default defineAction({
|
|
|
224
274
|
sampleEntry: entries[0],
|
|
225
275
|
now,
|
|
226
276
|
});
|
|
277
|
+
if (sourceType === "builder-cms" && builderRead) {
|
|
278
|
+
await updateBuilderCmsSourceReadMetadata({
|
|
279
|
+
sourceId: secondaryId,
|
|
280
|
+
sourceTable,
|
|
281
|
+
readState: builderRead.state,
|
|
282
|
+
entryCount: builderRead.entries.length,
|
|
283
|
+
matchedRowCount: entries.length,
|
|
284
|
+
fetchedAt: builderRead.fetchedAt,
|
|
285
|
+
now,
|
|
286
|
+
message: builderRead.message,
|
|
287
|
+
...builderCmsAttachReadMetadata(builderRead),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
227
290
|
await writeSourceFederation({
|
|
228
291
|
sourceId: secondaryId,
|
|
229
292
|
federation: identityFederation(
|
|
@@ -263,9 +326,8 @@ export default defineAction({
|
|
|
263
326
|
if (await databaseSourceExistsForTable(database.id, sourceTable)) {
|
|
264
327
|
throw new Error(`"${sourceTable}" is already attached as a source.`);
|
|
265
328
|
}
|
|
266
|
-
const additionalRead =
|
|
267
|
-
|
|
268
|
-
});
|
|
329
|
+
const additionalRead =
|
|
330
|
+
await readInitialBuilderCmsAttachEntries(sourceTable);
|
|
269
331
|
const additionalEntries =
|
|
270
332
|
additionalRead.state === "live" ? additionalRead.entries : [];
|
|
271
333
|
const additionalModelFields = await readBuilderCmsModelFields({
|
|
@@ -284,8 +346,12 @@ export default defineAction({
|
|
|
284
346
|
const priorDocumentIds = new Set(
|
|
285
347
|
beforeSetup.response.items.map((item) => item.document.id),
|
|
286
348
|
);
|
|
349
|
+
let importedEntriesByDocumentId = new Map<
|
|
350
|
+
string,
|
|
351
|
+
BuilderCmsSourceEntry
|
|
352
|
+
>();
|
|
287
353
|
if (additionalRead.state === "live") {
|
|
288
|
-
await importBuilderCmsEntriesAsDatabaseItems({
|
|
354
|
+
const importResult = await importBuilderCmsEntriesAsDatabaseItems({
|
|
289
355
|
database,
|
|
290
356
|
entries: additionalEntries,
|
|
291
357
|
now,
|
|
@@ -293,6 +359,7 @@ export default defineAction({
|
|
|
293
359
|
existingSourceRows: [],
|
|
294
360
|
skipTitleDedup: true,
|
|
295
361
|
});
|
|
362
|
+
importedEntriesByDocumentId = importResult.importedEntriesByDocumentId;
|
|
296
363
|
}
|
|
297
364
|
const additionalSetup = await sourceSetupPayload(database.id);
|
|
298
365
|
// Only the items this collection just created — exclude the primary's.
|
|
@@ -309,6 +376,9 @@ export default defineAction({
|
|
|
309
376
|
existingRows: [],
|
|
310
377
|
})
|
|
311
378
|
: undefined;
|
|
379
|
+
for (const [documentId, entry] of importedEntriesByDocumentId) {
|
|
380
|
+
additionalEntriesByDocumentId?.set(documentId, entry);
|
|
381
|
+
}
|
|
312
382
|
await seedMockSourceFields({
|
|
313
383
|
sourceId: additionalSourceId,
|
|
314
384
|
ownerEmail: database.ownerEmail,
|
|
@@ -347,7 +417,7 @@ export default defineAction({
|
|
|
347
417
|
fetchedAt: additionalRead.fetchedAt,
|
|
348
418
|
now,
|
|
349
419
|
message: additionalRead.message,
|
|
350
|
-
|
|
420
|
+
...builderCmsAttachReadMetadata(additionalRead),
|
|
351
421
|
});
|
|
352
422
|
await ensureDatabaseSourceProperty({ database, now });
|
|
353
423
|
|
|
@@ -374,9 +444,7 @@ export default defineAction({
|
|
|
374
444
|
});
|
|
375
445
|
const builderRead =
|
|
376
446
|
sourceType === "builder-cms"
|
|
377
|
-
? await
|
|
378
|
-
model: sourceTable,
|
|
379
|
-
})
|
|
447
|
+
? await readInitialBuilderCmsAttachEntries(sourceTable)
|
|
380
448
|
: null;
|
|
381
449
|
const builderEntries =
|
|
382
450
|
builderRead?.state === "live" ? builderRead.entries : [];
|
|
@@ -386,14 +454,16 @@ export default defineAction({
|
|
|
386
454
|
model: sourceTable,
|
|
387
455
|
})
|
|
388
456
|
: [];
|
|
457
|
+
let importedEntriesByDocumentId = new Map<string, BuilderCmsSourceEntry>();
|
|
389
458
|
if (builderRead?.state === "live") {
|
|
390
|
-
await importBuilderCmsEntriesAsDatabaseItems({
|
|
459
|
+
const importResult = await importBuilderCmsEntriesAsDatabaseItems({
|
|
391
460
|
database,
|
|
392
461
|
entries: builderEntries,
|
|
393
462
|
now,
|
|
394
463
|
sourceTable,
|
|
395
464
|
existingSourceRows,
|
|
396
465
|
});
|
|
466
|
+
importedEntriesByDocumentId = importResult.importedEntriesByDocumentId;
|
|
397
467
|
}
|
|
398
468
|
|
|
399
469
|
const refreshedSetup = await sourceSetupPayload(database.id);
|
|
@@ -407,6 +477,9 @@ export default defineAction({
|
|
|
407
477
|
existingRows: existingSourceRows,
|
|
408
478
|
})
|
|
409
479
|
: undefined;
|
|
480
|
+
for (const [documentId, entry] of importedEntriesByDocumentId) {
|
|
481
|
+
builderEntriesByDocumentId?.set(documentId, entry);
|
|
482
|
+
}
|
|
410
483
|
|
|
411
484
|
await seedMockSourceFields({
|
|
412
485
|
sourceId,
|
|
@@ -447,7 +520,7 @@ export default defineAction({
|
|
|
447
520
|
fetchedAt: builderRead.fetchedAt,
|
|
448
521
|
now,
|
|
449
522
|
message: builderRead.message,
|
|
450
|
-
|
|
523
|
+
...builderCmsAttachReadMetadata(builderRead),
|
|
451
524
|
});
|
|
452
525
|
}
|
|
453
526
|
|
|
@@ -343,8 +343,12 @@ export default defineAction({
|
|
|
343
343
|
.where(eq(schema.contentDatabaseSourceRows.sourceId, source.id));
|
|
344
344
|
await clearSourceFederation(source.id, now);
|
|
345
345
|
|
|
346
|
+
let importedEntriesByDocumentId = new Map<
|
|
347
|
+
string,
|
|
348
|
+
BuilderCmsSourceEntry
|
|
349
|
+
>();
|
|
346
350
|
if (read.state === "live") {
|
|
347
|
-
await importBuilderCmsEntriesAsDatabaseItems({
|
|
351
|
+
const importResult = await importBuilderCmsEntriesAsDatabaseItems({
|
|
348
352
|
database,
|
|
349
353
|
entries,
|
|
350
354
|
now,
|
|
@@ -352,6 +356,7 @@ export default defineAction({
|
|
|
352
356
|
existingSourceRows: [],
|
|
353
357
|
skipTitleDedup: true,
|
|
354
358
|
});
|
|
359
|
+
importedEntriesByDocumentId = importResult.importedEntriesByDocumentId;
|
|
355
360
|
}
|
|
356
361
|
const refreshedSetup = await sourceSetupPayload(database.id);
|
|
357
362
|
const builderEntriesByDocumentId =
|
|
@@ -364,6 +369,9 @@ export default defineAction({
|
|
|
364
369
|
existingRows: [],
|
|
365
370
|
})
|
|
366
371
|
: new Map<string, BuilderCmsSourceEntry>();
|
|
372
|
+
for (const [documentId, entry] of importedEntriesByDocumentId) {
|
|
373
|
+
builderEntriesByDocumentId.set(documentId, entry);
|
|
374
|
+
}
|
|
367
375
|
await seedMockSourceFields({
|
|
368
376
|
sourceId: source.id,
|
|
369
377
|
ownerEmail: database.ownerEmail,
|
|
@@ -49,9 +49,18 @@ export default defineAction({
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const access = await resolveAccess("document", args.id);
|
|
52
|
-
|
|
52
|
+
// Not-found is a deterministic client-state condition (deleted or
|
|
53
|
+
// inaccessible document still referenced by an open tab) — 404, not a
|
|
54
|
+
// 500 that floods the console as Internal Server Error.
|
|
55
|
+
if (!access) {
|
|
56
|
+
throw Object.assign(new Error(`Document "${args.id}" not found`), {
|
|
57
|
+
statusCode: 404,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
53
60
|
if (await isSoftDeletedDatabaseDocument(args.id)) {
|
|
54
|
-
throw new Error(`Document "${args.id}" not found`)
|
|
61
|
+
throw Object.assign(new Error(`Document "${args.id}" not found`), {
|
|
62
|
+
statusCode: 404,
|
|
63
|
+
});
|
|
55
64
|
}
|
|
56
65
|
const doc = access.resource;
|
|
57
66
|
const database = await getDatabaseByDocumentId(doc.id);
|
|
@@ -19,6 +19,10 @@ export default defineAction({
|
|
|
19
19
|
.string()
|
|
20
20
|
.optional()
|
|
21
21
|
.describe("Database id to omit from the results."),
|
|
22
|
+
excludeDatabaseIds: z
|
|
23
|
+
.array(z.string())
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Database ids to omit from the results."),
|
|
22
26
|
query: z.string().optional().describe("Optional title search text."),
|
|
23
27
|
limit: z.coerce
|
|
24
28
|
.number()
|
|
@@ -34,6 +38,12 @@ export default defineAction({
|
|
|
34
38
|
const db = getDb();
|
|
35
39
|
const query = args.query?.trim();
|
|
36
40
|
const pattern = query ? `%${escapeLike(query.toLowerCase())}%` : null;
|
|
41
|
+
const excludedDatabaseIds = new Set(
|
|
42
|
+
[
|
|
43
|
+
args.excludeDatabaseId?.trim(),
|
|
44
|
+
...(args.excludeDatabaseIds ?? []).map((id) => id.trim()),
|
|
45
|
+
].filter((id): id is string => !!id),
|
|
46
|
+
);
|
|
37
47
|
// The same access + discovery filter the sidebar uses, so the picker shows
|
|
38
48
|
// owned AND shared/org databases and never a trashed/hidden one.
|
|
39
49
|
const queryBuilder = db
|
|
@@ -52,8 +62,11 @@ export default defineAction({
|
|
|
52
62
|
accessFilter(schema.documents, schema.documentShares),
|
|
53
63
|
documentDiscoveryFilter(),
|
|
54
64
|
isNull(schema.contentDatabases.deletedAt),
|
|
55
|
-
|
|
56
|
-
? ne(
|
|
65
|
+
excludedDatabaseIds.size === 1
|
|
66
|
+
? ne(
|
|
67
|
+
schema.contentDatabases.id,
|
|
68
|
+
Array.from(excludedDatabaseIds)[0]!,
|
|
69
|
+
)
|
|
57
70
|
: undefined,
|
|
58
71
|
pattern
|
|
59
72
|
? sql`lower(${schema.documents.title}) LIKE ${pattern} ESCAPE '\\'`
|
|
@@ -66,13 +79,48 @@ export default defineAction({
|
|
|
66
79
|
? await queryBuilder.limit(args.limit)
|
|
67
80
|
: await queryBuilder;
|
|
68
81
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
const localTableSources =
|
|
83
|
+
excludedDatabaseIds.size > 0
|
|
84
|
+
? await db
|
|
85
|
+
.select({
|
|
86
|
+
databaseId: schema.contentDatabaseSources.databaseId,
|
|
87
|
+
sourceTable: schema.contentDatabaseSources.sourceTable,
|
|
88
|
+
})
|
|
89
|
+
.from(schema.contentDatabaseSources)
|
|
90
|
+
.where(eq(schema.contentDatabaseSources.sourceType, "local-table"))
|
|
91
|
+
: [];
|
|
92
|
+
const localTableTargetByDatabaseId = new Map(
|
|
93
|
+
localTableSources.map((source) => [
|
|
94
|
+
source.databaseId,
|
|
95
|
+
source.sourceTable,
|
|
96
|
+
]),
|
|
97
|
+
);
|
|
98
|
+
const sourceChainIncludesExcludedDatabase = (databaseId: string) => {
|
|
99
|
+
const seen = new Set<string>();
|
|
100
|
+
let current: string | undefined = databaseId;
|
|
101
|
+
while (current && !seen.has(current)) {
|
|
102
|
+
if (excludedDatabaseIds.has(current)) return true;
|
|
103
|
+
seen.add(current);
|
|
104
|
+
current = localTableTargetByDatabaseId.get(current);
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const databases = rows
|
|
110
|
+
// Exclusion ids may be database ids OR database document ids — the
|
|
111
|
+
// settings panel only has the document id before any source exists.
|
|
112
|
+
.filter(
|
|
113
|
+
(row) =>
|
|
114
|
+
!excludedDatabaseIds.has(row.documentId) &&
|
|
115
|
+
!sourceChainIncludesExcludedDatabase(row.id),
|
|
116
|
+
)
|
|
117
|
+
.map((row) => ({
|
|
118
|
+
databaseId: row.id,
|
|
119
|
+
documentId: row.documentId,
|
|
120
|
+
// The document's live title (matches the sidebar) rather than the
|
|
121
|
+
// possibly-stale content_databases.title.
|
|
122
|
+
title: row.title ?? "Untitled database",
|
|
123
|
+
}));
|
|
76
124
|
|
|
77
125
|
return { databases };
|
|
78
126
|
},
|
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
} from "./_database-source-utils.js";
|
|
29
29
|
import { getContentDatabaseResponse } from "./_database-utils.js";
|
|
30
30
|
|
|
31
|
+
export const BUILDER_SOURCE_REVIEW_PREPARE_LIMIT = 100;
|
|
32
|
+
|
|
31
33
|
function riskRank(level: ContentDatabaseSourceRiskLevel) {
|
|
32
34
|
if (level === "high") return 3;
|
|
33
35
|
if (level === "medium") return 2;
|
|
@@ -41,6 +43,12 @@ function maxRisk(
|
|
|
41
43
|
return riskRank(next) > riskRank(current) ? next : current;
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
function reviewPreparePriority(changeSet: ContentDatabaseSourceChangeSet) {
|
|
47
|
+
if (changeSet.state === "pending_push") return 0;
|
|
48
|
+
if (changeSet.state === "staged_revision") return 1;
|
|
49
|
+
return 2;
|
|
50
|
+
}
|
|
51
|
+
|
|
44
52
|
function parsePayload(value: string) {
|
|
45
53
|
try {
|
|
46
54
|
const parsed = JSON.parse(value) as unknown;
|
|
@@ -146,6 +154,8 @@ export function buildBuilderSourceReviewPayload(args: {
|
|
|
146
154
|
summary,
|
|
147
155
|
sourceName: args.source.sourceName,
|
|
148
156
|
sourceTable: args.source.sourceTable,
|
|
157
|
+
totalRowCount: args.changeSets.length,
|
|
158
|
+
preparedRowLimit: args.changeSets.length,
|
|
149
159
|
pushMode,
|
|
150
160
|
dryRunOnly: !args.source.capabilities.liveWritesEnabled,
|
|
151
161
|
liveWritesEnabled: args.source.capabilities.liveWritesEnabled,
|
|
@@ -399,16 +409,19 @@ export default defineAction({
|
|
|
399
409
|
if (!snapshot || snapshot.sourceType !== "builder-cms") {
|
|
400
410
|
throw new Error("Attach a Builder CMS source before reviewing updates.");
|
|
401
411
|
}
|
|
402
|
-
const
|
|
412
|
+
const allReviewableChanges = snapshot.changeSets.filter(
|
|
403
413
|
(changeSet) =>
|
|
404
414
|
changeSet.direction === "outbound" &&
|
|
405
415
|
(changeSet.state === "pending_push" ||
|
|
406
416
|
changeSet.state === "staged_revision" ||
|
|
407
417
|
changeSet.state === "approved"),
|
|
408
418
|
);
|
|
409
|
-
if (
|
|
419
|
+
if (allReviewableChanges.length === 0) {
|
|
410
420
|
throw new Error("No pending local Builder changes to review.");
|
|
411
421
|
}
|
|
422
|
+
const reviewableChanges = [...allReviewableChanges]
|
|
423
|
+
.sort((a, b) => reviewPreparePriority(a) - reviewPreparePriority(b))
|
|
424
|
+
.slice(0, BUILDER_SOURCE_REVIEW_PREPARE_LIMIT);
|
|
412
425
|
|
|
413
426
|
const now = new Date().toISOString();
|
|
414
427
|
const reviewerEmail =
|
|
@@ -466,12 +479,16 @@ export default defineAction({
|
|
|
466
479
|
);
|
|
467
480
|
const response = await getContentDatabaseResponse(database.id);
|
|
468
481
|
|
|
482
|
+
const review = buildBuilderSourceReviewPayload({
|
|
483
|
+
source: reviewedSnapshot,
|
|
484
|
+
changeSets: reviewedChangeSets,
|
|
485
|
+
});
|
|
486
|
+
review.totalRowCount = allReviewableChanges.length;
|
|
487
|
+
review.preparedRowLimit = BUILDER_SOURCE_REVIEW_PREPARE_LIMIT;
|
|
488
|
+
|
|
469
489
|
return {
|
|
470
490
|
...response,
|
|
471
|
-
review
|
|
472
|
-
source: reviewedSnapshot,
|
|
473
|
-
changeSets: reviewedChangeSets,
|
|
474
|
-
}),
|
|
491
|
+
review,
|
|
475
492
|
};
|
|
476
493
|
},
|
|
477
494
|
});
|
|
@@ -14,7 +14,7 @@ import { serializeDatabase } from "./_property-utils.js";
|
|
|
14
14
|
|
|
15
15
|
export default defineAction({
|
|
16
16
|
description:
|
|
17
|
-
"Refresh the local read-only source status envelope for a content database. Mock-local and Builder CMS fixture sources resync field mappings and row identity without
|
|
17
|
+
"Refresh the local read-only source status envelope for a content database. Mock-local and Builder CMS fixture sources resync field mappings and row identity without provider writes. For Builder CMS sources, set fullRefresh to true when you need to read every available page in one action call instead of continuing one partial page.",
|
|
18
18
|
schema: z.object({
|
|
19
19
|
databaseId: z.string().optional().describe("Database ID"),
|
|
20
20
|
documentId: z.string().optional().describe("Database document/page ID"),
|
|
@@ -22,6 +22,12 @@ export default defineAction({
|
|
|
22
22
|
.string()
|
|
23
23
|
.optional()
|
|
24
24
|
.describe("Target source ID (defaults to the primary source)"),
|
|
25
|
+
fullRefresh: z
|
|
26
|
+
.boolean()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe(
|
|
29
|
+
"For Builder CMS sources, read all available pages in this refresh instead of one continuation page.",
|
|
30
|
+
),
|
|
25
31
|
}),
|
|
26
32
|
run: async (args): Promise<ContentDatabaseSourceStatusResponse> => {
|
|
27
33
|
const database = await resolveDatabaseForSourceMutation(args);
|
|
@@ -42,7 +48,12 @@ export default defineAction({
|
|
|
42
48
|
if (source.sourceType === "mock-local") {
|
|
43
49
|
await resyncMockSourceSnapshot({ database, source, now });
|
|
44
50
|
} else if (source.sourceType === "builder-cms") {
|
|
45
|
-
await resyncBuilderCmsSourceSnapshot({
|
|
51
|
+
await resyncBuilderCmsSourceSnapshot({
|
|
52
|
+
database,
|
|
53
|
+
source,
|
|
54
|
+
now,
|
|
55
|
+
runFullRefresh: args.fullRefresh === true,
|
|
56
|
+
});
|
|
46
57
|
} else if (source.sourceType === "local-table") {
|
|
47
58
|
// Read-only federated secondary; its rows are re-read on demand, nothing
|
|
48
59
|
// to resync against the primary's local snapshot here.
|
|
@@ -54,11 +65,23 @@ export default defineAction({
|
|
|
54
65
|
args.sourceId,
|
|
55
66
|
);
|
|
56
67
|
|
|
68
|
+
const builderProgress =
|
|
69
|
+
snapshot?.sourceType === "builder-cms" ? snapshot.metadata : null;
|
|
70
|
+
const builderFetching =
|
|
71
|
+
builderProgress?.sourceFetchState === "fetching" ||
|
|
72
|
+
snapshot?.syncState === "refreshing";
|
|
73
|
+
const builderFetched =
|
|
74
|
+
typeof builderProgress?.lastReadFetchedEntryCount === "number"
|
|
75
|
+
? builderProgress.lastReadFetchedEntryCount
|
|
76
|
+
: undefined;
|
|
77
|
+
|
|
57
78
|
return {
|
|
58
79
|
database: serializeDatabase(database),
|
|
59
80
|
mode: "source-backed",
|
|
60
81
|
summary: snapshot
|
|
61
|
-
?
|
|
82
|
+
? builderFetching
|
|
83
|
+
? `${snapshot.sourceName} fetched ${builderFetched ?? "some"} rows. Run refresh again to continue loading the remaining Builder rows.`
|
|
84
|
+
: `${snapshot.sourceName} resynced locally; field mappings and row identity now reflect the current database snapshot.`
|
|
62
85
|
: "Source metadata refreshed.",
|
|
63
86
|
source: snapshot,
|
|
64
87
|
};
|