Skip to content

Conversation

@guitavano
Copy link
Contributor

@guitavano guitavano commented Sep 12, 2025

It was broken app runtime, then we were indexing MCP of vtex and figma with 0 tools.

Summary by CodeRabbit

  • Bug Fixes

    • Improved stability for Figma-related features by handling missing Figma client with clear errors instead of crashes.
    • Adjusted initialization to skip creating a Figma client when no access token is provided.
    • Made VTEX public URL handling resilient to undefined values to prevent errors.
  • Chores

    • Formatting updates to Slack actions and client code; no functional changes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 12, 2025

Walkthrough

Introduces nullable Figma client in state and adds runtime guards across Figma loader functions to throw "Figma client not found" when absent. Slack files receive signature and formatting adjustments without logic changes. VTEX module logs props and makes publicUrl check optional-safe.

Changes

Cohort / File(s) Change summary
Figma state nullability
figma/mod.ts
Makes state.figma type `FigmaClient
Figma loaders: client guards
figma/loaders/* (getComponents.ts, getFileImages.ts, getImagesSpecificNode.ts, getImagesToFills.ts, getNodes.ts, getSimplified.ts, getSimplifiedNodes.ts)
Adds runtime checks for ctx.figma; if missing, throws Error("Figma client not found"). Retains existing signatures and downstream calls/transformations. getSimplifiedNodes.ts now uses ctx.figma instead of constructing a client.
Slack: formatting-only edits
slack/actions/dms/send.ts, slack/actions/files/download.ts, slack/actions/files/info.ts, slack/client.ts
Reformats method signatures and some object/templated literals to multi-line forms. No behavioral changes; parameter and return types unchanged.
VTEX minor adjustments
vtex/mod.ts
Adds console.log("props", props). Safens URL scheme check to _publicUrl?.startsWith("https://"); behavior defers to else-branch when undefined.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant App as App (figma/mod.ts)
  participant State as State
  participant Loader as Figma Loader
  participant Figma as Figma API

  Caller->>App: init(props)
  App->>App: if props.accessToken\n create FigmaClient\n else null
  App-->>State: { figma: FigmaClient | null }

  Caller->>Loader: call loader(ctx)
  Loader->>Loader: guard ctx.figma?\n if not, throw "Figma client not found"
  alt figma present
    Loader->>Figma: request (getFile/getImages/...) with params
    Figma-->>Loader: response
    Loader-->>Caller: transformed result
  else figma missing
    Loader-->>Caller: error thrown
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • mcandeia

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The current description is a single vague sentence and does not follow the repository's required template: it omits a clear "What is this Contribution About?" summary, the required "Issue Link", the "Loom Video" screencast, and the "Demonstration Link", making the description insufficient for review. Please update the PR description to match the template by adding a concise summary of the changes and their purpose, linking the related issue (Issue: #NUMBER), and including a Loom video or demo link and a branch/environment where reviewers can test the changes; adding brief reproduction steps or expected behavior will also help the review.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The current title "Tavano/fix vtex and figma" is directly related to the primary changes in this branch (fixes to VTEX and multiple Figma loaders), so it communicates the main intent but includes a username prefix and is somewhat informal; it could be clearer about the nature of the fixes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Poem

A rabbit taps keys with a gentle thump,
Adds a guard so loaders won’t go bump.
If Figma’s gone, we fail with grace—
No mystery hops in API space.
Slack lines wrap neat, VTEX says “hi!”—
Carrots committed; tests whisk by. 🥕🐇

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tavano/fix-vtex-and-figma

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

Tagging Options

Should a new tag be published when this PR is merged?

  • 👍 for Patch 0.121.7 update
  • 🎉 for Minor 0.122.0 update
  • 🚀 for Major 1.0.0 update

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
figma/loaders/getImagesToFills.ts (1)

29-38: Possible undefined return when images are missing

images may be undefined; the else branch assigns imagesToReturn = images, causing the function to return undefined while the return type is Record<string, string>.

-  const images = (await ctx.figma.getImageFills(fileKey))?.meta?.images;
+  const images = (await ctx.figma.getImageFills(fileKey))?.meta?.images ?? {};
@@
-  } else {
-    imagesToReturn = images;
-  }
+  } else {
+    imagesToReturn = images;
+  }
🧹 Nitpick comments (9)
figma/loaders/getNodes.ts (1)

60-62: Prefer returning a typed error over throwing a generic Error

Throwing a plain Error likely surfaces as a 500. Consider returning a FigmaResponse with err to match downstream handling patterns.

-  if (!ctx.figma) {
-    throw new Error("Figma client not found");
-  }
+  if (!ctx.figma) {
+    return { err: "Figma client not found" } as FigmaResponse<FileNodesResponse>;
+  }
figma/loaders/getFileImages.ts (1)

93-96: Align error handling with FigmaResponse contract

Return a typed { err } instead of throwing to avoid 500s and keep callers’ response.err checks working.

-  if (!ctx.figma) {
-    throw new Error("Figma client not found");
-  }
+  if (!ctx.figma) {
+    return { err: "Figma client not found" } as FigmaResponse<{ images: Record<string, string | null> }>;
+  }
figma/loaders/getImagesSpecificNode.ts (1)

32-34: Consistent typed error instead of generic throw

For consistency with other loaders and consumers that check response.err, prefer returning a typed error.

-  if (!ctx.figma) {
-    throw new Error("Figma client not found");
-  }
+  if (!ctx.figma) {
+    return { err: "Figma client not found" } as FigmaResponse<{ images: Record<string, string> }>;
+  }
figma/loaders/getImagesToFills.ts (1)

26-28: Consider a typed/HTTP error instead of generic throw

Optional: return an HTTP 401/400 or a typed object for consistency across loaders.

-  if (!ctx.figma) {
-    throw new Error("Figma client not found");
-  }
+  if (!ctx.figma) {
+    throw new Error("Figma client not found");
+  }
vtex/mod.ts (1)

102-102: Remove noisy console log

Avoid logging props in production code.

-  console.log("props", props);
figma/loaders/getComponents.ts (1)

38-40: Prefer typed error return for consistency

Returning { err } keeps behavior consistent with subsequent response.err checks.

-  if (!ctx.figma) {
-    throw new Error("Figma client not found");
-  }
+  if (!ctx.figma) {
+    return { err: "Figma client not found" } as FigmaResponse<FigmaFile>;
+  }
slack/actions/files/download.ts (2)

40-42: Include status code in error for easier triage.
Minor ergonomics improvement.

-        message: `Failed to download file: ${
-          fileResponse.statusText || "Unknown error"
-        }`,
+        message: `Failed to download file: ${fileResponse.status} ${fileResponse.statusText || "Unknown error"}`,

56-56: Avoid O(n) string concat for base64; use std encoder (faster, lower memory).
The current Array(...).map(...).join("") pattern is costly for large files.

-    // Convert to base64
-    const base64 = btoa(
-      Array(bytes.length)
-        .fill("")
-        .map((_, i) => String.fromCharCode(bytes[i]))
-        .join(""),
-    );
+    // Convert to base64
+    const base64 = encodeBase64(bytes);

Add import at top:

import { encodeBase64 } from "jsr:@std/encoding/base64";

If you prefer pinned std, replace the import path accordingly.

slack/client.ts (1)

436-439: Consider adding timeouts/retries to all Slack fetches.
External calls currently have no timeouts or backoff. Recommend a small helper to add AbortController timeouts and optional retry-on-429/5xx.

Example helper:

async function fetchJson(url: string, init: RequestInit = {}, timeoutMs = 10000) {
  const ac = new AbortController();
  const t = setTimeout(() => ac.abort(), timeoutMs);
  try {
    const res = await fetch(url, { ...init, signal: ac.signal });
    return res.json();
  } finally {
    clearTimeout(t);
  }
}

Then swap return fetch(...).json() with fetchJson(...).

Also applies to: 480-483

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf06999 and dc19397.

📒 Files selected for processing (13)
  • figma/loaders/getComponents.ts (1 hunks)
  • figma/loaders/getFileImages.ts (1 hunks)
  • figma/loaders/getImagesSpecificNode.ts (1 hunks)
  • figma/loaders/getImagesToFills.ts (1 hunks)
  • figma/loaders/getNodes.ts (1 hunks)
  • figma/loaders/getSimplified.ts (1 hunks)
  • figma/loaders/getSimplifiedNodes.ts (1 hunks)
  • figma/mod.ts (2 hunks)
  • slack/actions/dms/send.ts (1 hunks)
  • slack/actions/files/download.ts (2 hunks)
  • slack/actions/files/info.ts (1 hunks)
  • slack/client.ts (4 hunks)
  • vtex/mod.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
figma/mod.ts (1)
figma/client.ts (1)
  • FigmaClient (84-294)
🔇 Additional comments (10)
slack/actions/files/info.ts (1)

25-27: LGTM — formatting-only

Template literal reformatting doesn’t alter runtime output.

figma/mod.ts (1)

14-15: State update looks good

Making figma nullable matches the new guards elsewhere.

slack/actions/dms/send.ts (2)

28-30: Signature formatting only — OK.
No behavioral change.


38-40: Error template reformat — OK.
Message content unchanged.

slack/actions/files/download.ts (2)

17-19: Signature formatting only — OK.
No runtime impact.


46-47: Content-Type defaulting — OK.
Sane default retained.

slack/client.ts (2)

436-439: Signature reformat — OK.
No logic change.


480-483: Signature reformat — OK.
No logic change.

figma/loaders/getSimplified.ts (1)

63-65: Null-guard added — OK. Verify error contract.
Throwing will bubble a 500 unless caught upstream. If callers expect a FigmaResponse error shape, prefer returning a structured error instead of throwing.

Would you like a patch returning a typed FigmaResponse error to align with other loaders’ contracts?

figma/loaders/getSimplifiedNodes.ts (1)

63-67: Null-guard + local alias — OK. Verify error contract.
Same note as getSimplified.ts regarding throw vs structured error.

Want a follow-up patch to return a FigmaResponse error instead of throwing here?

Comment on lines +26 to 33
const figma = props.accessToken
? new FigmaClient(
typeof props.accessToken === "string"
? props.accessToken
: props.accessToken.get()!,
)
: null;

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid non-null assertion and handle Secret.get() safely

props.accessToken being truthy doesn’t guarantee Secret.get() returns a string. This can create a client with an invalid token.

-  const figma = props.accessToken
-    ? new FigmaClient(
-      typeof props.accessToken === "string"
-        ? props.accessToken
-        : props.accessToken.get()!,
-    )
-    : null;
+  const token = typeof props.accessToken === "string"
+    ? props.accessToken.trim()
+    : props.accessToken.get()?.trim();
+  const figma = token ? new FigmaClient(token) : null;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In figma/mod.ts around lines 26–33, avoid using the non-null assertion on
props.accessToken.get(); instead obtain the token into a local variable (handle
both string and Secret cases), check that the result is a defined, non-empty
string, and only then pass it to new FigmaClient; if the token is
missing/invalid, set figma to null (or throw a clear error) so you don’t
construct a client with an invalid token. Ensure you do not use "!" and handle
the Secret.get() return safely.

Comment on lines +31 to +34
return {
success: false,
message: "Only Slack-hosted HTTPS file URLs are allowed.",
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Harden against cross-host redirects to prevent token leakage.
Even with an allowlist, automatic redirects could send Authorization headers to non-Slack hosts. Fetch with redirect: "manual" in the Slack client and validate Location/response.url stays allowed before following.

Apply in slack/client.ts:

-  downloadFile(fileUrl: string): Promise<Response> {
-    return fetch(fileUrl, { headers: this.botHeaders });
-  }
+  downloadFile(fileUrl: string): Promise<Response> {
+    return fetch(fileUrl, { headers: this.botHeaders, redirect: "manual" });
+  }

Then here, follow only safe redirects:

-    const fileResponse = await ctx.slack.downloadFile(props.fileUrl);
+    let fileResponse = await ctx.slack.downloadFile(props.fileUrl);
+    // Follow at most one redirect, staying within the allowlist
+    if (fileResponse.status >= 300 && fileResponse.status < 400) {
+      const location = fileResponse.headers.get("location");
+      if (!location) {
+        return { success: false, message: "Redirect without Location header." };
+      }
+      const next = new URL(location, props.fileUrl);
+      if (next.protocol !== "https:" || !allowed(next.hostname.toLowerCase())) {
+        return { success: false, message: "Redirect to non-Slack host blocked." };
+      }
+      fileResponse = await ctx.slack.downloadFile(next.toString());
+    }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +102 to 105
console.log("props", props);
const publicUrl = _publicUrl?.startsWith("https://")
? _publicUrl
: `https://${_publicUrl}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Bug: may produce "https://undefined" when publicUrl is absent

The optional chain makes the condition false when _publicUrl is undefined, yielding https://${_publicUrl} => https://undefined.

-  console.log("props", props);
-  const publicUrl = _publicUrl?.startsWith("https://")
-    ? _publicUrl
-    : `https://${_publicUrl}`;
+  if (!_publicUrl?.trim()) {
+    throw new Error("VTEX publicUrl is required");
+  }
+  const publicUrl = _publicUrl.startsWith("https://")
+    ? _publicUrl
+    : `https://${_publicUrl}`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log("props", props);
const publicUrl = _publicUrl?.startsWith("https://")
? _publicUrl
: `https://${_publicUrl}`;
if (!_publicUrl?.trim()) {
throw new Error("VTEX publicUrl is required");
}
const publicUrl = _publicUrl.startsWith("https://")
? _publicUrl
: `https://${_publicUrl}`;
🤖 Prompt for AI Agents
In vtex/mod.ts around lines 102 to 105, the current logic can produce
"https://undefined" because it uses optional chaining only in the startsWith
check; instead, first check that _publicUrl is defined/truthy before calling
startsWith or interpolating it. Update the assignment so it: 1) returns
_publicUrl unchanged if it's truthy and already starts with "https://", 2)
prefixes "https://" only when _publicUrl is a non-empty string that does not
already start with "https://", and 3) leaves publicUrl undefined (or another
safe default) when _publicUrl is missing. Ensure you perform the null/undefined
check before string operations to avoid "https://undefined".

@guitavano guitavano merged commit a2dc36b into main Sep 12, 2025
8 of 9 checks passed
@guitavano guitavano deleted the tavano/fix-vtex-and-figma branch September 12, 2025 16:06
@coderabbitai coderabbitai bot mentioned this pull request Nov 12, 2025
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.

3 participants