Skip to content

Commit 7609660

Browse files
constantantclaude
andcommitted
fix(openapi-resource-mocks): sanitize FormData/File/Blob args before DOM dispatch
CustomEvent.detail is cloned via structured clone when crossing Chrome Extension isolated worlds. FormData (and File/Blob) cannot be cloned across that boundary, causing detail to arrive as null in the content script and throwing on destructure. Sanitize non-cloneable args to descriptive strings in dispatchDomEvent (in-page history retains originals for getHistory()). Also add a null guard in the content script as a safety net for any future uncloneable type. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c9537a2 commit 7609660

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

tools/openapi-resource-devtools/src/content/content.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ function send(msg: unknown): void {
1414

1515
// ── Page → panel: relay live state-change events ─────────────────────────────
1616
function onMockEvent(e: Event): void {
17-
const { key, event } = (e as CustomEvent<{ key: string; event: unknown }>).detail;
17+
// detail is null when args contain a type that can't be structured-cloned across
18+
// Chrome Extension worlds (e.g. FormData, File, Blob).
19+
const detail = (e as CustomEvent<{ key: string; event: unknown } | null>).detail;
20+
if (!detail) return;
21+
const { key, event } = detail;
1822
send({ type: 'mock-event', key, event });
1923
}
2024
document.addEventListener('openapi-mock-event', onMockEvent);

tools/openapi-resource-mocks/src/lib/mock-resource-bus.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,25 @@ export class MockResourceBus {
120120
};
121121
}
122122

123+
private sanitizeArg(arg: unknown): unknown {
124+
if (typeof FormData !== 'undefined' && arg instanceof FormData) return '[FormData]';
125+
if (typeof File !== 'undefined' && arg instanceof File) return `[File: ${(arg as File).name}]`;
126+
if (typeof Blob !== 'undefined' && arg instanceof Blob) return '[Blob]';
127+
if (typeof ArrayBuffer !== 'undefined' && arg instanceof ArrayBuffer) return '[ArrayBuffer]';
128+
return arg;
129+
}
130+
131+
private sanitizeEventForDom(event: MockEvent): MockEvent {
132+
if (event.type === 'request' || event.type === 'caught') {
133+
return { ...event, args: event.args.map(a => this.sanitizeArg(a)) };
134+
}
135+
return event;
136+
}
137+
123138
private dispatchDomEvent(key: string, event: MockEvent): void {
124139
if (typeof document === 'undefined') return;
125140
document.dispatchEvent(
126-
new CustomEvent('openapi-mock-event', { detail: { key, event } }),
141+
new CustomEvent('openapi-mock-event', { detail: { key, event: this.sanitizeEventForDom(event) } }),
127142
);
128143
}
129144

0 commit comments

Comments
 (0)