diff --git a/src/ElectronNET.API/Bridge/BridgeConnector.cs b/src/ElectronNET.API/Bridge/BridgeConnector.cs
new file mode 100644
index 0000000..3c06b43
--- /dev/null
+++ b/src/ElectronNET.API/Bridge/BridgeConnector.cs
@@ -0,0 +1,15 @@
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+// ReSharper disable once CheckNamespace
+namespace ElectronNET.API
+{
+ internal static class BridgeConnector
+ {
+ public static SocketIoFacade Socket
+ {
+ get
+ {
+ return ElectronNetRuntime.GetSocket();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ElectronNET.API/Bridge/Events.cs b/src/ElectronNET.API/Bridge/Events.cs
new file mode 100644
index 0000000..732819a
--- /dev/null
+++ b/src/ElectronNET.API/Bridge/Events.cs
@@ -0,0 +1,101 @@
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+// ReSharper disable once CheckNamespace
+namespace ElectronNET.API
+{
+ using System;
+ using System.Globalization;
+ using System.Threading.Tasks;
+
+ ///
+ /// Generic Event Consumers for Electron Modules
+ ///
+ internal class Events
+ {
+ private static Events _events;
+ private static readonly object SyncRoot = new();
+ private readonly TextInfo _textInfo = new CultureInfo("en-US", false).TextInfo;
+
+ private Events()
+ { }
+
+ public static Events Instance
+ {
+ get
+ {
+ if (_events == null)
+ {
+ lock (SyncRoot)
+ {
+ if (_events == null)
+ {
+ _events = new Events();
+ }
+ }
+ }
+
+ return _events;
+ }
+ }
+
+ ///
+ /// Subscribe to an unmapped electron event.
+ ///
+ /// The name of the module, e.g. app, dock, etc...
+ /// The name of the event
+ /// The event handler
+ public async Task On(string moduleName, string eventName, Action action)
+ {
+ var listener = $"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed";
+ var subscriber = $"register-{moduleName}-on-event";
+
+ BridgeConnector.Socket.On(listener, action);
+ await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);
+ }
+
+
+ ///
+ /// Subscribe to an unmapped electron event.
+ ///
+ /// The name of the module, e.g. app, dock, etc...
+ /// The name of the event
+ /// The event handler
+ public async Task On(string moduleName, string eventName, Action action)
+ {
+ var listener = $"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed";
+ var subscriber = $"register-{moduleName}-on-event";
+
+ BridgeConnector.Socket.On(listener, action);
+ await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);
+ }
+
+ ///
+ /// Subscribe to an unmapped electron event.
+ ///
+ /// The name of the module, e.g. app, dock, etc...
+ /// The name of the event
+ /// The event handler
+ public async Task Once(string moduleName, string eventName, Action action)
+ {
+ var listener = $"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed";
+ var subscriber = $"register-{moduleName}-once-event";
+ BridgeConnector.Socket.Once(listener, action);
+ await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);
+ }
+
+
+ ///
+ /// Subscribe to an unmapped electron event.
+ ///
+ /// The name of the module, e.g. app, dock, etc...
+ /// The name of the event
+ /// The event handler
+ public async Task Once(string moduleName, string eventName, Action action)
+ {
+ var listener = $"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed";
+ var subscriber = $"register-{moduleName}-once-event";
+ BridgeConnector.Socket.Once(listener, action);
+ await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);
+ }
+
+ }
+}
diff --git a/src/ElectronNET.API/Bridge/SocketIOFacade.cs b/src/ElectronNET.API/Bridge/SocketIOFacade.cs
new file mode 100644
index 0000000..c3815d6
--- /dev/null
+++ b/src/ElectronNET.API/Bridge/SocketIOFacade.cs
@@ -0,0 +1,115 @@
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+// ReSharper disable once CheckNamespace
+namespace ElectronNET.API;
+
+using System;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+using SocketIO.Serializer.NewtonsoftJson;
+using SocketIO = SocketIOClient.SocketIO;
+
+internal class SocketIoFacade
+{
+ private readonly SocketIO _socket;
+
+ public SocketIoFacade(string uri)
+ {
+ _socket = new SocketIO(uri);
+ var jsonSerializer = new NewtonsoftJsonSerializer(new JsonSerializerSettings
+ {
+ ContractResolver = new CamelCasePropertyNamesContractResolver(),
+ NullValueHandling = NullValueHandling.Ignore,
+ DefaultValueHandling = DefaultValueHandling.Ignore
+ });
+
+ _socket.Serializer = jsonSerializer;
+ }
+
+ public event EventHandler BridgeDisconnected;
+
+ public event EventHandler BridgeConnected;
+
+ public void Connect()
+ {
+ _socket.OnError += (sender, e) =>
+ {
+ Console.WriteLine($"BridgeConnector Error: {sender} {e}");
+ };
+
+ _socket.OnConnected += (_, _) =>
+ {
+ Console.WriteLine("BridgeConnector connected!");
+ this.BridgeConnected?.Invoke(this, EventArgs.Empty);
+ };
+
+ _socket.OnDisconnected += (_, _) =>
+ {
+ Console.WriteLine("BridgeConnector disconnected!");
+ this.BridgeDisconnected?.Invoke(this, EventArgs.Empty);
+ };
+
+ _socket.ConnectAsync().GetAwaiter().GetResult();
+ }
+
+ public void On(string eventName, Action action)
+ {
+ _socket.On(eventName, _ =>
+ {
+ Task.Run(action);
+ });
+ }
+
+ public void On(string eventName, Action action)
+ {
+ _socket.On(eventName, response =>
+ {
+ var value = response.GetValue();
+ Task.Run(() => action(value));
+ });
+ }
+
+ // TODO: Remove this method when SocketIoClient supports object deserialization
+ public void On(string eventName, Action