mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 20:44:32 -05:00
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:
committed by
GitHub
parent
8ae90a7ad1
commit
f8b4e87a67
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
6
upcoming-release-notes/6942.md
Normal file
6
upcoming-release-notes/6942.md
Normal 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.
|
||||||
Reference in New Issue
Block a user