@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
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.90.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 74d3e5a: Prevent client fetch storms during high-volume background mutations: `useActionMutation` accepts `skipActionQueryInvalidation` so background mutations can perform narrow invalidation instead of refetching every action query, `useDbSync` accepts `suppressActionInvalidationFor` to skip whole-action-cache invalidation for named high-volume action sync events, and action-query retries are bounded to one attempt for network-level failures (Chrome reports connection-pool exhaustion as a generic fetch failure, so unbounded retries sustained the storm).
|
|
8
|
+
- 16f7429: Defer collaborative rich-markdown seed writes to a timer task so initial Y.Doc seeding does not call `setContent` from React lifecycle.
|
|
9
|
+
- 254f061: Defer agent-authored URL navigation out of React effects to avoid lifecycle flushSync warnings.
|
|
10
|
+
- 69e1e38: Defer collaborative awareness presence updates so editor creation does not trigger React render-time state warnings.
|
|
11
|
+
- 8976a28: Log framework route failures with route, status, message, and development stacks before returning JSON errors.
|
|
12
|
+
- d61ca0c: The collaborative reconcile applies external content on a timer task instead of a microtask, so `setContent` can no longer run inside a React lifecycle flush ("flushSync was called from inside a lifecycle method" console errors during collab reconciliation).
|
|
13
|
+
- 66ffcd9: Treat client-aborted framework route requests as disconnects instead of logging and returning 500 errors.
|
|
14
|
+
- a74a885: `useDbSync` batches consisting entirely of suppressed action events (via `suppressActionInvalidationFor`) now skip the fixed framework invalidation list (extension, slot, tool, and app-state keys) as well as the whole-action-cache invalidation — high-volume background mutations no longer refetch framework queries on every poll tick. Events are still forwarded to `onEvent` and per-source change versions still bump.
|
|
15
|
+
- d44ad4e: Concurrent top-level async transactions on the better-sqlite3 driver are serialized per connection. Previously a transaction starting while another was open saw `inTransaction` and opened a savepoint inside the other task's transaction, which then committed out from under it ("no such savepoint" 500s under concurrent reads/writes). Same-task nesting is detected via AsyncLocalStorage and keeps the direct savepoint path.
|
|
16
|
+
|
|
3
17
|
## 0.90.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.90.
|
|
3
|
+
"version": "0.90.2",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -2154,7 +2154,7 @@ function URLSync({ browserTabId }: { browserTabId?: string }) {
|
|
|
2154
2154
|
// Replace rather than push so repeated agent URL updates don't
|
|
2155
2155
|
// clutter the history stack and can't trigger extra remounts from
|
|
2156
2156
|
// router navigation lifecycle.
|
|
2157
|
-
navigate(url, { replace: true
|
|
2157
|
+
window.setTimeout(() => navigate(url, { replace: true }), 0);
|
|
2158
2158
|
} catch {
|
|
2159
2159
|
// Malformed command — ignore.
|
|
2160
2160
|
}
|
|
@@ -307,15 +307,17 @@ export function useCollabReconcile({
|
|
|
307
307
|
// Seed only when the shared doc is genuinely empty — either the fragment has
|
|
308
308
|
// no nodes yet, or it holds no semantic markdown (an empty paragraph, or an
|
|
309
309
|
// app's sentinel-empty filler via a custom `shouldSeed`).
|
|
310
|
-
seededRef.current = true;
|
|
311
310
|
if (
|
|
312
311
|
!shouldSeed({ value, currentMarkdown, fragmentLength: fragment.length })
|
|
313
312
|
) {
|
|
313
|
+
seededRef.current = true;
|
|
314
314
|
return;
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
let cancelled = false;
|
|
318
|
-
|
|
318
|
+
// Defer via a timer task (NOT a microtask — microtasks can still run
|
|
319
|
+
// inside React's commit and trigger flushSync-from-lifecycle warnings).
|
|
320
|
+
const seedTimer = setTimeout(() => {
|
|
319
321
|
if (cancelled || editor.isDestroyed) return;
|
|
320
322
|
isSettingContentRef.current = true;
|
|
321
323
|
try {
|
|
@@ -329,9 +331,11 @@ export function useCollabReconcile({
|
|
|
329
331
|
lastAppliedValueRef.current = value;
|
|
330
332
|
lastAppliedSerializedRef.current = serialized;
|
|
331
333
|
if (contentUpdatedAt) lastAppliedUpdatedAtRef.current = contentUpdatedAt;
|
|
332
|
-
|
|
334
|
+
seededRef.current = true;
|
|
335
|
+
}, 0);
|
|
333
336
|
return () => {
|
|
334
337
|
cancelled = true;
|
|
338
|
+
clearTimeout(seedTimer);
|
|
335
339
|
};
|
|
336
340
|
}, [
|
|
337
341
|
collab,
|
|
@@ -466,10 +470,10 @@ export function useCollabReconcile({
|
|
|
466
470
|
return;
|
|
467
471
|
}
|
|
468
472
|
|
|
469
|
-
|
|
473
|
+
const applyTimer = setTimeout(() => {
|
|
470
474
|
if (cancelled || editor.isDestroyed) return;
|
|
471
475
|
// Re-check doc-equivalence at apply time. Between the decision above and
|
|
472
|
-
// this
|
|
476
|
+
// this task a peer/Yjs edit (or our own prior apply) may have made
|
|
473
477
|
// the editor already represent this value — re-applying would be a
|
|
474
478
|
// wasted setContent that, for non-idempotent input, re-triggers the
|
|
475
479
|
// loop. Skip when the editor's current serialization already matches the
|
|
@@ -521,7 +525,8 @@ export function useCollabReconcile({
|
|
|
521
525
|
if (contentUpdatedAt) {
|
|
522
526
|
lastAppliedUpdatedAtRef.current = contentUpdatedAt;
|
|
523
527
|
}
|
|
524
|
-
});
|
|
528
|
+
}, 0);
|
|
529
|
+
retry = applyTimer;
|
|
525
530
|
};
|
|
526
531
|
|
|
527
532
|
apply();
|
|
@@ -68,9 +68,41 @@ export function defaultActionQueryRetry(
|
|
|
68
68
|
// A timeout already made the user wait the full timeout window once;
|
|
69
69
|
// silently retrying would multiply that wait. Surface it instead.
|
|
70
70
|
if (isActionTimeout(error)) return false;
|
|
71
|
+
if (isBrowserResourceExhaustion(error)) return false;
|
|
72
|
+
// Network-level failures never carry an HTTP `status` (actionFetch only
|
|
73
|
+
// sets it after a response arrives). Chrome reports connection-pool
|
|
74
|
+
// exhaustion (net::ERR_INSUFFICIENT_RESOURCES) as a generic "Failed to
|
|
75
|
+
// fetch", indistinguishable from a transient blip — allow one retry, not
|
|
76
|
+
// three, so an exhausted tab cannot sustain its own fetch storm.
|
|
77
|
+
if (isNetworkLevelFailure(error)) return failureCount < 1;
|
|
71
78
|
return failureCount < 3;
|
|
72
79
|
}
|
|
73
80
|
|
|
81
|
+
/** @internal alias kept for existing specs. */
|
|
82
|
+
export const shouldRetryActionQueryForError = defaultActionQueryRetry;
|
|
83
|
+
|
|
84
|
+
function isBrowserResourceExhaustion(error: unknown): boolean {
|
|
85
|
+
const message =
|
|
86
|
+
error instanceof Error
|
|
87
|
+
? error.message
|
|
88
|
+
: typeof error === "string"
|
|
89
|
+
? error
|
|
90
|
+
: "";
|
|
91
|
+
return /ERR_INSUFFICIENT_RESOURCES|insufficient resources/i.test(message);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isNetworkLevelFailure(error: unknown): boolean {
|
|
95
|
+
// Match the exact shape actionFetch produces for fetch-level failures (its
|
|
96
|
+
// catch wraps the cause as "Action <name> failed: <cause>" and never sets a
|
|
97
|
+
// status). Other status-less errors (test doubles, transport internals)
|
|
98
|
+
// keep the standard three-retry policy.
|
|
99
|
+
return (
|
|
100
|
+
error instanceof Error &&
|
|
101
|
+
(error as { status?: unknown }).status === undefined &&
|
|
102
|
+
/^Action .+ failed: /.test(error.message)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
74
106
|
/**
|
|
75
107
|
* Default retry backoff for action queries. React Query's stock retryDelay
|
|
76
108
|
* (1s → 2s → 4s) makes a failing query sit on a spinner for ~7s before the
|
|
@@ -436,12 +468,14 @@ export function useActionMutation<
|
|
|
436
468
|
"mutationFn"
|
|
437
469
|
> & {
|
|
438
470
|
method?: "POST" | "PUT" | "DELETE";
|
|
471
|
+
skipActionQueryInvalidation?: boolean;
|
|
439
472
|
},
|
|
440
473
|
) {
|
|
441
474
|
const queryClient = useQueryClient();
|
|
442
475
|
const {
|
|
443
476
|
method: methodOpt,
|
|
444
477
|
onSuccess,
|
|
478
|
+
skipActionQueryInvalidation = false,
|
|
445
479
|
...restOptions
|
|
446
480
|
} = options ?? ({} as any);
|
|
447
481
|
const method = methodOpt ?? "POST";
|
|
@@ -454,8 +488,11 @@ export function useActionMutation<
|
|
|
454
488
|
mutationFn: (params) =>
|
|
455
489
|
actionFetch<D>(actionName, method, params as Record<string, any>),
|
|
456
490
|
onSuccess: (...args: [any, any, any]) => {
|
|
457
|
-
//
|
|
458
|
-
|
|
491
|
+
// Most mutations change app data broadly. High-volume background
|
|
492
|
+
// mutations can opt out and perform narrower invalidation in onSuccess.
|
|
493
|
+
if (!skipActionQueryInvalidation) {
|
|
494
|
+
queryClient.invalidateQueries({ queryKey: ["action"] });
|
|
495
|
+
}
|
|
459
496
|
(onSuccess as Function)?.(...args);
|
|
460
497
|
},
|
|
461
498
|
});
|
|
@@ -561,6 +561,9 @@ export function subscribeSyncEvents(
|
|
|
561
561
|
* compatibility invalidate triggered by `action` events. Use this to keep
|
|
562
562
|
* expensive active queries on explicit-refresh semantics while still letting
|
|
563
563
|
* normal source-versioned queries react through `useChangeVersion`.
|
|
564
|
+
* @param options.suppressActionInvalidationFor - Action names whose sync events
|
|
565
|
+
* should not invalidate all action queries. Use only for high-volume
|
|
566
|
+
* background actions that perform their own narrow client invalidation.
|
|
564
567
|
*/
|
|
565
568
|
export function useDbSync(
|
|
566
569
|
options: {
|
|
@@ -576,6 +579,7 @@ export function useDbSync(
|
|
|
576
579
|
pauseWhenHidden?: boolean;
|
|
577
580
|
ignoreSource?: string;
|
|
578
581
|
actionInvalidatePredicate?: (query: Query) => boolean;
|
|
582
|
+
suppressActionInvalidationFor?: string[];
|
|
579
583
|
} = {},
|
|
580
584
|
): void {
|
|
581
585
|
const {
|
|
@@ -599,6 +603,11 @@ export function useDbSync(
|
|
|
599
603
|
options.actionInvalidatePredicate,
|
|
600
604
|
);
|
|
601
605
|
actionInvalidatePredicateRef.current = options.actionInvalidatePredicate;
|
|
606
|
+
const suppressActionInvalidationForRef = useRef(
|
|
607
|
+
options.suppressActionInvalidationFor,
|
|
608
|
+
);
|
|
609
|
+
suppressActionInvalidationForRef.current =
|
|
610
|
+
options.suppressActionInvalidationFor;
|
|
602
611
|
|
|
603
612
|
useEffect(() => {
|
|
604
613
|
const id = Symbol("useDbSync");
|
|
@@ -621,6 +630,18 @@ export function useDbSync(
|
|
|
621
630
|
const relevant = ignore
|
|
622
631
|
? events.filter((e) => e.requestSource !== ignore)
|
|
623
632
|
: events;
|
|
633
|
+
const suppressedActions = new Set(
|
|
634
|
+
suppressActionInvalidationForRef.current ?? [],
|
|
635
|
+
);
|
|
636
|
+
const isSuppressedActionEvent = (evt: SyncEvent) =>
|
|
637
|
+
evt.source === "action" &&
|
|
638
|
+
typeof evt.key === "string" &&
|
|
639
|
+
suppressedActions.has(evt.key);
|
|
640
|
+
const nonAwareness = relevant.filter((e) => e.source !== "awareness");
|
|
641
|
+
const suppressesWholeBatch =
|
|
642
|
+
nonAwareness.length > 0 &&
|
|
643
|
+
nonAwareness.every((evt) => evt.source === "action") &&
|
|
644
|
+
nonAwareness.every(isSuppressedActionEvent);
|
|
624
645
|
|
|
625
646
|
// Bump per-source change counters. Components that read these via
|
|
626
647
|
// `useChangeVersion(source)` and fold the value into a React Query
|
|
@@ -642,7 +663,7 @@ export function useDbSync(
|
|
|
642
663
|
|
|
643
664
|
if (invalidating.length > 0 && queryClient) {
|
|
644
665
|
const hasActionEvent = invalidating.some(
|
|
645
|
-
(evt) => evt.source === "action",
|
|
666
|
+
(evt) => evt.source === "action" && !isSuppressedActionEvent(evt),
|
|
646
667
|
);
|
|
647
668
|
if (hasActionEvent) {
|
|
648
669
|
// Custom apps frequently start with raw `useQuery` calls before
|
|
@@ -661,23 +682,28 @@ export function useDbSync(
|
|
|
661
682
|
// etc.). Templates' own data queries do NOT live here — they react
|
|
662
683
|
// through `useChangeVersion(source)` in their query keys instead, so
|
|
663
684
|
// a single change event doesn't fan out into "refetch everything".
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
queryClient.invalidateQueries({ queryKey: ["
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
685
|
+
// Suppressed-action-only batches skip this whole list (their
|
|
686
|
+
// mutations perform their own narrow invalidation) — but events must
|
|
687
|
+
// STILL reach the onEvent forwarding below, so guard, don't return.
|
|
688
|
+
if (!suppressesWholeBatch) {
|
|
689
|
+
queryClient.invalidateQueries({ queryKey: ["action"] });
|
|
690
|
+
queryClient.invalidateQueries({ queryKey: ["extension"] });
|
|
691
|
+
queryClient.invalidateQueries({ queryKey: ["extensions"] });
|
|
692
|
+
queryClient.invalidateQueries({ queryKey: ["extension-slots"] });
|
|
693
|
+
queryClient.invalidateQueries({ queryKey: ["slot-installs"] });
|
|
694
|
+
queryClient.invalidateQueries({ queryKey: ["slot-available"] });
|
|
695
|
+
queryClient.invalidateQueries({ queryKey: ["tool"] });
|
|
696
|
+
queryClient.invalidateQueries({ queryKey: ["tools"] });
|
|
697
|
+
queryClient.invalidateQueries({ queryKey: ["app-state"] });
|
|
698
|
+
if (hasAppStateEvent(invalidating, "navigate")) {
|
|
699
|
+
queryClient.invalidateQueries({ queryKey: ["navigate-command"] });
|
|
700
|
+
}
|
|
701
|
+
if (hasAppStateEvent(invalidating, "show-questions")) {
|
|
702
|
+
queryClient.invalidateQueries({ queryKey: ["show-questions"] });
|
|
703
|
+
}
|
|
704
|
+
if (hasAppStateEvent(invalidating, "__set_url__")) {
|
|
705
|
+
queryClient.invalidateQueries({ queryKey: ["__set_url__"] });
|
|
706
|
+
}
|
|
681
707
|
}
|
|
682
708
|
}
|
|
683
709
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
1
3
|
import { drizzle as drizzleD1 } from "drizzle-orm/d1";
|
|
2
4
|
import type { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
3
5
|
|
|
@@ -320,15 +322,26 @@ function getBetterSqliteDrizzle() {
|
|
|
320
322
|
* The patched transaction also patches the tx object it passes to the callback
|
|
321
323
|
* so that nested async calls (tx.transaction(async …)) work recursively.
|
|
322
324
|
*/
|
|
323
|
-
|
|
325
|
+
/** @internal exported for the async-tx concurrency spec */
|
|
326
|
+
export function patchBetterSqliteTransactions<
|
|
324
327
|
DB extends { transaction: (...args: any[]) => any; session: any },
|
|
325
328
|
>(db: DB, sqlite: { inTransaction: boolean; exec: (sql: string) => void }): DB {
|
|
326
329
|
let savepointSeq = 0;
|
|
330
|
+
// Concurrent TOP-LEVEL async transactions on the single better-sqlite3
|
|
331
|
+
// connection must not interleave: a second transaction starting while the
|
|
332
|
+
// first is open would see `inTransaction` and open a savepoint INSIDE the
|
|
333
|
+
// first transaction, which then commits out from under it ("no such
|
|
334
|
+
// savepoint"). Serialize top-level transactions through a promise chain;
|
|
335
|
+
// genuine same-task nesting (tx.transaction or db.transaction inside an
|
|
336
|
+
// open callback) is detected via AsyncLocalStorage and keeps the direct
|
|
337
|
+
// savepoint path so it cannot deadlock on the queue.
|
|
338
|
+
const txContext = new AsyncLocalStorage<boolean>();
|
|
339
|
+
let txChain: Promise<unknown> = Promise.resolve();
|
|
327
340
|
|
|
328
341
|
function makeAsyncTransaction(
|
|
329
342
|
originalTransaction: (...args: any[]) => any,
|
|
330
343
|
): (...args: any[]) => Promise<unknown> {
|
|
331
|
-
|
|
344
|
+
async function runTransactionBody(
|
|
332
345
|
cb: (tx: unknown) => unknown,
|
|
333
346
|
): Promise<unknown> {
|
|
334
347
|
// Extract the drizzle tx proxy synchronously — call the original with a
|
|
@@ -392,6 +405,23 @@ function patchBetterSqliteTransactions<
|
|
|
392
405
|
}
|
|
393
406
|
throw err;
|
|
394
407
|
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return function asyncTransaction(
|
|
411
|
+
cb: (tx: unknown) => unknown,
|
|
412
|
+
): Promise<unknown> {
|
|
413
|
+
if (txContext.getStore()) {
|
|
414
|
+
// Same-task nesting: run directly (savepoint path inside the open
|
|
415
|
+
// transaction). Queueing here would deadlock behind the outer tx.
|
|
416
|
+
return runTransactionBody(cb);
|
|
417
|
+
}
|
|
418
|
+
const run = () => txContext.run(true, () => runTransactionBody(cb));
|
|
419
|
+
const next = txChain.then(run, run);
|
|
420
|
+
txChain = next.then(
|
|
421
|
+
() => undefined,
|
|
422
|
+
() => undefined,
|
|
423
|
+
);
|
|
424
|
+
return next;
|
|
395
425
|
};
|
|
396
426
|
}
|
|
397
427
|
|
|
@@ -364,6 +364,48 @@ function installPluginReadyPlaceholders(
|
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
function logFrameworkRouteError(args: {
|
|
368
|
+
method: string | undefined;
|
|
369
|
+
route: string;
|
|
370
|
+
status: number;
|
|
371
|
+
error: unknown;
|
|
372
|
+
}): void {
|
|
373
|
+
const error = args.error as any;
|
|
374
|
+
const message = error?.message || String(args.error);
|
|
375
|
+
const prefix = `[agent-native] ${args.method ?? ""} ${args.route} failed (${args.status})`;
|
|
376
|
+
if (process.env.NODE_ENV === "production") {
|
|
377
|
+
console.error(`${prefix}: ${message}`);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
console.error(`${prefix}: ${message}`, error?.stack || args.error);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function isClientAbortError(error: unknown, event: H3Event): boolean {
|
|
384
|
+
const err = error as any;
|
|
385
|
+
const message = typeof err?.message === "string" ? err.message : "";
|
|
386
|
+
const code = typeof err?.code === "string" ? err.code : "";
|
|
387
|
+
const node = (event as any).node;
|
|
388
|
+
return (
|
|
389
|
+
message === "aborted" ||
|
|
390
|
+
code === "ECONNRESET" ||
|
|
391
|
+
node?.req?.destroyed === true ||
|
|
392
|
+
node?.res?.destroyed === true
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function debugClientAbort(args: {
|
|
397
|
+
method: string | undefined;
|
|
398
|
+
route: string;
|
|
399
|
+
error: unknown;
|
|
400
|
+
}): void {
|
|
401
|
+
if (process.env.NODE_ENV === "production") return;
|
|
402
|
+
const err = args.error as any;
|
|
403
|
+
const message = err?.message || String(args.error);
|
|
404
|
+
console.debug?.(
|
|
405
|
+
`[agent-native] ${args.method ?? ""} ${args.route} aborted by client: ${message}`,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
367
409
|
/**
|
|
368
410
|
* Await all tracked plugin initializations. Called by the readiness gate
|
|
369
411
|
* middleware before dispatching framework routes.
|
|
@@ -500,10 +542,16 @@ function registerMiddleware(
|
|
|
500
542
|
: typeof e?.status === "number"
|
|
501
543
|
? e.status
|
|
502
544
|
: 500;
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
545
|
+
if (isClientAbortError(err, event)) {
|
|
546
|
+
debugClientAbort({ method: event.method, route: reqPath, error: err });
|
|
547
|
+
return undefined;
|
|
548
|
+
}
|
|
549
|
+
logFrameworkRouteError({
|
|
550
|
+
method: event.method,
|
|
551
|
+
route: reqPath,
|
|
552
|
+
status,
|
|
553
|
+
error: err,
|
|
554
|
+
});
|
|
507
555
|
// Forward 5xx to server-side Sentry — Nitro's own `error` hook may not
|
|
508
556
|
// fire here because we convert the throw into a normal JSON response,
|
|
509
557
|
// and a console.error alone is invisible in deployed environments.
|
|
@@ -73,6 +73,11 @@ or generated image/video assets that another app can reference by ID and URL.
|
|
|
73
73
|
`assets.metadata.isStyleAnchor`.
|
|
74
74
|
6. Pass `tier: "fast"` for exploration, `tier: "best"` for final/high-value
|
|
75
75
|
output, or `tier: "auto"` when there is no clear preference.
|
|
76
|
+
- Model/ratio compatibility: Gemini image models accept any `aspectRatio`, but
|
|
77
|
+
`gpt-image-2` supports only `1:1`, `2:3`, and `3:2`. When the user needs
|
|
78
|
+
another ratio (16:9, 9:16, 4:5, 21:9, …), pick a Gemini model rather than
|
|
79
|
+
`gpt-image-2` — an unsupported pairing is rejected upstream. Source of truth
|
|
80
|
+
is `supportedAspectRatiosForModel` / `MODEL_ASPECT_RATIOS` in `shared/api.ts`.
|
|
76
81
|
7. Preserve returned `assetId`, `runId`, `previewUrl`, and `downloadUrl`.
|
|
77
82
|
8. Use `refine-image` for feedback on an existing asset, `edit-image` for
|
|
78
83
|
targeted changes, and `restyle-image` with `subjectAssetId` and
|
|
@@ -11,11 +11,39 @@ LLMs — including Gemini Pro — degrade complex logos. They smear gradients, d
|
|
|
11
11
|
|
|
12
12
|
1. The library has a `canonicalLogoUrl` (set via `set-canonical-logo --libraryId --assetId`). The asset's role is `logo_reference`.
|
|
13
13
|
2. **Logo compositing is a preset option.** A generation preset carries `includeLogo` (stored in the preset `settings` and surfaced as a first-class field). When a generation resolves to a preset with `includeLogo: true`, `generate-image` composites the logo. A generate call's own `includeLogo` arg, when passed, overrides the preset for that run; when omitted, the preset's value wins.
|
|
14
|
-
3.
|
|
14
|
+
3. **Preset skeletons generalize logo compositing.** A preset can also carry `settings.skeletonSpec`: background first, generated subject second, foreground layers last. If the skeleton already has a `foreground` layer with `source: "canonicalLogo"`, `includeLogo` is treated as a no-op for that run so the logo is not stamped twice. If the skeleton does not include the logo and `includeLogo` is true, the existing canonical-logo layer is appended at the default upper-right position during compositing.
|
|
15
|
+
4. When logo compositing is on, the prompt envelope adds:
|
|
15
16
|
> Leave a clean uncluttered area in the upper-right for the real brand logo; do not draw or approximate the logo yourself.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
5. Gemini returns an image with empty space in that corner.
|
|
18
|
+
6. `compositeLogo()` from `server/lib/image-processing.ts` (Sharp) loads the canonical logo PNG / SVG, resizes it to ~16% of the image width with reasonable inset, and composites it onto the generated image. Skeleton runs use `applyPresetSkeleton()` at the same seam.
|
|
19
|
+
7. Output: the image with the actual logo, pixel-perfect, vector-quality if the source is SVG.
|
|
20
|
+
|
|
21
|
+
## Preset skeletons
|
|
22
|
+
|
|
23
|
+
`settings.skeletonSpec` is the prototype storage shape:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
{
|
|
27
|
+
background: { type: "asset"; assetId: string };
|
|
28
|
+
mask?: { type: "asset"; assetId: string };
|
|
29
|
+
contentMode: "fill" | "cutout";
|
|
30
|
+
contentRegion?: { x: number; y: number; w: number; h: number };
|
|
31
|
+
dropShadow?: boolean;
|
|
32
|
+
foreground?: Array<{
|
|
33
|
+
source: "canonicalLogo" | { assetId: string };
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
w: number;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- The background is an uploaded or selected brand-library image asset. The compositor cover-fits it to the preset canvas and throws if the asset pixels are unavailable.
|
|
42
|
+
- `fill` drops an opaque generation into the content region, so it works through the normal managed provider path.
|
|
43
|
+
- When the resolved skeleton model is `gpt-image-2`, the action sends a managed edit/inpaint request instead of generate-then-composite: the uploaded plate is the `edit_target`, an optional same-size `mask` asset becomes the editable-area mask, and `maskFromPlateAlpha()` is only the fallback when no manual mask is set. Transparent mask pixels are editable, opaque pixels are sent as preserved regions, and the returned image is final. The manual mask or plate fallback must have transparent pixels.
|
|
44
|
+
- Other `cutout` skeletons ask for an isolated transparent subject, force `gpt-image-1`, attach the background plate as a `background_reference`/composition reference, request `background: "transparent"` through the managed Builder image provider, and only fall back to OpenAI BYOK when the managed provider fails. They clamp only the provider subject ratio to `1:1`, `2:3`, or `3:2`. The final skeleton canvas still uses the preset's requested aspect ratio.
|
|
45
|
+
- The prompt envelope for cutout mode asks for an isolated subject on an empty transparent background. The gpt-image-2 inpaint branch instead asks the model to render the requested foreground content inside the mask's transparent/open region while preserving logos, text, framing, and other opaque plate content.
|
|
46
|
+
- Background and foreground `assetId` values must belong to the selected brand kit and must be images.
|
|
19
47
|
|
|
20
48
|
## When to use it
|
|
21
49
|
|
|
@@ -26,8 +54,8 @@ LLMs — including Gemini Pro — degrade complex logos. They smear gradients, d
|
|
|
26
54
|
## When NOT to use it
|
|
27
55
|
|
|
28
56
|
- **Logo on a product** (a t-shirt mockup, a billboard scene, a coffee cup).
|
|
29
|
-
Compositing onto a flat corner is fine; compositing onto a curved or perspective surface needs mask-based inpainting
|
|
30
|
-
- **Multi-logo scenes** (a partner-logo wall, a footer sponsor row). Same reason
|
|
57
|
+
Compositing onto a flat corner is fine; compositing onto a curved or perspective surface needs mask-based inpainting. Use a gpt-image-2 skeleton plate with transparent editable regions when that exact layout is required.
|
|
58
|
+
- **Multi-logo scenes** (a partner-logo wall, a footer sponsor row). Same reason: use a prepared plate plus mask-inpaint skeleton, or ask the user to mock it up in design.
|
|
31
59
|
|
|
32
60
|
## Setting a canonical logo
|
|
33
61
|
|
|
@@ -43,10 +43,11 @@ prompt, aspectRatio }`.
|
|
|
43
43
|
`brand-kit` references to `libraryId`, `preset` references to `presetId`, and
|
|
44
44
|
`media-type` references to choosing image (`generate-image` /
|
|
45
45
|
`generate-image-batch`) or video (`generate-video`) generation. The current
|
|
46
|
-
library view auto-tags its brand kit as a visible removable chip
|
|
47
|
-
|
|
48
|
-
default; the image-model picker
|
|
49
|
-
generation actions may use when
|
|
46
|
+
library view auto-tags its brand kit as a visible removable chip, and the
|
|
47
|
+
generation preset editor auto-tags both its brand kit and preset. The image
|
|
48
|
+
model is the only remaining composer-side default; the image-model picker
|
|
49
|
+
writes `imageGenerationModel`, which image generation actions may use when
|
|
50
|
+
`model` is omitted.
|
|
50
51
|
- When a `preset` is tagged, the server embeds that preset's aesthetics and
|
|
51
52
|
creative philosophy (brand style brief, prompt template, text/logo policy,
|
|
52
53
|
output format) into your message inside a `<tagged-generation-presets>` block.
|
|
@@ -66,6 +67,24 @@ prompt, aspectRatio }`.
|
|
|
66
67
|
model never draws the logo itself. Pass `includeLogo` on a generate call only
|
|
67
68
|
to override the preset for that one run; otherwise omit it. See the
|
|
68
69
|
`logo-composite` skill.
|
|
70
|
+
- Preset skeletons live in `settings.skeletonSpec` on generation presets and
|
|
71
|
+
are edited from `/brand-kits/:libraryId/presets/:presetId`. They composite a
|
|
72
|
+
generated subject onto an uploaded brand background image and optional
|
|
73
|
+
foreground layers. When the resolved skeleton model is `gpt-image-2`, the
|
|
74
|
+
action uses managed mask inpainting: the uploaded plate is the edit source,
|
|
75
|
+
an optional same-size mask asset controls the editable area, and the plate's
|
|
76
|
+
alpha channel is used as the fallback mask when no manual mask is set. Opaque
|
|
77
|
+
mask pixels are sent as preserved regions, transparent mask pixels are
|
|
78
|
+
editable, and no local compositing runs. Other `cutout` skeletons force
|
|
79
|
+
`gpt-image-1`, request
|
|
80
|
+
transparent output through the managed Builder image provider, attach the
|
|
81
|
+
plate as a composition/background reference for layout awareness, clamp only
|
|
82
|
+
the provider subject ratio to a supported `gpt-image-1` ratio, and keep the
|
|
83
|
+
final skeleton canvas at the preset's requested ratio. See the
|
|
84
|
+
`logo-composite` skill.
|
|
85
|
+
- Humans can edit an existing generation preset from
|
|
86
|
+
`/brand-kits/:libraryId/presets/:presetId`. Use `navigate` with
|
|
87
|
+
`{ view: "preset", libraryId, presetId }` when sending a user to that editor.
|
|
69
88
|
- `asset-variants` is the shared live generation tray state. New image
|
|
70
89
|
candidates should appear there through `generate-image` or
|
|
71
90
|
`generate-image-batch`; do not invent page-local progress surfaces.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const fractionSchema = z.coerce.number().min(0).max(1);
|
|
4
|
+
const positiveFractionSchema = z.coerce.number().min(0.02).max(1);
|
|
5
|
+
|
|
6
|
+
export const presetSkeletonSpecSchema = z.object({
|
|
7
|
+
background: z.object({
|
|
8
|
+
type: z.literal("asset"),
|
|
9
|
+
assetId: z.string().min(1),
|
|
10
|
+
}),
|
|
11
|
+
mask: z
|
|
12
|
+
.object({
|
|
13
|
+
type: z.literal("asset"),
|
|
14
|
+
assetId: z.string().min(1),
|
|
15
|
+
})
|
|
16
|
+
.optional(),
|
|
17
|
+
contentMode: z.enum(["cutout", "fill"]),
|
|
18
|
+
contentRegion: z
|
|
19
|
+
.object({
|
|
20
|
+
x: fractionSchema,
|
|
21
|
+
y: fractionSchema,
|
|
22
|
+
w: positiveFractionSchema,
|
|
23
|
+
h: positiveFractionSchema,
|
|
24
|
+
})
|
|
25
|
+
.optional(),
|
|
26
|
+
dropShadow: z.coerce.boolean().optional(),
|
|
27
|
+
foreground: z
|
|
28
|
+
.array(
|
|
29
|
+
z.object({
|
|
30
|
+
source: z.union([
|
|
31
|
+
z.literal("canonicalLogo"),
|
|
32
|
+
z.object({ assetId: z.string().min(1) }),
|
|
33
|
+
]),
|
|
34
|
+
x: fractionSchema,
|
|
35
|
+
y: fractionSchema,
|
|
36
|
+
w: positiveFractionSchema,
|
|
37
|
+
}),
|
|
38
|
+
)
|
|
39
|
+
.max(8)
|
|
40
|
+
.optional(),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const generationPresetSettingsSchema = z
|
|
44
|
+
.object({
|
|
45
|
+
includeLogo: z.coerce.boolean().optional(),
|
|
46
|
+
skeletonSpec: presetSkeletonSpecSchema.nullable().optional(),
|
|
47
|
+
})
|
|
48
|
+
.catchall(z.unknown());
|
|
@@ -26,9 +26,14 @@ function accessContext(ctx?: AccessCtx) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export async function requireLibrary(id: string, ctx?: AccessCtx) {
|
|
29
|
+
const access = await requireLibraryAccess(id, ctx);
|
|
30
|
+
return access.resource;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function requireLibraryAccess(id: string, ctx?: AccessCtx) {
|
|
29
34
|
const access = await resolveAccess("asset-library", id, accessContext(ctx));
|
|
30
35
|
if (!access) throw new Error("Asset library not found or not accessible.");
|
|
31
|
-
return access
|
|
36
|
+
return access;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
export async function requireGenerationSessionInLibrary(
|
|
@@ -103,6 +108,7 @@ export function serializeLibrary(row: any) {
|
|
|
103
108
|
canonicalLogoAssetId: row.canonicalLogoAssetId,
|
|
104
109
|
coverAssetId: row.coverAssetId,
|
|
105
110
|
visibility: row.visibility,
|
|
111
|
+
accessRole: typeof row.accessRole === "string" ? row.accessRole : undefined,
|
|
106
112
|
archivedAt: row.archivedAt ?? null,
|
|
107
113
|
createdAt: row.createdAt,
|
|
108
114
|
updatedAt: row.updatedAt,
|
|
@@ -362,6 +368,7 @@ export function serializeAsset(
|
|
|
362
368
|
row.mediaType ?? (row.mimeType?.startsWith("video/") ? "video" : "image"),
|
|
363
369
|
role: row.role,
|
|
364
370
|
status: row.status,
|
|
371
|
+
category: metadata.category ?? null,
|
|
365
372
|
title: row.title,
|
|
366
373
|
description: row.description ?? metadata.description ?? null,
|
|
367
374
|
altText: row.altText,
|