From 52223d7aed77cb4e1f89fdc43ae5a5578772dff1 Mon Sep 17 00:00:00 2001 From: genkio <5327840+genkio@users.noreply.github.com> Date: Wed, 11 Mar 2026 18:03:37 +0900 Subject: [PATCH 1/4] Add external communication opt-out --- .../e2e/external-communication.spec.ts | 162 ++++++++++++++++++ packages/react-grab/src/core/index.tsx | 11 +- packages/react-grab/src/core/log-intro.ts | 9 +- .../react-grab/src/core/plugin-registry.ts | 3 + packages/react-grab/src/core/plugins/open.ts | 1 + packages/react-grab/src/index.ts | 5 +- packages/react-grab/src/types.ts | 8 + .../src/utils/get-script-options.ts | 4 + packages/react-grab/src/utils/mount-root.ts | 9 +- packages/react-grab/src/utils/open-file.ts | 14 ++ 10 files changed, 218 insertions(+), 8 deletions(-) create mode 100644 packages/react-grab/e2e/external-communication.spec.ts diff --git a/packages/react-grab/e2e/external-communication.spec.ts b/packages/react-grab/e2e/external-communication.spec.ts new file mode 100644 index 000000000..a8e0c9180 --- /dev/null +++ b/packages/react-grab/e2e/external-communication.spec.ts @@ -0,0 +1,162 @@ +import { test, expect } from "@playwright/test"; + +test.describe("External Communication", () => { + test("should skip external requests during initialization when disabled", async ({ + page, + }) => { + const requestedUrls: string[] = []; + + page.on("request", (request) => { + const requestUrl = request.url(); + if ( + requestUrl.startsWith("https://www.react-grab.com/api/version") || + requestUrl.startsWith("https://fonts.googleapis.com/") + ) { + requestedUrls.push(requestUrl); + } + }); + + await page.addInitScript(() => { + ( + window as { + __REACT_GRAB_OPTIONS__?: { + allowExternalCommunication?: boolean; + }; + } + ).__REACT_GRAB_OPTIONS__ = { + allowExternalCommunication: false, + }; + }); + + await page.goto("/", { waitUntil: "domcontentloaded" }); + await page.waitForFunction( + () => (window as { __REACT_GRAB__?: unknown }).__REACT_GRAB__ !== undefined, + { timeout: 5000 }, + ); + await page.waitForTimeout(300); + + expect(requestedUrls).toEqual([]); + + const hasFontLink = await page.evaluate(() => { + return document.getElementById("react-grab-fonts") !== null; + }); + + expect(hasFontLink).toBe(false); + }); + + test("should not open a remote open-file fallback when disabled", async ({ + page, + }) => { + const modifierKey = process.platform === "darwin" ? "Meta" : "Control"; + + await page.addInitScript(() => { + ( + window as { + __REACT_GRAB_OPTIONS__?: { + allowExternalCommunication?: boolean; + }; + } + ).__REACT_GRAB_OPTIONS__ = { + allowExternalCommunication: false, + }; + }); + + await page.goto("/", { waitUntil: "domcontentloaded" }); + await page.waitForFunction( + () => (window as { __REACT_GRAB__?: unknown }).__REACT_GRAB__ !== undefined, + { timeout: 5000 }, + ); + + await page.evaluate(() => { + (window as { __OPEN_FILE_URLS__?: string[] }).__OPEN_FILE_URLS__ = []; + + const originalFetch = window.fetch.bind(window); + window.fetch = async (input, init) => { + const requestUrl = + typeof input === "string" + ? input + : input instanceof URL + ? input.toString() + : input.url; + if ( + requestUrl.includes("/__open-in-editor") || + requestUrl.includes("/__nextjs_launch-editor") + ) { + return new Response("", { status: 404 }); + } + return originalFetch(input, init); + }; + + Object.defineProperty(window, "open", { + configurable: true, + value: (url?: string | URL) => { + const openUrls = + (window as { __OPEN_FILE_URLS__?: string[] }).__OPEN_FILE_URLS__ ?? + []; + openUrls.push(typeof url === "string" ? url : String(url ?? "")); + (window as { __OPEN_FILE_URLS__?: string[] }).__OPEN_FILE_URLS__ = + openUrls; + return null; + }, + }); + }); + + await page.evaluate(() => { + const api = ( + window as { + __REACT_GRAB__?: { + activate: () => void; + }; + } + ).__REACT_GRAB__; + api?.activate(); + }); + await page.waitForFunction( + () => + ( + window as { + __REACT_GRAB__?: { + isActive: () => boolean; + }; + } + ).__REACT_GRAB__?.isActive() === true, + { timeout: 5000 }, + ); + + const firstListItem = page.locator("li").first(); + await firstListItem.hover({ force: true }); + + await page.waitForFunction( + () => { + const api = ( + window as { + __REACT_GRAB__?: { + getState: () => { + isSelectionBoxVisible: boolean; + targetElement: unknown; + selectionFilePath: string | null; + }; + }; + } + ).__REACT_GRAB__; + const state = api?.getState(); + return Boolean( + (state?.isSelectionBoxVisible || state?.targetElement) && + state?.selectionFilePath, + ); + }, + { timeout: 5000 }, + ); + + await page.keyboard.down(modifierKey); + await page.keyboard.press("o"); + await page.keyboard.up(modifierKey); + await page.waitForTimeout(200); + + const openUrls = await page.evaluate(() => { + return (window as { __OPEN_FILE_URLS__?: string[] }).__OPEN_FILE_URLS__; + }); + + expect(openUrls ?? []).toEqual([]); + }); +}); diff --git a/packages/react-grab/src/core/index.tsx b/packages/react-grab/src/core/index.tsx index d05b4c85f..912f5a274 100644 --- a/packages/react-grab/src/core/index.tsx +++ b/packages/react-grab/src/core/index.tsx @@ -182,6 +182,7 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { activationMode: "toggle", keyHoldDuration: DEFAULT_KEY_HOLD_DURATION_MS, allowActivationInsideInput: true, + allowExternalCommunication: true, maxContextLines: DEFAULT_MAX_CONTEXT_LINES, ...scriptOptions, ...rawOptions, @@ -192,7 +193,7 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { } hasInited = true; - logIntro(); + logIntro(initialOptions.allowExternalCommunication ?? true); // eslint-disable-next-line @typescript-eslint/no-unused-vars -- need to omit enabled from settableOptions to avoid circular dependency const { enabled: _enabled, ...settableOptions } = initialOptions; @@ -2297,6 +2298,7 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { filePath, lineNumber ?? undefined, pluginRegistry.hooks.transformOpenFileUrl, + pluginRegistry.store.options.allowExternalCommunication, ); } return true; @@ -3131,7 +3133,10 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { }); const resolvedCssText = typeof cssText === "string" ? cssText : ""; - const rendererRoot = mountRoot(resolvedCssText); + const rendererRoot = mountRoot( + resolvedCssText, + pluginRegistry.store.options.allowExternalCommunication, + ); const isThemeEnabled = createMemo(() => pluginRegistry.store.theme.enabled); const isSelectionBoxThemeEnabled = createMemo( @@ -3504,6 +3509,8 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { copy: copyAction, hooks: { transformHtmlContent: pluginRegistry.hooks.transformHtmlContent, + allowExternalCommunication: + pluginRegistry.store.options.allowExternalCommunication, onOpenFile: pluginRegistry.hooks.onOpenFile, transformOpenFileUrl: pluginRegistry.hooks.transformOpenFileUrl, }, diff --git a/packages/react-grab/src/core/log-intro.ts b/packages/react-grab/src/core/log-intro.ts index 4d9165174..80ee05d80 100644 --- a/packages/react-grab/src/core/log-intro.ts +++ b/packages/react-grab/src/core/log-intro.ts @@ -1,7 +1,7 @@ import { LOGO_SVG } from "../constants.js"; import { isExtensionContext } from "../utils/is-extension-context.js"; -export const logIntro = () => { +export const logIntro = (allowExternalCommunication: boolean) => { try { const version = process.env.VERSION; const logoDataUri = `data:image/svg+xml;base64,${btoa(LOGO_SVG)}`; @@ -10,7 +10,12 @@ export const logIntro = () => { `background: #330039; color: #ffffff; border: 1px solid #d75fcb; padding: 4px 4px 4px 24px; border-radius: 4px; background-image: url("${logoDataUri}"); background-size: 16px 16px; background-repeat: no-repeat; background-position: 4px center; display: inline-block; margin-bottom: 4px;`, "", ); - if (navigator.onLine && version && !isExtensionContext()) { + if ( + allowExternalCommunication && + navigator.onLine && + version && + !isExtensionContext() + ) { fetch( `https://www.react-grab.com/api/version?source=browser&t=${Date.now()}`, { diff --git a/packages/react-grab/src/core/plugin-registry.ts b/packages/react-grab/src/core/plugin-registry.ts index 4f0e9dd15..1b7b4dfd0 100644 --- a/packages/react-grab/src/core/plugin-registry.ts +++ b/packages/react-grab/src/core/plugin-registry.ts @@ -36,6 +36,7 @@ interface OptionsState { activationMode: ActivationMode; keyHoldDuration: number; allowActivationInsideInput: boolean; + allowExternalCommunication: boolean; maxContextLines: number; activationKey: ActivationKey | undefined; getContent: ((elements: Element[]) => Promise | string) | undefined; @@ -46,6 +47,7 @@ const DEFAULT_OPTIONS: OptionsState = { activationMode: "toggle", keyHoldDuration: DEFAULT_KEY_HOLD_DURATION_MS, allowActivationInsideInput: true, + allowExternalCommunication: true, maxContextLines: DEFAULT_MAX_CONTEXT_LINES, activationKey: undefined, getContent: undefined, @@ -128,6 +130,7 @@ const createPluginRegistry = (initialOptions: SettableOptions = {}) => { "activationMode", "keyHoldDuration", "allowActivationInsideInput", + "allowExternalCommunication", "maxContextLines", "activationKey", "getContent", diff --git a/packages/react-grab/src/core/plugins/open.ts b/packages/react-grab/src/core/plugins/open.ts index 90672ac98..c9975fea0 100644 --- a/packages/react-grab/src/core/plugins/open.ts +++ b/packages/react-grab/src/core/plugins/open.ts @@ -22,6 +22,7 @@ export const openPlugin: Plugin = { context.filePath, context.lineNumber, context.hooks.transformOpenFileUrl, + context.hooks.allowExternalCommunication ?? true, ); } diff --git a/packages/react-grab/src/index.ts b/packages/react-grab/src/index.ts index 03066ad27..59d71cf29 100644 --- a/packages/react-grab/src/index.ts +++ b/packages/react-grab/src/index.ts @@ -44,12 +44,13 @@ export type { } from "./types.js"; import { init } from "./core/index.js"; -import type { Plugin, ReactGrabAPI } from "./types.js"; +import type { Options, Plugin, ReactGrabAPI } from "./types.js"; declare global { interface Window { __REACT_GRAB__?: ReactGrabAPI; __REACT_GRAB_DISABLED__?: boolean; + __REACT_GRAB_OPTIONS__?: Options; } } @@ -109,7 +110,7 @@ if (typeof window !== "undefined" && !window.__REACT_GRAB_DISABLED__) { if (window.__REACT_GRAB__) { globalApi = window.__REACT_GRAB__; } else { - globalApi = init(); + globalApi = init(window.__REACT_GRAB_OPTIONS__); window.__REACT_GRAB__ = globalApi; } flushPendingPlugins(globalApi); diff --git a/packages/react-grab/src/types.ts b/packages/react-grab/src/types.ts index 44135b9e6..f7c5a957d 100644 --- a/packages/react-grab/src/types.ts +++ b/packages/react-grab/src/types.ts @@ -210,6 +210,7 @@ export type ActivationMode = "toggle" | "hold"; export interface ActionContextHooks { transformHtmlContent: (html: string, elements: Element[]) => Promise; + allowExternalCommunication?: boolean; onOpenFile: (filePath: string, lineNumber?: number) => boolean | void; transformOpenFileUrl: ( url: string, @@ -368,6 +369,13 @@ export interface Options { activationMode?: ActivationMode; keyHoldDuration?: number; allowActivationInsideInput?: boolean; + /** + * Whether React Grab can make remote network requests or load remote assets. + * When disabled, React Grab skips version checks, remote font loading, and + * remote open-file fallbacks. + * @default true + */ + allowExternalCommunication?: boolean; maxContextLines?: number; activationKey?: ActivationKey; getContent?: (elements: Element[]) => Promise | string; diff --git a/packages/react-grab/src/utils/get-script-options.ts b/packages/react-grab/src/utils/get-script-options.ts index 6345a9726..4c707c076 100644 --- a/packages/react-grab/src/utils/get-script-options.ts +++ b/packages/react-grab/src/utils/get-script-options.ts @@ -28,6 +28,10 @@ const parseOptionsFromJson = (rawValue: unknown): Partial | null => { parsedOptions.allowActivationInsideInput = rawValue.allowActivationInsideInput; } + if (typeof rawValue.allowExternalCommunication === "boolean") { + parsedOptions.allowExternalCommunication = + rawValue.allowExternalCommunication; + } if ( typeof rawValue.maxContextLines === "number" && Number.isFinite(rawValue.maxContextLines) diff --git a/packages/react-grab/src/utils/mount-root.ts b/packages/react-grab/src/utils/mount-root.ts index e710ed6ea..05027220e 100644 --- a/packages/react-grab/src/utils/mount-root.ts +++ b/packages/react-grab/src/utils/mount-root.ts @@ -18,8 +18,13 @@ const loadFonts = () => { document.head.appendChild(link); }; -export const mountRoot = (cssText?: string) => { - loadFonts(); +export const mountRoot = ( + cssText?: string, + allowExternalCommunication = true, +) => { + if (allowExternalCommunication) { + loadFonts(); + } const mountedHost = document.querySelector(`[${ATTRIBUTE_NAME}]`); if (mountedHost) { diff --git a/packages/react-grab/src/utils/open-file.ts b/packages/react-grab/src/utils/open-file.ts index ad19996a8..6592dd314 100644 --- a/packages/react-grab/src/utils/open-file.ts +++ b/packages/react-grab/src/utils/open-file.ts @@ -26,6 +26,7 @@ export const openFile = async ( filePath: string, lineNumber: number | undefined, transformUrl?: (url: string, filePath: string, lineNumber?: number) => string, + allowExternalCommunication = true, ): Promise => { filePath = normalizeFileName(filePath); @@ -39,5 +40,18 @@ export const openFile = async ( const url = transformUrl ? transformUrl(rawUrl, filePath, lineNumber) : rawUrl; + if (!allowExternalCommunication) { + let targetUrl: URL; + try { + targetUrl = new URL(url, window.location.href); + } catch { + return; + } + const isHttpProtocol = + targetUrl.protocol === "http:" || targetUrl.protocol === "https:"; + if (isHttpProtocol && targetUrl.origin !== window.location.origin) { + return; + } + } window.open(url, "_blank", "noopener,noreferrer"); }; From 18b63c31febe199b911829baf7985484d36b0963 Mon Sep 17 00:00:00 2001 From: genkio <5327840+genkio@users.noreply.github.com> Date: Wed, 11 Mar 2026 18:21:57 +0900 Subject: [PATCH 2/4] Fix selection label external communication opt-out --- .../e2e/external-communication.spec.ts | 16 ++++++----- .../react-grab/src/components/renderer.tsx | 7 +---- packages/react-grab/src/core/index.tsx | 27 ++++++++++++------- packages/react-grab/src/core/plugins/open.ts | 2 +- packages/react-grab/src/types.ts | 3 ++- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/packages/react-grab/e2e/external-communication.spec.ts b/packages/react-grab/e2e/external-communication.spec.ts index a8e0c9180..d81434abf 100644 --- a/packages/react-grab/e2e/external-communication.spec.ts +++ b/packages/react-grab/e2e/external-communication.spec.ts @@ -44,11 +44,9 @@ test.describe("External Communication", () => { expect(hasFontLink).toBe(false); }); - test("should not open a remote open-file fallback when disabled", async ({ + test("should not open a remote open-file fallback from the selection label when disabled", async ({ page, }) => { - const modifierKey = process.platform === "darwin" ? "Meta" : "Control"; - await page.addInitScript(() => { ( window as { @@ -148,9 +146,15 @@ test.describe("External Communication", () => { { timeout: 5000 }, ); - await page.keyboard.down(modifierKey); - await page.keyboard.press("o"); - await page.keyboard.up(modifierKey); + await page.evaluate(() => { + const host = document.querySelector("[data-react-grab]"); + const shadowRoot = host?.shadowRoot; + const root = shadowRoot?.querySelector("[data-react-grab]"); + const clickableTagBadge = root?.querySelector( + "[data-react-grab-selection-label] .cursor-pointer", + ); + clickableTagBadge?.click(); + }); await page.waitForTimeout(200); const openUrls = await page.evaluate(() => { diff --git a/packages/react-grab/src/components/renderer.tsx b/packages/react-grab/src/components/renderer.tsx index 738cec8c4..737e0ae3c 100644 --- a/packages/react-grab/src/components/renderer.tsx +++ b/packages/react-grab/src/components/renderer.tsx @@ -6,7 +6,6 @@ import { FROZEN_GLOW_EDGE_PX, Z_INDEX_OVERLAY_CANVAS, } from "../constants.js"; -import { openFile } from "../utils/open-file.js"; import { isElementConnected } from "../utils/is-element-connected.js"; import { OverlayCanvas } from "./overlay-canvas.js"; import { SelectionLabel } from "./selection-label/index.js"; @@ -143,11 +142,7 @@ export const ReactGrabRenderer: Component = (props) => { isPendingDismiss={props.isPendingDismiss} onConfirmDismiss={props.onConfirmDismiss} onCancelDismiss={props.onCancelDismiss} - onOpen={() => { - if (props.selectionFilePath) { - openFile(props.selectionFilePath, props.selectionLineNumber); - } - }} + onOpen={props.onOpenSelectionFile} isContextMenuOpen={props.contextMenuPosition !== null} /> diff --git a/packages/react-grab/src/core/index.tsx b/packages/react-grab/src/core/index.tsx index 912f5a274..bd277eef5 100644 --- a/packages/react-grab/src/core/index.tsx +++ b/packages/react-grab/src/core/index.tsx @@ -2278,23 +2278,17 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { return false; }; - const handleOpenFileShortcut = (event: KeyboardEvent): boolean => { - if (event.key?.toLowerCase() !== "o" || isPromptMode()) return false; - if (!isActivated() || !(event.metaKey || event.ctrlKey)) return false; - + const openSelectionFile = (): boolean => { const filePath = store.selectionFilePath; const lineNumber = store.selectionLineNumber; if (!filePath) return false; - event.preventDefault(); - event.stopPropagation(); - const wasHandled = pluginRegistry.hooks.onOpenFile( filePath, lineNumber ?? undefined, ); if (!wasHandled) { - openFile( + void openFile( filePath, lineNumber ?? undefined, pluginRegistry.hooks.transformOpenFileUrl, @@ -2304,6 +2298,18 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { return true; }; + const handleOpenFileShortcut = (event: KeyboardEvent): boolean => { + if (event.key?.toLowerCase() !== "o" || isPromptMode()) return false; + if (!isActivated() || !(event.metaKey || event.ctrlKey)) return false; + + const didOpenSelectionFile = openSelectionFile(); + if (!didOpenSelectionFile) return false; + + event.preventDefault(); + event.stopPropagation(); + return true; + }; + const clearActionCycleIdleTimeout = () => { if (actionCycleIdleTimeoutId !== null) { window.clearTimeout(actionCycleIdleTimeoutId); @@ -3505,12 +3511,12 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { lineNumber, componentName, tagName, + allowExternalCommunication: + pluginRegistry.store.options.allowExternalCommunication, enterPromptMode: customEnterPromptMode ?? defaultEnterPromptMode, copy: copyAction, hooks: { transformHtmlContent: pluginRegistry.hooks.transformHtmlContent, - allowExternalCommunication: - pluginRegistry.store.options.allowExternalCommunication, onOpenFile: pluginRegistry.hooks.onOpenFile, transformOpenFileUrl: pluginRegistry.hooks.transformOpenFileUrl, }, @@ -4043,6 +4049,7 @@ export const init = (rawOptions?: Options): ReactGrabAPI => { selectionElementsCount={frozenElementsCount()} selectionFilePath={store.selectionFilePath ?? undefined} selectionLineNumber={store.selectionLineNumber ?? undefined} + onOpenSelectionFile={openSelectionFile} selectionTagName={selectionTagName()} selectionComponentName={resolvedComponentName()} selectionLabelVisible={selectionLabelVisible()} diff --git a/packages/react-grab/src/core/plugins/open.ts b/packages/react-grab/src/core/plugins/open.ts index c9975fea0..96a9c79d3 100644 --- a/packages/react-grab/src/core/plugins/open.ts +++ b/packages/react-grab/src/core/plugins/open.ts @@ -22,7 +22,7 @@ export const openPlugin: Plugin = { context.filePath, context.lineNumber, context.hooks.transformOpenFileUrl, - context.hooks.allowExternalCommunication ?? true, + context.allowExternalCommunication, ); } diff --git a/packages/react-grab/src/types.ts b/packages/react-grab/src/types.ts index f7c5a957d..c67304892 100644 --- a/packages/react-grab/src/types.ts +++ b/packages/react-grab/src/types.ts @@ -210,7 +210,6 @@ export type ActivationMode = "toggle" | "hold"; export interface ActionContextHooks { transformHtmlContent: (html: string, elements: Element[]) => Promise; - allowExternalCommunication?: boolean; onOpenFile: (filePath: string, lineNumber?: number) => boolean | void; transformOpenFileUrl: ( url: string, @@ -226,6 +225,7 @@ export interface ActionContext { lineNumber?: number; componentName?: string; tagName?: string; + allowExternalCommunication: boolean; enterPromptMode?: (agent?: AgentOptions) => void; hooks: ActionContextHooks; performWithFeedback: (action: () => Promise) => Promise; @@ -493,6 +493,7 @@ export interface ReactGrabRendererProps { selectionElementsCount?: number; selectionFilePath?: string; selectionLineNumber?: number; + onOpenSelectionFile?: () => void; selectionTagName?: string; selectionComponentName?: string; selectionLabelVisible?: boolean; From bb9da1f71e12537aad13a8e7efdb01d4c056bf3d Mon Sep 17 00:00:00 2001 From: genkio <5327840+genkio@users.noreply.github.com> Date: Wed, 11 Mar 2026 19:35:53 +0900 Subject: [PATCH 3/4] Harden external communication regression test --- .../react-grab/e2e/external-communication.spec.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/react-grab/e2e/external-communication.spec.ts b/packages/react-grab/e2e/external-communication.spec.ts index d81434abf..b7893eaa4 100644 --- a/packages/react-grab/e2e/external-communication.spec.ts +++ b/packages/react-grab/e2e/external-communication.spec.ts @@ -146,15 +146,11 @@ test.describe("External Communication", () => { { timeout: 5000 }, ); - await page.evaluate(() => { - const host = document.querySelector("[data-react-grab]"); - const shadowRoot = host?.shadowRoot; - const root = shadowRoot?.querySelector("[data-react-grab]"); - const clickableTagBadge = root?.querySelector( - "[data-react-grab-selection-label] .cursor-pointer", - ); - clickableTagBadge?.click(); - }); + const selectionLabelOpenButton = page.locator( + "[data-react-grab-selection-label] .cursor-pointer", + ); + await expect(selectionLabelOpenButton).toBeVisible(); + await selectionLabelOpenButton.click({ force: true }); await page.waitForTimeout(200); const openUrls = await page.evaluate(() => { From c4c9aabc5da08520d15eb36bcde37a712928d8e7 Mon Sep 17 00:00:00 2001 From: genkio <5327840+genkio@users.noreply.github.com> Date: Wed, 11 Mar 2026 20:33:34 +0900 Subject: [PATCH 4/4] Use void for fire-and-forget open action --- packages/react-grab/src/core/plugins/open.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-grab/src/core/plugins/open.ts b/packages/react-grab/src/core/plugins/open.ts index 96a9c79d3..3ebd61ef2 100644 --- a/packages/react-grab/src/core/plugins/open.ts +++ b/packages/react-grab/src/core/plugins/open.ts @@ -18,7 +18,7 @@ export const openPlugin: Plugin = { ); if (!wasHandled) { - openFile( + void openFile( context.filePath, context.lineNumber, context.hooks.transformOpenFileUrl,