Update send function to propagate any errors and fix catchErrors to return the error in result when an unknown command/method is sent to the browser server (#6942)

* Fix send not returning error when catchErrors option is enabled and an unknown method error is encountered

* Add release notes for PR #6942

* Fix send to properly propagate errors from the server

* Update release note

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Joel Jeremy Marquez
2026-02-12 15:47:21 -08:00
committed by GitHub
parent 8ae90a7ad1
commit f8b4e87a67
7 changed files with 95 additions and 29 deletions

View File

@@ -14,7 +14,7 @@ export const initServer: T.InitServer = handlers => {
if (catchErrors) { if (catchErrors) {
return promise.then( return promise.then(
data => ({ data }), data => ({ data }),
err => ({ error: { message: err.message } }), error => ({ error }),
); );
} }
return promise; return promise;

View File

@@ -4,6 +4,17 @@ import type { ServerEvents } from '../../../types/server-events';
export declare function init(worker: Worker): Promise<unknown>; export declare function init(worker: Worker): Promise<unknown>;
export type Init = typeof init; export type Init = typeof init;
/**
* Send a command to the browser server.
*
* @param name The name of the command to be executed by the browser server.
* @param args The command arguments.
* @param options The options for the command. If `catchErrors` is true,
* and an error occurs, the promise will be resolved with an object that
* has an `error` property. Otherwise, the promise will be rejected with the error.
* @returns A promise that resolves with the command result, or rejects with an error if one occurs.
* If you want to catch errors as part of the resolved value instead of rejecting, use `sendCatch` instead.
*/
export declare function send<K extends keyof Handlers>( export declare function send<K extends keyof Handlers>(
name: K, name: K,
args: Parameters<Handlers[K]>[0], args: Parameters<Handlers[K]>[0],
@@ -22,6 +33,14 @@ export declare function send<K extends keyof Handlers>(
): Promise<Awaited<ReturnType<Handlers[K]>>>; ): Promise<Awaited<ReturnType<Handlers[K]>>>;
export type Send = typeof send; export type Send = typeof send;
/**
* Send a command to the browser server.
*
* @param name The name of the command to be executed by the browser server.
* @param args The command arguments.
* @returns A promise that resolves with an object containing either the command result or an error if one occurs.
* The promise will never reject, as errors are caught and returned as part of the resolved value.
*/
export declare function sendCatch<K extends keyof Handlers>( export declare function sendCatch<K extends keyof Handlers>(
name: K, name: K,
args?: Parameters<Handlers[K]>[0], args?: Parameters<Handlers[K]>[0],
@@ -34,12 +53,26 @@ export declare function sendCatch<K extends keyof Handlers>(
>; >;
export type SendCatch = typeof sendCatch; export type SendCatch = typeof sendCatch;
/** Server push listeners */
/**
* Listen to events pushed to the client from the browser server.
*
* @param name The name of the event to listen to.
* @param cb The callback to be called when the event is received.
* @returns A function that can be called to unregister the listener.
*/
export declare function listen<K extends keyof ServerEvents>( export declare function listen<K extends keyof ServerEvents>(
name: K, name: K,
cb: (arg: ServerEvents[K]) => void, cb: (arg: ServerEvents[K]) => void,
): () => void; ): () => void;
export type Listen = typeof listen; export type Listen = typeof listen;
/**
* Stop listening to events pushed to the client from the browser server.
*
* @param name The name of the event to stop listening to.
*/
export declare function unlisten(name: string): void; export declare function unlisten(name: string): void;
export type Unlisten = typeof unlisten; export type Unlisten = typeof unlisten;

View File

@@ -42,12 +42,14 @@ class ReconstructedError extends Error {
function handleMessage(msg) { function handleMessage(msg) {
if (msg.type === 'error') { if (msg.type === 'error') {
// An error happened while handling a message so cleanup the // An error happened while handling a message so cleanup the
// current reply handler. We don't care about the actual error - // current reply handler and reject the promise. The error will
// generic backend errors are handled separately and if you want // be propagated to the caller through this promise rejection.
// more specific handling you should manually forward the error const { id, error } = msg;
// through a normal reply. const handler = replyHandlers.get(id);
const { id } = msg; if (handler) {
replyHandlers.delete(id); replyHandlers.delete(id);
handler.reject(error);
}
} else if (msg.type === 'reply') { } else if (msg.type === 'reply') {
const { id, result, mutated, undoTag } = msg; const { id, result, mutated, undoTag } = msg;

View File

@@ -17,12 +17,14 @@ function connectSocket(onOpen) {
if (msg.type === 'error') { if (msg.type === 'error') {
// An error happened while handling a message so cleanup the // An error happened while handling a message so cleanup the
// current reply handler. We don't care about the actual error - // current reply handler and reject the promise. The error will
// generic backend errors are handled separately and if you want // be propagated to the caller through this promise rejection.
// more specific handling you should manually forward the error const { id, error } = msg;
// through a normal reply. const handler = replyHandlers.get(id);
const { id } = msg; if (handler) {
replyHandlers.delete(id); replyHandlers.delete(id);
handler.reject(error);
}
} else if (msg.type === 'reply') { } else if (msg.type === 'reply') {
let { result } = msg; let { result } = msg;
const { id, mutated, undoTag } = msg; const { id, mutated, undoTag } = msg;

View File

@@ -52,7 +52,7 @@ export const init: T.Init = function (_socketName, handlers) {
result: { error, data: null }, result: { error, data: null },
}); });
} else { } else {
process.parentPort.postMessage({ type: 'error', id }); process.parentPort.postMessage({ type: 'error', id, error });
} }
if (error.type === 'InternalError' && name !== 'api/load-budget') { if (error.type === 'InternalError' && name !== 'api/load-budget') {
@@ -66,14 +66,25 @@ export const init: T.Init = function (_socketName, handlers) {
}, },
); );
} else { } else {
logger.warn('Unknown method: ' + name); logger.error('Unknown server method: ' + name);
captureException(new Error('Unknown server method: ' + name)); captureException(new Error('Unknown server method: ' + name));
process.parentPort.postMessage({ const unknownMethodError = APIError('Unknown server method: ' + name);
type: 'reply',
id, if (catchErrors) {
result: null, process.parentPort.postMessage({
error: APIError('Unknown method: ' + name), type: 'reply',
}); id,
result: catchErrors
? { error: unknownMethodError, data: null }
: null,
});
} else {
process.parentPort.postMessage({
type: 'error',
id,
error: unknownMethodError,
});
}
} }
}); });
}; };

View File

@@ -79,7 +79,7 @@ export const init: T.Init = function (serverChn, handlers) {
result: { error, data: null }, result: { error, data: null },
}); });
} else { } else {
serverChannel.postMessage({ type: 'error', id }); serverChannel.postMessage({ type: 'error', id, error });
} }
// Only report internal errors // Only report internal errors
@@ -94,13 +94,25 @@ export const init: T.Init = function (serverChn, handlers) {
}, },
); );
} else { } else {
logger.warn('Unknown method: ' + name); logger.error('Unknown server method: ' + name);
serverChannel.postMessage({ captureException(new Error('Unknown server method: ' + name));
type: 'reply', const unknownMethodError = APIError('Unknown server method: ' + name);
id,
result: null, if (catchErrors) {
error: APIError('Unknown method: ' + name), serverChannel.postMessage({
}); type: 'reply',
id,
result: catchErrors
? { error: unknownMethodError, data: null }
: null,
});
} else {
serverChannel.postMessage({
type: 'error',
id,
error: unknownMethodError,
});
}
} }
}, },
false, false,

View File

@@ -0,0 +1,6 @@
---
category: Bugfixes
authors: [joel-jeremy]
---
Update `send` function to propagate any errors and fix `catchErrors` to return the error in result when an unknown command/method is sent to the browser server.