Enable noImplicitAny and kill off request (#457)

* Enable noImplicitAny

* Switch from request to node-fetch

* Fix node-fetch via patch-package

* Add edge to handler

* Pin node-fetch to v2
This commit is contained in:
Michael Telatynski
2022-11-30 13:51:54 +00:00
committed by GitHub
parent c74fdb632b
commit 031ee44571
13 changed files with 232 additions and 86 deletions

View File

@@ -20,27 +20,26 @@ import AutoLaunch from "auto-launch";
import { AppLocalization } from "../language-helper";
// global type extensions need to use var for whatever reason
/* eslint-disable no-var */
declare global {
namespace NodeJS {
interface Global {
mainWindow: BrowserWindow;
appQuitting: boolean;
appLocalization: AppLocalization;
launcher: AutoLaunch;
vectorConfig: Record<string, any>;
trayConfig: {
// eslint-disable-next-line camelcase
icon_path: string;
brand: string;
};
store: Store<{
warnBeforeExit?: boolean;
minimizeToTray?: boolean;
spellCheckerEnabled?: boolean;
autoHideMenuBar?: boolean;
locale?: string | string[];
disableHardwareAcceleration?: boolean;
}>;
}
}
var mainWindow: BrowserWindow | null;
var appQuitting: boolean;
var appLocalization: AppLocalization;
var launcher: AutoLaunch;
var vectorConfig: Record<string, any>;
var trayConfig: {
// eslint-disable-next-line camelcase
icon_path: string;
brand: string;
};
var store: Store<{
warnBeforeExit?: boolean;
minimizeToTray?: boolean;
spellCheckerEnabled?: boolean;
autoHideMenuBar?: boolean;
locale?: string | string[];
disableHardwareAcceleration?: boolean;
}>;
}
/* eslint-enable no-var */

View File

@@ -126,6 +126,8 @@ async function tryPaths(name: string, root: string, rawPaths: string[]): Promise
throw new Error(`Failed to find ${name} files`);
}
const homeserverProps = ['default_is_url', 'default_hs_url', 'default_server_name', 'default_server_config'] as const;
// Find the webapp resources and set up things that require them
async function setupGlobals(): Promise<void> {
// find the webapp asar.
@@ -168,12 +170,14 @@ async function setupGlobals(): Promise<void> {
// If the local config has a homeserver defined, don't use the homeserver from the build
// config. This is to avoid a problem where Riot thinks there are multiple homeservers
// defined, and panics as a result.
const homeserverProps = ['default_is_url', 'default_hs_url', 'default_server_name', 'default_server_config'];
if (Object.keys(localConfig).find(k => homeserverProps.includes(k))) {
if (Object.keys(localConfig).find(k => homeserverProps.includes(<any>k))) {
// Rip out all the homeserver options from the vector config
global.vectorConfig = Object.keys(global.vectorConfig)
.filter(k => !homeserverProps.includes(k))
.reduce((obj, key) => {obj[key] = global.vectorConfig[key]; return obj;}, {});
.filter(k => !homeserverProps.includes(<any>k))
.reduce((obj, key) => {
obj[key] = global.vectorConfig[key];
return obj;
}, {} as Omit<Partial<typeof global["vectorConfig"]>, keyof typeof homeserverProps>);
}
global.vectorConfig = Object.assign(global.vectorConfig, localConfig);
@@ -244,7 +248,7 @@ const warnBeforeExit = (event: Event, input: Input): void => {
const exitShortcutPressed =
input.type === 'keyDown' && exitShortcuts.some(shortcutFn => shortcutFn(input, process.platform));
if (shouldWarnBeforeExit && exitShortcutPressed) {
if (shouldWarnBeforeExit && exitShortcutPressed && global.mainWindow) {
const shouldCancelCloseRequest = dialog.showMessageBoxSync(global.mainWindow, {
type: "question",
buttons: [_t("Cancel"), _t("Close %(brand)s", {
@@ -338,11 +342,11 @@ app.on('ready', async () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { default: installExt, REACT_DEVELOPER_TOOLS, REACT_PERF } = require('electron-devtools-installer');
installExt(REACT_DEVELOPER_TOOLS)
.then((name) => console.log(`Added Extension: ${name}`))
.catch((err) => console.log('An error occurred: ', err));
.then((name: string) => console.log(`Added Extension: ${name}`))
.catch((err: unknown) => console.log('An error occurred: ', err));
installExt(REACT_PERF)
.then((name) => console.log(`Added Extension: ${name}`))
.catch((err) => console.log('An error occurred: ', err));
.then((name: string) => console.log(`Added Extension: ${name}`))
.catch((err: unknown) => console.log('An error occurred: ', err));
} catch (e) {
console.log(e);
}
@@ -446,6 +450,7 @@ app.on('ready', async () => {
if (global.store.get('minimizeToTray', true)) tray.create(global.trayConfig);
global.mainWindow.once('ready-to-show', () => {
if (!global.mainWindow) return;
mainWindowState.manage(global.mainWindow);
if (!argv['hidden']) {
@@ -469,12 +474,12 @@ app.on('ready', async () => {
// behave, eg. Mail.app)
e.preventDefault();
if (global.mainWindow.isFullScreen()) {
global.mainWindow.once('leave-full-screen', () => global.mainWindow.hide());
if (global.mainWindow?.isFullScreen()) {
global.mainWindow.once('leave-full-screen', () => global.mainWindow?.hide());
global.mainWindow.setFullScreen(false);
} else {
global.mainWindow.hide();
global.mainWindow?.hide();
}
return false;
@@ -484,9 +489,9 @@ app.on('ready', async () => {
if (process.platform === 'win32') {
// Handle forward/backward mouse buttons in Windows
global.mainWindow.on('app-command', (e, cmd) => {
if (cmd === 'browser-backward' && global.mainWindow.webContents.canGoBack()) {
if (cmd === 'browser-backward' && global.mainWindow?.webContents.canGoBack()) {
global.mainWindow.webContents.goBack();
} else if (cmd === 'browser-forward' && global.mainWindow.webContents.canGoForward()) {
} else if (cmd === 'browser-forward' && global.mainWindow?.webContents.canGoForward()) {
global.mainWindow.webContents.goForward();
}
});
@@ -508,7 +513,7 @@ app.on('window-all-closed', () => {
});
app.on('activate', () => {
global.mainWindow.show();
global.mainWindow?.show();
});
function beforeQuit(): void {

View File

@@ -39,7 +39,7 @@ ipcMain.on('loudNotification', function(): void {
if (process.platform === 'win32' && global.mainWindow && !global.mainWindow.isFocused() && !focusHandlerAttached) {
global.mainWindow.flashFrame(true);
global.mainWindow.once('focus', () => {
global.mainWindow.flashFrame(false);
global.mainWindow?.flashFrame(false);
focusHandlerAttached = false;
});
focusHandlerAttached = true;

View File

@@ -63,7 +63,7 @@ export function _t(text: string, variables: IVariables = {}): string {
type Component = () => void;
type TypedStore = Store<{ locale?: string[] }>;
type TypedStore = Store<{ locale?: string | string[] }>;
export class AppLocalization {
private static readonly STORE_KEY = "locale";

View File

@@ -52,7 +52,7 @@ function processUrl(url: string): void {
global.mainWindow.loadURL(urlToLoad.href);
}
function readStore(): object {
function readStore(): Record<string, string> {
try {
const s = fs.readFileSync(storePath, { encoding: "utf8" });
const o = JSON.parse(s);
@@ -62,7 +62,7 @@ function readStore(): object {
}
}
function writeStore(data: object): void {
function writeStore(data: Record<string, string>): void {
fs.writeFileSync(storePath, JSON.stringify(data));
}
@@ -83,7 +83,7 @@ export function recordSSOSession(sessionID: string): void {
export function getProfileFromDeeplink(args: string[]): string | undefined {
// check if we are passed a profile in the SSO callback url
const deeplinkUrl = args.find(arg => arg.startsWith(PROTOCOL + '//'));
if (deeplinkUrl && deeplinkUrl.includes(SEARCH_PARAM)) {
if (deeplinkUrl?.includes(SEARCH_PARAM)) {
const parsedUrl = new URL(deeplinkUrl);
if (parsedUrl.protocol === PROTOCOL) {
const ssoID = parsedUrl.searchParams.get(SEARCH_PARAM)!;

View File

@@ -81,15 +81,12 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
// We do this here to ensure we get the path after --profile has been resolved
const eventStorePath = path.join(app.getPath('userData'), 'EventStore');
const sendError = (id, e) => {
const sendError = (id: string, e: Error) => {
const error = {
message: e.message,
};
global.mainWindow.webContents.send('seshatReply', {
id: id,
error: error,
});
global.mainWindow?.webContents.send('seshatReply', { id, error });
};
const args = payload.args || [];
@@ -138,7 +135,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
eventIndex = new Seshat(eventStorePath, { passphrase });
} else {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -153,7 +150,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
await index.shutdown();
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -182,7 +179,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
eventIndex?.addEvent(args[0], args[1]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
break;
@@ -191,7 +188,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex?.deleteEvent(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
break;
@@ -200,7 +197,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex?.commit();
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
break;
@@ -209,7 +206,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex?.search(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
break;
@@ -221,7 +218,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
ret = await eventIndex.addHistoricEvents(
args[0], args[1], args[2]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -233,7 +230,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.getStats();
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -245,7 +242,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.removeCrawlerCheckpoint(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -257,7 +254,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.addCrawlerCheckpoint(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -269,7 +266,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.loadFileEvents(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -292,7 +289,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
await eventIndex.setUserVersion(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -304,7 +301,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.getUserVersion();
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}

View File

@@ -44,12 +44,12 @@ export const Settings: Record<string, Setting> = {
},
"Electron.alwaysShowMenuBar": { // not supported on macOS
async read(): Promise<any> {
return !global.mainWindow.autoHideMenuBar;
return !global.mainWindow!.autoHideMenuBar;
},
async write(value: any): Promise<void> {
global.store.set('autoHideMenuBar', !value);
global.mainWindow.autoHideMenuBar = !value;
global.mainWindow.setMenuBarVisibility(value);
global.mainWindow!.autoHideMenuBar = !value;
global.mainWindow!.setMenuBarVisibility(value);
},
},
"Electron.showTrayIcon": { // not supported on macOS

View File

@@ -36,12 +36,12 @@ export function destroy(): void {
}
function toggleWin(): void {
if (global.mainWindow.isVisible() && !global.mainWindow.isMinimized() && global.mainWindow.isFocused()) {
if (global.mainWindow?.isVisible() && !global.mainWindow.isMinimized() && global.mainWindow.isFocused()) {
global.mainWindow.hide();
} else {
if (global.mainWindow.isMinimized()) global.mainWindow.restore();
if (!global.mainWindow.isVisible()) global.mainWindow.show();
global.mainWindow.focus();
if (global.mainWindow?.isMinimized()) global.mainWindow.restore();
if (!global.mainWindow?.isVisible()) global.mainWindow?.show();
global.mainWindow?.focus();
}
}
@@ -60,11 +60,11 @@ export function create(config: IConfig): void {
initApplicationMenu();
trayIcon.on('click', toggleWin);
let lastFavicon = null;
global.mainWindow.webContents.on('page-favicon-updated', async function(ev, favicons) {
let lastFavicon: string | null = null;
global.mainWindow?.webContents.on('page-favicon-updated', async function(ev, favicons) {
if (!favicons || favicons.length <= 0 || !favicons[0].startsWith('data:')) {
if (lastFavicon !== null) {
global.mainWindow.setIcon(defaultIcon);
global.mainWindow?.setIcon(defaultIcon);
trayIcon?.setImage(defaultIcon);
lastFavicon = null;
}
@@ -89,10 +89,10 @@ export function create(config: IConfig): void {
}
trayIcon?.setImage(newFavicon);
global.mainWindow.setIcon(newFavicon);
global.mainWindow?.setIcon(newFavicon);
});
global.mainWindow.webContents.on('page-title-updated', function(ev, title) {
global.mainWindow?.webContents.on('page-title-updated', function(ev, title) {
trayIcon?.setToolTip(title);
});
}

View File

@@ -98,7 +98,7 @@ export function buildMenuTemplate(): Menu {
// in macOS the Preferences menu item goes in the first menu
...(!isMac ? [{
label: _t('Preferences'),
click() { global.mainWindow.webContents.send('preferences'); },
click() { global.mainWindow?.webContents.send('preferences'); },
}] : []),
{
role: 'togglefullscreen',
@@ -153,7 +153,7 @@ export function buildMenuTemplate(): Menu {
{
label: _t('Preferences') + '…',
accelerator: 'Command+,', // Mac-only accelerator
click() { global.mainWindow.webContents.send('preferences'); },
click() { global.mainWindow?.webContents.send('preferences'); },
},
{ type: 'separator' },
{

View File

@@ -31,7 +31,8 @@ import {
} from 'electron';
import url from 'url';
import fs from 'fs';
import request from 'request';
import fetch from 'node-fetch';
import { pipeline } from 'stream';
import path from 'path';
import { _t } from './language-helper';
@@ -154,7 +155,10 @@ function onLinkContextMenu(ev: Event, params: ContextMenuParams, webContents: We
if (url.startsWith("data:")) {
await writeNativeImage(filePath, nativeImage.createFromDataURL(url));
} else {
request.get(url).pipe(fs.createWriteStream(filePath));
const resp = await fetch(url);
if (!resp.ok) throw new Error(`unexpected response ${resp.statusText}`);
if (!resp.body) throw new Error(`unexpected response has no body ${resp.statusText}`);
pipeline(resp.body, fs.createWriteStream(filePath));
}
} catch (err) {
console.error(err);
@@ -224,7 +228,7 @@ function cutCopyPasteSelectContextMenus(params: ContextMenuParams): MenuItemCons
return options;
}
function onSelectedContextMenu(ev, params) {
function onSelectedContextMenu(ev: Event, params: ContextMenuParams) {
const items = cutCopyPasteSelectContextMenus(params);
const popupMenu = Menu.buildFromTemplate(items);