Browse Source

refactor: simplify events (#37099)

Jeremy Rose 2 years ago
parent
commit
71944f2c3b

+ 0 - 3
docs/api/structures/event.md

@@ -1,3 +0,0 @@
-# Event Object extends `GlobalEvent`
-
-* `preventDefault` VoidFunction

+ 2 - 2
docs/api/web-contents.md

@@ -831,7 +831,7 @@ Emitted when the preload script `preloadPath` throws an unhandled exception `err
 
 Returns:
 
-* `event` Event
+* `event` [IpcMainEvent](structures/ipc-main-event.md)
 * `channel` string
 * `...args` any[]
 
@@ -843,7 +843,7 @@ See also [`webContents.ipc`](#contentsipc-readonly), which provides an [`IpcMain
 
 Returns:
 
-* `event` Event
+* `event` [IpcMainEvent](structures/ipc-main-event.md)
 * `channel` string
 * `...args` any[]
 

+ 0 - 1
filenames.auto.gni

@@ -79,7 +79,6 @@ auto_filenames = {
     "docs/api/structures/custom-scheme.md",
     "docs/api/structures/desktop-capturer-source.md",
     "docs/api/structures/display.md",
-    "docs/api/structures/event.md",
     "docs/api/structures/extension-info.md",
     "docs/api/structures/extension.md",
     "docs/api/structures/file-filter.md",

+ 4 - 5
filenames.gni

@@ -267,7 +267,6 @@ filenames = {
     "shell/browser/api/electron_api_dialog.cc",
     "shell/browser/api/electron_api_download_item.cc",
     "shell/browser/api/electron_api_download_item.h",
-    "shell/browser/api/electron_api_event.cc",
     "shell/browser/api/electron_api_event_emitter.cc",
     "shell/browser/api/electron_api_event_emitter.h",
     "shell/browser/api/electron_api_global_shortcut.cc",
@@ -320,8 +319,6 @@ filenames = {
     "shell/browser/api/electron_api_web_request.cc",
     "shell/browser/api/electron_api_web_request.h",
     "shell/browser/api/electron_api_web_view_manager.cc",
-    "shell/browser/api/event.cc",
-    "shell/browser/api/event.h",
     "shell/browser/api/frame_subscriber.cc",
     "shell/browser/api/frame_subscriber.h",
     "shell/browser/api/gpu_info_enumerator.cc",
@@ -382,7 +379,6 @@ filenames = {
     "shell/browser/electron_web_contents_utility_handler_impl.h",
     "shell/browser/electron_web_ui_controller_factory.cc",
     "shell/browser/electron_web_ui_controller_factory.h",
-    "shell/browser/event_emitter_mixin.cc",
     "shell/browser/event_emitter_mixin.h",
     "shell/browser/extended_web_contents_observer.h",
     "shell/browser/feature_list.cc",
@@ -606,10 +602,13 @@ filenames = {
     "shell/common/gin_helper/dictionary.h",
     "shell/common/gin_helper/error_thrower.cc",
     "shell/common/gin_helper/error_thrower.h",
-    "shell/common/gin_helper/event_emitter.cc",
+    "shell/common/gin_helper/event.cc",
+    "shell/common/gin_helper/event.h",
     "shell/common/gin_helper/event_emitter.h",
     "shell/common/gin_helper/event_emitter_caller.cc",
     "shell/common/gin_helper/event_emitter_caller.h",
+    "shell/common/gin_helper/event_emitter_template.cc",
+    "shell/common/gin_helper/event_emitter_template.h",
     "shell/common/gin_helper/function_template.cc",
     "shell/common/gin_helper/function_template.h",
     "shell/common/gin_helper/function_template_extensions.h",

+ 4 - 5
lib/browser/api/browser-window.ts

@@ -1,4 +1,4 @@
-import { BaseWindow, WebContents, Event, BrowserView, TouchBar } from 'electron/main';
+import { BaseWindow, WebContents, BrowserView, TouchBar } from 'electron/main';
 import type { BrowserWindow as BWT } from 'electron/main';
 import * as deprecate from '@electron/internal/common/deprecate';
 const { BrowserWindow } = process._linkedBinding('electron_browser_window') as { BrowserWindow: typeof BWT };
@@ -22,10 +22,10 @@ BrowserWindow.prototype._init = function (this: BWT) {
   };
 
   // Redirect focus/blur event to app instance too.
-  this.on('blur', (event: Event) => {
+  this.on('blur', (event: Electron.Event) => {
     app.emit('browser-window-blur', event, this);
   });
-  this.on('focus', (event: Event) => {
+  this.on('focus', (event: Electron.Event) => {
     app.emit('browser-window-focus', event, this);
   });
 
@@ -68,8 +68,7 @@ BrowserWindow.prototype._init = function (this: BWT) {
   });
 
   // Notify the creation of the window.
-  const event = process._linkedBinding('electron_browser_event').createEmpty();
-  app.emit('browser-window-created', event, this);
+  app.emit('browser-window-created', { preventDefault () {} }, this);
 
   Object.defineProperty(this, 'devToolsWebContents', {
     enumerable: true,

+ 2 - 2
lib/browser/api/menu-item.ts

@@ -1,5 +1,5 @@
 import * as roles from '@electron/internal/browser/api/menu-item-roles';
-import { Menu, Event, BrowserWindow, WebContents } from 'electron/main';
+import { Menu, BrowserWindow, WebContents, KeyboardEvent } from 'electron/main';
 
 let nextCommandId = 0;
 
@@ -53,7 +53,7 @@ const MenuItem = function (this: any, options: any) {
   });
 
   const click = options.click;
-  this.click = (event: Event, focusedWindow: BrowserWindow, focusedWebContents: WebContents) => {
+  this.click = (event: KeyboardEvent, focusedWindow: BrowserWindow, focusedWebContents: WebContents) => {
     // Manually flip the checked flags when clicked.
     if (!roles.shouldOverrideCheckStatus(this.role) &&
         (this.type === 'checkbox' || this.type === 'radio')) {

+ 26 - 21
lib/browser/api/web-contents.ts

@@ -524,7 +524,8 @@ const addReplyToEvent = (event: Electron.IpcMainEvent) => {
   };
 };
 
-const addSenderFrameToEvent = (event: Electron.IpcMainEvent | Electron.IpcMainInvokeEvent) => {
+const addSenderToEvent = (event: Electron.IpcMainEvent | Electron.IpcMainInvokeEvent, sender: Electron.WebContents) => {
+  event.sender = sender;
   const { processId, frameId } = event;
   Object.defineProperty(event, 'senderFrame', {
     get: () => webFrameMain.fromId(processId, frameId)
@@ -533,7 +534,7 @@ const addSenderFrameToEvent = (event: Electron.IpcMainEvent | Electron.IpcMainIn
 
 const addReturnValueToEvent = (event: Electron.IpcMainEvent) => {
   Object.defineProperty(event, 'returnValue', {
-    set: (value) => event.sendReply(value),
+    set: (value) => event._replyChannel.sendReply(value),
     get: () => {}
   });
 };
@@ -574,7 +575,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[]) {
-    addSenderFrameToEvent(event);
+    addSenderToEvent(event, this);
     if (internal) {
       ipcMainInternal.emit(channel, event, ...args);
     } else {
@@ -587,25 +588,30 @@ WebContents.prototype._init = function () {
     }
   });
 
-  this.on('-ipc-invoke' as any, function (event: Electron.IpcMainInvokeEvent, internal: boolean, channel: string, args: any[]) {
-    addSenderFrameToEvent(event);
-    event._reply = (result: any) => event.sendReply({ result });
-    event._throw = (error: Error) => {
+  this.on('-ipc-invoke' as any, async function (this: Electron.WebContents, event: Electron.IpcMainInvokeEvent, internal: boolean, channel: string, args: any[]) {
+    addSenderToEvent(event, this);
+    const replyWithResult = (result: any) => event._replyChannel.sendReply({ result });
+    const replyWithError = (error: Error) => {
       console.error(`Error occurred in handler for '${channel}':`, error);
-      event.sendReply({ error: error.toString() });
+      event._replyChannel.sendReply({ error: error.toString() });
     };
     const maybeWebFrame = getWebFrameForEvent(event);
     const targets: (ElectronInternal.IpcMainInternal| undefined)[] = internal ? [ipcMainInternal] : [maybeWebFrame?.ipc, ipc, ipcMain];
     const target = targets.find(target => target && (target as any)._invokeHandlers.has(channel));
     if (target) {
-      (target as any)._invokeHandlers.get(channel)(event, ...args);
+      const handler = (target as any)._invokeHandlers.get(channel);
+      try {
+        replyWithResult(await Promise.resolve(handler(event, ...args)));
+      } catch (err) {
+        replyWithError(err as Error);
+      }
     } else {
-      event._throw(`No handler registered for '${channel}'`);
+      replyWithError(new Error(`No handler registered for '${channel}'`));
     }
   });
 
   this.on('-ipc-message-sync' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
-    addSenderFrameToEvent(event);
+    addSenderToEvent(event, this);
     addReturnValueToEvent(event);
     if (internal) {
       ipcMainInternal.emit(channel, event, ...args);
@@ -622,8 +628,8 @@ WebContents.prototype._init = function () {
     }
   });
 
-  this.on('-ipc-ports' as any, function (event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) {
-    addSenderFrameToEvent(event);
+  this.on('-ipc-ports' as any, 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);
     maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, message);
@@ -651,7 +657,7 @@ 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: ElectronInternal.Event, url: string, frameName: string, disposition: Electron.HandlerDetails['disposition'],
+    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,
@@ -677,7 +683,7 @@ WebContents.prototype._init = function () {
       const options = result.browserWindowConstructorOptions;
       if (!event.defaultPrevented) {
         openGuestWindow({
-          embedder: event.sender,
+          embedder: this,
           disposition,
           referrer,
           postData,
@@ -690,7 +696,7 @@ WebContents.prototype._init = function () {
 
     let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null;
     let windowOpenOutlivesOpenerOption: boolean = false;
-    this.on('-will-add-new-contents' as any, (event: ElectronInternal.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: PostData) => {
+    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)
@@ -725,7 +731,7 @@ WebContents.prototype._init = function () {
         } : undefined;
         const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
         const webPreferences = makeWebPreferences({
-          embedder: event.sender,
+          embedder: this,
           insecureParsedWebPreferences: parsedWebPreferences,
           secureOverrideWebPreferences
         });
@@ -738,7 +744,7 @@ WebContents.prototype._init = function () {
     });
 
     // Create a new browser window for "window.open"
-    this.on('-add-new-contents' as any, (event: ElectronInternal.Event, webContents: Electron.WebContents, disposition: string,
+    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) => {
       const overriddenOptions = windowOpenOverriddenOptions || undefined;
@@ -754,7 +760,7 @@ WebContents.prototype._init = function () {
       }
 
       openGuestWindow({
-        embedder: event.sender,
+        embedder: this,
         guest: webContents,
         overrideBrowserWindowOptions: overriddenOptions,
         disposition,
@@ -791,8 +797,7 @@ WebContents.prototype._init = function () {
     }
   });
 
-  const event = process._linkedBinding('electron_browser_event').createEmpty();
-  app.emit('web-contents-created', event, this);
+  app.emit('web-contents-created', { sender: this, preventDefault () {}, get defaultPrevented () { return false; } }, this);
 
   // Properties
 

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

@@ -14,7 +14,6 @@ interface GuestInstance {
 }
 
 const webViewManager = process._linkedBinding('electron_browser_web_view_manager');
-const eventBinding = process._linkedBinding('electron_browser_event');
 const netBinding = process._linkedBinding('electron_browser_net');
 
 const supportedWebViewEvents = Object.keys(webViewEvents);
@@ -82,7 +81,13 @@ function makeLoadURLOptions (params: Record<string, any>) {
 // Create a new guest instance.
 const createGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, params: Record<string, any>) {
   const webPreferences = makeWebPreferences(embedder, params);
-  const event = eventBinding.createWithSender(embedder);
+  const event = {
+    sender: embedder,
+    preventDefault () {
+      this.defaultPrevented = true;
+    },
+    defaultPrevented: false
+  };
 
   const { instanceId } = params;
 

+ 1 - 7
lib/browser/ipc-main-impl.ts

@@ -18,13 +18,7 @@ export class IpcMainImpl extends EventEmitter {
     if (typeof fn !== 'function') {
       throw new Error(`Expected handler to be a function, but found type '${typeof fn}'`);
     }
-    this._invokeHandlers.set(method, async (e, ...args) => {
-      try {
-        e._reply(await Promise.resolve(fn(e, ...args)));
-      } catch (err) {
-        e._throw(err as Error);
-      }
-    });
+    this._invokeHandlers.set(method, fn);
   }
 
   handleOnce: Electron.IpcMain['handleOnce'] = (method, fn) => {

+ 2 - 2
package.json

@@ -7,10 +7,10 @@
     "@azure/storage-blob": "^12.9.0",
     "@dsanders11/vscode-markdown-languageservice": "^0.3.0-alpha.4",
     "@electron/asar": "^3.2.1",
-    "@electron/docs-parser": "^1.0.0",
+    "@electron/docs-parser": "^1.1.0",
     "@electron/fiddle-core": "^1.0.4",
     "@electron/github-app-auth": "^1.5.0",
-    "@electron/typescript-definitions": "^8.10.0",
+    "@electron/typescript-definitions": "^8.14.0",
     "@octokit/rest": "^19.0.7",
     "@primer/octicons": "^10.0.0",
     "@types/basic-auth": "^1.1.3",

+ 0 - 28
shell/browser/api/electron_api_event.cc

@@ -1,28 +0,0 @@
-// Copyright (c) 2018 GitHub, Inc.
-// Use of this source code is governed by the MIT license that can be
-// found in the LICENSE file.
-
-#include "shell/browser/api/event.h"
-#include "shell/common/gin_helper/dictionary.h"
-#include "shell/common/gin_helper/event_emitter.h"
-#include "shell/common/node_includes.h"
-
-namespace {
-
-v8::Local<v8::Object> CreateWithSender(v8::Isolate* isolate,
-                                       v8::Local<v8::Object> sender) {
-  return gin_helper::internal::CreateCustomEvent(isolate, sender);
-}
-
-void Initialize(v8::Local<v8::Object> exports,
-                v8::Local<v8::Value> unused,
-                v8::Local<v8::Context> context,
-                void* priv) {
-  gin_helper::Dictionary dict(context->GetIsolate(), exports);
-  dict.SetMethod("createWithSender", &CreateWithSender);
-  dict.SetMethod("createEmpty", &gin_helper::Event::Create);
-}
-
-}  // namespace
-
-NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_event, Initialize)

+ 1 - 2
shell/browser/api/electron_api_session.cc

@@ -1178,8 +1178,7 @@ gin::Handle<Session> Session::CreateFrom(
   // to use partition strings, instead of using the Session object directly.
   handle->Pin(isolate);
 
-  App::Get()->EmitCustomEvent("session-created",
-                              handle.ToV8().As<v8::Object>());
+  App::Get()->EmitWithoutEvent("session-created", handle);
 
   return handle;
 }

+ 8 - 8
shell/browser/api/electron_api_tray.cc

@@ -97,19 +97,19 @@ void Tray::OnClicked(const gfx::Rect& bounds,
                      int modifiers) {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
-  EmitCustomEvent("click", CreateEventFromFlags(modifiers), bounds, location);
+  EmitWithoutEvent("click", CreateEventFromFlags(modifiers), bounds, location);
 }
 
 void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
-  EmitCustomEvent("double-click", CreateEventFromFlags(modifiers), bounds);
+  EmitWithoutEvent("double-click", CreateEventFromFlags(modifiers), bounds);
 }
 
 void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
-  EmitCustomEvent("right-click", CreateEventFromFlags(modifiers), bounds);
+  EmitWithoutEvent("right-click", CreateEventFromFlags(modifiers), bounds);
 }
 
 void Tray::OnBalloonShow() {
@@ -139,31 +139,31 @@ void Tray::OnDropText(const std::string& text) {
 void Tray::OnMouseEntered(const gfx::Point& location, int modifiers) {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
-  EmitCustomEvent("mouse-enter", CreateEventFromFlags(modifiers), location);
+  EmitWithoutEvent("mouse-enter", CreateEventFromFlags(modifiers), location);
 }
 
 void Tray::OnMouseExited(const gfx::Point& location, int modifiers) {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
-  EmitCustomEvent("mouse-leave", CreateEventFromFlags(modifiers), location);
+  EmitWithoutEvent("mouse-leave", CreateEventFromFlags(modifiers), location);
 }
 
 void Tray::OnMouseMoved(const gfx::Point& location, int modifiers) {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
-  EmitCustomEvent("mouse-move", CreateEventFromFlags(modifiers), location);
+  EmitWithoutEvent("mouse-move", CreateEventFromFlags(modifiers), location);
 }
 
 void Tray::OnMouseUp(const gfx::Point& location, int modifiers) {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
-  EmitCustomEvent("mouse-up", CreateEventFromFlags(modifiers), location);
+  EmitWithoutEvent("mouse-up", CreateEventFromFlags(modifiers), location);
 }
 
 void Tray::OnMouseDown(const gfx::Point& location, int modifiers) {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
-  EmitCustomEvent("mouse-down", CreateEventFromFlags(modifiers), location);
+  EmitWithoutEvent("mouse-down", CreateEventFromFlags(modifiers), location);
 }
 
 void Tray::OnDragEntered() {

+ 6 - 6
shell/browser/api/electron_api_utility_process.cc

@@ -203,13 +203,13 @@ void UtilityProcessWrapper::OnServiceProcessLaunched(
   pid_ = process.Pid();
   GetAllUtilityProcessWrappers().AddWithID(this, pid_);
   if (stdout_read_fd_ != -1) {
-    EmitWithoutCustomEvent("stdout", stdout_read_fd_);
+    EmitWithoutEvent("stdout", stdout_read_fd_);
   }
   if (stderr_read_fd_ != -1) {
-    EmitWithoutCustomEvent("stderr", stderr_read_fd_);
+    EmitWithoutEvent("stderr", stderr_read_fd_);
   }
   // Emit 'spawn' event
-  EmitWithoutCustomEvent("spawn");
+  EmitWithoutEvent("spawn");
 }
 
 void UtilityProcessWrapper::OnServiceProcessDisconnected(
@@ -219,7 +219,7 @@ void UtilityProcessWrapper::OnServiceProcessDisconnected(
     GetAllUtilityProcessWrappers().Remove(pid_);
   CloseConnectorPort();
   // Emit 'exit' event
-  EmitWithoutCustomEvent("exit", error_code);
+  EmitWithoutEvent("exit", error_code);
   Unpin();
 }
 
@@ -238,7 +238,7 @@ void UtilityProcessWrapper::Shutdown(int exit_code) {
   node_service_remote_.reset();
   CloseConnectorPort();
   // Emit 'exit' event
-  EmitWithoutCustomEvent("exit", exit_code);
+  EmitWithoutEvent("exit", exit_code);
   Unpin();
 }
 
@@ -311,7 +311,7 @@ bool UtilityProcessWrapper::Accept(mojo::Message* mojo_message) {
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Value> message_value =
       electron::DeserializeV8Value(isolate, message);
-  EmitWithoutCustomEvent("message", message_value);
+  EmitWithoutEvent("message", message_value);
   return true;
 }
 

+ 75 - 0
shell/browser/api/electron_api_web_contents.cc

@@ -1812,6 +1812,81 @@ void WebContents::OnFirstNonEmptyLayout(
   }
 }
 
+// This object wraps the InvokeCallback so that if it gets GC'd by V8, we can
+// still call the callback and send an error. Not doing so causes a Mojo DCHECK,
+// since Mojo requires callbacks to be called before they are destroyed.
+class ReplyChannel : public gin::Wrappable<ReplyChannel> {
+ public:
+  using InvokeCallback = electron::mojom::ElectronApiIPC::InvokeCallback;
+  static gin::Handle<ReplyChannel> Create(v8::Isolate* isolate,
+                                          InvokeCallback callback) {
+    return gin::CreateHandle(isolate, new ReplyChannel(std::move(callback)));
+  }
+
+  // gin::Wrappable
+  static gin::WrapperInfo kWrapperInfo;
+  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) override {
+    return gin::Wrappable<ReplyChannel>::GetObjectTemplateBuilder(isolate)
+        .SetMethod("sendReply", &ReplyChannel::SendReply);
+  }
+  const char* GetTypeName() override { return "ReplyChannel"; }
+
+ private:
+  explicit ReplyChannel(InvokeCallback callback)
+      : callback_(std::move(callback)) {}
+  ~ReplyChannel() override {
+    if (callback_) {
+      v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
+      // If there's no current context, it means we're shutting down, so we
+      // don't need to send an event.
+      if (!isolate->GetCurrentContext().IsEmpty()) {
+        v8::HandleScope scope(isolate);
+        auto message = gin::DataObjectBuilder(isolate)
+                           .Set("error", "reply was never sent")
+                           .Build();
+        SendReply(isolate, message);
+      }
+    }
+  }
+
+  bool SendReply(v8::Isolate* isolate, v8::Local<v8::Value> arg) {
+    if (!callback_)
+      return false;
+    blink::CloneableMessage message;
+    if (!gin::ConvertFromV8(isolate, arg, &message)) {
+      return false;
+    }
+
+    std::move(callback_).Run(std::move(message));
+    return true;
+  }
+
+  InvokeCallback callback_;
+};
+
+gin::WrapperInfo ReplyChannel::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+gin::Handle<gin_helper::internal::Event> WebContents::MakeEventWithSender(
+    v8::Isolate* isolate,
+    content::RenderFrameHost* frame,
+    electron::mojom::ElectronApiIPC::InvokeCallback callback) {
+  v8::Local<v8::Object> wrapper;
+  if (!GetWrapper(isolate).ToLocal(&wrapper))
+    return gin::Handle<gin_helper::internal::Event>();
+  gin::Handle<gin_helper::internal::Event> event =
+      gin_helper::internal::Event::New(isolate);
+  gin_helper::Dictionary dict(isolate, event.ToV8().As<v8::Object>());
+  if (callback)
+    dict.Set("_replyChannel",
+             ReplyChannel::Create(isolate, std::move(callback)));
+  if (frame) {
+    dict.Set("frameId", frame->GetRoutingID());
+    dict.Set("processId", frame->GetProcess()->GetID());
+  }
+  return event;
+}
+
 void WebContents::ReceivePostMessage(
     const std::string& channel,
     blink::TransferableMessage message,

+ 12 - 6
shell/browser/api/electron_api_web_contents.h

@@ -352,20 +352,26 @@ class WebContents : public ExclusiveAccessContext,
   // this.emit(name, new Event(sender, message), args...);
   template <typename... Args>
   bool EmitWithSender(base::StringPiece name,
-                      content::RenderFrameHost* sender,
+                      content::RenderFrameHost* frame,
                       electron::mojom::ElectronApiIPC::InvokeCallback callback,
                       Args&&... args) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
     v8::HandleScope handle_scope(isolate);
-    v8::Local<v8::Object> wrapper;
-    if (!GetWrapper(isolate).ToLocal(&wrapper))
+
+    gin::Handle<gin_helper::internal::Event> event =
+        MakeEventWithSender(isolate, frame, std::move(callback));
+    if (event.IsEmpty())
       return false;
-    v8::Local<v8::Object> event = gin_helper::internal::CreateNativeEvent(
-        isolate, wrapper, sender, std::move(callback));
-    return EmitCustomEvent(name, event, std::forward<Args>(args)...);
+    EmitWithoutEvent(name, event, std::forward<Args>(args)...);
+    return event->GetDefaultPrevented();
   }
 
+  gin::Handle<gin_helper::internal::Event> MakeEventWithSender(
+      v8::Isolate* isolate,
+      content::RenderFrameHost* frame,
+      electron::mojom::ElectronApiIPC::InvokeCallback callback);
+
   WebContents* embedder() { return embedder_; }
 
 #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)

+ 0 - 77
shell/browser/api/event.cc

@@ -1,77 +0,0 @@
-// Copyright (c) 2014 GitHub, Inc.
-// Use of this source code is governed by the MIT license that can be
-// found in the LICENSE file.
-
-#include "shell/browser/api/event.h"
-
-#include <utility>
-
-#include "gin/data_object_builder.h"
-#include "gin/object_template_builder.h"
-#include "shell/browser/javascript_environment.h"
-#include "shell/common/gin_converters/blink_converter.h"
-#include "shell/common/gin_converters/std_converter.h"
-
-namespace gin_helper {
-
-gin::WrapperInfo Event::kWrapperInfo = {gin::kEmbedderNativeGin};
-
-Event::Event() = default;
-
-Event::~Event() {
-  if (callback_) {
-    v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
-    // If there's no current context, it means we're shutting down, so we don't
-    // need to send an event.
-    if (!isolate->GetCurrentContext().IsEmpty()) {
-      v8::HandleScope scope(isolate);
-      auto message = gin::DataObjectBuilder(isolate)
-                         .Set("error", "reply was never sent")
-                         .Build();
-      SendReply(isolate, message);
-    }
-  }
-}
-
-void Event::SetCallback(InvokeCallback callback) {
-  DCHECK(!callback_);
-  callback_ = std::move(callback);
-}
-
-void Event::PreventDefault(v8::Isolate* isolate) {
-  v8::Local<v8::Object> self = GetWrapper(isolate).ToLocalChecked();
-  self->Set(isolate->GetCurrentContext(),
-            gin::StringToV8(isolate, "defaultPrevented"), v8::True(isolate))
-      .Check();
-}
-
-bool Event::SendReply(v8::Isolate* isolate, v8::Local<v8::Value> result) {
-  if (!callback_)
-    return false;
-
-  blink::CloneableMessage message;
-  if (!gin::ConvertFromV8(isolate, result, &message)) {
-    return false;
-  }
-
-  std::move(callback_).Run(std::move(message));
-  return true;
-}
-
-gin::ObjectTemplateBuilder Event::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return gin::Wrappable<Event>::GetObjectTemplateBuilder(isolate)
-      .SetMethod("preventDefault", &Event::PreventDefault)
-      .SetMethod("sendReply", &Event::SendReply);
-}
-
-const char* Event::GetTypeName() {
-  return "Event";
-}
-
-// static
-gin::Handle<Event> Event::Create(v8::Isolate* isolate) {
-  return gin::CreateHandle(isolate, new Event());
-}
-
-}  // namespace gin_helper

+ 0 - 52
shell/browser/api/event.h

@@ -1,52 +0,0 @@
-// Copyright (c) 2014 GitHub, Inc.
-// Use of this source code is governed by the MIT license that can be
-// found in the LICENSE file.
-
-#ifndef ELECTRON_SHELL_BROWSER_API_EVENT_H_
-#define ELECTRON_SHELL_BROWSER_API_EVENT_H_
-
-#include "electron/shell/common/api/api.mojom.h"
-#include "gin/handle.h"
-#include "gin/wrappable.h"
-
-namespace gin_helper {
-
-class Event : public gin::Wrappable<Event> {
- public:
-  using InvokeCallback = electron::mojom::ElectronApiIPC::InvokeCallback;
-
-  static gin::WrapperInfo kWrapperInfo;
-
-  static gin::Handle<Event> Create(v8::Isolate* isolate);
-
-  // Pass the callback to be invoked.
-  void SetCallback(InvokeCallback callback);
-
-  // event.PreventDefault().
-  void PreventDefault(v8::Isolate* isolate);
-
-  // event.sendReply(value), used for replying to synchronous messages and
-  // `invoke` calls.
-  bool SendReply(v8::Isolate* isolate, v8::Local<v8::Value> result);
-
-  // disable copy
-  Event(const Event&) = delete;
-  Event& operator=(const Event&) = delete;
-
- protected:
-  Event();
-  ~Event() override;
-
-  // gin::Wrappable:
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-  const char* GetTypeName() override;
-
- private:
-  // Replier for the synchronous messages.
-  InvokeCallback callback_;
-};
-
-}  // namespace gin_helper
-
-#endif  // ELECTRON_SHELL_BROWSER_API_EVENT_H_

+ 7 - 41
shell/browser/event_emitter_mixin.h

@@ -7,16 +7,14 @@
 
 #include <utility>
 
+#include "gin/handle.h"
 #include "gin/object_template_builder.h"
 #include "shell/browser/javascript_environment.h"
+#include "shell/common/gin_helper/event.h"
 #include "shell/common/gin_helper/event_emitter.h"
 
 namespace gin_helper {
 
-namespace internal {
-v8::Local<v8::FunctionTemplate> GetEventEmitterTemplate(v8::Isolate* isolate);
-}  // namespace internal
-
 template <typename T>
 class EventEmitterMixin {
  public:
@@ -33,14 +31,15 @@ class EventEmitterMixin {
     v8::Local<v8::Object> wrapper;
     if (!static_cast<T*>(this)->GetWrapper(isolate).ToLocal(&wrapper))
       return false;
-    v8::Local<v8::Object> event = internal::CreateCustomEvent(isolate, wrapper);
-    return EmitWithEvent(isolate, wrapper, name, event,
-                         std::forward<Args>(args)...);
+    gin::Handle<internal::Event> event = internal::Event::New(isolate);
+    gin_helper::EmitEvent(isolate, wrapper, name, event,
+                          std::forward<Args>(args)...);
+    return event->GetDefaultPrevented();
   }
 
   // this.emit(name, args...);
   template <typename... Args>
-  void EmitWithoutCustomEvent(base::StringPiece name, Args&&... args) {
+  void EmitWithoutEvent(base::StringPiece name, Args&&... args) {
     v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
     v8::HandleScope handle_scope(isolate);
     v8::Local<v8::Object> wrapper;
@@ -49,20 +48,6 @@ class EventEmitterMixin {
     gin_helper::EmitEvent(isolate, wrapper, name, std::forward<Args>(args)...);
   }
 
-  // this.emit(name, event, args...);
-  template <typename... Args>
-  bool EmitCustomEvent(base::StringPiece name,
-                       v8::Local<v8::Object> custom_event,
-                       Args&&... args) {
-    v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
-    v8::HandleScope scope(isolate);
-    v8::Local<v8::Object> wrapper;
-    if (!static_cast<T*>(this)->GetWrapper(isolate).ToLocal(&wrapper))
-      return false;
-    return EmitWithEvent(isolate, wrapper, name, custom_event,
-                         std::forward<Args>(args)...);
-  }
-
  protected:
   EventEmitterMixin() = default;
 
@@ -82,25 +67,6 @@ class EventEmitterMixin {
                                       static_cast<T*>(this)->GetTypeName(),
                                       constructor->InstanceTemplate());
   }
-
- private:
-  // this.emit(name, event, args...);
-  template <typename... Args>
-  static bool EmitWithEvent(v8::Isolate* isolate,
-                            v8::Local<v8::Object> wrapper,
-                            base::StringPiece name,
-                            v8::Local<v8::Object> event,
-                            Args&&... args) {
-    auto context = isolate->GetCurrentContext();
-    gin_helper::EmitEvent(isolate, wrapper, name, event,
-                          std::forward<Args>(args)...);
-    v8::Local<v8::Value> defaultPrevented;
-    if (event->Get(context, gin::StringToV8(isolate, "defaultPrevented"))
-            .ToLocal(&defaultPrevented)) {
-      return defaultPrevented->BooleanValue(isolate);
-    }
-    return false;
-  }
 };
 
 }  // namespace gin_helper

+ 1 - 1
shell/common/gin_helper/constructible.h

@@ -7,7 +7,7 @@
 
 #include "gin/per_isolate_data.h"
 #include "gin/wrappable.h"
-#include "shell/browser/event_emitter_mixin.h"
+#include "shell/common/gin_helper/event_emitter_template.h"
 #include "shell/common/gin_helper/function_template_extensions.h"
 
 namespace gin_helper {

+ 31 - 0
shell/common/gin_helper/event.cc

@@ -0,0 +1,31 @@
+// Copyright (c) 2023 Salesforce, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "shell/common/gin_helper/event.h"
+#include "gin/dictionary.h"
+#include "gin/object_template_builder.h"
+
+namespace gin_helper::internal {
+
+// static
+gin::Handle<Event> Event::New(v8::Isolate* isolate) {
+  return gin::CreateHandle(isolate, new Event());
+}
+// static
+v8::Local<v8::ObjectTemplate> Event::FillObjectTemplate(
+    v8::Isolate* isolate,
+    v8::Local<v8::ObjectTemplate> templ) {
+  return gin::ObjectTemplateBuilder(isolate, "Event", templ)
+      .SetMethod("preventDefault", &Event::PreventDefault)
+      .SetProperty("defaultPrevented", &Event::GetDefaultPrevented)
+      .Build();
+}
+
+Event::Event() = default;
+
+Event::~Event() = default;
+
+gin::WrapperInfo Event::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+}  // namespace gin_helper::internal

+ 48 - 0
shell/common/gin_helper/event.h

@@ -0,0 +1,48 @@
+// Copyright (c) 2023 Salesforce, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_H_
+#define ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_H_
+
+#include "gin/handle.h"
+#include "gin/wrappable.h"
+#include "shell/common/gin_helper/constructible.h"
+
+namespace v8 {
+class Isolate;
+template <typename T>
+class Local;
+class Object;
+class ObjectTemplate;
+}  // namespace v8
+
+namespace gin_helper::internal {
+
+class Event : public gin::Wrappable<Event>,
+              public gin_helper::Constructible<Event> {
+ public:
+  // gin_helper::Constructible
+  static gin::Handle<Event> New(v8::Isolate* isolate);
+  static v8::Local<v8::ObjectTemplate> FillObjectTemplate(
+      v8::Isolate* isolate,
+      v8::Local<v8::ObjectTemplate> prototype);
+
+  // gin::Wrappable
+  static gin::WrapperInfo kWrapperInfo;
+
+  ~Event() override;
+
+  void PreventDefault() { default_prevented_ = true; }
+
+  bool GetDefaultPrevented() { return default_prevented_; }
+
+ private:
+  Event();
+
+  bool default_prevented_ = false;
+};
+
+}  // namespace gin_helper::internal
+
+#endif  // ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_H_

+ 0 - 76
shell/common/gin_helper/event_emitter.cc

@@ -1,76 +0,0 @@
-// Copyright (c) 2019 GitHub, Inc.
-// Use of this source code is governed by the MIT license that can be
-// found in the LICENSE file.
-
-#include "shell/common/gin_helper/event_emitter.h"
-
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "shell/browser/api/event.h"
-#include "shell/common/gin_helper/dictionary.h"
-#include "shell/common/gin_helper/object_template_builder.h"
-
-namespace gin_helper::internal {
-
-namespace {
-
-v8::Persistent<v8::ObjectTemplate> event_template;
-
-void PreventDefault(gin_helper::Arguments* args) {
-  Dictionary self;
-  if (args->GetHolder(&self))
-    self.Set("defaultPrevented", true);
-}
-
-}  // namespace
-
-v8::Local<v8::Object> CreateCustomEvent(v8::Isolate* isolate,
-                                        v8::Local<v8::Object> sender,
-                                        v8::Local<v8::Object> custom_event) {
-  if (event_template.IsEmpty()) {
-    event_template.Reset(
-        isolate,
-        ObjectTemplateBuilder(isolate, v8::ObjectTemplate::New(isolate))
-            .SetMethod("preventDefault", &PreventDefault)
-            .Build());
-  }
-
-  v8::Local<v8::Context> context = isolate->GetCurrentContext();
-  CHECK(!context.IsEmpty());
-  v8::Local<v8::Object> event =
-      v8::Local<v8::ObjectTemplate>::New(isolate, event_template)
-          ->NewInstance(context)
-          .ToLocalChecked();
-  if (!sender.IsEmpty())
-    Dictionary(isolate, event).Set("sender", sender);
-  if (!custom_event.IsEmpty())
-    event->SetPrototype(context, custom_event).IsJust();
-  return event;
-}
-
-v8::Local<v8::Object> CreateNativeEvent(
-    v8::Isolate* isolate,
-    v8::Local<v8::Object> sender,
-    content::RenderFrameHost* frame,
-    electron::mojom::ElectronApiIPC::MessageSyncCallback callback) {
-  v8::Local<v8::Object> event;
-  if (frame && callback) {
-    gin::Handle<Event> native_event = Event::Create(isolate);
-    native_event->SetCallback(std::move(callback));
-    event = native_event.ToV8().As<v8::Object>();
-  } else {
-    // No need to create native event if we do not need to send reply.
-    event = CreateCustomEvent(isolate);
-  }
-
-  Dictionary dict(isolate, event);
-  dict.Set("sender", sender);
-  // Should always set frameId even when callback is null.
-  if (frame) {
-    dict.Set("frameId", frame->GetRoutingID());
-    dict.Set("processId", frame->GetProcess()->GetID());
-  }
-  return event;
-}
-
-}  // namespace gin_helper::internal

+ 6 - 34
shell/common/gin_helper/event_emitter.h

@@ -10,6 +10,8 @@
 
 #include "content/public/browser/browser_thread.h"
 #include "electron/shell/common/api/api.mojom.h"
+#include "gin/handle.h"
+#include "shell/common/gin_helper/event.h"
 #include "shell/common/gin_helper/event_emitter_caller.h"
 #include "shell/common/gin_helper/wrappable.h"
 
@@ -19,20 +21,6 @@ class RenderFrameHost;
 
 namespace gin_helper {
 
-namespace internal {
-
-v8::Local<v8::Object> CreateCustomEvent(
-    v8::Isolate* isolate,
-    v8::Local<v8::Object> sender = v8::Local<v8::Object>(),
-    v8::Local<v8::Object> custom_event = v8::Local<v8::Object>());
-v8::Local<v8::Object> CreateNativeEvent(
-    v8::Isolate* isolate,
-    v8::Local<v8::Object> sender,
-    content::RenderFrameHost* frame,
-    electron::mojom::ElectronApiIPC::MessageSyncCallback callback);
-
-}  // namespace internal
-
 // Provide helperers to emit event in JavaScript.
 template <typename T>
 class EventEmitter : public gin_helper::Wrappable<T> {
@@ -48,16 +36,6 @@ class EventEmitter : public gin_helper::Wrappable<T> {
     return Base::GetWrapper(isolate);
   }
 
-  // this.emit(name, event, args...);
-  template <typename... Args>
-  bool EmitCustomEvent(base::StringPiece name,
-                       v8::Local<v8::Object> event,
-                       Args&&... args) {
-    return EmitWithEvent(
-        name, internal::CreateCustomEvent(isolate(), GetWrapper(), event),
-        std::forward<Args>(args)...);
-  }
-
   // this.emit(name, new Event(), args...);
   template <typename... Args>
   bool Emit(base::StringPiece name, Args&&... args) {
@@ -65,8 +43,8 @@ class EventEmitter : public gin_helper::Wrappable<T> {
     v8::Local<v8::Object> wrapper = GetWrapper();
     if (wrapper.IsEmpty())
       return false;
-    v8::Local<v8::Object> event =
-        internal::CreateCustomEvent(isolate(), wrapper);
+    gin::Handle<gin_helper::internal::Event> event =
+        internal::Event::New(isolate());
     return EmitWithEvent(name, event, std::forward<Args>(args)...);
   }
 
@@ -81,20 +59,14 @@ class EventEmitter : public gin_helper::Wrappable<T> {
   // this.emit(name, event, args...);
   template <typename... Args>
   bool EmitWithEvent(base::StringPiece name,
-                     v8::Local<v8::Object> event,
+                     gin::Handle<gin_helper::internal::Event> event,
                      Args&&... args) {
     // It's possible that |this| will be deleted by EmitEvent, so save anything
     // we need from |this| before calling EmitEvent.
     auto* isolate = this->isolate();
-    auto context = isolate->GetCurrentContext();
     gin_helper::EmitEvent(isolate, GetWrapper(), name, event,
                           std::forward<Args>(args)...);
-    v8::Local<v8::Value> defaultPrevented;
-    if (event->Get(context, gin::StringToV8(isolate, "defaultPrevented"))
-            .ToLocal(&defaultPrevented)) {
-      return defaultPrevented->BooleanValue(isolate);
-    }
-    return false;
+    return event->GetDefaultPrevented();
   }
 };
 

+ 6 - 3
shell/browser/event_emitter_mixin.cc → shell/common/gin_helper/event_emitter_template.cc

@@ -1,11 +1,14 @@
-// Copyright (c) 2019 Slack Technologies, Inc.
+// Copyright (c) 2023 Salesforce, Inc.
 // Use of this source code is governed by the MIT license that can be
 // found in the LICENSE file.
 
-#include "shell/browser/event_emitter_mixin.h"
+#include "shell/common/gin_helper/event_emitter_template.h"
 
-#include "gin/public/wrapper_info.h"
+#include "gin/converter.h"
+#include "gin/per_isolate_data.h"
 #include "shell/browser/api/electron_api_event_emitter.h"
+#include "v8/include/v8-function.h"
+#include "v8/include/v8-template.h"
 
 namespace gin_helper::internal {
 

+ 19 - 0
shell/common/gin_helper/event_emitter_template.h

@@ -0,0 +1,19 @@
+// Copyright (c) 2023 Salesforce, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_EMITTER_TEMPLATE_H_
+#define ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_EMITTER_TEMPLATE_H_
+
+namespace v8 {
+class Isolate;
+template <typename T>
+class Local;
+class FunctionTemplate;
+}  // namespace v8
+
+namespace gin_helper::internal {
+v8::Local<v8::FunctionTemplate> GetEventEmitterTemplate(v8::Isolate* isolate);
+}
+
+#endif  // ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_EMITTER_TEMPLATE_H_

+ 4 - 1
shell/common/node_bindings.cc

@@ -31,6 +31,7 @@
 #include "shell/common/electron_command_line.h"
 #include "shell/common/gin_converters/file_path_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
+#include "shell/common/gin_helper/event.h"
 #include "shell/common/gin_helper/event_emitter_caller.h"
 #include "shell/common/gin_helper/locker.h"
 #include "shell/common/gin_helper/microtasks_scope.h"
@@ -50,7 +51,6 @@
   V(electron_browser_content_tracing)    \
   V(electron_browser_crash_reporter)     \
   V(electron_browser_dialog)             \
-  V(electron_browser_event)              \
   V(electron_browser_event_emitter)      \
   V(electron_browser_global_shortcut)    \
   V(electron_browser_in_app_purchase)    \
@@ -463,6 +463,9 @@ void NodeBindings::Initialize() {
     SetErrorMode(GetErrorMode() & ~SEM_NOGPFAULTERRORBOX);
 #endif
 
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  gin_helper::internal::Event::GetConstructor(isolate->GetCurrentContext());
+
   g_is_initialized = true;
 }
 

+ 1 - 1
spec/api-web-contents-spec.ts

@@ -1619,7 +1619,7 @@ describe('webContents module', () => {
       await w.webContents.loadURL('about:blank');
       const promise: Promise<[string, string]> = new Promise(resolve => {
         w.webContents.once('ipc-message-sync', (event, channel, arg) => {
-          event.returnValue = 'foobar' as any;
+          event.returnValue = 'foobar';
           resolve([channel, arg]);
         });
       });

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

@@ -1,4 +1,5 @@
 // tslint:disable:ordered-imports curly no-console no-angle-bracket-type-assertion object-literal-sort-keys only-arrow-functions
+/* eslint-disable */
 
 import {
   app,
@@ -23,7 +24,6 @@ import {
   session,
   systemPreferences,
   webContents,
-  Event,
   TouchBar
 } from 'electron'
 
@@ -328,7 +328,7 @@ app.whenReady().then(() => {
 })
 app.on('accessibility-support-changed', (_, enabled) => console.log('accessibility: ' + enabled))
 
-ipcMain.on('online-status-changed', (event: any, status: any) => {
+ipcMain.on('online-status-changed', (event, status: any) => {
   console.log(status)
 })
 

+ 0 - 4
typings/internal-ambient.d.ts

@@ -197,10 +197,6 @@ declare namespace NodeJS {
     _linkedBinding(name: 'electron_browser_desktop_capturer'): {
       createDesktopCapturer(): ElectronInternal.DesktopCapturer;
     };
-    _linkedBinding(name: 'electron_browser_event'): {
-      createWithSender(sender: Electron.WebContents): Electron.Event;
-      createEmpty(): Electron.Event;
-    };
     _linkedBinding(name: 'electron_browser_event_emitter'): {
       setEventEmitterPrototype(prototype: Object): void;
     };

+ 7 - 9
typings/internal-electron.d.ts

@@ -110,7 +110,7 @@ declare namespace Electron {
     _shouldRegisterAcceleratorForCommandId(id: string): boolean;
     _getSharingItemForCommandId(id: string): SharingItem | null;
     _callMenuWillShow(): void;
-    _executeCommand(event: any, id: number): void;
+    _executeCommand(event: KeyboardEvent, id: number): void;
     _menuWillShow(): void;
     commandsMap: Record<string, MenuItem>;
     groupsMap: Record<string, MenuItem[]>;
@@ -138,14 +138,16 @@ declare namespace Electron {
     acceleratorWorksWhenHidden?: boolean;
   }
 
-  interface IpcMainEvent {
+  interface ReplyChannel {
     sendReply(value: any): void;
   }
 
+  interface IpcMainEvent {
+    _replyChannel: ReplyChannel;
+  }
+
   interface IpcMainInvokeEvent {
-    sendReply(value: any): void;
-    _reply(value: any): void;
-    _throw(error: Error | string): void;
+    _replyChannel: ReplyChannel;
   }
 
   class View {}
@@ -222,10 +224,6 @@ declare namespace ElectronInternal {
     once(channel: string, listener: (event: IpcMainInternalEvent, ...args: any[]) => void): this;
   }
 
-  interface Event extends Electron.Event {
-    sender: WebContents;
-  }
-
   interface LoadURLOptions extends Electron.LoadURLOptions {
     reloadIgnoringCache?: boolean;
   }

+ 8 - 8
yarn.lock

@@ -134,10 +134,10 @@
   optionalDependencies:
     "@types/glob" "^7.1.1"
 
-"@electron/docs-parser@^1.0.0":
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-1.0.1.tgz#f9856d00ec1663a0fb6301f55bc674f44c7dc543"
-  integrity sha512-jqUHwo3MWUhWusHtTVpSHTZqWSVuc1sPUfavI5Zwdx64q7qd4phqOPGoxScWS3JthKt7Wydvo/eReIUNDJ0gRg==
+"@electron/docs-parser@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-1.1.0.tgz#ba095def41746bde56bee731feaf22272bf0b765"
+  integrity sha512-qrjIKJk8t4/xAYldDVNQgcF8zdAAuG260bzPxdh/xI3p/yddm61bftoct+Tx2crnWFnOfOkr6nGERsDknNiT8A==
   dependencies:
     "@types/markdown-it" "^12.0.0"
     chai "^4.2.0"
@@ -187,10 +187,10 @@
     "@octokit/auth-app" "^3.6.1"
     "@octokit/rest" "^18.12.0"
 
-"@electron/typescript-definitions@^8.10.0":
-  version "8.10.0"
-  resolved "https://registry.yarnpkg.com/@electron/typescript-definitions/-/typescript-definitions-8.10.0.tgz#e9cf2b329ec4b0b76947ef751725383a6cf8994d"
-  integrity sha512-FVc2y0GUfxFZDoma0scYiMxkoalle19Fq332fNFGWoCJ9rCj5OUvriewSjPtGBsRuHv2xaMS5MhBuy2/pRuFuQ==
+"@electron/typescript-definitions@^8.14.0":
+  version "8.14.0"
+  resolved "https://registry.yarnpkg.com/@electron/typescript-definitions/-/typescript-definitions-8.14.0.tgz#a88f74e915317ba943b57ffe499b319d04f01ee3"
+  integrity sha512-J3b4is6L0NB4+r+7s1Hl1YlzaveKnQt1gswadRyMRwb4gFU3VAe2oBMJLOhFRJMs/9PK/Xp+y9QwyC92Tyqe6A==
   dependencies:
     "@types/node" "^11.13.7"
     chalk "^2.4.2"