fix(vscode,ui): stop postMessage crash when opening chat in Cursor (#2335)
VS Code webviews delete window.parent, so ChatContainer's settings-sync effect threw TypeError on chat open. Also harden the webview bridge when acquireVsCodeApi() returns undefined and SSE panel disposal races. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
Cursor Agent
Serhii Dziupin
parent
200c02cd00
commit
485efc7117
@@ -0,0 +1,51 @@
|
||||
import { describe, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
/**
|
||||
* When acquireVsCodeApi() returns undefined (broken Cursor/VSCodium webview slot),
|
||||
* getVSCodeAPI().postMessage used to throw:
|
||||
* TypeError: Cannot read properties of undefined (reading 'postMessage')
|
||||
*
|
||||
* The bridge must fall back to a noop API and fail via normal request timeout instead.
|
||||
*/
|
||||
describe('VS Code webview bridge acquireVsCodeApi fallback', () => {
|
||||
test('does not throw TypeError when acquireVsCodeApi returns undefined', async () => {
|
||||
const originalWindow = globalThis.window;
|
||||
const originalAcquire = (globalThis as typeof globalThis & { acquireVsCodeApi?: unknown }).acquireVsCodeApi;
|
||||
const originalWarn = console.warn;
|
||||
const warnings: unknown[][] = [];
|
||||
|
||||
try {
|
||||
Object.defineProperty(globalThis, 'window', {
|
||||
configurable: true,
|
||||
value: new EventTarget(),
|
||||
});
|
||||
Object.defineProperty(globalThis, 'acquireVsCodeApi', {
|
||||
configurable: true,
|
||||
value: () => undefined,
|
||||
});
|
||||
console.warn = (...args: unknown[]) => {
|
||||
warnings.push(args);
|
||||
};
|
||||
|
||||
const { sendBridgeMessageWithOptions } = await import(`./bridge?acquire-fallback-${Date.now()}`);
|
||||
|
||||
const result = await sendBridgeMessageWithOptions('api:proxy', { path: '/health' }, { timeoutMs: 20 }).then(
|
||||
() => 'resolved' as const,
|
||||
(error: unknown) => error,
|
||||
);
|
||||
|
||||
assert.ok(result instanceof Error, `expected Error, got ${String(result)}`);
|
||||
assert.notEqual((result as Error).name, 'TypeError');
|
||||
assert.match((result as Error).message, /timed out/i);
|
||||
assert.ok(
|
||||
warnings.some((entry) => String(entry[0] ?? '').includes('VS Code API unavailable')),
|
||||
'expected a one-time warning that the VS Code API was unavailable',
|
||||
);
|
||||
} finally {
|
||||
console.warn = originalWarn;
|
||||
Object.defineProperty(globalThis, 'window', { configurable: true, value: originalWindow });
|
||||
Object.defineProperty(globalThis, 'acquireVsCodeApi', { configurable: true, value: originalAcquire });
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -9,10 +9,24 @@ interface VSCodeAPI {
|
||||
}
|
||||
|
||||
let vscodeApi: VSCodeAPI | null = null;
|
||||
let noopWarned = false;
|
||||
|
||||
const noopVSCodeApi: VSCodeAPI = {
|
||||
postMessage: (message) => {
|
||||
// acquireVsCodeApi() can return undefined in broken/non-standard webview slots
|
||||
// (Cursor after extension update, VSCodium, headless). Drop the message instead
|
||||
// of throwing TypeError: Cannot read properties of undefined (reading 'postMessage').
|
||||
if (!noopWarned) {
|
||||
noopWarned = true;
|
||||
console.warn('[openchamber] VS Code API unavailable; dropping postMessage', message);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function getVSCodeAPI(): VSCodeAPI {
|
||||
if (!vscodeApi) {
|
||||
vscodeApi = acquireVsCodeApi();
|
||||
const acquired = typeof acquireVsCodeApi === 'function' ? acquireVsCodeApi() : undefined;
|
||||
vscodeApi = acquired ?? noopVSCodeApi;
|
||||
}
|
||||
return vscodeApi;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user