diff --git a/sources/code/common/main.ts b/sources/code/common/main.ts index 9b9c8e2f..e3d4d72d 100644 --- a/sources/code/common/main.ts +++ b/sources/code/common/main.ts @@ -204,7 +204,7 @@ let overwriteMain: (() => unknown) | undefined; argv.values["user-agent-arch"] : process.arch, }; - + if(argv.values["start-minimized"] === true) startHidden = true; if(argv.values["safe-mode"] === true) @@ -238,23 +238,29 @@ let overwriteMain: (() => unknown) | undefined; " '" + kolor.blue(kolor.underline(directory)) + "'!\n" ].join("\n")); app.quit(); - }).catch((err:NodeJS.ErrnoException) => { - const path = err.path !== undefined ? { + }).catch((err:unknown) => { + if(!(err instanceof Error)) return; + const path = "path" in err && typeof err.path === "string" ? { relative: relative(process.cwd(),err.path), absolute: resolvePath(process.cwd(),err.path), - } : {}; + original: err.path + } : {original: ""}; const finalPath = path.absolute !== undefined ? path.absolute.length > path.relative.length ? path.relative : path.absolute : null; + const syscall = "syscall" in err && typeof err.syscall === "string" ? err.syscall : ""; + const code = "code" in err && typeof err.code === "string" ? err.code : ""; console.error([ - "\n⛔️ " + kolor.red(kolor.bold(err.code ?? err.name)) + " " + (err.syscall ?? "") + ": ", + "\n⛔️ " + kolor.red(kolor.bold( + "code" in err && typeof err.code === "string" ? err.code : err.name + )) + " " + syscall + ": ", (finalPath !== null ? kolor.blue(kolor.underline(finalPath)) + ": " : ""), - err.message.replace((err.code ?? "") + ": ", "") - .replace(", " + (err.syscall ?? "") + " '" + (err.path ?? "") + "'", "") + ".\n" + err.message.replace(code + ": ", "") + .replace(", " + syscall + " '" + path.original + "'", "") + ".\n" ].join("")); - app.exit((err.errno??0)*(-1)); + app.exit(("errno" in err && typeof err.errno === "number" ? err.errno : 0)*(-1)); }); }; } @@ -303,7 +309,7 @@ let overwriteMain: (() => unknown) | undefined; // Apply recommended GPU flags if user had opt in for them. for(const flag of getRecommendedGPUFlags()) applyFlags(flag[0], flag[1]); - + // Enable MiddleClickAutoscroll for all windows. if(process.platform !== "win32" && appConfig.value.settings.advanced.unix.autoscroll && !safeMode) @@ -351,7 +357,7 @@ function main(): void { }, 30/*min*/*60000); checkVersion(updateInterval).catch(commonCatches.print); const mainWindow = createMainWindow(startHidden); - + // WebSocket server import("../main/modules/socket.mjs") .then(socket => socket.default()) @@ -392,7 +398,7 @@ app.on("web-contents-created", (_event, webContents) => { if (originUrl !== "" && (new URL(originUrl)).origin !== (new URL(url)).origin) event.preventDefault(); }); - + // Handle renderer crashes. webContents.on("render-process-gone", (_event, details) => { console.error(kolor.bold("[WC_%s:%d]")+" %s", webContents.getProcessId(), details.exitCode, details.reason); @@ -424,7 +430,7 @@ app.on("web-contents-created", (_event, webContents) => { if(protocols.allowed.includes(openUrl.protocol)) protocolMeta.allow = true; - /* + /* * If origins of `openUrl` and current webContents URL are different, * ask the end user to confirm if the URL is safe enough for him. * (unless an application user disabled that functionality) diff --git a/sources/code/main/modules/extensions.ts b/sources/code/main/modules/extensions.ts index f62b5ec6..a8b0b3b7 100644 --- a/sources/code/main/modules/extensions.ts +++ b/sources/code/main/modules/extensions.ts @@ -16,7 +16,7 @@ async function fetchOrRead(url:URL, signal?:AbortSignal) { /** * A function that recursively parses `@import` CSS statements, so they can be * understand for Electron on CSS insertion. - * + * * **Experimental** – it is unknown if that would work properly for all themes. */ async function parseImports(cssString: string, importCalls: string[], maxTries=5):Promise { @@ -98,7 +98,7 @@ async function addStyle(window?:Electron.BrowserWindow) { /** * Loads CSS styles from `${userdata}/Themes` directory and observes their changes. - * + * * Loaded themes are encrypted with {@link safeStorage.encryptString} whenever * Electron decides that encryption is available. */ @@ -150,8 +150,8 @@ async function loadStyles(webContents:Electron.WebContents) { .then(data => webContents.insertCSS(data)) ); callback(themeIDs); - }).catch(reason => reject(reason as Error)); - }).catch(reason => reject(reason as Error)); + }).catch((reason:unknown) => reject(reason as Error)); + }).catch((reason:unknown) => reject(reason as Error)); }); watch(stylesDir).once("change", () => { webContents.reload(); @@ -161,12 +161,12 @@ async function loadStyles(webContents:Electron.WebContents) { /** * Loads **unpacked** Chromium extensions from `{userData}/Extensions/Chromium`. - * + * * Due to limitations of Electron, there's no full support to whole API of * Chromium extensions and there's likely no support at all to `v3` manifest * based extensions. See [*Chrome Extension Support*][chrome-ext] for more * details what should work and what might not have been implemented yet. - * + * * [chrome-ext]: https://www.electronjs.org/docs/latest/api/extensions "Electron API documentation" */ export async function loadChromiumExtensions(session:Electron.Session) { diff --git a/sources/code/main/windows/main.ts b/sources/code/main/windows/main.ts index 8f1c5d01..88752ba1 100644 --- a/sources/code/main/windows/main.ts +++ b/sources/code/main/windows/main.ts @@ -161,7 +161,7 @@ export default function createMainWindow(...flags:MainWindowFlags): BrowserWindo .reduce((previousValue,currentValue) => (previousValue??false) && (currentValue??false))??true; }; /** Common handler for */ - const permissionHandler = (type:"request"|"check",webContentsUrl:string, permission:string, details:Electron.PermissionRequestHandlerHandlerDetails|Electron.PermissionCheckHandlerHandlerDetails):boolean|null => { + const permissionHandler = (type:"request"|"check",webContentsUrl:string, permission:string, details:Electron.PermissionRequest|Electron.MediaAccessPermissionRequest|Electron.PermissionCheckHandlerHandlerDetails):boolean|null => { // Verify URL address of the permissions. try { const webContents = new URL(webContentsUrl); @@ -253,10 +253,11 @@ export default function createMainWindow(...flags:MainWindowFlags): BrowserWindo // Either WebCord or system denies the request. default: if(permission === "media") { + const mediaTypes = "mediaTypes" in details ? details.mediaTypes : undefined; const promises:Promise[] = []; (["camera","microphone"] as const).forEach(media => { const permission = media === "camera" ? "video" : "audio"; - if(!(details.mediaTypes?.includes(permission)??false)) + if(!(mediaTypes?.includes(permission)??false)) return; // macOS: try asking for media access whenever possible. if(process.platform === "darwin" && systemPreferences.getMediaAccessStatus(media) === "not-determined") @@ -271,7 +272,7 @@ export default function createMainWindow(...flags:MainWindowFlags): BrowserWindo Promise.all(promises) // Re-check permissions and return their values. .then(dialogs => dialogs.reduce((prev,cur) => prev && cur, true)) - .then(result => result && getMediaTypesPermission(details.mediaTypes)) + .then(result => result && getMediaTypesPermission(mediaTypes)) .then(result => callback(result)) // Deny on failure. .catch(() => callback(false)); @@ -340,7 +341,7 @@ export default function createMainWindow(...flags:MainWindowFlags): BrowserWindo ]; // Fetch status for ping and title from current title const status=typeof dirty === "string" ? true : dirty ? false : null; - win.setTitle((status === true ? "["+dirty+"] " : status === false ? "*" : "") + client + " - " + section + (group !== null ? " ("+group+")" : "")); + win.setTitle((status === true ? "["+(dirty as string)+"] " : status === false ? "*" : "") + client + " - " + section + (group !== null ? " ("+group+")" : "")); if(lastStatus === status || !tray) return; // Set tray icon and taskbar flash { @@ -349,7 +350,7 @@ export default function createMainWindow(...flags:MainWindowFlags): BrowserWindo case true: icon = appInfo.icons.tray.warn; flash = true; - tooltipSuffix=` - ${dirty} ${l10nStrings.tray.mention[pluralRules.select(parseInt(`${dirty}`))]}`; + tooltipSuffix=` - ${dirty as string} ${l10nStrings.tray.mention[pluralRules.select(parseInt(dirty as string))]}`; break; case false: icon = appInfo.icons.tray.unread; @@ -440,7 +441,7 @@ export default function createMainWindow(...flags:MainWindowFlags): BrowserWindo // Load extensions for builds of type "devel". if(getBuildInfo().type === "devel") void loadChromiumExtensions(win.webContents.session); - + /** * Limitations for APIs to allow running WebCord properly with different * Electron releases. diff --git a/sources/code/renderer/preload/about.ts b/sources/code/renderer/preload/about.ts index 19976d3e..8a338efe 100644 --- a/sources/code/renderer/preload/about.ts +++ b/sources/code/renderer/preload/about.ts @@ -40,10 +40,10 @@ async function getUserAvatar(person: Person, size = 96) { function addContributor(person: Person, role?: string) { const container = document.createElement("div"); const description = document.createElement("div"); - + void getUserAvatar(person) .then(avatar => container.prepend(avatar)); - + container.classList.add("contributor"); const nameElement = document.createElement("h2"); @@ -139,10 +139,10 @@ async function generateAppContent(l10n:L10N["web"]["aboutWindow"], detailsPromis nameElement.innerText = details.appName + " ("+details.buildInfo.type+")"; versionElement.innerText = "v" + details.appVersion + (details.buildInfo.commit !== undefined ? "-"+details.buildInfo.commit.substring(0, 7) : ""); (document.getElementById("logo") as HTMLImageElement).src = appInfo.icons.app.toDataURL(); - + if(repoElement.tagName === "A") (repoElement as HTMLAnchorElement).href = details.appRepo??""; - + for (const id of Object.keys(l10n.about)) { const element = document.getElementById(id); if(element) @@ -222,7 +222,7 @@ window.addEventListener("DOMContentLoaded", () => { } // Get app details and inject them into the page const details = ipc.invoke("about.getDetails") as Promise; - generateAppContent(l10n, details).catch(e => { + generateAppContent(l10n, details).catch((e:unknown) => { if(e instanceof Error) throw e; else if(typeof e === "string") @@ -231,7 +231,7 @@ window.addEventListener("DOMContentLoaded", () => { console.error(e); }); generateLicenseContent(l10n, details); - + // Generate "credits" if(packageJson.data.author !== undefined) addContributor(new Person(packageJson.data.author), l10n.credits.people.author); diff --git a/sources/code/renderer/preload/docs.ts b/sources/code/renderer/preload/docs.ts index c3ea2147..b41c5654 100644 --- a/sources/code/renderer/preload/docs.ts +++ b/sources/code/renderer/preload/docs.ts @@ -14,7 +14,7 @@ import { protocols } from "../../common/global"; import { gfmHeadingId - //@ts-expect-error TS14790 + //@ts-expect-error due to TS14790 } from "marked-gfm-heading-id"; const htmlFileUrl = document.URL; @@ -22,7 +22,7 @@ const htmlFileUrl = document.URL; // Code highlighting and GFM heading IDs: marked.use( - //@ts-expect-error TS2379 + //@ts-expect-error due to TS2379 markedHighlight({ highlight: (code,language) => hljs.getLanguage(language) ? hljs.highlight(code,{ language } ).value : @@ -37,7 +37,7 @@ menu.id = "menu-hamburger"; const menuHeader = document.createElement("p"); -/** +/** * Handles URL clicks – it will open websites in default browser and load * markdown files instead of trying it to open. */ @@ -64,7 +64,7 @@ function fixImages(container:HTMLElement) { logo.src=logo.src.replace("/sources/assets",""); const newLogo = logo.cloneNode(); logoAnchor.appendChild(newLogo); - + // Remove badges (they require an internet connection). for(const image of container.getElementsByTagName("img")) if(image.src.startsWith("https:") && image.parentElement?.parentElement?.tagName === "P") { @@ -177,7 +177,7 @@ document.addEventListener("readystatechange", () => { .finally(() => { ipc.send("documentation-show"); }) - .catch(error => { + .catch((error:unknown) => { if(error instanceof Error) throw error; else if(typeof error === "string")