From 67f48ebf845a40e73b4933f8b28b55a0a6019be6 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sun, 26 Dec 2021 21:28:32 +0100 Subject: refactor: Improve error handling in preload --- .../src/contextBridge/SophieRendererImpl.ts | 58 ++++++++++++++++------ 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'packages') diff --git a/packages/preload/src/contextBridge/SophieRendererImpl.ts b/packages/preload/src/contextBridge/SophieRendererImpl.ts index 5d29071..153fdd1 100644 --- a/packages/preload/src/contextBridge/SophieRendererImpl.ts +++ b/packages/preload/src/contextBridge/SophieRendererImpl.ts @@ -32,35 +32,63 @@ import { RendererToMainIpcService } from '../services/RendererToMainIpcService'; class SophieRendererImpl implements SophieRenderer { readonly #ipcService: RendererToMainIpcService; + #onSharedStoreChangeCalled = false; + #listener: SharedStoreListener | null = null; constructor(ipcService: RendererToMainIpcService) { this.#ipcService = ipcService; ipcService.onSharedStorePatch((patch) => { - // `mobx-state-tree` will validate the patch, so we can safely cast here. - this.#listener?.onPatch(patch as IJsonPatch); + try { + // `mobx-state-tree` will validate the patch, so we can safely cast here. + this.#listener?.onPatch(patch as IJsonPatch); + } catch (err) { + console.log('Shared store listener onPatch failed', err); + } }); } - onSharedStoreChange(listener: SharedStoreListener): void { - this.#ipcService.getSharedStoreSnapshot().then((snapshot) => { - if (sharedStore.is(snapshot)) { + async #setSharedStoreChangeListener(listener: SharedStoreListener): Promise { + let snapshot: unknown; + try { + snapshot = await this.#ipcService.getSharedStoreSnapshot(); + } catch (err) { + console.error('Failed to get initial shared store snapshot', err); + return; + } + if (sharedStore.is(snapshot)) { + try { listener.onSnapshot(snapshot); - this.#listener = listener; - } else { - console.error('Got invalid initial shared store snapshot', snapshot); + } catch (err) { + console.error('Shared store listener onSnapshot failed', err); + return; } - }).catch((err) => { - console.error('Failed set initial shared store snapshot', err); + this.#listener = listener; + return; + } + console.error('Got invalid initial shared store snapshot', snapshot); + } + + onSharedStoreChange(listener: SharedStoreListener): void { + if (this.#onSharedStoreChangeCalled) { + throw new Error('Shared store change listener was already set'); + } + this.#setSharedStoreChangeListener(listener).catch((err) => { + console.log('Failed to set shared store change listener', err); }); } dispatchAction(actionToDispatch: Action): void { - const parsedAction = action.safeParse(actionToDispatch); - if (parsedAction.success) { - this.#ipcService.dispatchAction(parsedAction.data); - } else { - console.error('Trying to dispatch invalid action', actionToDispatch, parsedAction.error); + // Let the full zod parse error bubble up to the main world, + // since all data it may contain was provided from the main world. + const parsedAction = action.parse(actionToDispatch); + try { + this.#ipcService.dispatchAction(parsedAction); + } catch (err) { + // Do not leak IPC failure details into the main world. + const message = 'Failed to dispatch action'; + console.error(message, actionToDispatch, err); + throw new Error(message); } } } -- cgit v1.2.3-54-g00ecf