Skip to content

feat: figma copy paste#2268

Open
sidmohanty11 wants to merge 9 commits into
BuilderIO:mainfrom
sidmohanty11:figma-cpy-paste
Open

feat: figma copy paste#2268
sidmohanty11 wants to merge 9 commits into
BuilderIO:mainfrom
sidmohanty11:figma-cpy-paste

Conversation

@sidmohanty11

Copy link
Copy Markdown
Contributor

No description provided.

Importing feature-flag definitions from @agent-native/core/feature-flags
dragged the barrel's server store -> settings/store -> db/client ->
request-telemetry chain into the client dev graph. Vite dev does not
tree-shake, so the browser evaluated it and request-telemetry's top-level
new AsyncLocalStorage() threw against the externalized node:async_hooks
stub, breaking app load in dev (prod tree-shakes it away).

- Add client-safe @agent-native/core/feature-flags/registry entry
  (package export + dev source alias + optimizeDeps).
- Resolve AsyncLocalStorage / EventEmitter lazily via
  process.getBuiltinModule (shared/optional-node-builtins.ts); no
  top-level value import, no-op fallback off Node.
- Repoint design + clips shared config and all 15 feature-flags SKILL.md
  docs at /registry.
- Add browser-safe import-graph regression guard spec.
@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Here's a visual recap of what changed:

Visual recap

Open the full interactive recap

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 3 potential issues 🟡

Review Details

Code Review Summary

This incremental review covers the new tokenless Figma clipboard path, which extracts and decodes the Kiwi buffer into editable HTML, tracks unresolved image fills for later hydration, and relays image-only clipboard pastes from the canvas iframe. The overall architecture is sound: the import action retains the REST path when available, local decoding is bounded, hydration uses access-scoped reads and durable storage, and the new UI provides a clear token-connect flow. I classified this as Standard risk because it changes shared import logic, server-side persistence, and browser clipboard handling.

Key Findings

  • 🟡 MEDIUM — Transient REST failures can be silently converted into an empty fallback when no local buffer exists.
  • 🟡 MEDIUM — Fallback image requests now omit all nodes after the first 50, causing visible layers to be lost in larger imports.
  • 🟡 MEDIUM — The iframe base64-encodes all pasted images before host-side limits are applied, creating avoidable memory pressure on large pastes.

The review also found the access checks and bounded local decoder protections useful and appropriate for this feature.

🧪 Browser testing: Will run after this review (PR touches UI code)

Comment thread templates/design/actions/import-figma-clipboard.ts
};
},
);
const ids = nodeIds.slice(0, MAX_FIGMA_IMAGE_IDS_PER_REQUEST);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Fetch all fallback image nodes in batches

This now sends only nodeIds.slice(0, MAX_FIGMA_IMAGE_IDS_PER_REQUEST) to Figma, while the importer still allows up to 256 fallback references. The previous implementation batched every node ID; imports with more than 50 vector, mask, or unsupported layers now omit all fallback images after the first 50 and persist an incomplete screen. Restore batching for the full set or reject oversized imports rather than silently dropping visible layers.

Additional Info
Reported independently by two review agents.

Fix in Builder

Comment on lines +10429 to +10437
var imageFiles = Array.from(e.clipboardData?.items ?? [])
.filter(function (item) {
return item.kind === "file" && item.type.startsWith("image/");
})
.map(function (item) { return item.getAsFile(); })
.filter(function (f): f is File { return Boolean(f); });
if (imageFiles.length > 0) {
stopNativeInteraction(e);
var readPromises = imageFiles.map(function (file) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Apply clipboard image limits before reading files

The bridge starts a FileReader for every image clipboard item and expands each into a base64 data URL before DesignCanvas applies its 20-file and 20 MB limits. A large multi-image paste can therefore allocate and post far more data than the host accepts, causing avoidable memory pressure or freezing the editor. Filter by count and File.size before readAsDataURL, and bound the reads.

Additional Info
Reported by one review agent.

Fix in Builder

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 2 potential issues 🔴

Review Details

Code Review Summary

This incremental review rechecked PR #2268 at the latest head. The two currently open comments about truncated fallback-node requests and late iframe image limits remain unresolved and were intentionally not reposted. The PR’s overall approach—local Kiwi decoding for tokenless pastes, placeholder tracking, scoped hydration, and durable image storage—is reasonable, with appropriate decoder and access guards.

New Findings

  • 🔴 HIGH — Deferred image hydration calls the Figma image-fill endpoint without passing the requested image references, so the hydration action cannot reliably retrieve the URLs needed to replace placeholders.
  • 🟡 MEDIUM — Hydration accepts an unbounded number of image refs while the durable mirroring path rejects more than 256, causing large valid imports to fail hydration entirely.

This remains Standard risk because the changes span shared server import logic, external API calls, persistence, and user-facing editor state.

🧪 Browser testing: Will run after this review (PR touches UI code)

* Used by `hydrate-figma-paste-images` to fill in `about:blank` placeholders
* that the local-kiwi clipboard decode path leaves behind.
*/
export async function resolveImageFillRefs(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Pass image references to the Figma image-fill request

fetchImageFillUrls receives imageRefs but calls figmaGet(/files/${fileKey}/images) without sending them as query parameters. The response is then indexed by each requested ref, so hydration will return no matching URLs (or an incomplete/unbounded response) and leave the imported about:blank placeholders unresolved. Pass the supported image IDs/hashes parameter to this request, or use the endpoint variant that accepts the refs.

Additional Info
Reported independently by two review agents; anchored on the new helper declaration because the request line is outside a commentable added hunk.

Fix in Builder

Comment on lines +211 to +213
let resolvedUrls: Map<string, string>;
try {
resolvedUrls = await resolveImageFillRefs(figmaFileKey, hashesToResolve);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Bound or batch image references during hydration

collectImageRefHashes can return every unique image fill from a local Kiwi import, but this passes the full list to resolveImageFillRefs; its durable mirroring path rejects more than 256 URLs instead of batching. A valid paste with 257+ distinct image fills therefore hydrates none of them after the user connects Figma. Batch within the existing limit or return partial progress with a retryable remainder.

Additional Info
Reported independently by three review agents; this issue was not among the currently open comments.

Fix in Builder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants