diff --git a/src/ElectronNET.AspNet/Bridge/SignalRFacade.cs b/src/ElectronNET.AspNet/Bridge/SignalRFacade.cs
index 48b16bd..185fc31 100644
--- a/src/ElectronNET.AspNet/Bridge/SignalRFacade.cs
+++ b/src/ElectronNET.AspNet/Bridge/SignalRFacade.cs
@@ -11,6 +11,13 @@ namespace ElectronNET.API
///
/// SignalR-based facade that mimics the SocketIoFacade interface
/// for compatibility with existing Electron API code.
+ ///
+ /// Key implementation details:
+ /// - Uses IHubContext to send events to Electron via 'event' hub method
+ /// - Receives events from Electron via ElectronHub.ElectronEvent() method
+ /// - Includes ConvertToType<T> helper to handle JsonElement and numeric type conversions
+ /// - Event args are passed as arrays to match SignalR serialization behavior
+ /// - Connection ID is set by ElectronHub when Electron client connects
///
internal class SignalRFacade : IFacade
{
diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirstSignalR.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirstSignalR.cs
index 0291573..619b3af 100644
--- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirstSignalR.cs
+++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirstSignalR.cs
@@ -14,6 +14,14 @@ namespace ElectronNET.AspNet.Runtime
using Microsoft.AspNetCore.SignalR;
using ElectronNET.AspNet.Hubs;
+ ///
+ /// Runtime controller for SignalR-based .NET-first startup mode.
+ /// Key differences from Socket.IO mode:
+ /// - Waits for ASP.NET server to start, then captures the dynamic port
+ /// - Launches Electron with the actual URL (no port scanning needed)
+ /// - Uses SignalRFacade instead of SocketIOFacade for bidirectional communication
+ /// - Waits for 'electron-host-ready' signal to ensure API modules are loaded before calling app callback
+ ///
internal class RuntimeControllerAspNetDotnetFirstSignalR : RuntimeControllerAspNetBase
{
private ElectronProcessBase electronProcess;
diff --git a/src/ElectronNET.Host/api/signalr-bridge.js b/src/ElectronNET.Host/api/signalr-bridge.js
index b4d7053..fa9fdf0 100644
--- a/src/ElectronNET.Host/api/signalr-bridge.js
+++ b/src/ElectronNET.Host/api/signalr-bridge.js
@@ -1,4 +1,14 @@
-// SignalR connection module for Electron.NET
+/**
+ * SignalR connection module for Electron.NET
+ *
+ * This module provides a Socket.IO-compatible interface for SignalR communication.
+ * Key features:
+ * - Mimics Socket.IO's on() and emit() methods for compatibility with existing API modules
+ * - Handles event registration and propagation between Electron and .NET
+ * - Event args are always passed as arrays to match C# ElectronEvent(string, object[]) signature
+ * - Spreads args when calling handlers to match Socket.IO behavior
+ * - Supports automatic reconnection with configurable logging level
+ */
const signalR = require('@microsoft/signalr');
// Safe console wrapper that catches EPIPE errors
diff --git a/src/ElectronNET.Host/main.js b/src/ElectronNET.Host/main.js
index 515a731..3b7b1a7 100644
--- a/src/ElectronNET.Host/main.js
+++ b/src/ElectronNET.Host/main.js
@@ -171,6 +171,8 @@ app.on('ready', async () => {
}
// Check if we're using SignalR-based startup
+ // SignalR mode is activated by --unpackeddotnetsignalr or --dotnetpackedsignalr flags
+ // .NET passes the actual server URL via --electronurl parameter (no port scanning needed)
if (unpackeddotnetsignalr || dotnetpackedsignalr) {
if (!electronUrl) {
console.error('[Electron] ERROR: SignalR mode requires --electronUrl parameter');
@@ -179,6 +181,7 @@ app.on('ready', async () => {
}
// Create a temporary invisible window to keep Electron alive during startup.
+ // Without any windows, Electron would quit immediately on macOS.
// This will be destroyed once the first real window is created.
const { BrowserWindow } = require('electron');
const keepAliveWindow = new BrowserWindow({
@@ -420,6 +423,18 @@ function startSocketApiBridge(port) {
});
}
+/**
+ * Starts the SignalR API bridge for .NET-first SignalR mode.
+ *
+ * Flow:
+ * 1. Connect to SignalR hub at /electron-hub endpoint
+ * 2. Register as Electron client
+ * 3. Load all API modules (same modules as Socket.IO mode)
+ * 4. Signal 'electron-host-ready' to .NET to trigger app ready callback
+ *
+ * This ensures .NET doesn't call the app ready callback until all API modules
+ * are loaded and ready to handle requests from .NET code.
+ */
async function startSignalRApiBridge(baseUrl) {
const { SignalRBridge } = require('./api/signalr-bridge');
const hubUrl = `${baseUrl}/electron-hub`;