@agent-native/core 0.80.4 → 0.80.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +21 -2
- package/corpus/core/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -1
- package/corpus/core/docs/content/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/template-design.mdx +1 -1
- package/corpus/core/package.json +3 -7
- package/corpus/core/src/action.ts +21 -0
- package/corpus/core/src/agent/durable-background.ts +32 -11
- package/corpus/core/src/agent/production-agent.ts +11 -1
- package/corpus/core/src/agent/run-loop-with-resume.ts +3 -1
- package/corpus/core/src/brand-kit/fig/index.ts +17 -37
- package/corpus/core/src/cli/index.ts +1 -1
- package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
- package/corpus/core/src/cli/skills.ts +18 -3
- package/corpus/core/src/client/AssistantChat.tsx +11 -1
- package/corpus/core/src/client/agent-chat.ts +12 -1
- package/corpus/core/src/client/composer/PromptComposer.tsx +100 -41
- package/corpus/core/src/client/org/OrgSwitcher.tsx +1 -1
- package/corpus/core/src/client/sharing/ShareButton.tsx +3 -27
- package/corpus/core/src/collab/presence.ts +1 -1
- package/corpus/core/src/mcp/connect-route.ts +34 -5
- package/corpus/core/src/server/action-discovery.ts +4 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +20 -0
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
- package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
- package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
- package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
- package/corpus/templates/assets/actions/generate-image.ts +3 -0
- package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
- package/corpus/templates/assets/netlify.toml +3 -3
- package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
- package/corpus/templates/content/AGENTS.md +12 -0
- package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
- package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
- package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
- package/corpus/templates/content/app/global.css +9 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +12 -0
- package/corpus/templates/content/app/i18n-data.ts +140 -0
- package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
- package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
- package/corpus/templates/content/shared/builder-mdx.ts +141 -4
- package/corpus/templates/content/shared/nfm.ts +62 -0
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
- package/corpus/templates/design/AGENTS.md +5 -0
- package/corpus/templates/design/_gitignore +7 -0
- package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
- package/corpus/templates/design/actions/create-design-system.ts +15 -4
- package/corpus/templates/design/actions/create-file.ts +20 -1
- package/corpus/templates/design/actions/delete-design-system.ts +2 -2
- package/corpus/templates/design/actions/duplicate-design.ts +35 -9
- package/corpus/templates/design/actions/generate-design.ts +146 -69
- package/corpus/templates/design/actions/generate-screens.ts +51 -19
- package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
- package/corpus/templates/design/actions/get-design.ts +2 -0
- package/corpus/templates/design/actions/import-design-project.ts +28 -9
- package/corpus/templates/design/actions/import-document.ts +22 -8
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
- package/corpus/templates/design/actions/navigate.ts +105 -54
- package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
- package/corpus/templates/design/actions/show-design-questions.ts +2 -0
- package/corpus/templates/design/actions/update-design.ts +2 -1
- package/corpus/templates/design/actions/view-screen.ts +12 -6
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
- package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
- package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
- package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
- package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
- package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
- package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
- package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
- package/corpus/templates/design/app/global.css +4 -0
- package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
- package/corpus/templates/design/app/i18n-data.ts +527 -0
- package/corpus/templates/design/app/lib/design-systems.ts +6 -4
- package/corpus/templates/design/app/lib/design-templates.ts +15 -3
- package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
- package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
- package/corpus/templates/design/app/root.tsx +42 -9
- package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
- package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
- package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
- package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
- package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
- package/corpus/templates/design/e2e/README.md +71 -0
- package/corpus/templates/design/e2e/global-setup.ts +157 -0
- package/corpus/templates/design/e2e/helpers.ts +148 -0
- package/corpus/templates/design/netlify.toml +3 -4
- package/corpus/templates/design/package.json +5 -1
- package/corpus/templates/design/playwright.config.ts +51 -0
- package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
- package/corpus/templates/design/server/handlers/uploads.ts +89 -38
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
- package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
- package/corpus/templates/design/server/lib/design-export.ts +35 -8
- package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/design/server/plugins/auth.ts +10 -1
- package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
- package/corpus/templates/design/shared/api.ts +2 -0
- package/corpus/templates/design/shared/apply-edits.ts +12 -8
- package/corpus/templates/design/shared/canvas-math.ts +19 -1
- package/corpus/templates/design/shared/code-layer.ts +87 -28
- package/corpus/templates/design/shared/generation-session.ts +1 -0
- package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
- package/corpus/templates/design/shared/shader-presets.ts +10 -0
- package/corpus/templates/design/shared/source-mode.ts +9 -0
- package/corpus/templates/design/vitest.config.ts +2 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
- package/corpus/templates/plan/AGENTS.md +1 -1
- package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
- package/corpus/templates/plan/actions/validate-local-plan-source.ts +2 -10
- package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
- package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
- package/corpus/templates/plan/server/plan-content.ts +1 -1
- package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
- package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
- package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
- package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
- package/corpus/templates/slides/netlify.toml +3 -6
- package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
- package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
- package/dist/action.d.ts +15 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +6 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/durable-background.d.ts +9 -7
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +27 -11
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/production-agent.d.ts +7 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +4 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +2 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +2 -2
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/brand-kit/fig/index.d.ts +4 -4
- package/dist/brand-kit/fig/index.d.ts.map +1 -1
- package/dist/brand-kit/fig/index.js +14 -27
- package/dist/brand-kit/fig/index.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts +15 -7
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +198 -45
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/skills.d.ts +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +18 -3
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +11 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +15 -2
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +35 -1
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/org/OrgSwitcher.js +1 -1
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +2 -15
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/collab/presence.d.ts +1 -1
- package/dist/collab/presence.js +1 -1
- package/dist/collab/presence.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +34 -5
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +5 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +6 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +12 -3
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ar-SA/template-design.mdx +1 -1
- package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
- package/docs/content/locales/de-DE/template-design.mdx +1 -1
- package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/es-ES/template-design.mdx +1 -1
- package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/fr-FR/template-design.mdx +1 -1
- package/docs/content/locales/hi-IN/template-design.mdx +1 -1
- package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ja-JP/template-design.mdx +1 -1
- package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ko-KR/template-design.mdx +1 -1
- package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/pt-BR/template-design.mdx +1 -1
- package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/zh-CN/template-design.mdx +1 -1
- package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/zh-TW/template-design.mdx +1 -1
- package/docs/content/real-time-collaboration.mdx +2 -2
- package/docs/content/template-design.mdx +1 -1
- package/package.json +3 -7
- package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
- package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
- package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
- package/corpus/templates/design/actions/import-figma.ts +0 -55
- package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
- package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
- package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
- package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
- package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
- package/dist/brand-kit/fig/decode.d.ts +0 -33
- package/dist/brand-kit/fig/decode.d.ts.map +0 -1
- package/dist/brand-kit/fig/decode.js +0 -358
- package/dist/brand-kit/fig/decode.js.map +0 -1
- package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
- package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
- package/dist/brand-kit/fig/extract-design-system.js +0 -752
- package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
- package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
- package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
- package/dist/brand-kit/fig/fig-to-html.js +0 -1506
- package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
|
@@ -20,6 +20,7 @@ export const BUILDER_DOCS_MODELS = [
|
|
|
20
20
|
"docs-content",
|
|
21
21
|
"blog-article",
|
|
22
22
|
"agent-native-blog-article-test",
|
|
23
|
+
"symbol",
|
|
23
24
|
] as const;
|
|
24
25
|
|
|
25
26
|
export type BuilderDocsModel = (typeof BUILDER_DOCS_MODELS)[number] | string;
|
|
@@ -175,6 +176,7 @@ export function builderRawRootForEntry(model: string, entryId: string) {
|
|
|
175
176
|
function modelDirectory(model: string) {
|
|
176
177
|
if (model === "docs-content") return "docs";
|
|
177
178
|
if (model === "blog-article") return "blog";
|
|
179
|
+
if (model === "symbol") return "symbols";
|
|
178
180
|
return safePathPart(model);
|
|
179
181
|
}
|
|
180
182
|
|
|
@@ -194,6 +196,23 @@ export function builderMdxPathForEntry(entry: BuilderContentEntry) {
|
|
|
194
196
|
)}/${slug}${BUILDER_DOCS_MDX_EXTENSION}`;
|
|
195
197
|
}
|
|
196
198
|
|
|
199
|
+
function builderSymbolMdxPathForEntry(entry: BuilderContentEntry) {
|
|
200
|
+
const data = entry.data ?? {};
|
|
201
|
+
const title = builderEntryTitle(entry);
|
|
202
|
+
const handle = stringFromRecord(data, [
|
|
203
|
+
"handle",
|
|
204
|
+
"slug",
|
|
205
|
+
"urlPath",
|
|
206
|
+
"url",
|
|
207
|
+
"path",
|
|
208
|
+
]);
|
|
209
|
+
const slug = slugify(handle?.replace(/^\/+|\/+$/g, "") || title, entry.id);
|
|
210
|
+
return `${BUILDER_DOCS_CONTENT_ROOT}/symbols/${safePathPart(
|
|
211
|
+
entry.model,
|
|
212
|
+
"symbol",
|
|
213
|
+
)}/${slug}${BUILDER_DOCS_MDX_EXTENSION}`;
|
|
214
|
+
}
|
|
215
|
+
|
|
197
216
|
function stringFromRecord(
|
|
198
217
|
record: Record<string, unknown>,
|
|
199
218
|
keys: string[],
|
|
@@ -357,6 +376,50 @@ function childBlocks(block: unknown): unknown[] {
|
|
|
357
376
|
return Array.isArray(block.children) ? block.children : [];
|
|
358
377
|
}
|
|
359
378
|
|
|
379
|
+
function symbolContentEntry(
|
|
380
|
+
symbol: Record<string, unknown>,
|
|
381
|
+
): BuilderContentEntry | null {
|
|
382
|
+
const content = isRecord(symbol.content) ? symbol.content : null;
|
|
383
|
+
if (!content) return null;
|
|
384
|
+
const rawModel = stringFromRecord(symbol, ["model"]);
|
|
385
|
+
const rawEntry = stringFromRecord(symbol, ["entry"]);
|
|
386
|
+
const id = stringFromRecord(content, ["id", "entry", "uid"]) ?? rawEntry;
|
|
387
|
+
if (!id) return null;
|
|
388
|
+
|
|
389
|
+
const model =
|
|
390
|
+
stringFromRecord(content, ["model", "modelName", "queryModel"]) ??
|
|
391
|
+
rawModel ??
|
|
392
|
+
"symbol";
|
|
393
|
+
const data = isRecord(content.data)
|
|
394
|
+
? (JSON.parse(JSON.stringify(content.data)) as Record<string, unknown>)
|
|
395
|
+
: {};
|
|
396
|
+
if (!Array.isArray(data.blocks) && Array.isArray(content.blocks)) {
|
|
397
|
+
data.blocks = content.blocks;
|
|
398
|
+
}
|
|
399
|
+
if (!data.blocks) return null;
|
|
400
|
+
|
|
401
|
+
return {
|
|
402
|
+
...content,
|
|
403
|
+
id,
|
|
404
|
+
model,
|
|
405
|
+
name:
|
|
406
|
+
stringFromRecord(content, ["name"]) ??
|
|
407
|
+
stringFromRecord(data, ["title", "pageTitle", "name"]) ??
|
|
408
|
+
id,
|
|
409
|
+
published:
|
|
410
|
+
typeof content.published === "string" ? content.published : undefined,
|
|
411
|
+
lastUpdated:
|
|
412
|
+
typeof content.lastUpdated === "string" ||
|
|
413
|
+
typeof content.lastUpdated === "number"
|
|
414
|
+
? content.lastUpdated
|
|
415
|
+
: typeof content.updatedDate === "string" ||
|
|
416
|
+
typeof content.updatedDate === "number"
|
|
417
|
+
? content.updatedDate
|
|
418
|
+
: undefined,
|
|
419
|
+
data,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
360
423
|
function blockSummary(block: unknown) {
|
|
361
424
|
const name = componentName(block);
|
|
362
425
|
const options = componentOptions(block);
|
|
@@ -382,6 +445,7 @@ interface BlocksToMdxContext {
|
|
|
382
445
|
rawRoot: string;
|
|
383
446
|
files: Record<string, string>;
|
|
384
447
|
warnings: string[];
|
|
448
|
+
emitReferencedEntry: (entry: BuilderContentEntry) => Promise<string>;
|
|
385
449
|
}
|
|
386
450
|
|
|
387
451
|
async function builderBlocksToMdxBody(
|
|
@@ -493,10 +557,19 @@ async function builderBlockToMdx(
|
|
|
493
557
|
|
|
494
558
|
if (name === "Symbol") {
|
|
495
559
|
const symbol = isRecord(options.symbol) ? options.symbol : {};
|
|
560
|
+
const contentEntry = symbolContentEntry(symbol);
|
|
561
|
+
const source = contentEntry
|
|
562
|
+
? await ctx.emitReferencedEntry(contentEntry)
|
|
563
|
+
: undefined;
|
|
496
564
|
const data: BuilderSymbolData = {
|
|
497
565
|
...raw,
|
|
498
566
|
entry: typeof symbol.entry === "string" ? symbol.entry : undefined,
|
|
499
567
|
model: typeof symbol.model === "string" ? symbol.model : undefined,
|
|
568
|
+
source,
|
|
569
|
+
dynamic:
|
|
570
|
+
boolFromRecord(symbol, "dynamic") ??
|
|
571
|
+
boolFromRecord(symbol, "isDynamic") ??
|
|
572
|
+
boolFromRecord(options, "dynamicSymbol"),
|
|
500
573
|
data: isRecord(symbol.data) ? symbol.data : undefined,
|
|
501
574
|
};
|
|
502
575
|
return serializeRegistryBlockToMdx("builder-symbol", {
|
|
@@ -525,12 +598,76 @@ async function builderBlockToMdx(
|
|
|
525
598
|
export async function builderEntryToMdxBundle(
|
|
526
599
|
entry: BuilderContentEntry,
|
|
527
600
|
): Promise<BuilderMdxBundle> {
|
|
601
|
+
const files: Record<string, string> = {};
|
|
602
|
+
const warnings: string[] = [];
|
|
603
|
+
const emitted = new Set<string>();
|
|
604
|
+
const mdx = await emitBuilderEntryToMdxFile({
|
|
605
|
+
entry,
|
|
606
|
+
files,
|
|
607
|
+
warnings,
|
|
608
|
+
emitted,
|
|
609
|
+
symbolPath: false,
|
|
610
|
+
});
|
|
611
|
+
return { mdx, files, blocks: builderEntryBlocks(entry) };
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
async function emitBuilderEntryToMdxFile({
|
|
615
|
+
entry,
|
|
616
|
+
files,
|
|
617
|
+
warnings,
|
|
618
|
+
emitted,
|
|
619
|
+
symbolPath,
|
|
620
|
+
}: {
|
|
621
|
+
entry: BuilderContentEntry;
|
|
622
|
+
files: Record<string, string>;
|
|
623
|
+
warnings: string[];
|
|
624
|
+
emitted: Set<string>;
|
|
625
|
+
symbolPath: boolean;
|
|
626
|
+
}): Promise<BuilderMdxFile> {
|
|
627
|
+
const path = symbolPath
|
|
628
|
+
? builderSymbolMdxPathForEntry(entry)
|
|
629
|
+
: builderMdxPathForEntry(entry);
|
|
630
|
+
const key = `${entry.model}:${entry.id}:${path}`;
|
|
631
|
+
if (emitted.has(key)) {
|
|
632
|
+
return {
|
|
633
|
+
path,
|
|
634
|
+
documentId: builderDocumentId(entry.model, entry.id),
|
|
635
|
+
title: builderEntryTitle(entry),
|
|
636
|
+
metadata: {
|
|
637
|
+
model: entry.model,
|
|
638
|
+
entryId: entry.id,
|
|
639
|
+
lastUpdated: normalizeRemoteUpdatedAt(entry),
|
|
640
|
+
published: entry.published,
|
|
641
|
+
sourceHash: builderSourceHash(entry),
|
|
642
|
+
blocksHash: builderBlocksHash(builderEntryBlocks(entry)),
|
|
643
|
+
rawRoot: builderRawRootForEntry(entry.model, entry.id),
|
|
644
|
+
path,
|
|
645
|
+
},
|
|
646
|
+
frontmatter: {},
|
|
647
|
+
body: "",
|
|
648
|
+
source: files[path] ?? "",
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
emitted.add(key);
|
|
652
|
+
|
|
528
653
|
const blocks = builderEntryBlocks(entry);
|
|
529
654
|
const rawRoot = builderRawRootForEntry(entry.model, entry.id);
|
|
530
|
-
const
|
|
531
|
-
|
|
655
|
+
const ctx: BlocksToMdxContext = {
|
|
656
|
+
rawRoot,
|
|
657
|
+
files,
|
|
658
|
+
warnings,
|
|
659
|
+
emitReferencedEntry: async (referencedEntry) => {
|
|
660
|
+
const nested = await emitBuilderEntryToMdxFile({
|
|
661
|
+
entry: referencedEntry,
|
|
662
|
+
files,
|
|
663
|
+
warnings,
|
|
664
|
+
emitted,
|
|
665
|
+
symbolPath: true,
|
|
666
|
+
});
|
|
667
|
+
return nested.path;
|
|
668
|
+
},
|
|
669
|
+
};
|
|
532
670
|
const body = await builderBlocksToMdxBody(blocks, ctx);
|
|
533
|
-
const path = builderMdxPathForEntry(entry);
|
|
534
671
|
const blocksHash = builderBlocksHash(blocks);
|
|
535
672
|
const sourceHash = builderSourceHash(entry);
|
|
536
673
|
const frontmatter = frontmatterForEntry({
|
|
@@ -552,7 +689,7 @@ export async function builderEntryToMdxBundle(
|
|
|
552
689
|
source,
|
|
553
690
|
};
|
|
554
691
|
files[path] = source;
|
|
555
|
-
return
|
|
692
|
+
return mdx;
|
|
556
693
|
}
|
|
557
694
|
|
|
558
695
|
function parseFrontmatterValue(value: string): unknown {
|
|
@@ -673,6 +673,7 @@ function serializeBlock(node: PMNode, indent: number): string[] {
|
|
|
673
673
|
return serializeBlockAtom(node, ind);
|
|
674
674
|
case "registryBlock":
|
|
675
675
|
return serializeRegistryBlock(node, ind);
|
|
676
|
+
case "contentReference":
|
|
676
677
|
case "localMdxComponent":
|
|
677
678
|
return serializeRawSourceBlock(node, ind);
|
|
678
679
|
default: {
|
|
@@ -1199,6 +1200,19 @@ function parseSingleBlock(
|
|
|
1199
1200
|
return { nodes: [withIndentAttr(node)], end: childRes.end };
|
|
1200
1201
|
}
|
|
1201
1202
|
|
|
1203
|
+
// Content reference (Notion-style reusable MDX transclusion). The source
|
|
1204
|
+
// owns the reference; the editor resolves and previews it from local files.
|
|
1205
|
+
const contentReferenceTag = matchContentReferenceOpen(dedent);
|
|
1206
|
+
if (contentReferenceTag) {
|
|
1207
|
+
return parseContentReference(
|
|
1208
|
+
lines,
|
|
1209
|
+
start,
|
|
1210
|
+
indent,
|
|
1211
|
+
rel,
|
|
1212
|
+
contentReferenceTag,
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1202
1216
|
// Registry block (PascalCase MDX element: <Endpoint .../>, <Checklist .../>,
|
|
1203
1217
|
// <DataModel …>…</DataModel>, …). These are the dev-doc / OpenAPI library
|
|
1204
1218
|
// blocks shared with plan, encoded inline. They are recognized by the content
|
|
@@ -1288,6 +1302,12 @@ function matchRegistryBlockOpen(dedent: string): string | null {
|
|
|
1288
1302
|
return registryBlockSpecByTag(tag) ? tag : null;
|
|
1289
1303
|
}
|
|
1290
1304
|
|
|
1305
|
+
function matchContentReferenceOpen(dedent: string): string | null {
|
|
1306
|
+
return /^<ContentReference(?:[\s/>]|$)/.test(dedent)
|
|
1307
|
+
? "ContentReference"
|
|
1308
|
+
: null;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1291
1311
|
function matchLocalMdxComponentOpen(dedent: string): string | null {
|
|
1292
1312
|
const m = dedent.match(/^<([A-Z][\w-]*)(?:[\s/>]|$)/);
|
|
1293
1313
|
if (!m) return null;
|
|
@@ -1424,6 +1444,48 @@ function parseRegistryBlock(
|
|
|
1424
1444
|
return { nodes: [withIndentAttr(node)], end };
|
|
1425
1445
|
}
|
|
1426
1446
|
|
|
1447
|
+
function parseContentReference(
|
|
1448
|
+
lines: string[],
|
|
1449
|
+
start: number,
|
|
1450
|
+
indent: number,
|
|
1451
|
+
rel: number,
|
|
1452
|
+
_tag: string,
|
|
1453
|
+
): ParseResult {
|
|
1454
|
+
const withIndentAttr = (node: PMNode): PMNode => {
|
|
1455
|
+
if (rel > 0) node.attrs = { ...(node.attrs || {}), indent: rel };
|
|
1456
|
+
return node;
|
|
1457
|
+
};
|
|
1458
|
+
const dedented = lines.map((l) => stripTabs(l, indent));
|
|
1459
|
+
|
|
1460
|
+
let openEndLine = start;
|
|
1461
|
+
{
|
|
1462
|
+
let joined = "";
|
|
1463
|
+
for (let i = start; i < lines.length; i++) {
|
|
1464
|
+
joined += (i === start ? "" : "\n") + dedented[i];
|
|
1465
|
+
const res = scanOpenTagEnd(joined);
|
|
1466
|
+
if (res) {
|
|
1467
|
+
openEndLine = i;
|
|
1468
|
+
break;
|
|
1469
|
+
}
|
|
1470
|
+
openEndLine = i;
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
const rawLines = dedented.slice(start, openEndLine + 1);
|
|
1475
|
+
const raw = rawLines.join("\n");
|
|
1476
|
+
const props = parseAttrs(raw);
|
|
1477
|
+
const node: PMNode = {
|
|
1478
|
+
type: "contentReference",
|
|
1479
|
+
attrs: {
|
|
1480
|
+
sourcePath:
|
|
1481
|
+
props.sourcePath ?? props.path ?? props.source ?? props.href ?? "",
|
|
1482
|
+
title: props.title ?? null,
|
|
1483
|
+
__raw: raw,
|
|
1484
|
+
},
|
|
1485
|
+
};
|
|
1486
|
+
return { nodes: [withIndentAttr(node)], end: openEndLine + 1 };
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1427
1489
|
function parseLocalMdxComponent(
|
|
1428
1490
|
lines: string[],
|
|
1429
1491
|
start: number,
|
|
@@ -178,19 +178,18 @@ Extracts CSS tokens from a project's generated HTML, or clones an existing desig
|
|
|
178
178
|
### Source: Figma file
|
|
179
179
|
|
|
180
180
|
```bash
|
|
181
|
-
pnpm action
|
|
182
|
-
--
|
|
181
|
+
pnpm action index-design-system-with-builder \
|
|
182
|
+
--projectName "Acme Figma system" \
|
|
183
|
+
--codeFiles '[{"filename":"figma-summary.md","content":"<extracted tokens / styles summary>"}]'
|
|
183
184
|
```
|
|
184
185
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
4/8px scale. If no Figma MCP is connected, ask the user to paste the token
|
|
193
|
-
values or describe the file.
|
|
186
|
+
Builder is the required extraction/indexing path for Figma-backed design
|
|
187
|
+
systems. If a connected Figma MCP is available (tools like `get_variable_defs`,
|
|
188
|
+
`get_design_context`, `get_metadata`, `get_screenshot`), call those on the
|
|
189
|
+
file/selection first to pull real variables, color/text styles, and screenshot
|
|
190
|
+
notes, then pass that summary to `index-design-system-with-builder` as an
|
|
191
|
+
uploaded text context file. Do not build a local design system from the Figma
|
|
192
|
+
summary unless the user explicitly asks for a manual local fallback.
|
|
194
193
|
|
|
195
194
|
**When the user uploads a raw `.fig` file**, send it to Builder design-system
|
|
196
195
|
indexing through the setup page upload route. Do not parse `.fig` files locally
|
|
@@ -101,6 +101,11 @@ patterns live in `.agents/skills/`.
|
|
|
101
101
|
progress. External MCP hosts should use `present-design-variants` so the same
|
|
102
102
|
picker opens inline instead of writing `application_state` directly.
|
|
103
103
|
- Use framework sharing actions for design and design-system visibility/grants.
|
|
104
|
+
- `/visual-edit` is a public entry route and public `/design/:id` links may
|
|
105
|
+
render read-only public designs without a session. Do not open anonymous write
|
|
106
|
+
actions: save, share, generation, localhost connection, and screen persistence
|
|
107
|
+
should send signed-out visitors through `/_agent-native/sign-in?return=...`,
|
|
108
|
+
then save or copy the design into the authenticated account before sharing.
|
|
104
109
|
- When the user asks to download/export, use export actions or point to the
|
|
105
110
|
editor download menu.
|
|
106
111
|
- Design source modes are `inline`, `localhost`, and `fusion`. Inline is the
|
|
@@ -32,18 +32,28 @@ function parseJsonString(value: unknown): unknown {
|
|
|
32
32
|
|
|
33
33
|
const sourceSchema = z.preprocess(
|
|
34
34
|
parseJsonString,
|
|
35
|
-
z
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
z
|
|
36
|
+
.object({
|
|
37
|
+
kind: z
|
|
38
|
+
.enum(["design-file", "inline-html", "local-file", "remote-url"])
|
|
39
|
+
.default("design-file"),
|
|
40
|
+
designId: z.string().optional(),
|
|
41
|
+
fileId: z.string().optional(),
|
|
42
|
+
filename: z.string().optional().default("index.html"),
|
|
43
|
+
path: z.string().optional(),
|
|
44
|
+
url: z.string().optional(),
|
|
45
|
+
revision: z.string().optional(),
|
|
46
|
+
html: z.string().optional(),
|
|
47
|
+
})
|
|
48
|
+
.superRefine((source, ctx) => {
|
|
49
|
+
if (source.kind === "design-file" && !source.designId && !source.fileId) {
|
|
50
|
+
ctx.addIssue({
|
|
51
|
+
code: z.ZodIssueCode.custom,
|
|
52
|
+
path: ["designId"],
|
|
53
|
+
message: "designId or fileId is required for design-file sources",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}),
|
|
47
57
|
);
|
|
48
58
|
|
|
49
59
|
const targetSchema = z.object({
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
getRequestUserEmail,
|
|
4
4
|
getRequestOrgId,
|
|
5
5
|
} from "@agent-native/core/server/request-context";
|
|
6
|
-
import { eq } from "drizzle-orm";
|
|
6
|
+
import { and, eq, isNull } from "drizzle-orm";
|
|
7
7
|
import { nanoid } from "nanoid";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
@@ -66,12 +66,23 @@ export default defineAction({
|
|
|
66
66
|
if (!ownerEmail) throw new Error("no authenticated user");
|
|
67
67
|
const orgId = getRequestOrgId();
|
|
68
68
|
|
|
69
|
-
// Check only this user's owned systems. Shared systems
|
|
70
|
-
// the first system a user creates from becoming their
|
|
69
|
+
// Check only this user's owned systems within the same org. Shared systems
|
|
70
|
+
// should not prevent the first system a user creates from becoming their
|
|
71
|
+
// default, and systems in other orgs must not suppress the default in this org.
|
|
71
72
|
const existing = await db
|
|
72
73
|
.select({ id: schema.designSystems.id })
|
|
73
74
|
.from(schema.designSystems)
|
|
74
|
-
.where(
|
|
75
|
+
.where(
|
|
76
|
+
orgId
|
|
77
|
+
? and(
|
|
78
|
+
eq(schema.designSystems.ownerEmail, ownerEmail),
|
|
79
|
+
eq(schema.designSystems.orgId, orgId),
|
|
80
|
+
)
|
|
81
|
+
: and(
|
|
82
|
+
eq(schema.designSystems.ownerEmail, ownerEmail),
|
|
83
|
+
isNull(schema.designSystems.orgId),
|
|
84
|
+
),
|
|
85
|
+
)
|
|
75
86
|
.limit(1);
|
|
76
87
|
|
|
77
88
|
const isDefault = existing.length === 0;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { seedFromText } from "@agent-native/core/collab";
|
|
3
3
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
4
|
-
import { eq } from "drizzle-orm";
|
|
4
|
+
import { and, eq } from "drizzle-orm";
|
|
5
5
|
import { nanoid } from "nanoid";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
@@ -34,6 +34,25 @@ export default defineAction({
|
|
|
34
34
|
await assertAccess("design", designId, "editor");
|
|
35
35
|
|
|
36
36
|
const db = getDb();
|
|
37
|
+
|
|
38
|
+
// Guard against duplicate (designId, filename) — edit-design uses .limit(1)
|
|
39
|
+
// which is non-deterministic when multiple rows match the same key.
|
|
40
|
+
const [existing] = await db
|
|
41
|
+
.select({ id: schema.designFiles.id })
|
|
42
|
+
.from(schema.designFiles)
|
|
43
|
+
.where(
|
|
44
|
+
and(
|
|
45
|
+
eq(schema.designFiles.designId, designId),
|
|
46
|
+
eq(schema.designFiles.filename, filename),
|
|
47
|
+
),
|
|
48
|
+
)
|
|
49
|
+
.limit(1);
|
|
50
|
+
if (existing) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`File "${filename}" already exists in design ${designId} — use edit-design to modify it`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
37
56
|
const id = nanoid();
|
|
38
57
|
const now = new Date().toISOString();
|
|
39
58
|
|
|
@@ -7,12 +7,12 @@ import { getDb, schema } from "../server/db/index.js";
|
|
|
7
7
|
|
|
8
8
|
export default defineAction({
|
|
9
9
|
description:
|
|
10
|
-
"Delete a design system. Requires
|
|
10
|
+
"Delete a design system. Requires owner access. Designs linked to it are unlinked.",
|
|
11
11
|
schema: z.object({
|
|
12
12
|
id: z.string().min(1).describe("Design system ID to delete"),
|
|
13
13
|
}),
|
|
14
14
|
run: async ({ id }) => {
|
|
15
|
-
await assertAccess("design-system", id, "
|
|
15
|
+
await assertAccess("design-system", id, "owner");
|
|
16
16
|
|
|
17
17
|
const db = getDb();
|
|
18
18
|
|
|
@@ -31,14 +31,45 @@ export default defineAction({
|
|
|
31
31
|
const now = new Date().toISOString();
|
|
32
32
|
const newTitle = title || `Copy of ${source.title}`;
|
|
33
33
|
|
|
34
|
-
//
|
|
34
|
+
// Fetch source files first so we can remap canvasFrames before inserting
|
|
35
|
+
const files = await db
|
|
36
|
+
.select()
|
|
37
|
+
.from(schema.designFiles)
|
|
38
|
+
.where(eq(schema.designFiles.designId, id));
|
|
39
|
+
|
|
40
|
+
// Build old-to-new file ID mapping upfront
|
|
41
|
+
const idMap = new Map<string, string>(
|
|
42
|
+
files.map((file) => [file.id, nanoid()]),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Remap canvasFrames keys in source.data from old IDs to new IDs
|
|
46
|
+
let newData = source.data;
|
|
47
|
+
try {
|
|
48
|
+
const parsed =
|
|
49
|
+
typeof source.data === "string" ? JSON.parse(source.data) : source.data;
|
|
50
|
+
if (parsed && typeof parsed === "object" && parsed.canvasFrames) {
|
|
51
|
+
const remapped: Record<string, unknown> = {};
|
|
52
|
+
for (const [oldId, geometry] of Object.entries(parsed.canvasFrames)) {
|
|
53
|
+
const newFileId = idMap.get(oldId);
|
|
54
|
+
remapped[newFileId ?? oldId] = geometry;
|
|
55
|
+
}
|
|
56
|
+
newData =
|
|
57
|
+
typeof source.data === "string"
|
|
58
|
+
? JSON.stringify({ ...parsed, canvasFrames: remapped })
|
|
59
|
+
: { ...parsed, canvasFrames: remapped };
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// If data is unparseable, fall back to copying verbatim
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Copy the design with remapped canvasFrames
|
|
35
66
|
await db.insert(schema.designs).values({
|
|
36
67
|
id: newId,
|
|
37
68
|
title: newTitle,
|
|
38
69
|
description: source.description,
|
|
39
70
|
projectType: source.projectType,
|
|
40
71
|
designSystemId: source.designSystemId ?? null,
|
|
41
|
-
data:
|
|
72
|
+
data: newData,
|
|
42
73
|
ownerEmail: (() => {
|
|
43
74
|
const e = getRequestUserEmail();
|
|
44
75
|
if (!e) throw new Error("no authenticated user");
|
|
@@ -49,15 +80,10 @@ export default defineAction({
|
|
|
49
80
|
updatedAt: now,
|
|
50
81
|
});
|
|
51
82
|
|
|
52
|
-
// Copy all associated files
|
|
53
|
-
const files = await db
|
|
54
|
-
.select()
|
|
55
|
-
.from(schema.designFiles)
|
|
56
|
-
.where(eq(schema.designFiles.designId, id));
|
|
57
|
-
|
|
83
|
+
// Copy all associated files using the pre-generated IDs
|
|
58
84
|
for (const file of files) {
|
|
59
85
|
await db.insert(schema.designFiles).values({
|
|
60
|
-
id:
|
|
86
|
+
id: idMap.get(file.id)!,
|
|
61
87
|
designId: newId,
|
|
62
88
|
filename: file.filename,
|
|
63
89
|
fileType: file.fileType,
|