Skip to content

Commit f8b4e87

Browse files
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>
1 parent 8ae90a7 commit f8b4e87

File tree

7 files changed

+95
-29
lines changed

7 files changed

+95
-29
lines changed

packages/loot-core/src/platform/client/fetch/__mocks__/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const initServer: T.InitServer = handlers => {
1414
if (catchErrors) {
1515
return promise.then(
1616
data => ({ data }),
17-
err => ({ error: { message: err.message } }),
17+
error => ({ error }),
1818
);
1919
}
2020
return promise;

packages/loot-core/src/platform/client/fetch/index-types.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ import type { ServerEvents } from '../../../types/server-events';
44
export declare function init(worker: Worker): Promise<unknown>;
55
export type Init = typeof init;
66

7+
/**
8+
* Send a command to the browser server.
9+
*
10+
* @param name The name of the command to be executed by the browser server.
11+
* @param args The command arguments.
12+
* @param options The options for the command. If `catchErrors` is true,
13+
* and an error occurs, the promise will be resolved with an object that
14+
* has an `error` property. Otherwise, the promise will be rejected with the error.
15+
* @returns A promise that resolves with the command result, or rejects with an error if one occurs.
16+
* If you want to catch errors as part of the resolved value instead of rejecting, use `sendCatch` instead.
17+
*/
718
export declare function send<K extends keyof Handlers>(
819
name: K,
920
args: Parameters<Handlers[K]>[0],
@@ -22,6 +33,14 @@ export declare function send<K extends keyof Handlers>(
2233
): Promise<Awaited<ReturnType<Handlers[K]>>>;
2334
export type Send = typeof send;
2435

36+
/**
37+
* Send a command to the browser server.
38+
*
39+
* @param name The name of the command to be executed by the browser server.
40+
* @param args The command arguments.
41+
* @returns A promise that resolves with an object containing either the command result or an error if one occurs.
42+
* The promise will never reject, as errors are caught and returned as part of the resolved value.
43+
*/
2544
export declare function sendCatch<K extends keyof Handlers>(
2645
name: K,
2746
args?: Parameters<Handlers[K]>[0],
@@ -34,12 +53,26 @@ export declare function sendCatch<K extends keyof Handlers>(
3453
>;
3554
export type SendCatch = typeof sendCatch;
3655

56+
/** Server push listeners */
57+
58+
/**
59+
* Listen to events pushed to the client from the browser server.
60+
*
61+
* @param name The name of the event to listen to.
62+
* @param cb The callback to be called when the event is received.
63+
* @returns A function that can be called to unregister the listener.
64+
*/
3765
export declare function listen<K extends keyof ServerEvents>(
3866
name: K,
3967
cb: (arg: ServerEvents[K]) => void,
4068
): () => void;
4169
export type Listen = typeof listen;
4270

71+
/**
72+
* Stop listening to events pushed to the client from the browser server.
73+
*
74+
* @param name The name of the event to stop listening to.
75+
*/
4376
export declare function unlisten(name: string): void;
4477
export type Unlisten = typeof unlisten;
4578

packages/loot-core/src/platform/client/fetch/index.browser.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,14 @@ class ReconstructedError extends Error {
4242
function handleMessage(msg) {
4343
if (msg.type === 'error') {
4444
// An error happened while handling a message so cleanup the
45-
// current reply handler. We don't care about the actual error -
46-
// generic backend errors are handled separately and if you want
47-
// more specific handling you should manually forward the error
48-
// through a normal reply.
49-
const { id } = msg;
50-
replyHandlers.delete(id);
45+
// current reply handler and reject the promise. The error will
46+
// be propagated to the caller through this promise rejection.
47+
const { id, error } = msg;
48+
const handler = replyHandlers.get(id);
49+
if (handler) {
50+
replyHandlers.delete(id);
51+
handler.reject(error);
52+
}
5153
} else if (msg.type === 'reply') {
5254
const { id, result, mutated, undoTag } = msg;
5355

packages/loot-core/src/platform/client/fetch/index.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ function connectSocket(onOpen) {
1717

1818
if (msg.type === 'error') {
1919
// An error happened while handling a message so cleanup the
20-
// current reply handler. We don't care about the actual error -
21-
// generic backend errors are handled separately and if you want
22-
// more specific handling you should manually forward the error
23-
// through a normal reply.
24-
const { id } = msg;
25-
replyHandlers.delete(id);
20+
// current reply handler and reject the promise. The error will
21+
// be propagated to the caller through this promise rejection.
22+
const { id, error } = msg;
23+
const handler = replyHandlers.get(id);
24+
if (handler) {
25+
replyHandlers.delete(id);
26+
handler.reject(error);
27+
}
2628
} else if (msg.type === 'reply') {
2729
let { result } = msg;
2830
const { id, mutated, undoTag } = msg;

packages/loot-core/src/platform/server/connection/index.electron.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const init: T.Init = function (_socketName, handlers) {
5252
result: { error, data: null },
5353
});
5454
} else {
55-
process.parentPort.postMessage({ type: 'error', id });
55+
process.parentPort.postMessage({ type: 'error', id, error });
5656
}
5757

5858
if (error.type === 'InternalError' && name !== 'api/load-budget') {
@@ -66,14 +66,25 @@ export const init: T.Init = function (_socketName, handlers) {
6666
},
6767
);
6868
} else {
69-
logger.warn('Unknown method: ' + name);
69+
logger.error('Unknown server method: ' + name);
7070
captureException(new Error('Unknown server method: ' + name));
71-
process.parentPort.postMessage({
72-
type: 'reply',
73-
id,
74-
result: null,
75-
error: APIError('Unknown method: ' + name),
76-
});
71+
const unknownMethodError = APIError('Unknown server method: ' + name);
72+
73+
if (catchErrors) {
74+
process.parentPort.postMessage({
75+
type: 'reply',
76+
id,
77+
result: catchErrors
78+
? { error: unknownMethodError, data: null }
79+
: null,
80+
});
81+
} else {
82+
process.parentPort.postMessage({
83+
type: 'error',
84+
id,
85+
error: unknownMethodError,
86+
});
87+
}
7788
}
7889
});
7990
};

packages/loot-core/src/platform/server/connection/index.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export const init: T.Init = function (serverChn, handlers) {
7979
result: { error, data: null },
8080
});
8181
} else {
82-
serverChannel.postMessage({ type: 'error', id });
82+
serverChannel.postMessage({ type: 'error', id, error });
8383
}
8484

8585
// Only report internal errors
@@ -94,13 +94,25 @@ export const init: T.Init = function (serverChn, handlers) {
9494
},
9595
);
9696
} else {
97-
logger.warn('Unknown method: ' + name);
98-
serverChannel.postMessage({
99-
type: 'reply',
100-
id,
101-
result: null,
102-
error: APIError('Unknown method: ' + name),
103-
});
97+
logger.error('Unknown server method: ' + name);
98+
captureException(new Error('Unknown server method: ' + name));
99+
const unknownMethodError = APIError('Unknown server method: ' + name);
100+
101+
if (catchErrors) {
102+
serverChannel.postMessage({
103+
type: 'reply',
104+
id,
105+
result: catchErrors
106+
? { error: unknownMethodError, data: null }
107+
: null,
108+
});
109+
} else {
110+
serverChannel.postMessage({
111+
type: 'error',
112+
id,
113+
error: unknownMethodError,
114+
});
115+
}
104116
}
105117
},
106118
false,

upcoming-release-notes/6942.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
category: Bugfixes
3+
authors: [joel-jeremy]
4+
---
5+
6+
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.

0 commit comments

Comments
 (0)