Browse Source

build: update some build dependencies (#44072)

* build: update some build dependencies (#43882)

* build: update some build dependencies

* build: fix eslint issues after updating

* build: disable ts check on busted js example

* build: update internal types for stricter event handling

* restore url.parse behavior

* fix typing issues

* sigh

* build: update easy deps

* build: skip woa engines check

* build: s/colors/chalk

* build: node 20 on windows
Samuel Attard 6 months ago
parent
commit
8d5eeb2b4b
49 changed files with 1161 additions and 654 deletions
  1. 1 1
      .eslintrc.json
  2. 4 3
      appveyor-woa.yml
  3. 1 1
      appveyor.yml
  4. 1 0
      default_app/main.ts
  5. 8 0
      docs/api/base-window.md
  6. 1 1
      docs/api/client-request.md
  7. 1 1
      docs/api/incoming-message.md
  8. 1 1
      docs/api/session.md
  9. 37 33
      lib/browser/api/menu-item-roles.ts
  10. 27 19
      lib/browser/api/touch-bar.ts
  11. 47 43
      lib/browser/api/web-contents.ts
  12. 29 27
      lib/browser/default-menu.ts
  13. 23 17
      lib/browser/devtools.ts
  14. 2 2
      lib/browser/guest-view-manager.ts
  15. 2 2
      lib/common/api/net-client-request.ts
  16. 1 1
      npm/install.js
  17. 35 45
      package.json
  18. 1 0
      script/doc-only-change.js
  19. 1 1
      script/lib/get-version.js
  20. 3 3
      script/lib/utils.js
  21. 0 1
      script/lint.js
  22. 4 4
      script/release/prepare-release.ts
  23. 3 3
      script/release/release-artifact-cleanup.ts
  24. 3 3
      script/release/release.ts
  25. 4 4
      script/spec-runner.js
  26. 2 2
      spec/api-browser-window-spec.ts
  27. 6 2
      spec/api-context-bridge-spec.ts
  28. 2 1
      spec/api-crash-reporter-spec.ts
  29. 2 2
      spec/api-ipc-renderer-spec.ts
  30. 3 4
      spec/api-net-spec.ts
  31. 3 3
      spec/api-protocol-spec.ts
  32. 11 9
      spec/api-web-contents-spec.ts
  33. 1 1
      spec/api-web-frame-main-spec.ts
  34. 13 13
      spec/api-web-request-spec.ts
  35. 7 4
      spec/chromium-spec.ts
  36. 1 1
      spec/extensions-spec.ts
  37. 1 1
      spec/fixtures/api/fork-with-node-options.js
  38. 2 1
      spec/fixtures/api/singleton-data/main.js
  39. 4 3
      spec/fixtures/native-addon/uv-dlopen/index.js
  40. 4 4
      spec/lib/video-helpers.js
  41. 12 1
      spec/package.json
  42. 1 2
      spec/security-warnings-spec.ts
  43. 2 0
      spec/ts-smoke/electron/main.ts
  44. 1 0
      spec/ts-smoke/electron/renderer.ts
  45. 5 5
      spec/webview-spec.ts
  46. 492 23
      spec/yarn.lock
  47. 1 1
      tsconfig.json
  48. 22 0
      typings/internal-electron.d.ts
  49. 323 355
      yarn.lock

+ 1 - 1
.eslintrc.json

@@ -19,7 +19,7 @@
     "prefer-const": ["error", {
       "destructuring": "all"
     }],
-    "standard/no-callback-literal": "off"
+    "n/no-callback-literal": "off"
   },
   "parserOptions": {
     "ecmaVersion": 6,

+ 4 - 3
appveyor-woa.yml

@@ -29,7 +29,7 @@
 
 version: 1.0.{build}
 build_cloud: electronhq-16-core
-image: e-123.0.6312.5
+image: e-131.0.6734.0
 environment:
   GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
   ELECTRON_OUT_DIR: Default
@@ -70,8 +70,9 @@ for:
         - job_name: Build Arm on X64 Windows
 
     build_script:
+      # TODO: Remove --ignore-engines once WOA image is up to node 20
       - ps: |
-          node script/yarn.js install --frozen-lockfile
+          node script/yarn.js install --frozen-lockfile --ignore-engines
           node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
           $env:SHOULD_SKIP_ARTIFACT_VALIDATION = "false"
           if ($LASTEXITCODE -eq 0) {
@@ -263,7 +264,7 @@ for:
 
     build_script:
       - ps: |
-          node script/yarn.js install --frozen-lockfile
+          node script/yarn.js install --frozen-lockfile --ignore-engines
           node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
           if ($LASTEXITCODE -eq 0) {
             Write-warning "Skipping build for doc only change"

+ 1 - 1
appveyor.yml

@@ -29,7 +29,7 @@
 
 version: 1.0.{build}
 build_cloud: electronhq-16-core
-image: e-123.0.6312.5
+image: e-131.0.6734.0
 environment:
   GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
   ELECTRON_OUT_DIR: Default

+ 1 - 0
default_app/main.ts

@@ -255,6 +255,7 @@ async function startRepl () {
 // start the default app.
 if (option.file && !option.webdriver) {
   const file = option.file;
+  // eslint-disable-next-line n/no-deprecated-api
   const protocol = url.parse(file).protocol;
   const extension = path.extname(file);
   if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:' || protocol === 'chrome:') {

+ 8 - 0
docs/api/base-window.md

@@ -126,10 +126,18 @@ or session log off.
 
 #### Event: 'blur'
 
+Returns:
+
+* `event` Event
+
 Emitted when the window loses focus.
 
 #### Event: 'focus'
 
+Returns:
+
+* `event` Event
+
 Emitted when the window gains focus.
 
 #### Event: 'show'

+ 1 - 1
docs/api/client-request.md

@@ -53,7 +53,7 @@ following properties:
     [`request.followRedirect`](#requestfollowredirect) is invoked synchronously
     during the [`redirect`](#event-redirect) event.  Defaults to `follow`.
   * `origin` string (optional) - The origin URL of the request.
-  * `referrerPolicy` string (optional) - can be `""`, `no-referrer`,
+  * `referrerPolicy` string (optional) - can be "", `no-referrer`,
     `no-referrer-when-downgrade`, `origin`, `origin-when-cross-origin`,
     `unsafe-url`, `same-origin`, `strict-origin`, or
     `strict-origin-when-cross-origin`. Defaults to

+ 1 - 1
docs/api/incoming-message.md

@@ -31,7 +31,7 @@ Emitted when a request has been canceled during an ongoing HTTP transaction.
 
 Returns:
 
-`error` Error - Typically holds an error string identifying failure root cause.
+* `error` Error - Typically holds an error string identifying failure root cause.
 
 Emitted when an error was encountered while streaming response data events. For
 instance, if the server closes the underlying while the response is still

+ 1 - 1
docs/api/session.md

@@ -495,7 +495,7 @@ app.whenReady().then(() => {
 })
 ```
 
-```js
+```js @ts-nocheck
 // Renderer Process
 
 const portConnect = async () => {

+ 37 - 33
lib/browser/api/menu-item-roles.ts

@@ -245,33 +245,35 @@ export const roleList: Record<RoleId, Role> = {
       { role: 'cut' },
       { role: 'copy' },
       { role: 'paste' },
-      ...(isMac ? [
-        { role: 'pasteAndMatchStyle' },
-        { role: 'delete' },
-        { role: 'selectAll' },
-        { type: 'separator' },
-        {
-          label: 'Substitutions',
-          submenu: [
-            { role: 'showSubstitutions' },
-            { type: 'separator' },
-            { role: 'toggleSmartQuotes' },
-            { role: 'toggleSmartDashes' },
-            { role: 'toggleTextReplacement' }
-          ]
-        },
-        {
-          label: 'Speech',
-          submenu: [
-            { role: 'startSpeaking' },
-            { role: 'stopSpeaking' }
-          ]
-        }
-      ] as MenuItemConstructorOptions[] : [
-        { role: 'delete' },
-        { type: 'separator' },
-        { role: 'selectAll' }
-      ] as MenuItemConstructorOptions[])
+      ...(isMac
+        ? [
+          { role: 'pasteAndMatchStyle' },
+          { role: 'delete' },
+          { role: 'selectAll' },
+          { type: 'separator' },
+          {
+            label: 'Substitutions',
+            submenu: [
+              { role: 'showSubstitutions' },
+              { type: 'separator' },
+              { role: 'toggleSmartQuotes' },
+              { role: 'toggleSmartDashes' },
+              { role: 'toggleTextReplacement' }
+            ]
+          },
+          {
+            label: 'Speech',
+            submenu: [
+              { role: 'startSpeaking' },
+              { role: 'stopSpeaking' }
+            ]
+          }
+        ] as MenuItemConstructorOptions[]
+        : [
+          { role: 'delete' },
+          { type: 'separator' },
+          { role: 'selectAll' }
+        ] as MenuItemConstructorOptions[])
     ]
   },
   // View submenu
@@ -295,12 +297,14 @@ export const roleList: Record<RoleId, Role> = {
     submenu: [
       { role: 'minimize' },
       { role: 'zoom' },
-      ...(isMac ? [
-        { type: 'separator' },
-        { role: 'front' }
-      ] as MenuItemConstructorOptions[] : [
-        { role: 'close' }
-      ] as MenuItemConstructorOptions[])
+      ...(isMac
+        ? [
+          { type: 'separator' },
+          { role: 'front' }
+        ] as MenuItemConstructorOptions[]
+        : [
+          { role: 'close' }
+        ] as MenuItemConstructorOptions[])
     ]
   },
   // Share submenu

+ 27 - 19
lib/browser/api/touch-bar.ts

@@ -117,10 +117,12 @@ class TouchBarColorPicker extends TouchBarItem<Electron.TouchBarColorPickerConst
   @LiveProperty<TouchBarColorPicker>(config => config.selectedColor)
     selectedColor!: string;
 
-  @ImmutableProperty<TouchBarColorPicker>(({ change: onChange }, setInternalProp) => typeof onChange === 'function' ? (details: { color: string }) => {
-    setInternalProp('selectedColor', details.color);
-    onChange(details.color);
-  } : null)
+  @ImmutableProperty<TouchBarColorPicker>(({ change: onChange }, setInternalProp) => typeof onChange === 'function'
+    ? (details: { color: string }) => {
+        setInternalProp('selectedColor', details.color);
+        onChange(details.color);
+      }
+    : null)
     onInteraction!: Function | null;
 }
 
@@ -203,10 +205,12 @@ class TouchBarSlider extends TouchBarItem<Electron.TouchBarSliderConstructorOpti
   @LiveProperty<TouchBarSlider>(config => config.value)
     value!: number;
 
-  @ImmutableProperty<TouchBarSlider>(({ change: onChange }, setInternalProp) => typeof onChange === 'function' ? (details: { value: number }) => {
-    setInternalProp('value', details.value);
-    onChange(details.value);
-  } : null)
+  @ImmutableProperty<TouchBarSlider>(({ change: onChange }, setInternalProp) => typeof onChange === 'function'
+    ? (details: { value: number }) => {
+        setInternalProp('value', details.value);
+        onChange(details.value);
+      }
+    : null)
     onInteraction!: Function | null;
 }
 
@@ -236,10 +240,12 @@ class TouchBarSegmentedControl extends TouchBarItem<Electron.TouchBarSegmentedCo
   @LiveProperty<TouchBarSegmentedControl>(config => config.mode)
     mode!: Electron.TouchBarSegmentedControl['mode'];
 
-  @ImmutableProperty<TouchBarSegmentedControl>(({ change: onChange }, setInternalProp) => typeof onChange === 'function' ? (details: { selectedIndex: number, isSelected: boolean }) => {
-    setInternalProp('selectedIndex', details.selectedIndex);
-    onChange(details.selectedIndex, details.isSelected);
-  } : null)
+  @ImmutableProperty<TouchBarSegmentedControl>(({ change: onChange }, setInternalProp) => typeof onChange === 'function'
+    ? (details: { selectedIndex: number, isSelected: boolean }) => {
+        setInternalProp('selectedIndex', details.selectedIndex);
+        onChange(details.selectedIndex, details.isSelected);
+      }
+    : null)
     onInteraction!: Function | null;
 }
 
@@ -265,13 +271,15 @@ class TouchBarScrubber extends TouchBarItem<Electron.TouchBarScrubberConstructor
   @LiveProperty<TouchBarScrubber>(config => typeof config.continuous === 'undefined' ? true : config.continuous)
     continuous!: boolean;
 
-  @ImmutableProperty<TouchBarScrubber>(({ select: onSelect, highlight: onHighlight }) => typeof onSelect === 'function' || typeof onHighlight === 'function' ? (details: { type: 'select'; selectedIndex: number } | { type: 'highlight'; highlightedIndex: number }) => {
-    if (details.type === 'select') {
-      if (onSelect) onSelect(details.selectedIndex);
-    } else {
-      if (onHighlight) onHighlight(details.highlightedIndex);
-    }
-  } : null)
+  @ImmutableProperty<TouchBarScrubber>(({ select: onSelect, highlight: onHighlight }) => typeof onSelect === 'function' || typeof onHighlight === 'function'
+    ? (details: { type: 'select'; selectedIndex: number } | { type: 'highlight'; highlightedIndex: number }) => {
+        if (details.type === 'select') {
+          if (onSelect) onSelect(details.selectedIndex);
+        } else {
+          if (onHighlight) onHighlight(details.highlightedIndex);
+        }
+      }
+    : null)
     onInteraction!: Function | null;
 }
 

+ 47 - 43
lib/browser/api/web-contents.ts

@@ -1,5 +1,5 @@
 import { app, ipcMain, session, webFrameMain, dialog } from 'electron/main';
-import type { BrowserWindowConstructorOptions, LoadURLOptions, MessageBoxOptions, WebFrameMain } from 'electron/main';
+import type { BrowserWindowConstructorOptions, MessageBoxOptions } from 'electron/main';
 
 import * as url from 'url';
 import * as path from 'path';
@@ -24,8 +24,6 @@ const getNextId = function () {
   return ++nextId;
 };
 
-type PostData = LoadURLOptions['postData']
-
 // Stock page sizes
 const PDFPageSizes: Record<string, ElectronInternal.MediaSize> = {
   Letter: {
@@ -403,7 +401,7 @@ WebContents.prototype.loadURL = function (url, options) {
       // the only one is with a bad scheme, perhaps ERR_INVALID_ARGUMENT
       // would be more appropriate.
       if (!error) {
-        error = { errorCode: -2, errorDescription: 'ERR_FAILED', url: url };
+        error = { errorCode: -2, errorDescription: 'ERR_FAILED', url };
       }
       finishListener();
     };
@@ -544,7 +542,7 @@ WebContents.prototype._init = function () {
   });
 
   // Dispatch IPC messages to the ipc module.
-  this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
+  this.on('-ipc-message', function (this: Electron.WebContents, event, internal, channel, args) {
     addSenderToEvent(event, this);
     if (internal) {
       ipcMainInternal.emit(channel, event, ...args);
@@ -558,7 +556,7 @@ WebContents.prototype._init = function () {
     }
   });
 
-  this.on('-ipc-invoke' as any, async function (this: Electron.WebContents, event: Electron.IpcMainInvokeEvent, internal: boolean, channel: string, args: any[]) {
+  this.on('-ipc-invoke', async function (this: Electron.WebContents, event, internal, channel, args) {
     addSenderToEvent(event, this);
     const replyWithResult = (result: any) => event._replyChannel.sendReply({ result });
     const replyWithError = (error: Error) => {
@@ -580,7 +578,7 @@ WebContents.prototype._init = function () {
     }
   });
 
-  this.on('-ipc-message-sync' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
+  this.on('-ipc-message-sync', function (this: Electron.WebContents, event, internal, channel, args) {
     addSenderToEvent(event, this);
     addReturnValueToEvent(event);
     if (internal) {
@@ -598,7 +596,7 @@ WebContents.prototype._init = function () {
     }
   });
 
-  this.on('-ipc-ports' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) {
+  this.on('-ipc-ports', function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) {
     addSenderToEvent(event, this);
     event.ports = ports.map(p => new MessagePortMain(p));
     const maybeWebFrame = getWebFrameForEvent(event);
@@ -616,7 +614,7 @@ WebContents.prototype._init = function () {
     }
   });
 
-  this.on('-before-unload-fired' as any, function (this: Electron.WebContents, event: Electron.Event, proceed: boolean) {
+  this.on('-before-unload-fired', function (this: Electron.WebContents, event, proceed) {
     const type = this.getType();
     // These are the "interactive" types, i.e. ones a user might be looking at.
     // All other types should ignore the "proceed" signal and unload
@@ -633,12 +631,13 @@ WebContents.prototype._init = function () {
 
   if (this.getType() !== 'remote') {
     // Make new windows requested by links behave like "window.open".
-    this.on('-new-window' as any, (event: Electron.Event, url: string, frameName: string, disposition: Electron.HandlerDetails['disposition'],
-      rawFeatures: string, referrer: Electron.Referrer, postData: PostData) => {
-      const postBody = postData ? {
-        data: postData,
-        ...parseContentTypeFormat(postData)
-      } : undefined;
+    this.on('-new-window', (event, url, frameName, disposition, rawFeatures, referrer, postData) => {
+      const postBody = postData
+        ? {
+            data: postData,
+            ...parseContentTypeFormat(postData)
+          }
+        : undefined;
       const details: Electron.HandlerDetails = {
         url,
         frameName,
@@ -672,11 +671,14 @@ WebContents.prototype._init = function () {
 
     let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null;
     let windowOpenOutlivesOpenerOption: boolean = false;
-    this.on('-will-add-new-contents' as any, (event: Electron.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: PostData) => {
-      const postBody = postData ? {
-        data: postData,
-        ...parseContentTypeFormat(postData)
-      } : undefined;
+
+    this.on('-will-add-new-contents', (event, url, frameName, rawFeatures, disposition, referrer, postData) => {
+      const postBody = postData
+        ? {
+            data: postData,
+            ...parseContentTypeFormat(postData)
+          }
+        : undefined;
       const details: Electron.HandlerDetails = {
         url,
         frameName,
@@ -697,14 +699,16 @@ WebContents.prototype._init = function () {
       windowOpenOutlivesOpenerOption = result.outlivesOpener;
       windowOpenOverriddenOptions = result.browserWindowConstructorOptions;
       if (!event.defaultPrevented) {
-        const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
-          // Allow setting of backgroundColor as a webPreference even though
-          // it's technically a BrowserWindowConstructorOptions option because
-          // we need to access it in the renderer at init time.
-          backgroundColor: windowOpenOverriddenOptions.backgroundColor,
-          transparent: windowOpenOverriddenOptions.transparent,
-          ...windowOpenOverriddenOptions.webPreferences
-        } : undefined;
+        const secureOverrideWebPreferences = windowOpenOverriddenOptions
+          ? {
+              // Allow setting of backgroundColor as a webPreference even though
+            // it's technically a BrowserWindowConstructorOptions option because
+            // we need to access it in the renderer at init time.
+              backgroundColor: windowOpenOverriddenOptions.backgroundColor,
+              transparent: windowOpenOverriddenOptions.transparent,
+              ...windowOpenOverriddenOptions.webPreferences
+            }
+          : undefined;
         const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
         const webPreferences = makeWebPreferences({
           embedder: this,
@@ -720,9 +724,7 @@ WebContents.prototype._init = function () {
     });
 
     // Create a new browser window for "window.open"
-    this.on('-add-new-contents' as any, (event: Electron.Event, webContents: Electron.WebContents, disposition: string,
-      _userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string,
-      referrer: Electron.Referrer, rawFeatures: string, postData: PostData) => {
+    this.on('-add-new-contents', (event, webContents, disposition, _userGesture, _left, _top, _width, _height, url, frameName, referrer, rawFeatures, postData) => {
       const overriddenOptions = windowOpenOverriddenOptions || undefined;
       const outlivesOpener = windowOpenOutlivesOpenerOption;
       windowOpenOverriddenOptions = null;
@@ -756,7 +758,7 @@ WebContents.prototype._init = function () {
     app.emit('login', event, this, ...args);
   });
 
-  this.on('ready-to-show' as any, () => {
+  this.on('ready-to-show', () => {
     const owner = this.getOwnerBrowserWindow();
     if (owner && !owner.isDestroyed()) {
       process.nextTick(() => {
@@ -775,7 +777,7 @@ WebContents.prototype._init = function () {
 
   const originCounts = new Map<string, number>();
   const openDialogs = new Set<AbortController>();
-  this.on('-run-dialog' as any, async (info: {frame: WebFrameMain, dialogType: 'prompt' | 'confirm' | 'alert', messageText: string, defaultPromptText: string}, callback: (success: boolean, user_input: string) => void) => {
+  this.on('-run-dialog', async (info, callback) => {
     const originUrl = new URL(info.frame.url);
     const origin = originUrl.protocol === 'file:' ? originUrl.href : originUrl.origin;
     if ((originCounts.get(origin) ?? 0) < 0) return callback(false, '');
@@ -796,15 +798,17 @@ WebContents.prototype._init = function () {
       message: info.messageText,
       checkboxLabel: checkbox,
       signal: abortController.signal,
-      ...(info.dialogType === 'confirm') ? {
-        buttons: ['OK', 'Cancel'],
-        defaultId: 0,
-        cancelId: 1
-      } : {
-        buttons: ['OK'],
-        defaultId: -1, // No default button
-        cancelId: 0
-      }
+      ...(info.dialogType === 'confirm')
+        ? {
+            buttons: ['OK', 'Cancel'],
+            defaultId: 0,
+            cancelId: 1
+          }
+        : {
+            buttons: ['OK'],
+            defaultId: -1, // No default button
+            cancelId: 0
+          }
     };
     openDialogs.add(abortController);
     const promise = parent && !prefs.offscreen ? dialog.showMessageBox(parent, options) : dialog.showMessageBox(options);
@@ -818,7 +822,7 @@ WebContents.prototype._init = function () {
     }
   });
 
-  this.on('-cancel-dialogs' as any, () => {
+  this.on('-cancel-dialogs', () => {
     for (const controller of openDialogs) { controller.abort(); }
     openDialogs.clear();
   });

+ 29 - 27
lib/browser/default-menu.ts

@@ -14,33 +14,35 @@ export const setDefaultApplicationMenu = () => {
 
   const helpMenu: Electron.MenuItemConstructorOptions = {
     role: 'help',
-    submenu: app.isPackaged ? [] : [
-      {
-        label: 'Learn More',
-        click: async () => {
-          await shell.openExternal('https://electronjs.org');
-        }
-      },
-      {
-        label: 'Documentation',
-        click: async () => {
-          const version = process.versions.electron;
-          await shell.openExternal(`https://github.com/electron/electron/tree/v${version}/docs#readme`);
-        }
-      },
-      {
-        label: 'Community Discussions',
-        click: async () => {
-          await shell.openExternal('https://discord.gg/electronjs');
-        }
-      },
-      {
-        label: 'Search Issues',
-        click: async () => {
-          await shell.openExternal('https://github.com/electron/electron/issues');
-        }
-      }
-    ]
+    submenu: app.isPackaged
+      ? []
+      : [
+          {
+            label: 'Learn More',
+            click: async () => {
+              await shell.openExternal('https://electronjs.org');
+            }
+          },
+          {
+            label: 'Documentation',
+            click: async () => {
+              const version = process.versions.electron;
+              await shell.openExternal(`https://github.com/electron/electron/tree/v${version}/docs#readme`);
+            }
+          },
+          {
+            label: 'Community Discussions',
+            click: async () => {
+              await shell.openExternal('https://discord.gg/electronjs');
+            }
+          },
+          {
+            label: 'Search Issues',
+            click: async () => {
+              await shell.openExternal('https://github.com/electron/electron/issues');
+            }
+          }
+        ]
   };
 
   const macAppMenu: Electron.MenuItemConstructorOptions = { role: 'appMenu' };

+ 23 - 17
lib/browser/devtools.ts

@@ -7,23 +7,29 @@ import { IPC_MESSAGES } from '@electron/internal//common/ipc-messages';
 
 const convertToMenuTemplate = function (items: ContextMenuItem[], handler: (id: number) => void) {
   return items.map(function (item) {
-    const transformed: Electron.MenuItemConstructorOptions = item.type === 'subMenu' ? {
-      type: 'submenu',
-      label: item.label,
-      enabled: item.enabled,
-      submenu: convertToMenuTemplate(item.subItems, handler)
-    } : item.type === 'separator' ? {
-      type: 'separator'
-    } : item.type === 'checkbox' ? {
-      type: 'checkbox',
-      label: item.label,
-      enabled: item.enabled,
-      checked: item.checked
-    } : {
-      type: 'normal',
-      label: item.label,
-      enabled: item.enabled
-    };
+    const transformed: Electron.MenuItemConstructorOptions = item.type === 'subMenu'
+      ? {
+          type: 'submenu',
+          label: item.label,
+          enabled: item.enabled,
+          submenu: convertToMenuTemplate(item.subItems, handler)
+        }
+      : item.type === 'separator'
+        ? {
+            type: 'separator'
+          }
+        : item.type === 'checkbox'
+          ? {
+              type: 'checkbox',
+              label: item.label,
+              enabled: item.enabled,
+              checked: item.checked
+            }
+          : {
+              type: 'normal',
+              label: item.label,
+              enabled: item.enabled
+            };
 
     if (item.id != null) {
       transformed.click = () => handler(item.id);

+ 2 - 2
lib/browser/guest-view-manager.ts

@@ -237,7 +237,7 @@ const watchEmbedder = function (embedder: Electron.WebContents) {
       }
     }
   };
-  embedder.on('-window-visibility-change' as any, onVisibilityChange);
+  embedder.on('-window-visibility-change', onVisibilityChange);
 
   embedder.once('will-destroy' as any, () => {
     // Usually the guestInstances is cleared when guest is destroyed, but it
@@ -249,7 +249,7 @@ const watchEmbedder = function (embedder: Electron.WebContents) {
       }
     }
     // Clear the listeners.
-    embedder.removeListener('-window-visibility-change' as any, onVisibilityChange);
+    embedder.removeListener('-window-visibility-change', onVisibilityChange);
     watchedEmbedders.delete(embedder);
   });
 };

+ 2 - 2
lib/common/api/net-client-request.ts

@@ -210,7 +210,7 @@ type ExtraURLLoaderOptions = {
    allowNonHttpProtocols: boolean;
 }
 function parseOptions (optionsIn: ClientRequestConstructorOptions | string): NodeJS.CreateURLLoaderOptions & ExtraURLLoaderOptions {
-  // eslint-disable-next-line node/no-deprecated-api
+  // eslint-disable-next-line n/no-deprecated-api
   const options: any = typeof optionsIn === 'string' ? url.parse(optionsIn) : { ...optionsIn };
 
   let urlStr: string = options.url;
@@ -243,7 +243,7 @@ function parseOptions (optionsIn: ClientRequestConstructorOptions | string): Nod
       // an invalid request.
       throw new TypeError('Request path contains unescaped characters');
     }
-    // eslint-disable-next-line node/no-deprecated-api
+    // eslint-disable-next-line n/no-deprecated-api
     const pathObj = url.parse(options.path || '/');
     urlObj.pathname = pathObj.pathname;
     urlObj.search = pathObj.search;

+ 1 - 1
npm/install.js

@@ -59,7 +59,7 @@ function isInstalled () {
     if (fs.readFileSync(path.join(__dirname, 'path.txt'), 'utf-8') !== platformPath) {
       return false;
     }
-  } catch (ignored) {
+  } catch {
     return false;
   }
 

+ 35 - 45
package.json

@@ -4,72 +4,62 @@
   "repository": "https://github.com/electron/electron",
   "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
   "devDependencies": {
-    "@azure/storage-blob": "^12.9.0",
-    "@electron/asar": "^3.2.1",
-    "@electron/docs-parser": "^1.2.0",
-    "@electron/fiddle-core": "^1.0.4",
-    "@electron/github-app-auth": "^2.0.0",
+    "@azure/storage-blob": "^12.25.0",
+    "@electron/asar": "^3.2.13",
+    "@electron/docs-parser": "^1.2.3",
+    "@electron/fiddle-core": "^1.3.4",
+    "@electron/github-app-auth": "^2.2.1",
     "@electron/lint-roller": "^1.12.1",
-    "@electron/typescript-definitions": "^8.15.2",
+    "@electron/typescript-definitions": "^8.15.8",
     "@octokit/rest": "^20.0.2",
     "@primer/octicons": "^10.0.0",
-    "@types/basic-auth": "^1.1.3",
-    "@types/busboy": "^1.5.0",
-    "@types/chai": "^4.2.12",
-    "@types/chai-as-promised": "^7.1.3",
-    "@types/dirty-chai": "^2.0.2",
-    "@types/express": "^4.17.13",
-    "@types/minimist": "^1.2.0",
-    "@types/mocha": "^7.0.2",
+    "@types/minimist": "^1.2.5",
     "@types/node": "^20.9.0",
-    "@types/semver": "^7.3.3",
-    "@types/send": "^0.14.5",
-    "@types/split": "^1.0.0",
-    "@types/stream-json": "^1.5.1",
-    "@types/temp": "^0.8.34",
-    "@types/uuid": "^3.4.6",
-    "@types/w3c-web-serial": "^1.0.3",
-    "@types/webpack": "^5.28.0",
-    "@types/webpack-env": "^1.17.0",
-    "@typescript-eslint/eslint-plugin": "^5.59.7",
-    "@typescript-eslint/parser": "^5.59.7",
+    "@types/semver": "^7.5.8",
+    "@types/stream-json": "^1.7.7",
+    "@types/temp": "^0.9.4",
+    "@types/webpack": "^5.28.5",
+    "@types/webpack-env": "^1.18.5",
+    "@typescript-eslint/eslint-plugin": "^8.7.0",
+    "@typescript-eslint/parser": "^8.7.0",
     "buffer": "^6.0.3",
+    "chalk": "^4.1.0",
     "check-for-leaks": "^1.2.1",
-    "colors": "1.4.0",
-    "dugite": "^2.3.0",
-    "eslint": "^8.41.0",
-    "eslint-config-standard": "^14.1.1",
-    "eslint-plugin-import": "^2.26.0",
-    "eslint-plugin-mocha": "^7.0.1",
+    "dotenv-safe": "^4.0.4",
+    "dugite": "^2.7.1",
+    "eslint": "^8.57.1",
+    "eslint-config-standard": "^17.1.0",
+    "eslint-plugin-import": "^2.30.0",
+    "eslint-plugin-mocha": "^10.5.0",
+    "eslint-plugin-n": "^16.6.2",
     "eslint-plugin-node": "^11.1.0",
-    "eslint-plugin-promise": "^4.2.1",
-    "eslint-plugin-standard": "^4.0.1",
-    "eslint-plugin-unicorn": "^46.0.1",
+    "eslint-plugin-promise": "^6.6.0",
+    "eslint-plugin-standard": "^5.0.0",
+    "eslint-plugin-unicorn": "^55.0.0",
     "events": "^3.2.0",
-    "express": "^4.16.4",
     "folder-hash": "^2.1.1",
     "got": "^11.8.5",
     "husky": "^8.0.1",
     "lint": "^1.1.2",
     "lint-staged": "^10.2.11",
-    "minimist": "^1.2.6",
-    "null-loader": "^4.0.0",
-    "pre-flight": "^1.1.0",
+    "minimist": "^1.2.8",
+    "null-loader": "^4.0.1",
+    "pre-flight": "^2.0.0",
     "process": "^0.11.10",
     "remark-cli": "^10.0.0",
     "remark-preset-lint-markdown-style-guide": "^4.0.0",
-    "semver": "^7.5.2",
-    "shx": "^0.3.2",
-    "stream-json": "^1.7.1",
+    "semver": "^7.6.3",
+    "shx": "^0.3.4",
+    "stream-json": "^1.8.0",
     "tap-xunit": "^2.4.1",
-    "temp": "^0.8.3",
+    "temp": "^0.9.4",
     "timers-browserify": "1.4.2",
     "ts-loader": "^8.0.2",
     "ts-node": "6.2.0",
     "typescript": "^5.6.2",
-    "url": "^0.11.0",
-    "webpack": "^5.76.0",
-    "webpack-cli": "^4.10.0",
+    "url": "^0.11.4",
+    "webpack": "^5.94.0",
+    "webpack-cli": "^5.1.4",
     "wrapper-webpack-plugin": "^2.2.0"
   },
   "private": true,

+ 1 - 0
script/doc-only-change.js

@@ -26,6 +26,7 @@ async function checkIfDocOnlyChange () {
       const nonDocChange = filesChanged.length === 0 || filesChanged.find(({ filename }) => {
         const fileDirs = filename.split('/');
         if (fileDirs[0] !== 'docs') return true;
+        return false;
       });
 
       process.exit(nonDocChange ? 1 : 0);

+ 1 - 1
script/lib/get-version.js

@@ -15,7 +15,7 @@ module.exports.getElectronVersion = () => {
     if (match) {
       return match[1];
     }
-  } catch (error) {
+  } catch {
     // Error may happen when trying to get version before running gn, which is a
     // valid case and error will be ignored.
   }

+ 3 - 3
script/lib/utils.js

@@ -1,3 +1,4 @@
+const chalk = require('chalk');
 const { GitProcess } = require('dugite');
 const fs = require('node:fs');
 const os = require('node:os');
@@ -6,10 +7,9 @@ const path = require('node:path');
 const ELECTRON_DIR = path.resolve(__dirname, '..', '..');
 const SRC_DIR = path.resolve(ELECTRON_DIR, '..');
 
-require('colors');
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
-const pass = '✓'.green;
-const fail = '✗'.red;
+const pass = chalk.green('✓');
+const fail = chalk.red('✗');
 
 function getElectronExec () {
   const OUT_DIR = getOutDir();

+ 0 - 1
script/lint.js

@@ -138,7 +138,6 @@ const LINTERS = [{
       cacheLocation: `node_modules/.eslintcache.${crypto.createHash('md5').update(fs.readFileSync(__filename)).digest('hex')}`,
       extensions: ['.js', '.ts'],
       fix: opts.fix,
-      overrideConfigFile: path.join(ELECTRON_ROOT, '.eslintrc.json'),
       resolvePluginsRelativeTo: ELECTRON_ROOT
     });
     const formatter = await eslint.loadFormatter();

+ 4 - 4
script/release/prepare-release.ts

@@ -1,6 +1,7 @@
 #!/usr/bin/env node
 
 import { Octokit } from '@octokit/rest';
+import * as chalk from 'chalk';
 import { GitProcess } from 'dugite';
 import { execSync } from 'node:child_process';
 import { join } from 'node:path';
@@ -45,9 +46,8 @@ const octokit = new Octokit({
   authStrategy: createGitHubTokenStrategy(getRepo())
 });
 
-require('colors');
-const pass = '✓'.green;
-const fail = '✗'.red;
+const pass = chalk.green('✓');
+const fail = chalk.red('✗');
 
 if (!bumpType && !notesOnly) {
   console.log('Usage: prepare-release [stable | minor | beta | alpha | nightly]' +
@@ -218,7 +218,7 @@ async function promptForVersion (version: string) {
       input: process.stdin,
       output: process.stdout
     });
-    rl.question(`Do you want to create the release ${version.green} (y/N)? `, (answer) => {
+    rl.question(`Do you want to create the release ${chalk.green(version)} (y/N)? `, (answer) => {
       rl.close();
       resolve(answer);
     });

+ 3 - 3
script/release/release-artifact-cleanup.ts

@@ -1,6 +1,7 @@
 #!/usr/bin/env node
 
 import { Octokit } from '@octokit/rest';
+import * as chalk from 'chalk';
 import { parseArgs } from 'node:util';
 
 import { createGitHubTokenStrategy } from './github-token';
@@ -25,9 +26,8 @@ if (!_tag) {
 
 const tag = _tag;
 
-require('colors');
-const pass = '✓'.green;
-const fail = '✗'.red;
+const pass = chalk.green('✓');
+const fail = chalk.red('✗');
 
 async function deleteDraft (releaseId: string, targetRepo: ElectronReleaseRepo) {
   const octokit = new Octokit({

+ 3 - 3
script/release/release.ts

@@ -2,6 +2,7 @@
 
 import { BlobServiceClient } from '@azure/storage-blob';
 import { Octokit } from '@octokit/rest';
+import * as chalk from 'chalk';
 import got from 'got';
 import { execSync, ExecSyncOptions } from 'node:child_process';
 import { statSync, createReadStream, writeFileSync, close } from 'node:fs';
@@ -18,9 +19,8 @@ import { parseArgs } from 'node:util';
 
 const temp = trackTemp();
 
-require('colors');
-const pass = '✓'.green;
-const fail = '✗'.red;
+const pass = chalk.green('✓');
+const fail = chalk.red('✗');
 
 const pkgVersion = `v${getElectronVersion()}`;
 

+ 4 - 4
script/spec-runner.js

@@ -1,6 +1,7 @@
 #!/usr/bin/env node
 
 const { ElectronVersions, Installer } = require('@electron/fiddle-core');
+const chalk = require('chalk');
 const childProcess = require('node:child_process');
 const crypto = require('node:crypto');
 const fs = require('node:fs');
@@ -9,9 +10,8 @@ const os = require('node:os');
 const path = require('node:path');
 const unknownFlags = [];
 
-require('colors');
-const pass = '✓'.green;
-const fail = '✗'.red;
+const pass = chalk.green('✓');
+const fail = chalk.red('✗');
 
 const args = require('minimist')(process.argv, {
   string: ['runners', 'target', 'electronVersion'],
@@ -80,7 +80,7 @@ async function main () {
     }
 
     const versionString = `v${args.electronVersion}`;
-    console.log(`Running against Electron ${versionString.green}`);
+    console.log(`Running against Electron ${chalk.green(versionString)}`);
   }
 
   const [lastSpecHash, lastSpecInstallHash] = loadLastSpecHash();

+ 2 - 2
spec/api-browser-window-spec.ts

@@ -318,7 +318,7 @@ describe('BrowserWindow module', () => {
         },
         {
           type: 'file',
-          filePath: filePath,
+          filePath,
           offset: 0,
           length: fileStats.size,
           modificationTime: fileStats.mtime.getTime() / 1000
@@ -1664,7 +1664,7 @@ describe('BrowserWindow module', () => {
         const backgroundColor = '#BBAAFF';
         w.destroy();
         w = new BrowserWindow({
-          backgroundColor: backgroundColor
+          backgroundColor
         });
         expect(w.getBackgroundColor()).to.equal(backgroundColor);
       });

+ 6 - 2
spec/api-context-bridge-spec.ts

@@ -67,7 +67,9 @@ describe('contextBridge', () => {
     describe(`with sandbox=${useSandbox}`, () => {
       const makeBindingWindow = async (bindingCreator: Function, worldId: number = 0) => {
         const preloadContentForMainWorld = `const renderer_1 = require('electron');
-        ${useSandbox ? '' : `require('node:v8').setFlagsFromString('--expose_gc');
+        ${useSandbox
+? ''
+: `require('node:v8').setFlagsFromString('--expose_gc');
         const gc=require('node:vm').runInNewContext('gc');
         renderer_1.contextBridge.exposeInMainWorld('GCRunner', {
           run: () => gc()
@@ -75,7 +77,9 @@ describe('contextBridge', () => {
         (${bindingCreator.toString()})();`;
 
         const preloadContentForIsolatedWorld = `const renderer_1 = require('electron');
-        ${useSandbox ? '' : `require('node:v8').setFlagsFromString('--expose_gc');
+        ${useSandbox
+? ''
+: `require('node:v8').setFlagsFromString('--expose_gc');
         const gc=require('node:vm').runInNewContext('gc');
         renderer_1.webFrame.setIsolatedWorldInfo(${worldId}, {
           name: "Isolated World"

+ 2 - 1
spec/api-crash-reporter-spec.ts

@@ -530,7 +530,8 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
       }
     }
 
-    const processList = process.platform === 'linux' ? ['main', 'renderer', 'sandboxed-renderer']
+    const processList = process.platform === 'linux'
+      ? ['main', 'renderer', 'sandboxed-renderer']
       : ['main', 'renderer', 'sandboxed-renderer', 'node'];
     for (const crashingProcess of processList) {
       describe(`when ${crashingProcess} crashes`, () => {

+ 2 - 2
spec/api-ipc-renderer-spec.ts

@@ -88,8 +88,8 @@ describe('ipcRenderer module', () => {
       }`);
 
       const child = { hello: 'world' };
-      const foo = { name: 'foo', child: child };
-      const bar = { name: 'bar', child: child };
+      const foo = { name: 'foo', child };
+      const bar = { name: 'bar', child };
       const array = [foo, bar];
 
       const [, arrayValue, fooValue, barValue, childValue] = await once(ipcMain, 'message');

+ 3 - 4
spec/api-net-spec.ts

@@ -2,7 +2,6 @@ import { expect } from 'chai';
 import { net, ClientRequest, ClientRequestConstructorOptions, utilityProcess } from 'electron/main';
 import * as http from 'node:http';
 import * as path from 'node:path';
-import * as url from 'node:url';
 import { once } from 'node:events';
 import { setTimeout } from 'node:timers/promises';
 import { collectStreamBody, collectStreamBodyBuffer, getResponse, kOneKiloByte, kOneMegaByte, randomBuffer, randomString, respondNTimes, respondOnce } from './lib/net-helpers';
@@ -934,7 +933,7 @@ describe('net module', () => {
           response.statusMessage = 'OK';
           response.end();
         });
-        const serverUrl = url.parse(serverUrlUnparsed);
+        const serverUrl = new URL(serverUrlUnparsed);
         const urlRequest = net.request({
           port: serverUrl.port ? parseInt(serverUrl.port, 10) : undefined,
           hostname: '127.0.0.1',
@@ -1307,10 +1306,10 @@ describe('net module', () => {
         ]);
         const netRequest = net.request(netServerUrl);
         const netResponse = await getResponse(netRequest);
-        const serverUrl = url.parse(nodeServerUrl);
+        const serverUrl = new URL(nodeServerUrl);
         const nodeOptions = {
           method: 'POST',
-          path: serverUrl.path,
+          path: serverUrl.pathname,
           port: serverUrl.port
         };
         const nodeRequest = http.request(nodeOptions);

+ 3 - 3
spec/api-protocol-spec.ts

@@ -649,7 +649,7 @@ describe('protocol module', () => {
       const { url } = await listen(server);
       interceptHttpProtocol('http', (request, callback) => {
         const data: Electron.ProtocolResponse = {
-          url: url,
+          url,
           method: 'POST',
           uploadData: {
             contentType: 'application/x-www-form-urlencoded',
@@ -910,7 +910,7 @@ describe('protocol module', () => {
     });
 
     it('allows CORS requests by default', async () => {
-      await allowsCORSRequests('cors', 200, new RegExp(''), () => {
+      await allowsCORSRequests('cors', 200, /(?:)/, () => {
         const { ipcRenderer } = require('electron');
         fetch('cors://myhost').then(function (response) {
           ipcRenderer.send('response', response.status);
@@ -1695,7 +1695,7 @@ describe('protocol module', () => {
       const filePath = path.join(fixturesPath, 'pages', 'form-with-data.html');
       await contents.loadFile(filePath);
 
-      const loadPromise = new Promise((resolve, reject) => {
+      const loadPromise = new Promise<void>((resolve, reject) => {
         contents.once('did-finish-load', resolve);
         contents.once('did-fail-load', (_, errorCode, errorDescription) =>
           reject(new Error(`did-fail-load: ${errorCode} ${errorDescription}. See AssertionError for details.`))

+ 11 - 9
spec/api-web-contents-spec.ts

@@ -2625,15 +2625,17 @@ describe('webContents module', () => {
       expect({
         width: w.getBounds().width,
         height: w.getBounds().height
-      }).to.deep.equal(process.platform === 'win32' ? {
-        // The width is reported as being larger on Windows? I'm not sure why
-        // this is.
-        width: 136,
-        height: 100
-      } : {
-        width: 100,
-        height: 100
-      });
+      }).to.deep.equal(process.platform === 'win32'
+        ? {
+            // The width is reported as being larger on Windows? I'm not sure why
+            // this is.
+            width: 136,
+            height: 100
+          }
+        : {
+            width: 100,
+            height: 100
+          });
     });
 
     it('does not change window bounds if cancelled', async () => {

+ 1 - 1
spec/api-web-frame-main-spec.ts

@@ -20,7 +20,7 @@ describe('webFrameMain module', () => {
   /** Creates an HTTP server whose handler embeds the given iframe src. */
   const createServer = async () => {
     const server = http.createServer((req, res) => {
-      const params = new URLSearchParams(url.parse(req.url || '').search || '');
+      const params = new URLSearchParams(new URL(req.url || '', `http://${req.headers.host}`).search || '');
       if (params.has('frameSrc')) {
         res.end(`<iframe src="${params.get('frameSrc')}"></iframe>`);
       } else {

+ 13 - 13
spec/api-web-request-spec.ts

@@ -295,7 +295,7 @@ describe('webRequest module', () => {
       ses.webRequest.onBeforeSendHeaders((details, callback) => {
         const requestHeaders = details.requestHeaders;
         requestHeaders.Accept = '*/*;test/header';
-        callback({ requestHeaders: requestHeaders });
+        callback({ requestHeaders });
       });
       const { data } = await ajax(defaultURL);
       expect(data).to.equal('/header/received');
@@ -328,7 +328,7 @@ describe('webRequest module', () => {
         ses.webRequest.onBeforeSendHeaders((details, callback) => {
           const requestHeaders = details.requestHeaders;
           requestHeaders.Accept = '*/*;test/header';
-          callback({ requestHeaders: requestHeaders });
+          callback({ requestHeaders });
         });
         const { data } = await ajax('no-cors://fake-host/redirect');
         expect(data).to.equal('header-received');
@@ -341,7 +341,7 @@ describe('webRequest module', () => {
       ses.webRequest.onBeforeSendHeaders((details, callback) => {
         const requestHeaders = details.requestHeaders;
         requestHeaders.Origin = 'http://new-origin';
-        callback({ requestHeaders: requestHeaders });
+        callback({ requestHeaders });
       });
       const { data } = await ajax(defaultURL);
       expect(data).to.equal('/new/origin');
@@ -362,7 +362,7 @@ describe('webRequest module', () => {
         Test: 'header'
       };
       ses.webRequest.onBeforeSendHeaders((details, callback) => {
-        callback({ requestHeaders: requestHeaders });
+        callback({ requestHeaders });
       });
       ses.webRequest.onSendHeaders((details) => {
         expect(details.requestHeaders).to.deep.equal(requestHeaders);
@@ -388,7 +388,7 @@ describe('webRequest module', () => {
       };
       let onSendHeadersCalled = false;
       ses.webRequest.onBeforeSendHeaders((details, callback) => {
-        callback({ requestHeaders: requestHeaders });
+        callback({ requestHeaders });
       });
       ses.webRequest.onSendHeaders((details) => {
         expect(details.requestHeaders).to.deep.equal(requestHeaders);
@@ -437,7 +437,7 @@ describe('webRequest module', () => {
       ses.webRequest.onHeadersReceived((details, callback) => {
         const responseHeaders = details.responseHeaders!;
         responseHeaders.Custom = ['Changed'] as any;
-        callback({ responseHeaders: responseHeaders });
+        callback({ responseHeaders });
       });
       const { headers } = await ajax(defaultURL);
       expect(headers).to.to.have.property('custom', 'Changed');
@@ -447,7 +447,7 @@ describe('webRequest module', () => {
       ses.webRequest.onHeadersReceived((details, callback) => {
         const responseHeaders = details.responseHeaders!;
         responseHeaders['access-control-allow-origin'] = ['http://new-origin'] as any;
-        callback({ responseHeaders: responseHeaders });
+        callback({ responseHeaders });
       });
       const { headers } = await ajax(defaultURL);
       expect(headers).to.to.have.property('access-control-allow-origin', 'http://new-origin');
@@ -457,7 +457,7 @@ describe('webRequest module', () => {
       ses.webRequest.onHeadersReceived((details, callback) => {
         const responseHeaders = details.responseHeaders!;
         responseHeaders.Custom = ['Changed'] as any;
-        callback({ responseHeaders: responseHeaders });
+        callback({ responseHeaders });
       });
       const { headers } = await ajax('cors://host');
       expect(headers).to.to.have.property('custom', 'Changed');
@@ -486,7 +486,7 @@ describe('webRequest module', () => {
     it('follows server redirect', async () => {
       ses.webRequest.onHeadersReceived((details, callback) => {
         const responseHeaders = details.responseHeaders;
-        callback({ responseHeaders: responseHeaders });
+        callback({ responseHeaders });
       });
       const { headers } = await ajax(defaultURL + 'serverRedirect');
       expect(headers).to.to.have.property('custom', 'Header');
@@ -496,7 +496,7 @@ describe('webRequest module', () => {
       ses.webRequest.onHeadersReceived((details, callback) => {
         const responseHeaders = details.responseHeaders;
         callback({
-          responseHeaders: responseHeaders,
+          responseHeaders,
           statusLine: 'HTTP/1.1 404 Not Found'
         });
       });
@@ -533,7 +533,7 @@ describe('webRequest module', () => {
       const redirectURL = defaultURL + 'redirect';
       ses.webRequest.onBeforeRequest((details, callback) => {
         if (details.url === defaultURL) {
-          callback({ redirectURL: redirectURL });
+          callback({ redirectURL });
         } else {
           callback({});
         }
@@ -600,7 +600,7 @@ describe('webRequest module', () => {
         });
       });
       server.on('upgrade', function upgrade (request, socket, head) {
-        const pathname = require('node:url').parse(request.url).pathname;
+        const pathname = new URL(request.url!, `http://${request.headers.host}`).pathname;
         if (pathname === '/websocket') {
           reqHeaders[request.url!] = request.headers;
           wss.handleUpgrade(request, socket as Socket, head, function done (ws) {
@@ -622,7 +622,7 @@ describe('webRequest module', () => {
         callback({ requestHeaders: details.requestHeaders });
       });
       ses.webRequest.onHeadersReceived((details, callback) => {
-        const pathname = require('node:url').parse(details.url).pathname;
+        const pathname = new URL(details.url).pathname;
         receivedHeaders[pathname] = details.responseHeaders;
         callback({ cancel: false });
       });

+ 7 - 4
spec/chromium-spec.ts

@@ -704,7 +704,7 @@ describe('chromium features', () => {
     it('should register for intercepted file scheme', (done) => {
       const customSession = session.fromPartition('intercept-file');
       customSession.protocol.interceptBufferProtocol('file', (request, callback) => {
-        let file = url.parse(request.url).pathname!;
+        let file = new URL(request.url).pathname!;
         if (file[0] === '/' && process.platform === 'win32') file = file.slice(1);
 
         const content = fs.readFileSync(path.normalize(file));
@@ -745,7 +745,7 @@ describe('chromium features', () => {
     it('should register for custom scheme', (done) => {
       const customSession = session.fromPartition('custom-scheme');
       customSession.protocol.registerFileProtocol(serviceWorkerScheme, (request, callback) => {
-        let file = url.parse(request.url).pathname!;
+        let file = new URL(request.url).pathname!;
         if (file[0] === '/' && process.platform === 'win32') file = file.slice(1);
 
         callback({ path: path.normalize(file) } as any);
@@ -1999,7 +1999,7 @@ describe('chromium features', () => {
       let contents: WebContents;
       before(() => {
         protocol.registerFileProtocol(protocolName, (request, callback) => {
-          const parsedUrl = url.parse(request.url);
+          const parsedUrl = new URL(request.url);
           let filename;
           switch (parsedUrl.pathname) {
             case '/localStorage' : filename = 'local_storage.html'; break;
@@ -2627,7 +2627,7 @@ describe('chromium features', () => {
     it('has user agent', async () => {
       const server = http.createServer();
       const { port } = await listen(server);
-      const wss = new ws.Server({ server: server });
+      const wss = new ws.Server({ server });
       const finished = new Promise<string | undefined>((resolve, reject) => {
         wss.on('error', reject);
         wss.on('connection', (ws, upgradeReq) => {
@@ -3612,6 +3612,7 @@ describe('navigator.hid', () => {
             haveDevices = true;
             return true;
           }
+          return false;
         });
         if (foundDevice) {
           callback(foundDevice.deviceId);
@@ -3659,6 +3660,7 @@ describe('navigator.hid', () => {
               return true;
             }
           }
+          return false;
         });
       }
       callback();
@@ -3838,6 +3840,7 @@ describe('navigator.usb', () => {
             haveDevices = true;
             return true;
           }
+          return false;
         });
         if (foundDevice) {
           callback(foundDevice.deviceId);

+ 1 - 1
spec/extensions-spec.ts

@@ -606,7 +606,7 @@ describe('chrome extensions', () => {
 
     const addExtension = (name: string) => session.defaultSession.loadExtension(path.resolve(extensionPath, name));
     const removeAllExtensions = () => {
-      Object.keys(session.defaultSession.getAllExtensions()).map(extName => {
+      Object.keys(session.defaultSession.getAllExtensions()).forEach(extName => {
         session.defaultSession.removeExtension(extName);
       });
     };

+ 1 - 1
spec/fixtures/api/fork-with-node-options.js

@@ -19,7 +19,7 @@ try {
     ['--require', path.join(fixtures, 'module', 'noop.js')],
     { env, stdio: 'inherit' });
   process.exit(0);
-} catch (error) {
+} catch {
   console.log('NODE_OPTIONS passed to child');
   process.exit(1);
 }

+ 2 - 1
spec/fixtures/api/singleton-data/main.js

@@ -23,7 +23,8 @@ if (app.commandLine.hasSwitch('data-content')) {
 }
 
 const gotTheLock = sendAdditionalData
-  ? app.requestSingleInstanceLock(obj) : app.requestSingleInstanceLock();
+  ? app.requestSingleInstanceLock(obj)
+  : app.requestSingleInstanceLock();
 
 app.on('second-instance', (event, args, workingDirectory, data) => {
   setImmediate(() => {

+ 4 - 3
spec/fixtures/native-addon/uv-dlopen/index.js

@@ -1,13 +1,14 @@
+const path = require('node:path');
 const testLoadLibrary = require('./build/Release/test_module');
 
 const lib = (() => {
   switch (process.platform) {
     case 'linux':
-      return `${__dirname}/build/Release/foo.so`;
+      return path.resolve(__dirname, 'build/Release/foo.so');
     case 'darwin':
-      return `${__dirname}/build/Release/foo.dylib`;
+      return path.resolve(__dirname, 'build/Release/foo.dylib');
     case 'win32':
-      return `${__dirname}/build/Release/libfoo.dll`;
+      return path.resolve(__dirname, 'build/Release/libfoo.dll');
     default:
       throw new Error('unsupported os');
   }

+ 4 - 4
spec/lib/video-helpers.js

@@ -259,9 +259,9 @@ function checkFrames (frames) {
     duration += frames[i].duration;
   }
   return {
-    duration: duration,
-    width: width,
-    height: height
+    duration,
+    width,
+    height
   };
 }
 
@@ -399,7 +399,7 @@ function parseWebP (riff) {
     horizontalScale,
     verticalScale,
     data: VP8,
-    riff: riff
+    riff
   };
 }
 

+ 12 - 1
spec/package.json

@@ -7,6 +7,18 @@
     "node-gyp-install": "node-gyp install"
   },
   "devDependencies": {
+    "@types/basic-auth": "^1.1.8",
+    "@types/busboy": "^1.5.4",
+    "@types/chai": "^4.3.19",
+    "@types/chai-as-promised": "^7.1.3",
+    "@types/dirty-chai": "^2.0.5",
+    "@types/express": "^4.17.13",
+    "@types/mocha": "^7.0.2",
+    "@types/send": "^0.14.5",
+    "@types/split": "^1.0.5",
+    "@types/uuid": "^3.4.6",
+    "@types/w3c-web-serial": "^1.0.7",
+    "express": "^4.20.0",
     "@electron-ci/echo": "file:./fixtures/native-addon/echo",
     "@electron-ci/is-valid-window": "file:./is-valid-window",
     "@electron-ci/uv-dlopen": "file:./fixtures/native-addon/uv-dlopen/",
@@ -33,7 +45,6 @@
     "send": "^0.16.2",
     "sinon": "^9.0.1",
     "split": "^1.0.1",
-    "temp": "^0.9.0",
     "uuid": "^3.3.3",
     "walkdir": "^0.3.2",
     "winreg": "^1.2.4",

+ 1 - 2
spec/security-warnings-spec.ts

@@ -2,7 +2,6 @@ import { expect } from 'chai';
 import * as http from 'node:http';
 import * as fs from 'node:fs/promises';
 import * as path from 'node:path';
-import * as url from 'node:url';
 
 import { BrowserWindow, WebPreferences } from 'electron/main';
 
@@ -28,7 +27,7 @@ describe('security warnings', () => {
   before(async () => {
     // Create HTTP Server
     server = http.createServer(async (request, response) => {
-      const uri = url.parse(request.url!).pathname!;
+      const uri = new URL(request.url!, `http://${request.headers.host}`).pathname!;
       let filename = path.join(__dirname, 'fixtures', 'pages', uri);
 
       try {

+ 2 - 0
spec/ts-smoke/electron/main.ts

@@ -1,3 +1,5 @@
+/* eslint-disable */
+
 import {
   app,
   autoUpdater,

+ 1 - 0
spec/ts-smoke/electron/renderer.ts

@@ -1,3 +1,4 @@
+/* eslint-disable */
 
 import { ipcRenderer, webFrame } from 'electron/renderer';
 import { clipboard, crashReporter, shell } from 'electron/common';

+ 5 - 5
spec/webview-spec.ts

@@ -326,8 +326,8 @@ describe('<webview> tag', function () {
 
     before(() => {
       const protocol = webviewSession.protocol;
-      protocol.registerStringProtocol(zoomScheme, (request, callback) => {
-        callback('hello');
+      protocol.registerStringProtocol(zoomScheme, (request, respond) => {
+        respond('hello');
       });
     });
 
@@ -847,12 +847,12 @@ describe('<webview> tag', function () {
 
     function setUpRequestHandler (webContentsId: number, requestedPermission: string) {
       return new Promise<void>((resolve, reject) => {
-        session.fromPartition(partition).setPermissionRequestHandler(function (webContents, permission, callback) {
+        session.fromPartition(partition).setPermissionRequestHandler(function (webContents, permission, allow) {
           if (webContents.id === webContentsId) {
             // requestMIDIAccess with sysex requests both midi and midiSysex so
             // grant the first midi one and then reject the midiSysex one
             if (requestedPermission === 'midiSysex' && permission === 'midi') {
-              return callback(true);
+              return allow(true);
             }
 
             try {
@@ -860,7 +860,7 @@ describe('<webview> tag', function () {
             } catch (e) {
               return reject(e);
             }
-            callback(false);
+            allow(false);
             resolve();
           }
         });

+ 492 - 23
spec/yarn.lock

@@ -175,6 +175,28 @@
   dependencies:
     defer-to-connect "^2.0.0"
 
+"@types/basic-auth@^1.1.8":
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/@types/basic-auth/-/basic-auth-1.1.8.tgz#ea235203c89e233faae66b99e03665747576e9e9"
+  integrity sha512-dKcUeixGuZn8pBjcUrf1N7x5K6lWuKuwHHitM2IZ4vwZUDWEhhNtwCWiba8jTA9zn0GQQ+fTFkWpKx8pOU/enw==
+  dependencies:
+    "@types/node" "*"
+
+"@types/body-parser@*":
+  version "1.19.5"
+  resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4"
+  integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==
+  dependencies:
+    "@types/connect" "*"
+    "@types/node" "*"
+
+"@types/busboy@^1.5.4":
+  version "1.5.4"
+  resolved "https://registry.yarnpkg.com/@types/busboy/-/busboy-1.5.4.tgz#0038c31102ca90f2a7f0d8bc27ee5ebf1088e230"
+  integrity sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==
+  dependencies:
+    "@types/node" "*"
+
 "@types/cacheable-request@^6.0.1":
   version "6.0.3"
   resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
@@ -185,11 +207,63 @@
     "@types/node" "*"
     "@types/responselike" "^1.0.0"
 
+"@types/chai-as-promised@^7", "@types/chai-as-promised@^7.1.3":
+  version "7.1.8"
+  resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz#f2b3d82d53c59626b5d6bbc087667ccb4b677fe9"
+  integrity sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==
+  dependencies:
+    "@types/chai" "*"
+
+"@types/chai@*", "@types/chai@^4.3.19":
+  version "4.3.19"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.19.tgz#14519f437361d41e84102ed3fbc922ddace3e228"
+  integrity sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw==
+
+"@types/connect@*":
+  version "3.4.38"
+  resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858"
+  integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==
+  dependencies:
+    "@types/node" "*"
+
+"@types/dirty-chai@^2.0.5":
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/@types/dirty-chai/-/dirty-chai-2.0.5.tgz#f743c5735ba0453e2ec8036610356b1aee5f522b"
+  integrity sha512-7plNsOhNtFn/4eD47et+3CRFNX4tgUrbJRutGhBFqQrWWIyRAV1XP7BYZY0YTOr49t/ZwM/lOW6sxnEXqwVdKg==
+  dependencies:
+    "@types/chai" "*"
+    "@types/chai-as-promised" "^7"
+
+"@types/express-serve-static-core@^4.17.33":
+  version "4.19.5"
+  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6"
+  integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==
+  dependencies:
+    "@types/node" "*"
+    "@types/qs" "*"
+    "@types/range-parser" "*"
+    "@types/send" "*"
+
+"@types/express@^4.17.13":
+  version "4.17.21"
+  resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d"
+  integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==
+  dependencies:
+    "@types/body-parser" "*"
+    "@types/express-serve-static-core" "^4.17.33"
+    "@types/qs" "*"
+    "@types/serve-static" "*"
+
 "@types/http-cache-semantics@*":
   version "4.0.4"
   resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
   integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==
 
+"@types/http-errors@*":
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
+  integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
+
 "@types/keyv@^3.1.4":
   version "3.1.4"
   resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
@@ -197,6 +271,16 @@
   dependencies:
     "@types/node" "*"
 
+"@types/mime@^1":
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
+  integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
+
+"@types/mocha@^7.0.2":
+  version "7.0.2"
+  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce"
+  integrity sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==
+
 "@types/node@*":
   version "20.12.7"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384"
@@ -204,6 +288,16 @@
   dependencies:
     undici-types "~5.26.4"
 
+"@types/qs@*":
+  version "6.9.16"
+  resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794"
+  integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==
+
+"@types/range-parser@*":
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
+  integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
+
 "@types/responselike@^1.0.0":
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
@@ -211,6 +305,31 @@
   dependencies:
     "@types/node" "*"
 
+"@types/send@*":
+  version "0.17.4"
+  resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a"
+  integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==
+  dependencies:
+    "@types/mime" "^1"
+    "@types/node" "*"
+
+"@types/send@^0.14.5":
+  version "0.14.7"
+  resolved "https://registry.yarnpkg.com/@types/send/-/send-0.14.7.tgz#ee6224edd5a593d7f553235f350569accb56a4af"
+  integrity sha512-WCUMbzWW1sTEZX31cRMcBxflUXX/JmAYejhjxXtrLGn+vd/yyFjHh/F9FIigAEjE2LauhfH94BT7NJj9Ru2Wlg==
+  dependencies:
+    "@types/mime" "^1"
+    "@types/node" "*"
+
+"@types/serve-static@*":
+  version "1.15.7"
+  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714"
+  integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==
+  dependencies:
+    "@types/http-errors" "*"
+    "@types/node" "*"
+    "@types/send" "*"
+
 "@types/sinon@^9.0.4":
   version "9.0.11"
   resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.11.tgz#7af202dda5253a847b511c929d8b6dda170562eb"
@@ -223,6 +342,31 @@
   resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz#5fd3592ff10c1e9695d377020c033116cc2889f2"
   integrity sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==
 
+"@types/split@^1.0.5":
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/@types/split/-/split-1.0.5.tgz#4bd47164b81d6381db37978d5344b374b6825f6c"
+  integrity sha512-gMiDr4vA6YofTpAkPQtP+5pvStIf3CMYphf32YAG/3RwogNL8ii1CQKDc+sxN62KuxPoRaJXcf2zDCDkEBH4FA==
+  dependencies:
+    "@types/node" "*"
+    "@types/through" "*"
+
+"@types/through@*":
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.33.tgz#14ebf599320e1c7851e7d598149af183c6b9ea56"
+  integrity sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==
+  dependencies:
+    "@types/node" "*"
+
+"@types/uuid@^3.4.6":
+  version "3.4.13"
+  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.13.tgz#fe890e517fb840620be284ee213e81d702b1f76b"
+  integrity sha512-pAeZeUbLE4Z9Vi9wsWV2bYPTweEHeJJy0G4pEjOA/FSvy1Ad5U5Km8iDV6TKre1mjBiVNfAdVHKruP8bAh4Q5A==
+
+"@types/w3c-web-serial@^1.0.7":
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/@types/w3c-web-serial/-/w3c-web-serial-1.0.7.tgz#44416509af271e5196833ff5e1337c7c256991c6"
+  integrity sha512-jzcwm//EZ0Z306L1/O1GXC3GthRd//9eaNB4/Yagm98UjEQViTzDS8bYvL+y+rTk1r9OFt9Yhp5pprUQFzSiiQ==
+
 "@types/ws@^7.2.0":
   version "7.4.7"
   resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702"
@@ -242,7 +386,7 @@
   resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
   integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==
 
-"abstract-socket@github:saghul/node-abstractsocket#35b1b1491fabc04899bde5be3428abf5cf9cd528":
+abstract-socket@^2.0.0:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/abstract-socket/-/abstract-socket-2.1.1.tgz#243a7e6e6ff65bb9eab16a22fa90699b91e528f7"
   integrity sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA==
@@ -250,6 +394,14 @@
     bindings "^1.2.1"
     nan "^2.12.1"
 
+accepts@~1.3.8:
+  version "1.3.8"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+  integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+  dependencies:
+    mime-types "~2.1.34"
+    negotiator "0.6.3"
+
 [email protected]:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
@@ -285,6 +437,11 @@ argparse@^2.0.1:
   resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
   integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
 
[email protected]:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+  integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
+
 assertion-error@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
@@ -334,6 +491,24 @@ bluebird@^3.1.1:
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
   integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
 
[email protected]:
+  version "1.20.3"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
+  integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
+  dependencies:
+    bytes "3.1.2"
+    content-type "~1.0.5"
+    debug "2.6.9"
+    depd "2.0.0"
+    destroy "1.2.0"
+    http-errors "2.0.0"
+    iconv-lite "0.4.24"
+    on-finished "2.4.1"
+    qs "6.13.0"
+    raw-body "2.5.2"
+    type-is "~1.6.18"
+    unpipe "1.0.0"
+
 boolean@^3.0.1:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b"
@@ -378,6 +553,11 @@ busboy@^1.6.0:
   dependencies:
     streamsearch "^1.1.0"
 
[email protected]:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+  integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
 cacheable-lookup@^5.0.3:
   version "5.0.4"
   resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
@@ -396,6 +576,17 @@ cacheable-request@^7.0.2:
     normalize-url "^6.0.1"
     responselike "^2.0.0"
 
+call-bind@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
+  integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
+  dependencies:
+    es-define-property "^1.0.0"
+    es-errors "^1.3.0"
+    function-bind "^1.1.2"
+    get-intrinsic "^1.2.4"
+    set-function-length "^1.2.1"
+
 camelcase@^6.0.0:
   version "6.3.0"
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
@@ -509,6 +700,28 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
   integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
 
[email protected]:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+  integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+  dependencies:
+    safe-buffer "5.2.1"
+
+content-type@~1.0.4, content-type@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+  integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
[email protected]:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+  integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+
[email protected]:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
+  integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
+
 cross-dirname@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/cross-dirname/-/cross-dirname-0.1.0.tgz#b899599f30a5389f59e78c150e19f957ad16a37c"
@@ -540,7 +753,7 @@ [email protected]:
     safe-buffer "^5.1.1"
     xml2js "^0.4.17"
   optionalDependencies:
-    abstract-socket "github:saghul/node-abstractsocket#35b1b1491fabc04899bde5be3428abf5cf9cd528"
+    abstract-socket "^2.0.0"
 
 [email protected], debug@^2.2.0:
   version "2.6.9"
@@ -580,7 +793,7 @@ defer-to-connect@^2.0.0:
   resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
   integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
 
-define-data-property@^1.0.1:
+define-data-property@^1.0.1, define-data-property@^1.1.4:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
   integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
@@ -598,11 +811,21 @@ define-properties@^1.2.1:
     has-property-descriptors "^1.0.0"
     object-keys "^1.1.1"
 
[email protected]:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+  integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
 depd@~1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
   integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
 
[email protected]:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+  integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
 destroy@~1.0.4:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
@@ -661,6 +884,11 @@ encodeurl@~1.0.2:
   resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
   integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
 
+encodeurl@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
+  integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
+
 end-of-stream@^1.1.0:
   version "1.4.4"
   resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
@@ -740,6 +968,43 @@ event-stream@^4.0.0:
     stream-combiner "^0.2.2"
     through "^2.3.8"
 
+express@^4.20.0:
+  version "4.21.0"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915"
+  integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==
+  dependencies:
+    accepts "~1.3.8"
+    array-flatten "1.1.1"
+    body-parser "1.20.3"
+    content-disposition "0.5.4"
+    content-type "~1.0.4"
+    cookie "0.6.0"
+    cookie-signature "1.0.6"
+    debug "2.6.9"
+    depd "2.0.0"
+    encodeurl "~2.0.0"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    finalhandler "1.3.1"
+    fresh "0.5.2"
+    http-errors "2.0.0"
+    merge-descriptors "1.0.3"
+    methods "~1.1.2"
+    on-finished "2.4.1"
+    parseurl "~1.3.3"
+    path-to-regexp "0.1.10"
+    proxy-addr "~2.0.7"
+    qs "6.13.0"
+    range-parser "~1.2.1"
+    safe-buffer "5.2.1"
+    send "0.19.0"
+    serve-static "1.16.2"
+    setprototypeof "1.2.0"
+    statuses "2.0.1"
+    type-is "~1.6.18"
+    utils-merge "1.0.1"
+    vary "~1.1.2"
+
 extract-zip@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
@@ -784,6 +1049,19 @@ fill-range@^7.0.1:
   dependencies:
     to-regex-range "^5.0.1"
 
[email protected]:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019"
+  integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==
+  dependencies:
+    debug "2.6.9"
+    encodeurl "~2.0.0"
+    escape-html "~1.0.3"
+    on-finished "2.4.1"
+    parseurl "~1.3.3"
+    statuses "2.0.1"
+    unpipe "~1.0.0"
+
 [email protected]:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
@@ -812,6 +1090,11 @@ flora-colossus@^2.0.0:
     debug "^4.3.4"
     fs-extra "^10.1.0"
 
[email protected]:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+  integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+
 [email protected]:
   version "0.5.2"
   resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@@ -939,7 +1222,7 @@ [email protected]:
     minimatch "^5.0.1"
     once "^1.3.0"
 
-glob@^7.1.3, glob@^7.1.6:
+glob@^7.1.6:
   version "7.2.3"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
   integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@@ -1005,7 +1288,7 @@ has-flag@^4.0.0:
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
   integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
 
-has-property-descriptors@^1.0.0:
+has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
   integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
@@ -1049,6 +1332,17 @@ http-cache-semantics@^4.0.0:
   resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
   integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
 
[email protected]:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+  integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+  dependencies:
+    depd "2.0.0"
+    inherits "2.0.4"
+    setprototypeof "1.2.0"
+    statuses "2.0.1"
+    toidentifier "1.0.1"
+
 http-errors@~1.6.2:
   version "1.6.3"
   resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
@@ -1067,6 +1361,13 @@ http2-wrapper@^1.0.0-beta.5.2:
     quick-lru "^5.1.1"
     resolve-alpn "^1.0.0"
 
[email protected]:
+  version "0.4.24"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+  integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3"
+
 inflight@^1.0.4:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -1075,7 +1376,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@2:
+inherits@2, [email protected]:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -1085,6 +1386,11 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
   integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
 
[email protected]:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+  integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
 is-arrayish@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -1287,11 +1593,43 @@ md5@^2.1.0:
     crypt "0.0.2"
     is-buffer "~1.1.6"
 
[email protected]:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+  integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
[email protected]:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
+  integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
+
+methods@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+  integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
[email protected]:
+  version "1.52.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@~2.1.24, mime-types@~2.1.34:
+  version "2.1.35"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+  dependencies:
+    mime-db "1.52.0"
+
 [email protected]:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
   integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
 
[email protected]:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+  integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
 mimic-response@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
@@ -1410,6 +1748,11 @@ [email protected]:
 [email protected], nan@^2.12.1, "nan@file:../../third_party/nan":
   version "2.18.0"
 
[email protected]:
+  version "0.6.3"
+  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+  integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
 nise@^4.0.4:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6"
@@ -1441,11 +1784,23 @@ normalize-url@^6.0.1:
   resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
   integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
 
+object-inspect@^1.13.1:
+  version "1.13.2"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
+  integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
+
 object-keys@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
   integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
 
[email protected]:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+  integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+  dependencies:
+    ee-first "1.1.1"
+
 on-finished@~2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
@@ -1520,6 +1875,11 @@ parse-json@^2.2.0:
   dependencies:
     error-ex "^1.2.0"
 
+parseurl@~1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+  integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
 path-exists@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
@@ -1545,6 +1905,11 @@ path-parse@^1.0.7:
   resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
   integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
 
[email protected]:
+  version "0.1.10"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b"
+  integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==
+
 path-to-regexp@^1.7.0:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
@@ -1628,6 +1993,14 @@ promise-retry@^2.0.1:
     err-code "^2.0.2"
     retry "^0.12.0"
 
+proxy-addr@~2.0.7:
+  version "2.0.7"
+  resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+  integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
+  dependencies:
+    forwarded "0.2.0"
+    ipaddr.js "1.9.1"
+
 ps-list@^7.0.0:
   version "7.2.0"
   resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-7.2.0.tgz#3d110e1de8249a4b178c9b1cf2a215d1e4e42fc0"
@@ -1646,6 +2019,13 @@ q@^1.5.1:
   resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
   integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==
 
[email protected]:
+  version "6.13.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
+  integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
+  dependencies:
+    side-channel "^1.0.6"
+
 quick-lru@^5.1.1:
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
@@ -1658,11 +2038,21 @@ randombytes@^2.1.0:
   dependencies:
     safe-buffer "^5.1.0"
 
-range-parser@~1.2.0:
+range-parser@~1.2.0, range-parser@~1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
   integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
 
[email protected]:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+  integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
+  dependencies:
+    bytes "3.1.2"
+    http-errors "2.0.0"
+    iconv-lite "0.4.24"
+    unpipe "1.0.0"
+
 read-pkg-up@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
@@ -1725,13 +2115,6 @@ retry@^0.12.0:
   resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
   integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==
 
-rimraf@~2.6.2:
-  version "2.6.3"
-  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
-  integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
-  dependencies:
-    glob "^7.1.3"
-
 roarr@^2.15.3:
   version "2.15.4"
   resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd"
@@ -1749,11 +2132,16 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
   integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
 
-safe-buffer@^5.1.0, safe-buffer@^5.1.1:
+[email protected], safe-buffer@^5.1.0, safe-buffer@^5.1.1:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
 
+"safer-buffer@>= 2.1.2 < 3":
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+  integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
 sax@>=0.6.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
@@ -1779,6 +2167,25 @@ semver@^7.1.3, semver@^7.3.2:
   resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
   integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
 
[email protected]:
+  version "0.19.0"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
+  integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
+  dependencies:
+    debug "2.6.9"
+    depd "2.0.0"
+    destroy "1.2.0"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "2.0.0"
+    mime "1.6.0"
+    ms "2.1.3"
+    on-finished "2.4.1"
+    range-parser "~1.2.1"
+    statuses "2.0.1"
+
 send@^0.16.2:
   version "0.16.2"
   resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
@@ -1812,11 +2219,38 @@ [email protected]:
   dependencies:
     randombytes "^2.1.0"
 
[email protected]:
+  version "1.16.2"
+  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296"
+  integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==
+  dependencies:
+    encodeurl "~2.0.0"
+    escape-html "~1.0.3"
+    parseurl "~1.3.3"
+    send "0.19.0"
+
+set-function-length@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
+  integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
+  dependencies:
+    define-data-property "^1.1.4"
+    es-errors "^1.3.0"
+    function-bind "^1.1.2"
+    get-intrinsic "^1.2.4"
+    gopd "^1.0.1"
+    has-property-descriptors "^1.0.2"
+
 [email protected]:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
   integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
 
[email protected]:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+  integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
 shebang-command@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -1829,6 +2263,16 @@ shebang-regex@^3.0.0:
   resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
   integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
 
+side-channel@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
+  integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
+  dependencies:
+    call-bind "^1.0.7"
+    es-errors "^1.3.0"
+    get-intrinsic "^1.2.4"
+    object-inspect "^1.13.1"
+
 sinon@^9.0.1:
   version "9.2.4"
   resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b"
@@ -1879,6 +2323,11 @@ sprintf-js@^1.1.2:
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
   integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
 
[email protected]:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+  integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
 "statuses@>= 1.4.0 < 2":
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
@@ -1968,14 +2417,6 @@ supports-preserve-symlinks-flag@^1.0.0:
   resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
   integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
 
-temp@^0.9.0:
-  version "0.9.4"
-  resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.4.tgz#cd20a8580cb63635d0e4e9d4bd989d44286e7620"
-  integrity sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==
-  dependencies:
-    mkdirp "^0.5.1"
-    rimraf "~2.6.2"
-
 through@2, through@^2.3.8, through@~2.3, through@~2.3.4:
   version "2.3.8"
   resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -1988,6 +2429,11 @@ to-regex-range@^5.0.1:
   dependencies:
     is-number "^7.0.0"
 
[email protected]:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+  integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
 trim-repeated@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21"
@@ -2005,6 +2451,14 @@ type-fest@^0.13.1:
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934"
   integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
 
+type-is@~1.6.18:
+  version "1.6.18"
+  resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+  integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+  dependencies:
+    media-typer "0.3.0"
+    mime-types "~2.1.24"
+
 undici-types@~5.26.4:
   version "5.26.5"
   resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
@@ -2020,6 +2474,16 @@ universalify@^2.0.0:
   resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
   integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
 
[email protected], unpipe@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+  integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
[email protected]:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+  integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
 uuid@^3.3.3:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
@@ -2033,6 +2497,11 @@ validate-npm-package-license@^3.0.1:
     spdx-correct "^3.0.0"
     spdx-expression-parse "^3.0.0"
 
+vary@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+  integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
 walkdir@^0.3.2:
   version "0.3.2"
   resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.3.2.tgz#ac8437a288c295656848ebc19981ebc677a5f590"

+ 1 - 1
tsconfig.json

@@ -14,7 +14,7 @@
     "allowJs": true,
     "noUnusedLocals": true,
     "outDir": "ts-gen",
-    "typeRoots" : ["./node_modules/@types"],
+    "typeRoots" : ["./node_modules/@types", "./spec/node_modules/@types"],
     "paths": {
       "@electron/internal/*": ["lib/*"]
     }

+ 22 - 0
typings/internal-electron.d.ts

@@ -185,6 +185,28 @@ declare namespace Electron {
     registerProtocol(scheme: string, handler: any): boolean;
     interceptProtocol(scheme: string, handler: any): boolean;
   }
+
+  interface WebContents {
+    on(event: '-new-window', listener: (event: Electron.Event, url: string, frameName: string, disposition: Electron.HandlerDetails['disposition'],
+      rawFeatures: string, referrer: Electron.Referrer, postData: LoadURLOptions['postData']) => void): this;
+    on(event: '-add-new-contents', listener: (event: Event, webContents: Electron.WebContents, disposition: string,
+      _userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string,
+      referrer: Electron.Referrer, rawFeatures: string, postData: LoadURLOptions['postData']) => void): this;
+    on(event: '-will-add-new-contents', listener: (event: Electron.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: LoadURLOptions['postData']) => void): this;
+    on(event: '-ipc-message', listener: (event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) => void): this;
+    on(event: '-ipc-message-sync', listener: (event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) => void): this;
+    on(event: '-ipc-invoke', listener: (event: Electron.IpcMainInvokeEvent, internal: boolean, channel: string, args: any[]) => void): this;
+    on(event: '-ipc-ports', listener: (event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) => void): this;
+    on(event: '-run-dialog', listener: (info: {frame: WebFrameMain, dialogType: 'prompt' | 'confirm' | 'alert', messageText: string, defaultPromptText: string}, callback: (success: boolean, user_input: string) => void) => void): this;
+    on(event: '-cancel-dialogs', listener: () => void): this;
+    on(event: 'ready-to-show', listener: () => void): this;
+    on(event: '-before-unload-fired', listener: (event: Electron.Event, proceed: boolean) => void): this;
+
+    on(event: '-window-visibility-change', listener: (visibilityState: 'hidden' | 'visible') => void): this;
+    removeListener(event: '-window-visibility-change', listener: (visibilityState: 'hidden' | 'visible') => void): this;
+
+    once(event: 'destroyed', listener: (event: Electron.Event) => void): this;
+  }
 }
 
 declare namespace ElectronInternal {

File diff suppressed because it is too large
+ 323 - 355
yarn.lock


Some files were not shown because too many files changed in this diff