From 37fa5785db4a9c070a6a5bf9f934a85cb627154f Mon Sep 17 00:00:00 2001 From: Matt Lyons Date: Wed, 13 Dec 2023 12:28:59 -0600 Subject: [PATCH] PR feedback --- lib/papi-dts/papi.d.ts | 15 ++++++++++-- src/renderer/index.tsx | 24 +++---------------- .../services/papi-frontend.service.ts | 4 ++-- .../services/renderer-web-socket.service.ts | 1 + .../services/web-view.service-host.ts | 4 ++-- src/shared/utils/util.ts | 21 ++++++++++++++++ 6 files changed, 42 insertions(+), 27 deletions(-) diff --git a/lib/papi-dts/papi.d.ts b/lib/papi-dts/papi.d.ts index 7b2b929410..9f68dd2b73 100644 --- a/lib/papi-dts/papi.d.ts +++ b/lib/papi-dts/papi.d.ts @@ -549,6 +549,17 @@ declare module 'shared/utils/util' { }, objId?: string, ): Set; + /** + * Run an array of promises, and either return an array of the outcomes if them all were fulfilled + * or throw if at least one of them was rejected + * + * @param promises Array of promises to resolve + * @returns Array of `PromiseSettledResult` values from each promise if all promises were fulfilled. + * Otherwise an exception will be thrown. + */ + export function runPromisesAndThrowIfRejected( + ...promises: Promise[] + ): Promise[]>; } declare module 'shared/utils/papi-util' { import { ProcessType } from 'shared/global-this.model'; @@ -4794,14 +4805,14 @@ declare module '@papi/frontend' { * * Note that the Node WebSocket implementation is different and not wrapped here. */ - webSocket: typeof PapiRendererWebSocket; + WebSocket: typeof PapiRendererWebSocket; /** This wraps the browser's XMLHttpRequest implementation to * provide better control over internet access. It is isomorphic with the standard XMLHttpRequest, * so it should act as a drop-in replacement. * * Note that Node doesn't have a native implementation, so this is only for the renderer. */ - xmlHttpRequest: typeof PapiRendererXMLHttpRequest; + XMLHttpRequest: typeof PapiRendererXMLHttpRequest; /** * * The command service allows you to exchange messages with other components in the platform. You diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 76f6877b13..5d8429cc3e 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -6,31 +6,13 @@ import { startWebViewService } from '@renderer/services/web-view.service-host'; import logger from '@shared/services/logger.service'; import webViewProviderService from '@shared/services/web-view-provider.service'; import { startDialogService } from '@renderer/services/dialog.service-host'; +import { runPromisesAndThrowIfRejected } from '@shared/utils/util'; import App from './app.component'; import { cleanupOldWebViewState } from './services/web-view-state.service'; import { blockWebSocketsToPapiNetwork } from './services/renderer-web-socket.service'; logger.info('Starting renderer'); -window.onerror = (message, source, lineno, colno, error): void => { - logger.error(`An error occurred: ${message}`); - logger.error(`Source file: ${source}`); - logger.error(`Line number: ${lineno}`); - logger.error(`Column number: ${colno}`); - logger.error(`Error object: ${error}`); -}; - -if (window.process) { - window.process.on('uncaughtException', (error) => { - const { dialog } = window.require('electron'); - dialog.showMessageBoxSync({ - type: 'error', - message: `Unexpected error occurred: ${error}`, - title: 'Error', - }); - }); -} - // App-wide service setup // We are not awaiting these service startups for a few reasons: // - They internally await other services when they need others in order to start @@ -44,12 +26,12 @@ if (window.process) { // This needs to run before web views start running and after the network service is running blockWebSocketsToPapiNetwork(); - await Promise.allSettled([ + await runPromisesAndThrowIfRejected( commandService.initialize(), webViewProviderService.initialize(), startWebViewService(), startDialogService(), - ]); + ); } catch (e) { logger.error(`Service(s) failed to initialize! Error: ${e}`); } diff --git a/src/renderer/services/papi-frontend.service.ts b/src/renderer/services/papi-frontend.service.ts index 5b116168ea..a2f68c6e2d 100644 --- a/src/renderer/services/papi-frontend.service.ts +++ b/src/renderer/services/papi-frontend.service.ts @@ -45,9 +45,9 @@ const papi = { // Classes /** JSDOC DESTINATION PapiRendererWebSocket */ - webSocket: PapiRendererWebSocket, + WebSocket: PapiRendererWebSocket, /** JSDOC DESTINATION PapiRendererXMLHttpRequest */ - xmlHttpRequest: PapiRendererXMLHttpRequest, + XMLHttpRequest: PapiRendererXMLHttpRequest, // Services/modules /** JSDOC DESTINATION commandService */ diff --git a/src/renderer/services/renderer-web-socket.service.ts b/src/renderer/services/renderer-web-socket.service.ts index 64d448c8e1..e334540986 100644 --- a/src/renderer/services/renderer-web-socket.service.ts +++ b/src/renderer/services/renderer-web-socket.service.ts @@ -24,6 +24,7 @@ function isPotentialConnectionToPapiNetwork(url: string | URL): boolean { hostname === '127.0.0.1' || hostname === '::1' || hostname.endsWith('.local') || + hostname.endsWith('.localhost') || parseInt(port, 10) === parseInt(`${WEBSOCKET_PORT}`, 10) ); } diff --git a/src/renderer/services/web-view.service-host.ts b/src/renderer/services/web-view.service-host.ts index f16bc2b082..41104960de 100644 --- a/src/renderer/services/web-view.service-host.ts +++ b/src/renderer/services/web-view.service-host.ts @@ -864,8 +864,8 @@ export const getWebView = async ( var updateWebViewDefinitionById = window.parent.updateWebViewDefinitionById; window.updateWebViewDefinition = (webViewDefinitionUpdateInfo) => { return updateWebViewDefinitionById('${webView.id}', webViewDefinitionUpdateInfo)} window.fetch = papi.fetch; - window.WebSocket = papi.webSocket; - window.XMLHttpRequest = papi.xmlHttpRequest; + window.WebSocket = papi.WebSocket; + window.XMLHttpRequest = papi.XMLHttpRequest; delete window.parent; delete window.top; delete window.frameElement; diff --git a/src/shared/utils/util.ts b/src/shared/utils/util.ts index 9d2f8a977e..4456623e7c 100644 --- a/src/shared/utils/util.ts +++ b/src/shared/utils/util.ts @@ -202,3 +202,24 @@ export function getAllObjectFunctionNames( return objectFunctionNames; } + +/** + * Run an array of promises, and either return an array of the outcomes if them all were fulfilled + * or throw if at least one of them was rejected + * + * @param promises Array of promises to resolve + * @returns Array of `PromiseSettledResult` values from each promise if all promises were fulfilled. + * Otherwise an exception will be thrown. + */ +export async function runPromisesAndThrowIfRejected(...promises: Promise[]) { + const resolutions = await Promise.allSettled(promises); + const rejections = resolutions.filter((resolution) => resolution.status === 'rejected'); + if (rejections.length > 0) { + const reasons = rejections.map((rejection, index) => { + if (rejection.status !== 'rejected') return "Why doesn't TS know we already checked this?"; + return `[${index}]: ${rejection.reason}`; + }); + throw new Error(`${reasons}`); + } + return resolutions; +}