Compare commits

...

85 Commits

Author SHA1 Message Date
Florian Rappl
32bcfa95ab Restore logging 2026-02-04 11:44:27 +01:00
Florian Rappl
cf735fab4c Original formatting 2026-02-04 11:33:15 +01:00
Florian Rappl
cf1cb18d7a Merge branch 'develop' of https://github.com/ElectronNET/Electron.NET into feature/secure-connection 2026-02-04 11:29:01 +01:00
Florian Rappl
8009348941 Update transformed files 2026-02-04 11:26:06 +01:00
Florian Rappl
b3b124bde1 Updated TS formatting to match prettier 2026-02-04 11:25:30 +01:00
Florian Rappl
21226e1ef0 Updated deps 2026-02-04 11:18:55 +01:00
Florian Rappl
7174118a3e Merge pull request #1019 from DYH1319/feat/submit_new_event_for_ipc
feat: submit new events for ipcMain
2026-02-03 00:32:04 +01:00
Florian Rappl
931aec8cd9 Updated lodash 2026-02-02 16:15:19 +01:00
Florian Rappl
bbd1065a05 Merge branch 'epsitec-improvements' into feature/secure-connection 2026-02-02 16:13:18 +01:00
Florian Rappl
0fa0abd093 Merge branch 'develop' of https://github.com/ElectronNET/Electron.NET into feature/secure-connection 2026-02-02 16:01:30 +01:00
Pierre Arnaud
bfd51e64f7 Fix dead-lock on shutdown 2026-01-31 15:37:52 +01:00
Pierre Arnaud
bb4337a31c Cosmetic 2026-01-31 15:37:35 +01:00
Pierre Arnaud
57753eb632 Replace Console.WriteLine with ILogger for startup time
Changed startup time measurement to use structured logging via ILogger
instead of Console.WriteLine. This provides:
- Consistent logging format with other app messages
- Proper log level (Information)
- Structured data (ElapsedMilliseconds as named parameter)
- Better integration with logging infrastructure

Output now appears as:
info: Electron.Startup[0]
      App startup time until Electron launch: 1284 ms
2026-01-31 14:37:32 +01:00
Pierre Arnaud
614673605a Add explicit BrowserRefresh logging filter
Added 'Microsoft.AspNetCore.Watch.BrowserRefresh' to Warning level
to suppress the 'Middleware loaded' and 'Script injected' debug messages
that appear when running with dotnet watch or Ctrl+F5 from Visual Studio.
2026-01-31 14:30:07 +01:00
Pierre Arnaud
52744a1922 Final cleanup: Suppress remaining debug output
- Removed '|| ' prefix from ProcessRunner stdout/stderr redirection
  * Changed to Debug.WriteLine (only visible when debugger attached)
- Suppressed [Startup] timing messages in StartupManager
  * Moved to Debug.WriteLine for diagnostic purposes
- Suppressed 'No testhost detected' messages
- Added logging configuration to suppress ASP.NET Watch debug messages
  * Microsoft.AspNetCore.Watch set to Warning level

Result: Clean console output in development with only meaningful messages.
Timing and debug traces still available when debugger is attached.
2026-01-31 14:27:34 +01:00
Pierre Arnaud
03da5cd7cb Phase 4: Replace Console output with Debug.WriteLine in diagnostic code
- Replaced Console.WriteLine with System.Diagnostics.Debug.WriteLine in:
  * LaunchOrderDetector (probe scoring)
  * UnpackagedDetector (probe scoring)
  * ElectronProcessActive (StartInternal traces)
- Removed '[StartInternal]: after run:' trace
- Debug.WriteLine only outputs when debugger is attached

These were the noisiest debugging traces. Other Console.WriteLine usage
in StartupManager, ProcessRunner, etc. would require ILogger injection
which is a larger architectural change deferred for now.
2026-01-31 11:19:28 +01:00
Pierre Arnaud
805d942b11 Phase 3: Configure SignalR logging to reduce verbosity
- Updated SafeLogger to support minimum log level threshold
- Configure SignalR log level based on environment:
  * Debug mode: Info level (connection events only)
  * Development/Production: Warning level (errors/warnings only)
- Eliminates verbose packet-level logging
- Connection lifecycle events still visible in debug mode

This dramatically reduces console noise while preserving important events.
2026-01-31 11:17:26 +01:00
Pierre Arnaud
29b1f088ce Phase 2: Clean up debugging traces and use environment-aware logging
- Removed 'Entry!!!:' debugging leftover from main.js
- Replaced all console.log/warn/error with logger methods
- Preserved console.time/timeEnd for performance measurements
- Updated browserWindows.js and webContents.js to use logger
- Changed debug traces to DEBUG level (won't show in production)
- Changed info messages to INFO level (show in development)
- All errors use ERROR level (always shown)

Socket.IO connection messages now respect log levels based on environment.
2026-01-31 11:16:11 +01:00
Pierre Arnaud
4a62103749 Phase 1: Add environment-aware logging infrastructure
- Created logger.js with log levels (DEBUG, INFO, WARN, ERROR)
- Implemented environment detection (debug/development/production)
- Auto-detect based on flags, NODE_ENV, and debugger
- Preserve console.time/timeEnd for performance measurements
- Updated SignalR bridge to use new logger system
- Replaced safeConsole calls with environment-aware logger

Default log levels:
- Debug mode: DEBUG and above
- Development: INFO and above
- Production: WARN and above
2026-01-31 11:09:25 +01:00
Pierre Arnaud
38ee6fabb4 Only enable SignalR detailed errors in development
Changed EnableDetailedErrors to be conditional based on:
- Debugger attached (DebuggerHelper.IsAttached)
- context.HostingEnvironment.IsDevelopment()

Updated ConfigureServices to accept WebHostBuilderContext to properly
access the hosting environment instead of directly reading environment
variables. This prevents detailed error messages from being exposed in
production builds, which is important for security.
2026-01-31 10:04:29 +01:00
Pierre Arnaud
0ee2bbe31c Refactor debugger detection to use shared DebuggerHelper
Created a new DebuggerHelper class with Lazy<bool> initialization that is
shared by both LaunchOrderDetector and UnpackagedDetector. This eliminates
code duplication and provides a cleaner, more maintainable solution.

- Added DebuggerHelper.cs with lazy-initialized IsAttached property
- Refactored LaunchOrderDetector to use DebuggerHelper
- Refactored UnpackagedDetector to use DebuggerHelper
- Removed nullable bool pattern in favor of Lazy<bool>
2026-01-31 09:38:26 +01:00
Pierre Arnaud
a88e10bbf2 Measure total startup time 2026-01-31 09:18:24 +01:00
Pierre Arnaud
39c7e61ae5 Auto-quit Electron when pipe to .NET process breaks
When an EPIPE error is detected (indicating the .NET process has terminated),
Electron now automatically quits gracefully instead of just suppressing the error.
This ensures the Electron window doesn't remain open after the backend dies.

Uses setImmediate to allow any pending operations to complete before quitting,
and includes a flag to prevent multiple quit attempts.
2026-01-31 09:17:09 +01:00
Pierre Arnaud
96c454aedb Add process-level EPIPE error handlers
The previous fix using try-catch wasn't sufficient because EPIPE errors
are thrown asynchronously at the socket level when writing to stdout/stderr.
Added error event handlers to process.stdout and process.stderr to catch
and suppress EPIPE errors at the source, preventing the error dialog entirely.
2026-01-31 09:10:48 +01:00
Pierre Arnaud
5a77284610 Fix EPIPE error when .NET process terminates before Electron
- Added SafeLogger class to wrap SignalR logging and prevent EPIPE errors
- Enhanced safeConsole wrapper to include warn method
- Replaced all console calls in SignalRBridge with safeConsole
- Configured SignalR to use custom SafeLogger instead of default ConsoleLogger

This prevents the 'broken pipe, write' error dialog when the .NET process
is killed before the Electron process can cleanly shut down.
2026-01-31 09:04:58 +01:00
Pierre Arnaud
0a23659196 Phase 1b: Optimize startup detection for faster .NET initialization
Performance optimizations to startup detection:
- Reduced GatherBuildInfo: >1000ms → 7ms (99% faster!)
- Reduced CollectProcessData: →  86ms
- Reduced DetectAppTypeAndStartup: → 91ms
- Total StartupManager.Initialize: → 91ms (down from >1 second)

Electron startup also improved significantly:
- Module loading: 719ms → 108ms (85% faster!)
- SignalR connection: 884ms → 403ms (54% faster!)
- Total Electron startup: 2.3s → 700ms (70% faster!)

Optimizations applied:

1. Directory checks (UnpackagedDetector):
   - Changed GetDirectories().Any() to direct Directory.Exists()
   - Avoids expensive directory enumeration
   - Saves ~200-500ms on slow disks

2. Debugger state caching:
   - Cache Debugger.IsAttached result in static field
   - Avoids multiple expensive debugger checks
   - Used by both UnpackagedDetector and LaunchOrderDetector
   - Saves ~50-100ms per check

3. Added timing measurements:
   - Added Stopwatch to StartupManager.Initialize()
   - Detailed timing for each initialization phase
   - Visibility into startup performance

Results:
- .NET startup detection: >1000ms → 91ms
- Electron module loading: 719ms → 108ms
- SignalR connection: 884ms → 403ms
- **Total improvement: ~70% faster startup**

The combination of faster directory checks, cached debugger state,
and parallel module loading (from previous commit) results in
sub-second startup times in development mode.
2026-01-30 23:02:13 +01:00
Pierre Arnaud
5d224568d0 Phase 1: Implement parallel module loading for faster startup
Performance optimization:
- Refactored 18 sequential require() calls to load in parallel
- Use Promise.all() to load all API modules simultaneously
- Added comprehensive startup timing measurements

Timing breakdown (before → after):
- Module loading: ~900-1200ms → 719ms (20-40% faster)
- Total Electron startup: Measured at 2.3 seconds
- SignalR connection: 884ms
- Host ready signal: 33ms

Implementation:
- Load all modules in parallel using Promise.resolve().then()
- Organize modules by priority (critical, secondary, utility)
- Maintain backward compatibility with global variable assignments
- Add console.time() measurements for each phase

Benefits:
- Faster perceived startup time
- Non-blocking module initialization
- Clear visibility into startup bottlenecks
- Foundation for future lazy loading optimizations

This is the first phase of startup optimization, targeting the
biggest bottleneck (sequential module loading) with the least effort.
2026-01-30 22:56:37 +01:00
Pierre Arnaud
1c0b9378d2 Phase 6: Add comprehensive authentication documentation
Created new authentication guide:
- docs/SignalR-Authentication-Guide.md (500+ lines)
- Complete threat model and security architecture
- Flow diagrams and implementation details
- Troubleshooting guide with common issues
- FAQ covering design decisions and usage

Updated SignalR implementation summary:
- Added authentication & security section
- Documented token flow and cookie management
- Security properties and protection scope
- Logging & monitoring guidelines
- Multi-user testing procedures
- Updated file changes summary and success metrics

Documentation includes:
- Architecture diagrams (ASCII art)
- Code examples for all components
- Step-by-step authentication flow
- Security considerations and rationale
- Common troubleshooting scenarios
- Testing recommendations
2026-01-30 22:39:45 +01:00
Pierre Arnaud
c12a706289 Phase 5.2: Add comprehensive logging and error handling for authentication
Middleware logging:
- Log successful authentication with cookie setting
- Log failed authentication attempts with path and remote IP
- Log token prefix (first 8 chars) for invalid tokens, never full token
- Added structured logging with ILogger<T>

Electron error handling:
- Detect 401 authentication errors in SignalR connection
- Provide helpful error message about --authtoken parameter
- Differentiate auth errors from other connection failures

Documentation:
- Added XML comments explaining security model
- Documented token generation rationale (128-bit entropy)
- Clarified middleware validation flow in comments

Security:
- Never log full token values
- Generic error messages to prevent information leakage
- Failed auth attempts logged for security monitoring
2026-01-30 22:37:37 +01:00
Pierre Arnaud
8cc3fe4fd7 Phase 5.1: Fix quit handler to support both Socket.IO and SignalR modes
- Added checks for undefined variables before cleanup
- Socket.IO resources (server, apiProcess, io) only cleaned up in legacy mode
- SignalR connection properly stopped in SignalR mode
- Improved error messages to identify which cleanup failed
- Prevents 'Cannot read properties of undefined' error on app quit
2026-01-30 22:36:18 +01:00
Pierre Arnaud
893de1510d Phase 3: Pass authentication token to SignalR connection URL
- Modified main.js to pass authToken to SignalRBridge constructor
- Updated signalr-bridge.js to append token to hub URL
- Removed skip logic for negotiate endpoint in middleware
- SignalR negotiate request now includes token for authentication
- Cookie is set after successful negotiate for subsequent requests

This enables SignalR connections to authenticate using the same
token-based mechanism as HTTP requests, completing the authentication
flow for both Blazor pages and SignalR hub communication.
2026-01-30 22:35:39 +01:00
Pierre Arnaud
6f49a663ea Phase 4: Inject authentication service into RuntimeController and set token 2026-01-30 19:20:03 +01:00
Pierre Arnaud
5b9e2b8b3b Phase 2.1: Register authentication services and middleware in Program.cs 2026-01-30 19:19:23 +01:00
Pierre Arnaud
dee640c526 Phase 1.2: Extract token in Electron and append to URL
- Extract authtoken from command-line in main.js

- Store token in global.authToken for access by API modules

- Append token to initial window URL as query parameter

- Update both JS and TS versions of browserWindows

- First request will be: http://localhost:PORT/?token=GUID
2026-01-30 19:14:09 +01:00
Pierre Arnaud
f598fbf5ce Phase 1.1: Generate authentication token in RuntimeController
- Add authenticationToken field to store GUID

- Generate secure token using Guid.NewGuid().ToString('N')

- Pass token to Electron via --authtoken command-line parameter

- Token is 32 hex characters with 128 bits of entropy
2026-01-30 19:13:12 +01:00
Pierre Arnaud
6847520ea8 Remove HSTS and HTTPS redirection for Electron apps
HSTS and HTTPS redirection are designed for public web servers, not
desktop applications:

- ASP.NET Core only listens on http://localhost (local-only)
- No man-in-the-middle risk for same-machine communication
- HTTPS would require certificate setup with no security benefit
- HTTPS overhead slows down local IPC unnecessarily

Electron apps should use plain HTTP for localhost communication.
2026-01-30 17:30:07 +01:00
Pierre Arnaud
75151282ff Remove unnecessary UseWebSockets() call
SignalR's MapHub<T>() automatically enables WebSocket support, making
explicit UseWebSockets() redundant. SignalR also supports fallback
transports (Server-Sent Events, Long Polling) if WebSockets are unavailable.

Updated documentation to reflect this and clarify that WebSockets are
enabled automatically by MapHub().
2026-01-30 17:28:40 +01:00
Pierre Arnaud
17ef6853ab Fix ASP0014 warning: Use top-level route registration for ElectronHub
Changed from app.UseEndpoints() pattern to direct app.MapHub() call,
following modern ASP.NET Core conventions. This removes the analyzer
warning while maintaining the same functionality.
2026-01-30 17:14:14 +01:00
Pierre Arnaud
12f011bc33 Add comprehensive SignalR implementation documentation
Created detailed summary document incorporating:
- All 6 implementation phases (complete)
- Usage examples with code snippets
- Architecture decisions and rationale
- Critical fixes and their solutions
- Blazor Server integration considerations
- Backward compatibility guarantees
- Known limitations and future enhancements
- Success metrics and validation

Document serves as both implementation reference and user guide.
2026-01-30 17:11:57 +01:00
Pierre Arnaud
217fe83334 Add documentation comments to SignalR implementation
Added comprehensive code comments explaining:
- RuntimeControllerAspNetDotnetFirstSignalR: .NET-first startup flow and key differences from Socket.IO
- SignalRFacade: Type conversion handling and event propagation details
- signalr-bridge.js: Socket.IO compatibility layer and arg handling
- main.js: Keep-alive window pattern and SignalR startup sequence

Comments focus on explaining WHY decisions were made, not just WHAT the code does.
2026-01-30 17:08:37 +01:00
Pierre Arnaud
1fc881674d Clean up debug logging from SignalR implementation
Remove excessive console logging that was added during debugging:
- Removed verbose logging from Program.cs (app ready callback steps)
- Removed HTTP request logging middleware
- Cleaned up RuntimeControllerAspNetDotnetFirstSignalR lifecycle logging
- Streamlined ElectronHub connection/event logging
- Simplified SignalRFacade event handling logging
- Reduced JavaScript logging in main.js and signalr-bridge.js
- Reset log levels to Warning for SignalR components in appsettings

Kept only essential error logging and critical state transitions.
Production-ready logging levels maintained.
2026-01-30 17:07:24 +01:00
Pierre Arnaud
6e369aabef Fix static files and CSS asset reference for SignalR sample
- Fix middleware order: UseAntiforgery must be between UseRouting and UseEndpoints
- Add UseStaticFiles() to serve wwwroot content
- Fix scoped CSS bundle reference: use lowercase 'electronnet-samples-blazorsignalr.styles.css' to match generated asset name
- Add HTTP request logging for debugging
- Enable detailed logging for routing and static files in development
2026-01-30 16:58:29 +01:00
Pierre Arnaud
06a332827b Fix window shutdown and URL port for SignalR mode
- Destroy keep-alive window when first real window is created (enables proper window-all-closed behavior)
- Update ElectronNetRuntime.AspNetWebPort with actual port after Kestrel starts (fixes http://localhost:0 issue)
2026-01-30 16:43:53 +01:00
Pierre Arnaud
23f79244ae Fix SignalR event args spreading for Electron handlers
- Changed event handler to receive args as single array parameter
- Spread array elements as individual arguments to match Socket.IO behavior
2026-01-30 16:40:20 +01:00
Pierre Arnaud
6b9187cf6e Fix SignalR bridge communication issues
- Fix duplicate SignalR connection in main.js (removed redundant connect block)
- Fix race condition: Electron now signals 'electron-host-ready' after loading API modules
- Fix type conversion in SignalRFacade for event handlers (handle JsonElement and numeric types)
- Fix SignalR argument mismatch: pass args as array instead of spread, use object[] instead of params
- .NET now waits for electron-host-ready before calling app ready callback
2026-01-30 16:36:27 +01:00
Pierre Arnaud
108ef19a3b CRITICAL FIX: Prevent Electron from quitting in SignalR mode
ROOT CAUSE: Electron quits when app.on('ready') completes with 0 windows.
In SignalR mode, no windows are created immediately, so Electron exits,
triggering ElectronProcess_Stopped and shutting down ASP.NET.

SOLUTION: Create an invisible 1x1 keep-alive window in SignalR mode to
prevent Electron from quitting while waiting for SignalR connection.

Also:
- Make app.on('ready') async and await startSignalRApiBridge()
- Add window-all-closed handler for SignalR mode
- Add extensive debug logging to track lifecycle
- Don't subscribe to electronProcess.Ready in SignalR controller

This fixes the premature shutdown that prevented SignalR connection.
2026-01-30 15:29:48 +01:00
Pierre Arnaud
8c6020e35b WIP: Debugging SignalR connection timeout
- Add WebSockets middleware to ASP.NET pipeline
- Move HTTPS redirect to production only
- Add extensive debug logging in startSignalRApiBridge
- Enable Warning level logging in SignalR client

Issue: signalRBridge.connect() hangs and never resolves
- Connection starts but never completes
- No error messages from SignalR client
- ASP.NET shuts down after timeout
- ElectronHub.OnConnectedAsync never called

Next: Investigate why WebSocket connection doesn't establish
2026-01-30 13:27:03 +01:00
Pierre Arnaud
547e9f1196 Fix: Add safe console wrapper to prevent EPIPE errors
- Wrap all console.log/error calls in try-catch to handle EPIPE
- Disable SignalR client logging (LogLevel.None)
- Prevents Electron crash when console pipes are closed

This fixes the 'EPIPE: broken pipe, write' error that was preventing
the Electron window from displaying.
2026-01-30 13:22:35 +01:00
Pierre Arnaud
4b971af119 Fix: Execute app ready callback in SignalR mode
- Add RunReadyCallback execution when SignalR connects
- This triggers window creation and other app initialization
- Fixes missing variables in main.js (desktopCapturer, electronHostHook, touchBar, shellApi)
- Window now opens successfully in SignalR mode

Known issue: EPIPE console error when logging to closed pipe (to be fixed)
2026-01-30 13:19:49 +01:00
Pierre Arnaud
da8216b292 Implement bidirectional event routing for SignalR mode
- Update signalr-bridge.js to handle .NET→Electron events via 'event' channel
- Add socket.io-compatible .on() and .emit() methods to SignalRBridge
- Update main.js to load all Electron API modules with SignalR bridge
- Update SignalRFacade.Emit() to send events via 'event' channel
- Add ElectronHub.ElectronEvent() to receive Electron→.NET events
- Add SignalRFacade.TriggerEvent() to invoke .NET event handlers
- Remove duplicate ElectronEvent method from hub

This enables full bidirectional communication:
- .NET can call Electron APIs via Emit (e.g., createBrowserWindow)
- Electron can send events back to .NET (e.g., BrowserWindowCreated)
- Event handlers registered via On/Once now work with SignalR
2026-01-30 13:09:55 +01:00
Pierre Arnaud
be609a513e Refactor: Introduce IFacade interface for SocketIO and SignalR facades
- Create IFacade interface defining common API for SocketIO and SignalR
- Update SocketIoFacade to implement IFacade
- Update SignalRFacade to implement IFacade (add Connect no-op)
- Update RuntimeControllerBase.Socket to return IFacade
- Update RuntimeControllerAspNetBase.Socket to return IFacade
- Update RuntimeControllerDotNetFirst.Socket to return IFacade
- Update ElectronNetRuntime.GetSocket() to return IFacade
- Update BridgeConnector.Socket to return IFacade

This enables polymorphic usage of both facades throughout the codebase
and prepares for full Electron API integration with SignalR mode.
2026-01-30 13:03:19 +01:00
Pierre Arnaud
c4a8de6c4e Fix psl dist folder issue by copying from source after npm install 2026-01-30 12:52:40 +01:00
Pierre Arnaud
5b3d5e07ee Add @microsoft/signalr to package.template.json for npm install during build 2026-01-30 12:46:57 +01:00
Pierre Arnaud
9135aff855 Fix electronurl parameter case sensitivity for Electron command line 2026-01-30 12:39:32 +01:00
Pierre Arnaud
e9efb26dff Fix main.js to check SignalR flags first before legacy mode flags 2026-01-30 12:37:12 +01:00
Pierre Arnaud
e29a3bc27a Fix IsUnpackaged extension to include UnpackedDotnetFirstSignalR 2026-01-30 12:34:42 +01:00
Pierre Arnaud
f55abb357c Fix Electron launch: subscribe to ASP.NET Ready event in SignalR controller 2026-01-30 12:26:17 +01:00
Pierre Arnaud
0b92336de2 Fix dynamic port binding: use 127.0.0.1 instead of localhost for port 0 2026-01-30 12:22:07 +01:00
Pierre Arnaud
4c17027039 Add BlazorSignalR sample to solution file 2026-01-30 12:20:08 +01:00
Pierre Arnaud
5d04ab686a Add ElectronNET.Samples.BlazorSignalR - complete sample app for SignalR mode 2026-01-30 12:17:20 +01:00
Pierre Arnaud
de0c02c503 Add comprehensive documentation for SignalR-based startup mode 2026-01-30 12:11:48 +01:00
Pierre Arnaud
054f5b1c4c Complete Phase 5: Add SignalR startup detection and port 0 configuration 2026-01-30 12:10:49 +01:00
Pierre Arnaud
04ec52208a Fix compilation errors - Phase 4 complete (basic structure) 2026-01-30 12:08:43 +01:00
Pierre Arnaud
268b9c90ce Update RuntimeControllerAspNetDotnetFirstSignalR to use SignalRFacade 2026-01-30 12:06:29 +01:00
Pierre Arnaud
cb7d721b7d Add SignalRFacade for SignalR-based API communication 2026-01-30 12:04:33 +01:00
Pierre Arnaud
c1740b53fc Add SignalR client support to Electron Host for new startup modes 2026-01-30 12:02:46 +01:00
Pierre Arnaud
40aed60c7d Add RuntimeControllerAspNetDotnetFirstSignalR for SignalR-based startup 2026-01-30 12:00:27 +01:00
Pierre Arnaud
8ee81f6abd Add ElectronHub and SignalR infrastructure for new startup modes 2026-01-30 11:58:31 +01:00
Pierre Arnaud
7f2ea4839e Add PackagedDotnetFirstSignalR and UnpackedDotnetFirstSignalR startup methods 2026-01-30 11:57:40 +01:00
DYH1319
092789a5ec feat: Add overloaded methods in IpcMain that supports listeners with a return type of Task<object>. 2026-01-25 00:47:35 +08:00
DYH1319
bff3fffcbd feat: Add the Handle, HandleOnce, and RemoveHandler events to IpcMain 2026-01-24 23:18:16 +08:00
Florian Rappl
456135a562 Merge pull request #1015 from hillin/main
Update Migration Guide
2026-01-21 12:18:25 +01:00
lucas
300f52510c Update Migration Guide with details on electron-builder.json location and launch settings 2026-01-21 15:30:44 +08:00
Florian Rappl
d85a64f515 Merge pull request #1014 from softworkz/submit_new_event
BrowserWindow: Add OnBoundsChanged event
2026-01-21 08:19:16 +01:00
Florian Rappl
53698d1d44 Merge pull request #1013 from softworkz/submit_timeout
Double-up timeout for electron-builder and other fixes
2026-01-21 08:07:50 +01:00
Florian Rappl
04a224aa4f Merge pull request #1012 from softworkz/submit_migcheck_updates
Relax Migration check for package.json in root
2026-01-21 08:06:55 +01:00
softworkz
891da140b7 Relax Migration check for package.json in root 2026-01-21 06:50:07 +01:00
softworkz
17f761d184 Fix FormatException 2026-01-21 06:48:28 +01:00
softworkz
9f6489891e ElectronNET.Host: Revert JS SDK to default value from VS 2026 2026-01-21 06:48:28 +01:00
softworkz
c8f1cdf59f Add tests for BrowserWindow.OnBoundsChanged event 2026-01-21 06:47:28 +01:00
softworkz
6c95dfd476 BrowserWindow: Add OnBoundsChanged event
While not being an original Electron event, this one includes the bounds values,
saving the additional roundtrip for calling GetBoundsAsync
2026-01-21 06:47:28 +01:00
softworkz
b180fc2ea8 Double-up timeout for electron-builder 2026-01-21 05:10:24 +01:00
Florian Rappl
682a1c38ed Optional 2025-12-23 21:10:57 +01:00
Florian Rappl
809b0a6be7 Added missing methods 2025-12-23 00:38:37 +01:00
Florian Rappl
ae3f755648 Fixed center handling 2025-12-22 12:32:52 +01:00
178 changed files with 66433 additions and 1996 deletions

View File

@@ -1,3 +1,10 @@
# 0.4.1
## ElectronNET.Core
- Fixed handling of `Center` property for windows (#1001)
- Added missing methods on `Cookies` (#1000)
# 0.4.0
## ElectronNET.Core

View File

@@ -8,7 +8,9 @@ When you build an Electron.NET project, the following validation checks are perf
| Code | Check | Description |
|------|-------|-------------|
| [ELECTRON001](#1-packagejson-not-allowed) | package.json not allowed | Ensures no package.json exists outside ElectronHostHook |
| [ELECTRON001](#1-packagejson-rules) | package.json location rules | Ensures `package.json`/`package-lock.json` arent present in unsupported locations (root `package.json` handled separately) |
| [ELECTRON008](#1-packagejson-rules) | root package.json contains electron | Warns when root `package.json` contains the word `electron` (case-insensitive) |
| [ELECTRON009](#1-packagejson-rules) | root package.json copied to output | Warns when root `package.json` is configured to be copied to output/publish |
| [ELECTRON002](#2-electron-manifestjson-not-allowed) | electron-manifest.json not allowed | Detects deprecated manifest files |
| [ELECTRON003](#3-electron-builderjson-location) | electron-builder.json location | Verifies electron-builder.json exists in Properties folder |
| [ELECTRON004](#3-electron-builderjson-location) | electron-builder.json wrong location | Warns if electron-builder.json is found in incorrect locations |
@@ -18,24 +20,38 @@ When you build an Electron.NET project, the following validation checks are perf
---
## 1. package.json not allowed
## 1. package.json rules
**Warning Code:** `ELECTRON001`
**Warning Codes:** `ELECTRON001`, `ELECTRON008`, `ELECTRON009`
### What is checked
The build system scans for `package.json` and `package-lock.json` files in your project directory. These files should not exist in the project root or subdirectories (with one exception).
The build system scans for `package.json` and `package-lock.json` files in your project directory.
Rules:
- **ELECTRON001**: `package.json` / `package-lock.json` must not exist in the project directory or subdirectories
- Exception: `ElectronHostHook` folder is allowed
- Note: a **root** `package.json` is **excluded** from `ELECTRON001` and validated by `ELECTRON008` / `ELECTRON009`
- **ELECTRON008**: If a root `package.json` exists, it must **not** contain electron-related dependencies or configuration.
- **ELECTRON009**: If a root `package.json` exists, it must **not** be configured to be copied to output/publish (for example via `CopyToOutputDirectory` / `CopyToPublishDirectory` metadata)
### Why this matters
In previous versions of Electron.NET, a `package.json` file was required in the project. The new version generates this file automatically from MSBuild properties defined in your `.csproj` file.
Electron.NET generates its Electron-related `package.json` during publishing based on MSBuild properties. A user-maintained Electron-related `package.json` can conflict with that process.
Also, ensuring the root `package.json` is not copied prevents accidentally shipping it with the published app.
### Exception
A `package.json` file **is allowed** in the `ElectronHostHook` folder if you're using custom host hooks. This is the only valid location for a manually maintained package.json.
A `package.json` / `package-lock.json` file **is allowed** in the `ElectronHostHook` folder if you're using custom host hooks.
### How to fix
If you have an Electron-related `package.json` from older Electron.NET versions:
1. **Open your project's `.csproj` file**
2. **Add the required properties** to a PropertyGroup with the label `ElectronNetCommon`:
@@ -51,7 +67,12 @@ A `package.json` file **is allowed** in the `ElectronHostHook` folder if you're
</PropertyGroup>
```
3. **Delete the old `package.json`** file from your project root
3. **Delete** Electron-related `package.json` / `package-lock.json` files (except those under `ElectronHostHook` if applicable)
If you keep a root `package.json` for non-Electron reasons:
- Ensure it does **not** contain electron dependencies or configuration (fixes `ELECTRON008`)
- Ensure it is **not** copied to output/publish (fixes `ELECTRON009`)
> **See also:** [Migration Guide](Migration-Guide.md) for complete migration instructions.

View File

@@ -31,7 +31,7 @@ dotnet add package ElectronNET.Core.AspNet # For ASP.NET projects
### Step 2: Configure Project Settings
**Auto-generated Configuration:**
ElectronNET.Core automatically creates `electron-builder.json` during the first build or NuGet restore. No manual configuration is needed for basic setups.
ElectronNET.Core automatically creates `electron-builder.json` in the `Properties` folder of your project during the first build or NuGet restore. No manual configuration is needed for basic setups.
**Migrate Existing Configuration:**
If you have an existing `electron.manifest.json` file:
@@ -63,6 +63,9 @@ You can also manually edit `electron-builder.json`:
}
```
**Modify Launch Settings:**
ElectronNET.Core no longer needs a separate CLI tool (electronize.exe) for launching. You should update your launch settings to use either the ASP.NET-first or Electron-first approach. See [Debugging](../Using/Debugging.md) for details.
## 🎯 Testing Migration
After completing the migration steps:

View File

@@ -54,7 +54,7 @@ Add the Electron.NET configuration to your `.csproj` file:
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.4.0" />
<PackageReference Include="ElectronNET.Core" Version="0.4.1" />
</ItemGroup>
```

View File

@@ -0,0 +1,583 @@
# Electron.NET SignalR Authentication Guide
This guide explains the token-based authentication system implemented for SignalR mode in Electron.NET, designed to protect applications in multi-user environments.
## Table of Contents
1. [Overview](#overview)
2. [Threat Model](#threat-model)
3. [Authentication Architecture](#authentication-architecture)
4. [Implementation Details](#implementation-details)
5. [Security Properties](#security-properties)
6. [Troubleshooting](#troubleshooting)
7. [FAQ](#faq)
## Overview
Electron.NET's SignalR mode includes built-in authentication to ensure that only the Electron process spawned by a specific .NET instance can connect to that instance's HTTP and SignalR endpoints.
**When is this important?**
- Multi-user Windows Server environments (Terminal Services, RDP)
- Shared development machines with multiple users
- Any scenario where multiple users run the same application simultaneously
**What does it protect against?**
- User A's Electron process connecting to User B's .NET backend
- Unauthorized port scanning and connection attempts from other users
- Accidental misconfigurations causing cross-user connections
## Threat Model
### The Problem
When multiple users run the same Electron.NET application on a shared server:
1. Each .NET process binds to a TCP port (e.g., `http://localhost:58971`)
2. TCP ports are visible to **all users** on the machine
3. Without authentication, User A's Electron could connect to User B's backend
```
┌─────────────────────────────────────────────────┐
│ Windows Server (Terminal Services) │
├─────────────────────────────────────────────────┤
│ User A Session │
│ ├─ .NET Process (localhost:58971) │
│ └─ Electron Process │
│ │
│ User B Session │
│ ├─ .NET Process (localhost:61234) │
│ └─ Electron Process (could connect to 58971) │ ❌ Prevent this!
└─────────────────────────────────────────────────┘
```
### The Solution
Each .NET process generates a unique authentication token when launching Electron. Only requests with the correct token are allowed to connect.
```
┌─────────────────────────────────────────────────┐
│ User A Session │
│ ├─ .NET (token: abc123...) │
│ └─ Electron (has token abc123...) │ ✅ Authenticated
│ │
│ User B Session │
│ ├─ .NET (token: xyz789...) │
│ └─ Electron (has token xyz789...) │ ✅ Authenticated
│ │
│ ❌ User B's Electron → User A's .NET │
│ (lacks token abc123...) │ ❌ Rejected (401)
└─────────────────────────────────────────────────┘
```
## Authentication Architecture
### Flow Diagram
```
┌──────────────┐ ┌─────────────────┐
│ .NET Process │ │ Electron Process│
└──────┬───────┘ └────────┬────────┘
│ │
│ 1. Generate Token (GUID) │
│ Token: a3f8b2c1d4e5... │
│ │
│ 2. Launch Electron │
│ --authtoken=a3f8b2c1d4e5... │
│────────────────────────────────────────────────────>│
│ │
│ │ 3. Extract Token
│ │ global.authToken = ...
│ │
│ │ 4. Initial Page Load
│<────────────────────────────────────────────────────│
│ GET /?token=a3f8b2c1d4e5... │
│ │
│ 5. Validate Token │
│ ✓ Valid → Set Cookie │
│────────────────────────────────────────────────────>│
│ HTTP 200 + Set-Cookie: ElectronAuth=... │
│ │
│ │ 6. SignalR Connection
│<────────────────────────────────────────────────────│
│ GET /electron-hub?token=a3f8b2c1d4e5... │
│ │
│ 7. Validate Token, Set Cookie │
│────────────────────────────────────────────────────>│
│ HTTP 200 + Set-Cookie │
│ │
│ │ 8. Subsequent Requests
│<────────────────────────────────────────────────────│
│ GET /api/data │
│ Cookie: ElectronAuth=a3f8b2c1d4e5... │
│ │
│ 9. Validate Cookie │
│────────────────────────────────────────────────────>│
│ HTTP 200 (authenticated) │
│ │
```
### Key Steps
1. **Token Generation**: .NET generates 128-bit cryptographic random GUID
2. **Command-Line Passing**: Token passed to Electron via `--authtoken` parameter
3. **Token Extraction**: Electron stores token in `global.authToken`
4. **URL Appending**: Token appended to initial page and SignalR connection URLs
5. **Middleware Validation**: Every HTTP request validated by middleware
6. **Cookie Setting**: Valid token results in secure HttpOnly cookie
7. **Cookie-Based Requests**: Subsequent requests use cookie (no token in URL)
## Implementation Details
### 1. Token Generation (.NET)
**File**: `src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirstSignalR.cs`
```csharp
private void LaunchElectron()
{
// Generate secure authentication token (128-bit cryptographic random GUID)
this.authenticationToken = Guid.NewGuid().ToString("N"); // 32 hex chars
// Register token with authentication service
this.authenticationService.SetExpectedToken(this.authenticationToken);
// Launch Electron with token
var args = $"--unpackeddotnetsignalr --electronurl={this.actualUrl} --authtoken={this.authenticationToken}";
this.electronProcess = new ElectronProcessActive(isUnPacked, ElectronNetRuntime.ElectronExecutable, args, this.port.Value);
_ = this.electronProcess.Start();
}
```
**Token Format**: 32-character hexadecimal string (e.g., `a3f8b2c1d4e5f6a7b8c9d0e1f2a3b4c5`)
### 2. Authentication Service (.NET)
**File**: `src/ElectronNET.AspNet/Services/ElectronAuthenticationService.cs`
```csharp
public class ElectronAuthenticationService : IElectronAuthenticationService
{
private string _expectedToken;
private readonly object _lock = new object();
public void SetExpectedToken(string token)
{
lock (_lock)
{
_expectedToken = token;
}
}
public bool ValidateToken(string token)
{
if (string.IsNullOrEmpty(token))
return false;
lock (_lock)
{
if (string.IsNullOrEmpty(_expectedToken))
return false;
// Constant-time comparison prevents timing attacks
return ConstantTimeEquals(token, _expectedToken);
}
}
private static bool ConstantTimeEquals(string a, string b)
{
if (a == null || b == null || a.Length != b.Length)
return false;
var result = 0;
for (int i = 0; i < a.Length; i++)
{
result |= a[i] ^ b[i];
}
return result == 0;
}
}
```
**Key Features**:
- Thread-safe with lock
- Constant-time comparison (prevents timing attacks)
- Singleton lifetime (one per .NET instance)
### 3. Authentication Middleware (.NET)
**File**: `src/ElectronNET.AspNet/Middleware/ElectronAuthenticationMiddleware.cs`
```csharp
public async Task InvokeAsync(HttpContext context)
{
// Check if authentication cookie exists
var authCookie = context.Request.Cookies["ElectronAuth"];
if (!string.IsNullOrEmpty(authCookie))
{
if (_authService.ValidateToken(authCookie))
{
await _next(context);
return;
}
else
{
_logger.LogWarning("Invalid cookie for path {Path}", context.Request.Path);
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized: Invalid authentication");
return;
}
}
// No cookie - check for token in query string
var token = context.Request.Query["token"].ToString();
if (!string.IsNullOrEmpty(token) && _authService.ValidateToken(token))
{
// Valid token - set cookie for future requests
context.Response.Cookies.Append("ElectronAuth", token, new CookieOptions
{
HttpOnly = true,
SameSite = SameSiteMode.Strict,
Path = "/",
Secure = false, // localhost is HTTP
IsEssential = true
});
await _next(context);
return;
}
// Reject - no valid cookie or token
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized: Authentication required");
}
```
**Middleware Order** (IMPORTANT):
```csharp
app.UseMiddleware<ElectronAuthenticationMiddleware>(); // ← FIRST
app.UseRouting();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapHub<ElectronHub>("/electron-hub");
app.MapRazorComponents<App>();
```
### 4. Token Extraction (Electron)
**File**: `src/ElectronNET.Host/main.js`
```javascript
// Extract authentication token from command-line
if (app.commandLine.hasSwitch('authtoken')) {
global.authToken = app.commandLine.getSwitchValue('authtoken');
}
```
### 5. Token in URLs (Electron)
**Initial Page Load** (`src/ElectronNET.Host/api/browserWindows.js`):
```javascript
// Append token to window URL
if (global.authToken) {
const separator = electronUrl.includes('?') ? '&' : '?';
electronUrl = `${electronUrl}${separator}token=${global.authToken}`;
}
window.loadURL(electronUrl);
```
**SignalR Connection** (`src/ElectronNET.Host/api/signalr-bridge.js`):
```javascript
async connect() {
// Append token to SignalR hub URL
const connectionUrl = this.authToken ?
`${this.hubUrl}?token=${this.authToken}` :
this.hubUrl;
this.connection = new signalR.HubConnectionBuilder()
.withUrl(connectionUrl)
.build();
await this.connection.start();
}
```
### 6. Service Registration (Application)
**File**: Your application's `Program.cs`
```csharp
var builder = WebApplication.CreateBuilder(args);
// Register authentication service as singleton
builder.Services.AddSingleton<IElectronAuthenticationService, ElectronAuthenticationService>();
builder.Services.AddElectron();
var app = builder.Build();
// Register middleware BEFORE UseRouting()
app.UseMiddleware<ElectronAuthenticationMiddleware>();
app.UseRouting();
app.MapHub<ElectronHub>("/electron-hub");
app.Run();
```
## Security Properties
### Cookie Configuration
| Property | Value | Purpose |
|----------|-------|---------|
| `HttpOnly` | `true` | Prevents JavaScript access (XSS protection) |
| `SameSite` | `Strict` | Prevents CSRF attacks |
| `Path` | `/` | Cookie sent with all requests |
| `Secure` | `false` | Cannot use on localhost HTTP |
| `IsEssential` | `true` | Required for app to function |
| **Lifetime** | Session | Expires when Electron closes |
### Token Properties
- **Entropy**: 128 bits (2^128 possible values)
- **Format**: 32 hexadecimal characters (GUID without hyphens)
- **Generation**: `Guid.NewGuid()` uses cryptographically secure RNG
- **Lifetime**: Entire application session
- **Uniqueness**: Each .NET instance generates unique token
### What's Protected
**All HTTP endpoints**:
- Blazor Server pages (`/`, `/counter`, etc.)
- Static files (`/css/app.css`, `/js/script.js`)
- API endpoints (custom controllers)
- SignalR hub (`/electron-hub`)
**Both transport modes**:
- Initial token-based authentication (query parameter)
- Cookie-based subsequent requests
**Cross-user isolation**:
- Different users = different tokens
- Invalid token = 401 Unauthorized
### What's NOT Protected Against
**Same-user attacks** (by design):
- Process memory inspection
- Debugger attachment
- Command-line parameter visibility
**Rationale**: A malicious process running as the same user already has full access to:
- Process memory (can read token from RAM)
- Cookies (stored in Electron's data directory)
- All files owned by the user
Token-based authentication focuses on **cross-user isolation**, not same-user security.
## Troubleshooting
### Problem: 401 Unauthorized on Initial Load
**Symptoms**:
```
GET / HTTP/1.1
Response: 401 Unauthorized
```
**Possible Causes**:
1. Token not passed to Electron
2. Token not appended to URL
3. Middleware rejecting valid token
**Debugging Steps**:
1. Check Electron command-line:
```javascript
console.log('Auth Token:', global.authToken);
```
Should print 32-character hex string.
2. Check URL in browser window:
```javascript
console.log('Loading URL:', electronUrl);
```
Should include `?token=<guid>` parameter.
3. Check .NET logs:
```
[Warning] Authentication failed: Invalid token (prefix: a3f8b2c1...)
```
4. Verify middleware registration:
```csharp
app.UseMiddleware<ElectronAuthenticationMiddleware>(); // Before UseRouting()
```
### Problem: SignalR Connection Fails
**Symptoms**:
```
[SignalRBridge] Authentication failed: The authentication token is invalid or missing.
```
**Possible Causes**:
1. Token not passed to `SignalRBridge` constructor
2. Token not appended to hub URL
3. Cookie not being sent
**Debugging Steps**:
1. Check token passed to SignalRBridge:
```javascript
console.log('SignalRBridge token:', this.authToken);
```
2. Check connection URL:
```javascript
console.log('Hub URL:', connectionUrl);
```
Should be `http://localhost:PORT/electron-hub?token=<guid>`.
3. Enable verbose logging:
```javascript
.configureLogging(signalR.LogLevel.Debug)
```
### Problem: Cookie Not Persisting
**Symptoms**: Every request includes token in URL, cookie never set.
**Possible Causes**:
1. Cookie settings incompatible with browser
2. Middleware not setting cookie
3. Response headers not sent
**Debugging Steps**:
1. Check response headers:
```
Set-Cookie: ElectronAuth=a3f8b2c1...; Path=/; HttpOnly; SameSite=Strict
```
2. Check subsequent requests:
```
Cookie: ElectronAuth=a3f8b2c1...
```
3. Enable middleware logging:
```csharp
_logger.LogInformation("Setting cookie for path {Path}", path);
```
### Problem: Token Visible in Process List
**Observation**:
```powershell
wmic process where "name='electron.exe'" get commandline
...--authtoken=a3f8b2c1d4e5f6a7b8c9d0e1f2a3b4c5...
```
**Is this a problem?** No, by design.
**Explanation**:
- Command-line parameters are visible to same-user processes
- This is acceptable because:
- Same user already has access to process memory
- Same user can read cookies from Electron's data directory
- Token-based auth protects against **other users**, not same-user processes
**If you need same-user protection**: Use OS-level access controls (file permissions, process isolation) or consider named pipes with ACLs.
## FAQ
### Q: Why use tokens instead of Process ID validation?
**A**: PIDs can be recycled and reused, making validation unreliable. Additionally:
- PIDs don't provide cryptographic security
- Parent-child validation is platform-specific
- Adds complexity without meaningful security benefit
Token-based authentication provides:
- Cryptographic randomness (128-bit entropy)
- Simple cross-platform implementation
- No race conditions or PID recycling issues
### Q: Why not use HTTPS with certificates?
**A**: Localhost doesn't support HTTPS certificates easily:
- Self-signed certificates trigger browser warnings
- Certificate management adds complexity
- Token-based auth provides equivalent security for localhost IPC
### Q: Can I disable authentication?
**A**: Not recommended, but possible by removing middleware registration:
```csharp
// Remove this line:
// app.UseMiddleware<ElectronAuthenticationMiddleware>();
```
**Warning**: Only do this if:
- Application runs on single-user machines only
- No Terminal Services / RDP access
- You understand the security implications
### Q: Does this work with hot reload?
**A**: Yes, cookie persists across hot reload as long as Electron process keeps running.
### Q: What about multiple Electron windows?
**A**: All windows in the same Electron process share cookies automatically. Authentication works seamlessly across multiple windows.
### Q: How do I test authentication?
**Test 1 - Happy Path**:
1. Run application normally
2. Check logs for "Authentication successful"
3. Verify cookie is set (DevTools → Application → Cookies)
4. Subsequent requests should not include token in URL
**Test 2 - Invalid Token**:
1. Modify token in browser URL: `?token=invalid`
2. Should receive 401 Unauthorized
3. Check logs for "Authentication failed: Invalid token"
**Test 3 - No Token**:
1. Open browser manually to `http://localhost:PORT/`
2. Should receive 401 Unauthorized
3. Check logs for "Authentication failed: No cookie or token"
**Test 4 - Multi-User** (Windows Server/Terminal Services):
1. Launch app as User A
2. In User B session, try to connect to User A's port
3. Should receive 401 Unauthorized
### Q: What about packaged applications?
**A**: Authentication works identically in packaged mode. The `--authtoken` parameter is included in the packaged Electron executable.
### Q: Can I customize the cookie name?
**A**: Yes, modify `AuthCookieName` constant in `ElectronAuthenticationMiddleware.cs`:
```csharp
private const string AuthCookieName = "MyCustomCookieName";
```
## Summary
Electron.NET's token-based authentication provides:
**Security**: 128-bit entropy, constant-time comparison, secure cookies
**Simplicity**: Automatic token generation and validation
**Compatibility**: Works with Blazor, SignalR, and static files
**Monitoring**: Structured logging for security events
**Multi-User**: Cross-user isolation on shared servers
The authentication system is **enabled by default** in SignalR mode and requires minimal configuration. For most applications, simply register the services and middleware - everything else happens automatically.
For additional help or questions, see the [SignalR Implementation Summary](SignalR-Implementation-Summary.md) or open an issue on GitHub.

View File

@@ -0,0 +1,450 @@
# SignalR Implementation Summary
This document summarizes the completed implementation of SignalR-based bidirectional communication in Electron.NET as an alternative to Socket.IO.
## Overview
The SignalR implementation provides a modern, .NET-native alternative to Socket.IO for communication between the ASP.NET Core host and the Electron process. This new startup mode was designed specifically for **Blazor Server applications** where ASP.NET Core and Electron need tighter integration and lifecycle control.
**Key Innovation**: .NET-first startup with dynamic port assignment - ASP.NET Core starts first, binds to port 0 (letting Kestrel choose an available port), then launches Electron with the actual URL.
## Primary Use Case
Blazor Server applications where:
- ASP.NET Core owns the application lifecycle
- Dynamic port binding is needed (no fixed port configuration)
- Modern SignalR infrastructure is preferred over Socket.IO
- Single process debugging is desired (.NET process controls Electron)
## Implementation Phases (All Complete)
### Phase 1: Core Infrastructure ✅
- Added new `StartupMethod` enum values:
- `UnpackagedDotnetFirstSignalR`
- `PackagedDotnetFirstSignalR`
- Created `ElectronHub` SignalR hub for bidirectional communication
- Registered hub endpoint at `/electron-hub` (separate from Blazor's `/_blazor` hub)
### Phase 2: Runtime Controller ✅
- Created `RuntimeControllerAspNetDotnetFirstSignalR`
- Implemented logic to:
- Bind Kestrel to port 0
- Wait for Kestrel startup and capture actual port via `IServerAddressesFeature`
- Launch Electron with `--electronurl` parameter
- Wait for SignalR connection from Electron
- Transition to Ready state when connected
### Phase 3: Electron/Node.js Side ✅
- Added `@microsoft/signalr` npm package dependency
- Created SignalR connection module (`signalr-bridge.js`)
- Updated `main.js` to detect SignalR modes and connect to `/electron-hub`
- Implemented Socket.IO-compatible interface for API compatibility
### Phase 4: API Bridge Adaptation ✅
- Created `SignalRFacade` implementing `IFacade` interface
- Ensured existing Electron API classes work with SignalR
- Implemented type conversion helper for SignalR's JSON deserialization
- Event routing from both directions (.NET ↔ Electron)
### Phase 5: Configuration & Extensions ✅
- Updated `WebHostBuilderExtensions` for automatic SignalR configuration
- Added startup mode detection via command-line flags
- Configured dynamic port binding (port 0) for SignalR modes
- Integrated with `UseElectron()` API for seamless usage
### Phase 6: Testing & Fixes ✅
- Created sample Blazor Server application
- Fixed multiple critical issues discovered during integration testing
- Cleaned up debug logging
- Added comprehensive code documentation
## Key Components
### 1. SignalRFacade (`src/ElectronNET.AspNet/Bridge/SignalRFacade.cs`)
- Implements `IFacade` interface to match Socket.IO facade API
- Handles bidirectional event routing using `IHubContext<ElectronHub>`
- Includes `ConvertToType<T>` helper for handling SignalR's JSON deserialization quirks
- Critical fix: Handles `JsonElement` and numeric type conversions (long → int)
### 2. ElectronHub (`src/ElectronNET.AspNet/Hubs/ElectronHub.cs`)
- SignalR hub for .NET ↔ Electron communication
- Key methods:
- `RegisterElectronClient()` - Called by Electron on connection
- `ElectronEvent(string, object[])` - Receives events from Electron
- Connection/disconnection handlers notify runtime controller
### 3. RuntimeControllerAspNetDotnetFirstSignalR
- Manages SignalR mode lifecycle
- Critical flow:
1. Wait for ASP.NET server to start
2. Capture dynamic port from `IServerAddressesFeature`
3. Update `ElectronNetRuntime.AspNetWebPort` with actual port
4. Launch Electron with `--electronurl` parameter
5. Wait for `electron-host-ready` signal before calling app ready callback
### 4. SignalRBridge (`src/ElectronNET.Host/api/signalr-bridge.js`)
- JavaScript SignalR client that mimics Socket.IO interface
- Provides `on()` and `emit()` methods for API compatibility
- Critical fix: Event args passed as arrays, spread when calling handlers
- Uses `@microsoft/signalr` npm package
### 5. Main.js Startup (`src/ElectronNET.Host/main.js`)
- Detects SignalR mode via `--unpackeddotnetsignalr` or `--dotnetpackedsignalr` flags
- Creates invisible keep-alive window (destroyed when first real window is created)
- Loads API modules then signals `electron-host-ready` to .NET
## Usage
Enable SignalR mode by passing the appropriate command-line flag:
```bash
# Unpacked mode (development)
dotnet run --unpackeddotnetsignalr
# Packed mode (production)
dotnet run --dotnetpackedsignalr
```
Or set environment variable (deprecated, flags preferred):
```bash
ELECTRON_USE_SIGNALR=true
```
In your ASP.NET Core Program.cs:
```csharp
var builder = WebApplication.CreateBuilder(args);
// Add Electron.NET services
builder.Services.AddElectron();
// Configure Electron with SignalR mode
builder.WebHost.UseElectron(args, async () =>
{
var window = await Electron.WindowManager.CreateWindowAsync();
window.OnReadyToShow += () => window.Show();
});
var app = builder.Build();
app.UseRouting();
// Map SignalR hub for Electron communication
app.MapHub<ElectronHub>("/electron-hub");
app.MapRazorComponents<App>().AddInteractiveServerRenderMode();
app.Run();
```
**Note**: `UseElectron()` automatically detects SignalR mode and configures everything. The rest happens automatically:
1. Port 0 binding (dynamic port assignment)
2. Electron launch with actual URL
3. SignalR connection establishment (WebSockets enabled automatically by MapHub)
4. App ready callback execution
2. Electron launch with actual URL
3. SignalR connection establishment (WebSockets enabled automatically by `MapHub`)
4. App ready callback execution
## Architecture Decisions
### Why .NET-First Startup?
SignalR mode uses .NET-first startup (vs. Electron-first in Socket.IO mode) because:
1. **No port scanning needed** - .NET can pass the actual URL to Electron
2. **SignalR hub must be registered** before Electron connects
3. **Simpler lifecycle** - ASP.NET controls when Electron launches
4. **Better for Blazor Server** - Blazor is already running when Electron starts
5. **Single process debugging** - Developer debugs .NET process which owns Electron
### Why IFacade Interface?
Introducing `IFacade` allows `BridgeConnector.Socket` to return either `SocketIOFacade` or `SignalRFacade` based on startup mode, ensuring existing API code works with both transport mechanisms without modification.
### Why Keep-Alive Window?
Electron quits immediately on macOS if no windows exist. The keep-alive window ensures Electron stays running during the connection and API initialization phase. It's automatically destroyed when the first real window is created.
### Why 'electron-host-ready' Signal?
Without this signal, .NET would call the app ready callback before Electron finished loading API modules, causing API calls to fail. The signal ensures proper initialization order:
1. Electron connects to SignalR
2. Electron loads all API modules (browserWindows, dialog, menu, etc.)
3. Electron signals `electron-host-ready`
4. .NET calls app ready callback
5. App code can safely use Electron APIs
## Blazor Server Considerations
### SignalR Hub Coexistence
Blazor Server already uses SignalR for component communication (`/_blazor` hub). Our implementation:
- Uses separate endpoint (`/electron-hub`) to avoid conflicts
- Both hubs coexist on the same Kestrel server without interference
- No impact on Blazor's reconnection logic
- Compatible with hot reload scenarios
### Lifecycle Integration
- Electron window creation happens **after** Blazor app is ready
- `UseElectron()` callback fires when SignalR hub is connected
- Blazor components can inject Electron services to control windows
- Proper disposal when Electron process exits
### Development Experience
- Hot reload works for both Blazor and Electron integration
- F5 debugging works seamlessly
- No need to manually coordinate ports
- Single process to debug (.NET process owns the lifecycle)
## Critical Fixes Applied
### 1. Race Condition: API Module Loading
**Problem**: .NET called app ready callback before Electron finished loading API modules.
**Solution**: Electron signals `electron-host-ready` after loading all API modules. .NET waits for this signal before calling the app ready callback.
### 2. Event Argument Mismatch
**Problem**: SignalR sent event data as nested arrays `[[data]]` instead of `[data]`.
**Solution**:
- C#: Use explicit `object[] args` parameter (not `params`)
- JS: Always pass args as array: `invoke('ElectronEvent', eventName, args)`
- JS: Spread args when calling handlers: `handler(...argsArray)`
### 3. Type Conversion Failures
**Problem**: SignalR deserializes JSON numbers as `JsonElement` or `long`, causing `Once<int>` handlers to fail silently.
**Solution**: `SignalRFacade.ConvertToType<T>` handles JsonElement deserialization and numeric conversions.
### 4. Window Shutdown Not Triggering Exit
**Problem**: Keep-alive window prevented `window-all-closed` event from firing.
**Solution**: Destroy keep-alive window when first real window is created using `app.once('browser-window-created')`.
### 5. Dynamic Port Not Propagated
**Problem**: When using port 0, Kestrel assigns a dynamic port, but `ElectronNetRuntime.AspNetWebPort` was not updated.
**Solution**: Update `AspNetWebPort` after capturing port from `IServerAddressesFeature` in `CapturePortAndLaunchElectron()`.
### 7. Blazor Static Files Not Loading
**Problem**: Blazor CSS and framework files returned 404 errors.
**Solution**:
- Added `app.UseStaticFiles()` to serve wwwroot content
- Fixed middleware order: `UseAntiforgery()` must be between `UseRouting()` and `UseEndpoints()`
- Updated scoped CSS asset reference to use lowercase name matching .NET 9+ convention
## Authentication & Security
### Token-Based Authentication (Multi-User Protection)
SignalR mode includes built-in authentication to prevent unauthorized connections in multi-user scenarios (e.g., Windows Server with Terminal Services/RDP).
**Threat Model**: On shared servers, multiple users can run the same application simultaneously. Without authentication, User A's Electron process could potentially connect to User B's ASP.NET backend.
**Solution**: Token-based authentication with secure cookies.
### Authentication Flow
1. **.NET generates token**: When launching Electron, `RuntimeControllerAspNetDotnetFirstSignalR` generates a cryptographically secure GUID (128-bit entropy)
2. **Token passed via command-line**: Electron receives `--authtoken=<guid>` parameter
3. **Token appended to URLs**:
- Initial page load: `http://localhost:PORT/?token=<guid>`
- SignalR connection: `http://localhost:PORT/electron-hub?token=<guid>`
4. **Middleware validates token**: `ElectronAuthenticationMiddleware` checks every HTTP request
5. **Cookie set on first request**: After successful token validation, secure HttpOnly cookie is set
6. **Subsequent requests use cookie**: No token in URLs after initial authentication
### Security Properties
- **Cookie Settings**:
- `HttpOnly`: true (prevents JavaScript access, XSS protection)
- `SameSite`: Strict (prevents CSRF)
- `Path`: / (applies to all routes)
- `Secure`: false (localhost is HTTP, not HTTPS)
- `IsEssential`: true (required for app to function)
- **Lifetime**: Session scope (expires when Electron closes)
- **Token Validation**:
- Constant-time string comparison (prevents timing attacks)
- Token stored in singleton service (one per .NET instance)
- Never logged in full (only first 8 characters for debugging)
- **Protection Scope**:
- All HTTP endpoints (Blazor pages, static files, API calls)
- SignalR hub connection (negotiate and all hub traffic)
- Both initial request and cookie-based requests validated
### What This Protects Against
**Protected**:
- Cross-user connections (User A → User B's backend)
- Port scanning attacks from other users
- Accidental connections from misconfigured processes
**NOT Protected Against** (By Design):
- Malicious same-user processes with debugger access
- Process memory inspection tools (same privilege level)
- Command-line parameter visibility (same user can see all processes)
**Rationale**: Same-user attacks already have full access to process memory, files, and cookies. Token-based authentication focuses on cross-user isolation, which is the primary threat in multi-user environments.
### Implementation Components
1. **IElectronAuthenticationService** (`src/ElectronNET.AspNet/Services/`)
- Singleton service storing expected token
- Thread-safe with lock-based validation
- Constant-time comparison to prevent timing attacks
2. **ElectronAuthenticationMiddleware** (`src/ElectronNET.AspNet/Middleware/`)
- Validates every HTTP request before routing
- Checks cookie first, then token query parameter
- Sets cookie on first valid token
- Returns 401 for invalid/missing authentication
- Structured logging for security monitoring
3. **Token Generation** (`RuntimeControllerAspNetDotnetFirstSignalR.cs`)
- `Guid.NewGuid().ToString("N")` = 32 hex characters
- Called in `LaunchElectron()` method
- Registered with authentication service immediately
4. **Electron Integration** (`main.js`, `signalr-bridge.js`)
- Extracts token from `--authtoken` parameter
- Stores in `global.authToken` for module access
- Appends to browser window URL and SignalR connection URL
### Usage in Custom Applications
Authentication is **enabled by default** in SignalR mode. No additional configuration required beyond service registration:
```csharp
var builder = WebApplication.CreateBuilder(args);
// Register authentication service (singleton)
builder.Services.AddSingleton<IElectronAuthenticationService, ElectronAuthenticationService>();
builder.Services.AddElectron();
var app = builder.Build();
// Register middleware BEFORE UseRouting()
app.UseMiddleware<ElectronAuthenticationMiddleware>();
app.UseRouting();
app.MapHub<ElectronHub>("/electron-hub");
app.MapRazorComponents<App>().AddInteractiveServerRenderMode();
app.Run();
```
The rest is automatic:
- Token generation happens when Electron launches
- Token validation happens on every request
- Cookie management is handled by the middleware
### Logging & Monitoring
Authentication events are logged with structured logging:
**Successful authentication**:
```
[Information] Authentication successful: Setting cookie for path /
```
**Failed authentication**:
```
[Warning] Authentication failed: Invalid token (prefix: a3f8b2c1...) for path / from 127.0.0.1
[Warning] Authentication failed: No cookie or token provided for path /api/data from 127.0.0.1
[Warning] Authentication failed: Invalid cookie for path /_blazor from 127.0.0.1
```
**SignalR connection failures**:
```
[SignalRBridge] Authentication failed: The authentication token is invalid or missing.
[SignalRBridge] Please ensure the --authtoken parameter is correctly passed to Electron.
```
Log failed authentication attempts for security monitoring and troubleshooting.
### Testing Multi-User Scenarios
To test authentication in multi-user environments:
1. **Run as different Windows users**:
```powershell
# User A session
dotnet run
# User B session (different RDP/Terminal Services session)
dotnet run
```
2. **Verify isolation**: User A's Electron cannot access User B's backend
3. **Check logs**: Failed auth attempts should be logged
4. **Monitor tokens**: Each instance generates unique token
For development testing on single-user machines, simulate by running multiple instances and attempting to connect with wrong/missing tokens.
## Backward Compatibility
This is a **new optional startup mode** - all existing modes continue to work unchanged:
- `PackagedElectronFirst` - unchanged
- `PackagedDotnetFirst` - unchanged
- `UnpackedElectronFirst` - unchanged
- `UnpackedDotnetFirst` - unchanged
Existing applications do not need to change. SignalR mode is opt-in via command-line flags.
## File Changes Summary
**New Files**:
- `src/ElectronNET.AspNet/Bridge/SignalRFacade.cs` (225 lines)
- `src/ElectronNET.AspNet/Hubs/ElectronHub.cs` (108 lines)
- `src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirstSignalR.cs` (163 lines)
- `src/ElectronNET.AspNet/Services/IElectronAuthenticationService.cs` (20 lines)
- `src/ElectronNET.AspNet/Services/ElectronAuthenticationService.cs` (65 lines)
- `src/ElectronNET.AspNet/Middleware/ElectronAuthenticationMiddleware.cs` (105 lines)
- `src/ElectronNET.Host/api/signalr-bridge.js` (125 lines)
**Modified Files**:
- `src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs` - Added SignalR service registration
- `src/ElectronNET.Host/main.js` - Added SignalR startup flow and token extraction
- `src/ElectronNET.Host/api/browserWindows.js` - Token appended to window URLs
- `src/ElectronNET.Host/package.json` - Added `@microsoft/signalr` dependency
- `src/ElectronNET.Samples.BlazorSignalR/Program.cs` - Sample with authentication
**Total Changes**: ~1,220 lines added
## Testing Recommendations
1. Test with dynamic port (port 0) to ensure URL propagation works
2. Verify window-all-closed triggers app exit
3. Test rapid window creation/destruction
4. Verify reconnection behavior if SignalR connection drops
5. Test with both packed and unpacked modes
6. Verify API calls work correctly (especially those returning data)
## Known Limitations
1. **Request-response pattern not yet implemented** - `InvokeElectronApi` is a placeholder. Current API calls use event-based pattern.
2. **TouchBar API not yet supported** on macOS SignalR mode
3. **SignalR automatic reconnection** may cause issues with pending API calls (needs circuit breaker pattern)
## Future Enhancements
1. **Request-response pattern** - Implement proper async/await pattern for API calls that return values
2. **Metrics/diagnostics** - Add SignalR connection health monitoring
3. **Circuit breaker** - Handle reconnection scenarios gracefully
4. **Integration tests** - Comprehensive test suite for SignalR mode
5. **Performance benchmarks** - Compare SignalR vs Socket.IO performance
## Success Metrics
The implementation is considered complete and functional:
- ✅ .NET starts first with dynamic port (port 0)
- ✅ Electron launches with actual URL
- ✅ SignalR connection establishes successfully
- ✅ API modules load before app ready callback
- ✅ Window creation works from .NET
- ✅ Window shutdown triggers app exit
- ✅ Blazor Server pages load with correct styling
- ✅ Both SignalR hubs coexist (Electron + Blazor)
- ✅ Clean codebase with minimal debug logging
- ✅ Comprehensive inline documentation
- ✅ Token-based authentication for multi-user scenarios
- ✅ Secure cookie-based session management
- ✅ Structured logging for security monitoring
- ✅ Protection against cross-user connection attempts

View File

@@ -0,0 +1,236 @@
# SignalR-Based Startup Mode for Electron.NET
## Overview
This feature adds a new startup mode for Electron.NET where:
- **.NET/ASP.NET Core starts first** and binds to port 0 (dynamic port)
- **Kestrel picks an available port** automatically
- **Electron process is launched** with the actual URL
- **SignalR is used for communication** instead of socket.io
- **Blazor Server apps** can coexist with Electron control
## Status
**Phases 1-5 Complete** - Infrastructure ready, basic functionality implemented
⏸️ **Phase 6 Pending** - Full API integration, testing, and documentation
## How It Works
### Startup Sequence
1. ASP.NET Core application starts
2. Kestrel binds to `http://localhost:0` (random available port)
3. `RuntimeControllerAspNetDotnetFirstSignalR` captures the actual port via `IServerAddressesFeature`
4. Electron process is launched with `--electronUrl=http://localhost:XXXXX`
5. Electron's main.js detects SignalR mode (via `--dotnetpackedsignalr` or `--unpackeddotnetsignalr` flag)
6. Electron connects to SignalR hub at `/electron-hub`
7. Hub notifies runtime controller of successful connection
8. Application transitions to "Ready" state
9. `ElectronAppReady` callback is invoked
### Communication Flow
```
.NET/Kestrel (Port 0) ←→ SignalR Hub (/electron-hub) ←→ Electron Process
↓ ↓ ↓
Blazor Server ElectronHub class SignalR Client
(/_blazor hub) (API commands) (main.js + signalr-bridge.js)
```
## Usage
### 1. Enable SignalR Mode
Set the environment variable:
```bash
ELECTRON_USE_SIGNALR=true
```
Or in launchSettings.json:
```json
{
"environmentVariables": {
"ELECTRON_USE_SIGNALR": "true"
}
}
```
### 2. Configure ASP.NET Core
In your `Program.cs`:
```csharp
using ElectronNET.API;
using ElectronNET.API.Entities;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddElectron();
builder.UseElectron(args, async () =>
{
var window = await Electron.WindowManager.CreateWindowAsync(
new BrowserWindowOptions { Show = false });
window.OnReadyToShow += () => window.Show();
});
var app = builder.Build();
// Configure middleware
app.UseStaticFiles();
app.UseRouting();
// Map the Electron SignalR hub
app.MapElectronHub(); // ← Required for SignalR mode
app.MapRazorPages();
app.Run();
```
### 3. Run Your Application
Just press F5 in Visual Studio or run:
```bash
dotnet run
```
The application will:
- Automatically detect SignalR mode via environment variable
- Bind Kestrel to port 0
- Launch Electron with the correct URL
- Establish SignalR connection
## Components
### .NET Side
- **`ElectronHub`** - SignalR hub at `/electron-hub`
- **`SignalRFacade`** - Mimics `SocketIoFacade` interface for compatibility
- **`RuntimeControllerAspNetDotnetFirstSignalR`** - Lifecycle management
- **`StartupMethod.PackagedDotnetFirstSignalR`** - For packaged apps
- **`StartupMethod.UnpackedDotnetFirstSignalR`** - For debugging
### Electron Side
- **`signalr-bridge.js`** - SignalR client wrapper
- **`main.js`** - Detects SignalR mode and connects to hub
- **`@microsoft/signalr`** npm package
## Key Features
**Dynamic Port Assignment** - No hardcoded ports, no conflicts
**Blazor Server Compatible** - Separate hub endpoints (`/electron-hub` vs `/_blazor`)
**Bidirectional Communication** - Both .NET→Electron and Electron→.NET
**Hot Reload Support** - SignalR automatic reconnection
**Multiple Instances** - Each instance gets its own port
## Current Limitations (Phase 6 Work Needed)
⚠️ **Electron API Integration** - Existing Electron APIs (WindowManager, Dialog, etc.) still use SocketIoFacade. Full integration requires:
- Refactoring APIs to work with both facades, or
- Creating an adapter pattern
⚠️ **Request-Response Pattern** - Current hub methods are one-way. Need to implement proper async request-response for API calls.
⚠️ **Event Routing** - Electron events need to be routed through SignalR back to .NET.
⚠️ **Testing** - Integration tests needed to validate end-to-end functionality.
## What's Implemented
### Phase 1: Core Infrastructure ✅
- New `StartupMethod` enum values
- `ElectronHub` SignalR hub
- Hub endpoint registration
### Phase 2: Runtime Controller ✅
- `RuntimeControllerAspNetDotnetFirstSignalR`
- Port 0 binding logic
- Electron launch with URL parameter
- SignalR connection tracking
### Phase 3: Electron/Node.js Side ✅
- `@microsoft/signalr` package integration
- SignalR connection module
- Startup mode detection
- URL parameter handling
### Phase 4: API Bridge ✅ (Basic Structure)
- `SignalRFacade` class
- Event handler system
- Hub connection integration
### Phase 5: Configuration ✅
- Environment variable detection
- Port 0 configuration
- Automatic service registration
## Next Steps (Phase 6)
To fully utilize this feature, the following work is recommended:
1. **API Integration** - Make existing Electron APIs work with SignalR
2. **Sample Application** - Create a Blazor Server demo
3. **Integration Tests** - Validate end-to-end scenarios
4. **Documentation** - Complete user guides and examples
5. **Performance Testing** - Compare with socket.io mode
## Files Changed
### .NET
- `src/ElectronNET.API/Runtime/Data/StartupMethod.cs`
- `src/ElectronNET.AspNet/Hubs/ElectronHub.cs`
- `src/ElectronNET.AspNet/Bridge/SignalRFacade.cs`
- `src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirstSignalR.cs`
- `src/ElectronNET.AspNet/API/ElectronEndpointRouteBuilderExtensions.cs`
- `src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs`
- `src/ElectronNET.API/Runtime/StartupManager.cs`
### Electron/Node.js
- `src/ElectronNET.Host/package.json`
- `src/ElectronNET.Host/main.js`
- `src/ElectronNET.Host/api/signalr-bridge.js` (new file)
## Commits
```
7f2ea48 - Add PackagedDotnetFirstSignalR and UnpackedDotnetFirstSignalR startup methods
8ee81f6 - Add ElectronHub and SignalR infrastructure for new startup modes
40aed60 - Add RuntimeControllerAspNetDotnetFirstSignalR for SignalR-based startup
c1740b5 - Add SignalR client support to Electron Host for new startup modes
cb7d721 - Add SignalRFacade for SignalR-based API communication
268b9c9 - Update RuntimeControllerAspNetDotnetFirstSignalR to use SignalRFacade
04ec522 - Fix compilation errors - Phase 4 complete (basic structure)
054f5b1 - Complete Phase 5: Add SignalR startup detection and port 0 configuration
```
## Benefits Over Socket.io Mode
- **Better Integration** - Native SignalR is part of ASP.NET Core stack
- **Type Safety** - SignalR has better TypeScript support
- **Performance** - SignalR is optimized for ASP.NET Core
- **Reliability** - Built-in reconnection and error handling
- **Scalability** - Can leverage SignalR's scale-out features
- **Consistency** - Blazor Server already uses SignalR
## Contributing
To contribute to Phase 6 (full API integration):
1. Focus on adapting existing Electron API classes to work with SignalRFacade
2. Implement request-response pattern in ElectronHub
3. Add integration tests
4. Create sample applications
5. Update documentation
## License
MIT - Same as Electron.NET
---
**Created**: January 30, 2026
**Status**: Infrastructure Complete, API Integration Pending
**Contact**: See Electron.NET maintainers

View File

@@ -314,7 +314,9 @@ namespace ElectronNET.API
{
if (this.tcs != null)
{
var ex = new TimeoutException($"No response after {timeout:D}ms trying to retrieve value {apiBase.objectName}.{callerName}()");
var ex = new TimeoutException(
$"No response after {(long)timeout.TotalMilliseconds}ms trying to retrieve value {apiBase.objectName}.{callerName}()"
);
this.tcs.TrySetException(ex);
this.tcs = null;
}

View File

@@ -186,6 +186,19 @@ public class BrowserWindow : ApiBase
remove => RemoveEvent(value, Id);
}
/// <summary>
/// Emitted when the window is moved or resized.
/// </summary>
/// <remarks>
/// While not being an original Electron event, this one includes the bounds values,
/// saving the additional roundtrip for calling <see cref="GetBoundsAsync"/>.
/// </remarks>
public event Action<Rectangle> OnBoundsChanged
{
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
/// <summary>
/// macOS: Emitted once when the window is moved to a new position.
/// </summary>

View File

@@ -2,6 +2,7 @@ using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
{
@@ -54,10 +55,79 @@ namespace ElectronNET.API
_changed -= value;
if (_changed == null)
{
BridgeConnector.Socket.Off("webContents-session-cookies-changed" + Id);
}
}
}
private event Action<Cookie, CookieChangedCause, bool> _changed;
/// <summary>
/// Sends a request to get all cookies matching filter, and resolves a callack with the response.
/// </summary>
/// <param name="filter">
/// </param>
/// <returns>A task which resolves an array of cookie objects.</returns>
public Task<Cookie[]> GetAsync(CookieFilter filter)
{
var tcs = new TaskCompletionSource<Cookie[]>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<Cookie[]>("webContents-session-cookies-get-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-cookies-get", Id, filter, guid);
return tcs.Task;
}
/// <summary>
///
/// </summary>
/// <param name="details"></param>
/// <returns></returns>
public Task SetAsync(CookieDetails details)
{
var tcs = new TaskCompletionSource<object>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<object>("webContents-session-cookies-set-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-cookies-set", Id, details, guid);
return tcs.Task;
}
/// <summary>
/// Removes the cookies matching url and name
/// </summary>
/// <param name="url">The URL associated with the cookie.</param>
/// <param name="name">The name of cookie to remove.</param>
/// <returns>A task which resolves when the cookie has been removed</returns>
public Task RemoveAsync(string url, string name)
{
var tcs = new TaskCompletionSource<object>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<object>("webContents-session-cookies-remove-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-cookies-remove", Id, url, name, guid);
return tcs.Task;
}
/// <summary>
/// Writes any unwritten cookies data to disk.
/// </summary>
/// <returns>A task which resolves when the cookie store has been flushed</returns>
public Task FlushStoreAsync()
{
var tcs = new TaskCompletionSource<object>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<object>("webContents-session-cookies-flushStore-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-cookies-flushStore", Id, guid);
return tcs.Task;
}
}
}

View File

@@ -24,13 +24,13 @@ namespace ElectronNET.API.Entities
/// ( if y is used) Window's left offset from screen. Default is to center the
/// window.
/// </summary>
public int X { get; set; } = -1;
public int? X { get; set; }
/// <summary>
/// ( if x is used) Window's top offset from screen. Default is to center the
/// window.
/// </summary>
public int Y { get; set; } = -1;
public int? Y { get; set; }
/// <summary>
/// The width and height would be used as web page's size, which means the actual

View File

@@ -24,7 +24,7 @@
/// <summary>
/// Gets or sets a value indicating whether the cookie is a host-only cookie; this will only be true if no domain was passed.
/// </summary>
public bool HostOnly { get; set; }
public bool? HostOnly { get; set; }
/// <summary>
/// Gets or sets the path of the cookie.
@@ -34,22 +34,22 @@
/// <summary>
/// Gets or sets a value indicating whether the cookie is marked as secure.
/// </summary>
public bool Secure { get; set; }
public bool? Secure { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the cookie is marked as HTTP only.
/// </summary>
public bool HttpOnly { get; set; }
public bool? HttpOnly { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the cookie is a session cookie or a persistent cookie with an expiration date.
/// </summary>
public bool Session { get; set; }
public bool? Session { get; set; }
/// <summary>
/// Gets or sets the expiration date of the cookie as the number of seconds since the UNIX epoch. Not provided for session cookies.
/// </summary>
public double ExpirationDate { get; set; }
public double? ExpirationDate { get; set; }
/// <summary>
/// Gets or sets the SameSite policy applied to this cookie. Can be "unspecified", "no_restriction", "lax" or "strict".

View File

@@ -29,16 +29,16 @@
/// <summary>
/// (optional) - Filters cookies by their Secure property.
/// </summary>
public bool Secure { get; set; }
public bool? Secure { get; set; }
/// <summary>
/// (optional) - Filters out session or persistent cookies.
/// </summary>
public bool Session { get; set; }
public bool? Session { get; set; }
/// <summary>
/// (optional) - Filters cookies by httpOnly.
/// </summary>
public bool HttpOnly { get; set; }
public bool? HttpOnly { get; set; }
}
}

View File

@@ -102,6 +102,29 @@ namespace ElectronNET.API
});
}
/// <summary>
/// Send a message to the renderer process synchronously via channel,
/// you can also send arbitrary arguments.
///
/// Note: Sending a synchronous message will block the whole renderer process,
/// unless you know what you are doing you should never use it.
/// </summary>
/// <param name="channel"></param>
/// <param name="listener"></param>
public void OnSync(string channel, Func<object, Task<object>> listener)
{
BridgeConnector.Socket.Emit("registerSyncIpcMainChannel", channel);
BridgeConnector.Socket.On<JsonElement>(channel, (args) =>
{
Task.Run(async () =>
{
var arg = FormatArguments(args);
var result = await listener(arg);
BridgeConnector.Socket.Emit(channel + "Sync", result);
});
});
}
/// <summary>
/// Adds a one time listener method for the event. This listener is invoked only
/// the next time a message is sent to channel, after which it is removed.
@@ -154,5 +177,88 @@ namespace ElectronNET.API
{
BridgeConnector.Socket.Emit("sendToIpcRendererBrowserView", browserView.Id, channel, data);
}
/// <summary>
/// Adds a handler for an invokeable IPC. This handler will be called
/// whenever a renderer calls ipcRenderer.invoke(channel, ...args).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void Handle(string channel, Func<object, object> listener)
{
BridgeConnector.Socket.Emit("registerHandleIpcMainChannel", channel);
BridgeConnector.Socket.On<JsonElement>(channel, (args) =>
{
var arg = FormatArguments(args);
var result = listener(arg);
BridgeConnector.Socket.Emit(channel + "Handle", result);
});
}
/// <summary>
/// Adds a handler for an invokeable IPC. This handler will be called
/// whenever a renderer calls ipcRenderer.invoke(channel, ...args).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void Handle(string channel, Func<object, Task<object>> listener)
{
BridgeConnector.Socket.Emit("registerHandleIpcMainChannel", channel);
BridgeConnector.Socket.On<JsonElement>(channel, (args) =>
{
Task.Run(async () =>
{
var arg = FormatArguments(args);
var result = await listener(arg);
BridgeConnector.Socket.Emit(channel + "Handle", result);
});
});
}
/// <summary>
/// Handles a single invokeable IPC message, then removes the listener.
/// See ipcMain.handle(channel, listener).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void HandleOnce(string channel, Func<object, object> listener)
{
BridgeConnector.Socket.Emit("registerHandleOnceIpcMainChannel", channel);
BridgeConnector.Socket.Once<JsonElement>(channel, (args) =>
{
var arg = FormatArguments(args);
var result = listener(arg);
BridgeConnector.Socket.Emit(channel + "HandleOnce", result);
});
}
/// <summary>
/// Handles a single invokeable IPC message, then removes the listener.
/// See ipcMain.handle(channel, listener).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void HandleOnce(string channel, Func<object, Task<object>> listener)
{
BridgeConnector.Socket.Emit("registerHandleOnceIpcMainChannel", channel);
BridgeConnector.Socket.Once<JsonElement>(channel, (args) =>
{
Task.Run(async () =>
{
var arg = FormatArguments(args);
var result = await listener(arg);
BridgeConnector.Socket.Emit(channel + "HandleOnce", result);
});
});
}
/// <summary>
/// Removes any handler for channel, if present.
/// </summary>
/// <param name="channel">Channelname.</param>
public void RemoveHandler(string channel)
{
BridgeConnector.Socket.Emit("removeHandlerIpcMainChannel", channel);
}
}
}

View File

@@ -130,11 +130,8 @@ namespace ElectronNET.API
options.Height += 7;
}
if (options.X == -1 && options.Y == -1)
if (!options.X.HasValue && !options.Y.HasValue)
{
options.X = 0;
options.Y = 0;
await BridgeConnector.Socket.Emit("createBrowserWindow", options, loadUrl).ConfigureAwait(false);
}
else

View File

@@ -2,9 +2,11 @@
// ReSharper disable once CheckNamespace
namespace ElectronNET.API
{
using ElectronNET.API.Bridge;
internal static class BridgeConnector
{
public static SocketIoFacade Socket
public static IFacade Socket
{
get
{

View File

@@ -0,0 +1,62 @@
namespace ElectronNET.API.Bridge
{
using System;
using System.Threading.Tasks;
/// <summary>
/// Common interface for communication facades (SocketIO and SignalR).
/// Provides methods for bidirectional communication between .NET and Electron.
/// </summary>
internal interface IFacade
{
/// <summary>
/// Raised when the bridge connection is established.
/// </summary>
event EventHandler BridgeConnected;
/// <summary>
/// Raised when the bridge connection is lost.
/// </summary>
event EventHandler BridgeDisconnected;
/// <summary>
/// Establishes the connection to Electron.
/// </summary>
void Connect();
/// <summary>
/// Registers a persistent event handler.
/// </summary>
void On(string eventName, Action action);
/// <summary>
/// Registers a persistent event handler with a typed parameter.
/// </summary>
void On<T>(string eventName, Action<T> action);
/// <summary>
/// Registers a one-time event handler.
/// </summary>
void Once(string eventName, Action action);
/// <summary>
/// Registers a one-time event handler with a typed parameter.
/// </summary>
void Once<T>(string eventName, Action<T> action);
/// <summary>
/// Removes an event handler.
/// </summary>
void Off(string eventName);
/// <summary>
/// Sends a message to Electron.
/// </summary>
Task Emit(string eventName, params object[] args);
/// <summary>
/// Disposes the connection.
/// </summary>
void DisposeSocket();
}
}

View File

@@ -4,11 +4,12 @@ namespace ElectronNET.API;
using System;
using System.Threading.Tasks;
using ElectronNET.API.Bridge;
using ElectronNET.API.Serialization;
using SocketIO.Serializer.SystemTextJson;
using SocketIO = SocketIOClient.SocketIO;
internal class SocketIoFacade
internal class SocketIoFacade : IFacade
{
private readonly SocketIO _socket;
private readonly object _lockObj = new object();

View File

@@ -14,6 +14,7 @@ namespace ElectronNET.Common
{
case StartupMethod.UnpackedElectronFirst:
case StartupMethod.UnpackedDotnetFirst:
case StartupMethod.UnpackedDotnetFirstSignalR:
return true;
default:
return false;

View File

@@ -1,6 +1,7 @@
namespace ElectronNET
{
using ElectronNET.API;
using ElectronNET.API.Bridge;
using ElectronNET.Runtime;
using ElectronNET.Runtime.Controllers;
using ElectronNET.Runtime.Data;
@@ -49,7 +50,7 @@
internal static Func<Task> OnAppReadyCallback { get; set; }
internal static SocketIoFacade GetSocket()
internal static IFacade GetSocket()
{
return RuntimeControllerCore?.Socket;
}

View File

@@ -1,6 +1,7 @@
namespace ElectronNET.Runtime.Controllers
{
using ElectronNET.API;
using ElectronNET.API.Bridge;
using ElectronNET.Runtime.Services;
using ElectronNET.Runtime.Services.ElectronProcess;
using ElectronNET.Runtime.Services.SocketBridge;
@@ -12,7 +13,7 @@
{
}
internal abstract SocketIoFacade Socket { get; }
internal abstract IFacade Socket { get; }
internal abstract ElectronProcessBase ElectronProcess { get; }

View File

@@ -1,6 +1,7 @@
namespace ElectronNET.Runtime.Controllers
{
using ElectronNET.API;
using ElectronNET.API.Bridge;
using ElectronNET.Common;
using ElectronNET.Runtime.Data;
using ElectronNET.Runtime.Helpers;
@@ -19,7 +20,7 @@
{
}
internal override SocketIoFacade Socket
internal override IFacade Socket
{
get
{

View File

@@ -33,5 +33,23 @@
/// On the command lines, this is "unpackeddotnet"
/// </remarks>
UnpackedDotnetFirst,
/// <summary>Packaged Electron app where DotNet launches Electron and uses SignalR for communication.</summary>
/// <remarks>
/// DotNet starts first on port 0 (dynamic), launches Electron with the actual URL,
/// and uses SignalR instead of socket.io for bidirectional communication.
/// Optimized for Blazor Server scenarios. ASP.NET Core only.
/// On the command lines, this is "dotnetpackedsignalr"
/// </remarks>
PackagedDotnetFirstSignalR,
/// <summary>Unpackaged execution where DotNet launches Electron and uses SignalR for communication.</summary>
/// <remarks>
/// Similar to PackagedDotnetFirstSignalR but for debugging scenarios.
/// DotNet starts first on port 0 (dynamic), launches Electron with the actual URL,
/// and uses SignalR instead of socket.io for bidirectional communication.
/// On the command lines, this is "unpackeddotnetsignalr"
/// </remarks>
UnpackedDotnetFirstSignalR,
}
}

View File

@@ -0,0 +1,18 @@
namespace ElectronNET.Runtime.Helpers
{
using System;
using System.Diagnostics;
/// <summary>
/// Helper class for debugger detection with lazy initialization.
/// </summary>
internal static class DebuggerHelper
{
/// <summary>
/// Gets whether a debugger is attached. This value is cached for performance.
/// </summary>
public static bool IsAttached => _isAttached.Value;
private static readonly Lazy<bool> _isAttached = new Lazy<bool>(() => Debugger.IsAttached);
}
}

View File

@@ -61,7 +61,7 @@
private static bool? CheckIsDotNetStartup3()
{
if (Debugger.IsAttached)
if (DebuggerHelper.IsAttached)
{
return true;
}

View File

@@ -63,13 +63,16 @@
private static bool? CheckUnpackaged2()
{
var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
var dir = new DirectoryInfo(baseDir);
if (dir.Name == "bin" && dir.Parent?.Name == "resources")
{
return false;
}
if (dir.GetDirectories().Any(e => e.Name == ".electron"))
// Faster: Direct path check instead of directory enumeration
if (Directory.Exists(Path.Combine(baseDir, ".electron")))
{
return true;
}
@@ -79,12 +82,11 @@
private static bool? CheckUnpackaged3()
{
if (Debugger.IsAttached)
if (DebuggerHelper.IsAttached)
{
return true;
}
return null;
}

View File

@@ -25,9 +25,7 @@
this.CollectProcessData();
this.SetElectronExecutable();
ElectronNetRuntime.StartupMethod = this.DetectAppTypeAndStartup();
Console.WriteLine((string)("Evaluated StartupMethod: " + ElectronNetRuntime.StartupMethod));
if (ElectronNetRuntime.DotnetAppType != DotnetAppType.AspNetCoreApp)
{
@@ -54,15 +52,19 @@
{
var isLaunchedByDotNet = LaunchOrderDetector.CheckIsLaunchedByDotNet();
var isUnPackaged = UnpackagedDetector.CheckIsUnpackaged();
// Check for SignalR mode via environment variable
var useSignalR = Environment.GetEnvironmentVariable("ELECTRON_USE_SIGNALR");
var isSignalRMode = !string.IsNullOrEmpty(useSignalR) && useSignalR.Equals("true", StringComparison.OrdinalIgnoreCase);
if (isLaunchedByDotNet)
{
if (isUnPackaged)
{
return StartupMethod.UnpackedDotnetFirst;
return isSignalRMode ? StartupMethod.UnpackedDotnetFirstSignalR : StartupMethod.UnpackedDotnetFirst;
}
return StartupMethod.PackagedDotnetFirst;
return isSignalRMode ? StartupMethod.PackagedDotnetFirstSignalR : StartupMethod.PackagedDotnetFirst;
}
else
{

View File

@@ -0,0 +1,24 @@
namespace ElectronNET.API
{
using ElectronNET.AspNet.Hubs;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
/// <summary>
/// Extension methods for mapping the Electron SignalR hub.
/// </summary>
public static class ElectronEndpointRouteBuilderExtensions
{
/// <summary>
/// Maps the Electron SignalR hub to the /electron-hub endpoint.
/// This is required when using SignalR-based startup modes.
/// </summary>
/// <param name="endpoints">The endpoint route builder.</param>
/// <returns>The endpoint route builder for chaining.</returns>
public static IEndpointRouteBuilder MapElectronHub(this IEndpointRouteBuilder endpoints)
{
endpoints.MapHub<ElectronHub>("/electron-hub");
return endpoints;
}
}
}

View File

@@ -10,6 +10,7 @@
using ElectronNET.Runtime.Helpers;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
/// <summary>
/// Provides extension methods for <see cref="IWebHostBuilder"/> to enable Electron.NET
@@ -66,23 +67,31 @@
// work as expected, see issue #952
Environment.SetEnvironmentVariable("ELECTRON_RUN_AS_NODE", null);
var webPort = PortHelper.GetFreePort(ElectronNetRuntime.AspNetWebPort ?? ElectronNetRuntime.DefaultWebPort);
// For SignalR modes, use port 0 for dynamic port assignment
var usePort0 = ElectronNetRuntime.StartupMethod == StartupMethod.PackagedDotnetFirstSignalR ||
ElectronNetRuntime.StartupMethod == StartupMethod.UnpackedDotnetFirstSignalR;
var webPort = usePort0 ? 0 : PortHelper.GetFreePort(ElectronNetRuntime.AspNetWebPort ?? ElectronNetRuntime.DefaultWebPort);
ElectronNetRuntime.AspNetWebPort = webPort;
// check for the content folder if its exists in base director otherwise no need to include
// It was used before because we are publishing the project which copies everything to bin folder and contentroot wwwroot was folder there.
// now we have implemented the live reload if app is run using /watch then we need to use the default project path.
// For port 0 (dynamic port assignment), Kestrel requires binding to specific IP (127.0.0.1) not localhost
var host = usePort0 ? "127.0.0.1" : "localhost";
if (Directory.Exists($"{AppDomain.CurrentDomain.BaseDirectory}\\wwwroot"))
{
builder = builder.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
.UseUrls("http://localhost:" + webPort);
.UseUrls($"http://{host}:{webPort}");
}
else
{
builder = builder.UseUrls("http://localhost:" + webPort);
builder = builder.UseUrls($"http://{host}:{webPort}");
}
builder = builder.ConfigureServices(services =>
builder = builder.ConfigureServices((context, services) =>
{
services.AddTransient<IStartupFilter, ServerReadyStartupFilter>();
services.AddSingleton<AspNetLifetimeAdapter>();
@@ -97,6 +106,17 @@
case StartupMethod.UnpackedDotnetFirst:
services.AddSingleton<IElectronNetRuntimeController, RuntimeControllerAspNetDotnetFirst>();
break;
case StartupMethod.PackagedDotnetFirstSignalR:
case StartupMethod.UnpackedDotnetFirstSignalR:
services.AddSignalR(options =>
{
// Enable detailed errors only in development for security
options.EnableDetailedErrors =
DebuggerHelper.IsAttached ||
context.HostingEnvironment.IsDevelopment();
});
services.AddSingleton<IElectronNetRuntimeController, RuntimeControllerAspNetDotnetFirstSignalR>();
break;
default:
throw new ArgumentOutOfRangeException();
}

View File

@@ -0,0 +1,232 @@
namespace ElectronNET.API
{
using System;
using System.Collections.Concurrent;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using ElectronNET.API.Bridge;
using ElectronNET.AspNet.Hubs;
/// <summary>
/// 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&lt;T&gt; 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
/// </summary>
internal class SignalRFacade : IFacade
{
private readonly IHubContext<ElectronHub> _hubContext;
private string _connectionId;
private readonly ConcurrentDictionary<string, Action<object>> _eventHandlers;
private readonly object _lockObj = new object();
public SignalRFacade(IHubContext<ElectronHub> hubContext)
{
_hubContext = hubContext;
_eventHandlers = new ConcurrentDictionary<string, Action<object>>();
}
public event EventHandler BridgeDisconnected;
public event EventHandler BridgeConnected;
/// <summary>
/// SignalR connections are managed by ASP.NET Core, so this is a no-op.
/// Connection establishment happens via the ElectronHub.
/// </summary>
public void Connect()
{
// No-op: SignalR connection is managed by ASP.NET Core
}
public void SetConnectionId(string connectionId)
{
_connectionId = connectionId;
this.BridgeConnected?.Invoke(this, EventArgs.Empty);
}
public void OnDisconnected()
{
this.BridgeDisconnected?.Invoke(this, EventArgs.Empty);
}
public void On(string eventName, Action action)
{
lock (_lockObj)
{
_eventHandlers[eventName] = _ => Task.Run(action);
}
}
public void On<T>(string eventName, Action<T> action)
{
lock (_lockObj)
{
_eventHandlers[eventName] = obj =>
{
var converted = ConvertToType<T>(obj);
if (converted != null)
{
Task.Run(() => action(converted));
}
else
{
Console.Error.WriteLine($"[SignalRFacade] Failed to convert event data to type {typeof(T).Name}");
}
};
}
}
public void Once(string eventName, Action action)
{
lock (_lockObj)
{
_eventHandlers[eventName] = _ =>
{
this.Off(eventName);
Task.Run(action);
};
}
}
public void Once<T>(string eventName, Action<T> action)
{
lock (_lockObj)
{
_eventHandlers[eventName] = obj =>
{
this.Off(eventName);
var converted = ConvertToType<T>(obj);
if (converted != null)
{
Task.Run(() => action(converted));
}
else
{
Console.Error.WriteLine($"[SignalRFacade] Failed to convert event data to type {typeof(T).Name} for event '{eventName}'");
}
};
}
}
public void Off(string eventName)
{
lock (_lockObj)
{
_eventHandlers.TryRemove(eventName, out _);
}
}
public async Task Emit(string eventName, params object[] args)
{
if (string.IsNullOrEmpty(_connectionId))
{
Console.Error.WriteLine($"[SignalRFacade] Cannot emit '{eventName}' - no connection ID");
return;
}
try
{
// Send message to specific Electron client via the 'event' hub method
// This will be received by signalr-bridge.js's connection.on('event', ...)
await _hubContext.Clients.Client(_connectionId).SendAsync("event", eventName, args);
}
catch (Exception ex)
{
Console.Error.WriteLine($"[SignalRFacade] Error emitting '{eventName}': {ex.Message}");
throw;
}
}
public void TriggerEvent(string eventName, params object[] args)
{
if (_eventHandlers.TryGetValue(eventName, out var handler))
{
// If single arg, pass it directly; otherwise pass the array
var data = args.Length == 1 ? args[0] : args;
handler(data);
}
}
/// <summary>
/// Converts an object to the specified type, handling JsonElement and numeric conversions.
/// </summary>
private static T ConvertToType<T>(object obj)
{
if (obj == null)
return default;
// Direct type match
if (obj is T typedValue)
return typedValue;
var targetType = typeof(T);
// Handle JsonElement (common from SignalR deserialization)
if (obj is JsonElement jsonElement)
{
try
{
return JsonSerializer.Deserialize<T>(jsonElement.GetRawText());
}
catch (Exception ex)
{
Console.Error.WriteLine($"[SignalRFacade] JsonElement deserialization failed: {ex.Message}");
return default;
}
}
// Handle numeric conversions (SignalR often sends numbers as long/double)
try
{
if (targetType == typeof(int) || targetType == typeof(int?))
{
return (T)(object)Convert.ToInt32(obj);
}
if (targetType == typeof(long) || targetType == typeof(long?))
{
return (T)(object)Convert.ToInt64(obj);
}
if (targetType == typeof(double) || targetType == typeof(double?))
{
return (T)(object)Convert.ToDouble(obj);
}
if (targetType == typeof(bool) || targetType == typeof(bool?))
{
return (T)(object)Convert.ToBoolean(obj);
}
if (targetType == typeof(string))
{
return (T)(object)obj.ToString();
}
// For arrays, try JSON serialization roundtrip
if (targetType.IsArray && obj is object[] arr)
{
var json = JsonSerializer.Serialize(arr);
return JsonSerializer.Deserialize<T>(json);
}
// Last resort: try to serialize and deserialize
var serialized = JsonSerializer.Serialize(obj);
return JsonSerializer.Deserialize<T>(serialized);
}
catch (Exception ex)
{
Console.Error.WriteLine($"[SignalRFacade] Type conversion failed from {obj.GetType().Name} to {targetType.Name}: {ex.Message}");
return default;
}
}
public void DisposeSocket()
{
// SignalR connections are managed by ASP.NET Core
_eventHandlers.Clear();
}
}
}

View File

@@ -0,0 +1,108 @@
namespace ElectronNET.AspNet.Hubs
{
using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
using ElectronNET;
using ElectronNET.API;
using ElectronNET.AspNet.Runtime;
using ElectronNET.Runtime;
/// <summary>
/// SignalR hub for bidirectional communication between ASP.NET Core and Electron.
/// Replaces socket.io for SignalR-based startup modes.
/// </summary>
public class ElectronHub : Hub
{
/// <summary>
/// Called when Electron client connects to the hub.
/// </summary>
public override async Task OnConnectedAsync()
{
// Notify the runtime controller about the connection
var runtimeController = ElectronNetRuntime.RuntimeController as RuntimeControllerAspNetDotnetFirstSignalR;
if (runtimeController != null)
{
runtimeController.OnSignalRConnected(Context.ConnectionId);
}
await base.OnConnectedAsync();
}
/// <summary>
/// Called when Electron client disconnects from the hub.
/// </summary>
public override async Task OnDisconnectedAsync(Exception exception)
{
if (exception != null)
{
Console.Error.WriteLine($"[ElectronHub] Disconnect error: {exception.Message}");
}
// Notify the runtime controller about the disconnection
var runtimeController = ElectronNetRuntime.RuntimeController as RuntimeControllerAspNetDotnetFirstSignalR;
if (runtimeController != null)
{
runtimeController.OnSignalRDisconnected();
}
await base.OnDisconnectedAsync(exception);
}
/// <summary>
/// Registers the Electron client. Called by Electron on connection.
/// </summary>
public async Task RegisterElectronClient()
{
await Task.CompletedTask;
}
/// <summary>
/// Receives events from Electron (e.g., "BrowserWindowCreated", "dialogResult").
/// Called by Electron to send data back to .NET.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="args">The event arguments as an array</param>
public async Task ElectronEvent(string eventName, object[] args)
{
// Get the SignalRFacade and trigger the event handlers
var runtimeController = ElectronNetRuntime.RuntimeController as RuntimeControllerAspNetDotnetFirstSignalR;
if (runtimeController?.SignalRSocket is SignalRFacade signalRFacade)
{
// Invoke the event handlers registered via On/Once
signalRFacade.TriggerEvent(eventName, args ?? Array.Empty<object>());
}
await Task.CompletedTask;
}
/// <summary>
/// Invokes an Electron API method. Called by .NET to control Electron.
/// This is a placeholder for future API invocation patterns.
/// </summary>
/// <param name="method">The API method name</param>
/// <param name="data">The method parameters as JSON</param>
/// <returns>The result of the API call</returns>
public async Task<string> InvokeElectronApi(string method, string data)
{
// Forward to Electron client
await Clients.Caller.SendAsync("electronApiCall", method, data);
// TODO: Implement proper request-response pattern
return null;
}
/// <summary>
/// Handles responses from Electron API calls.
/// This is a placeholder for future API invocation patterns.
/// </summary>
/// <param name="callId">The unique identifier for this API call</param>
/// <param name="result">The result data as JSON</param>
public async Task ElectronApiResponse(string callId, string result)
{
// This will be handled by the SignalR facade to complete pending tasks
await Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,103 @@
namespace ElectronNET.AspNet.Middleware
{
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using ElectronNET.AspNet.Services;
/// <summary>
/// Middleware that validates authentication for all Electron requests.
/// Checks for authentication cookie or token query parameter on first request.
/// Sets HttpOnly cookie for subsequent requests.
///
/// Security Model:
/// - First request includes token as query parameter (?token=guid)
/// - Middleware validates token and sets secure HttpOnly cookie
/// - Subsequent requests use cookie (no token in URL)
/// - Both HTTP endpoints and SignalR hub protected
/// </summary>
public class ElectronAuthenticationMiddleware
{
private readonly RequestDelegate _next;
private readonly IElectronAuthenticationService _authService;
private readonly ILogger<ElectronAuthenticationMiddleware> _logger;
private const string AuthCookieName = "ElectronAuth";
public ElectronAuthenticationMiddleware(
RequestDelegate next,
IElectronAuthenticationService authService,
ILogger<ElectronAuthenticationMiddleware> logger)
{
_next = next;
_authService = authService;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var path = context.Request.Path.Value;
// Check if authentication cookie exists
var authCookie = context.Request.Cookies[AuthCookieName];
if (!string.IsNullOrEmpty(authCookie))
{
// Cookie present - validate it
if (_authService.ValidateToken(authCookie))
{
await _next(context);
return;
}
else
{
// Invalid cookie - reject
_logger.LogWarning("Authentication failed: Invalid cookie for path {Path} from {RemoteIp}",
path, context.Connection.RemoteIpAddress);
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized: Invalid authentication");
return;
}
}
// No cookie - check for token in query string (first-time authentication)
var token = context.Request.Query["token"].ToString();
if (!string.IsNullOrEmpty(token))
{
if (_authService.ValidateToken(token))
{
// Valid token - set cookie for future requests
_logger.LogInformation("Authentication successful: Setting cookie for path {Path}", path);
context.Response.Cookies.Append(AuthCookieName, token, new CookieOptions
{
HttpOnly = true, // Prevent JavaScript access (XSS protection)
SameSite = SameSiteMode.Strict, // CSRF protection
Path = "/", // Valid for all routes
Secure = false, // False because localhost is HTTP
IsEssential = true // Required for app to function
});
await _next(context);
return;
}
else
{
// Invalid token - reject
_logger.LogWarning("Authentication failed: Invalid token (prefix: {TokenPrefix}...) for path {Path} from {RemoteIp}",
token.Length > 8 ? token.Substring(0, 8) : token, path, context.Connection.RemoteIpAddress);
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized: Invalid authentication");
return;
}
}
// Neither cookie nor valid token present - reject
_logger.LogWarning("Authentication failed: No cookie or token provided for path {Path} from {RemoteIp}",
path, context.Connection.RemoteIpAddress);
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized: Authentication required");
}
}
}

View File

@@ -3,6 +3,7 @@
using System;
using System.Threading.Tasks;
using ElectronNET.API;
using ElectronNET.API.Bridge;
using ElectronNET.Common;
using ElectronNET.Runtime.Controllers;
using ElectronNET.Runtime.Data;
@@ -25,7 +26,7 @@
internal override SocketBridgeService SocketBridge => this.socketBridge;
internal override SocketIoFacade Socket
internal override IFacade Socket
{
get
{

View File

@@ -0,0 +1,189 @@
namespace ElectronNET.AspNet.Runtime
{
using System;
using System.Linq;
using System.Threading.Tasks;
using ElectronNET.API;
using ElectronNET.API.Bridge;
using ElectronNET.Common;
using ElectronNET.Runtime.Data;
using ElectronNET.Runtime.Services.ElectronProcess;
using ElectronNET.Runtime.Services.SocketBridge;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.SignalR;
using ElectronNET.AspNet.Hubs;
using ElectronNET.AspNet.Services;
/// <summary>
/// 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
/// </summary>
internal class RuntimeControllerAspNetDotnetFirstSignalR : RuntimeControllerAspNetBase
{
private ElectronProcessBase electronProcess;
private readonly IServer server;
private readonly IHubContext<ElectronHub> hubContext;
private readonly IElectronAuthenticationService authenticationService;
private SignalRFacade signalRFacade;
private int? port;
private string actualUrl;
private bool electronLaunched;
private string authenticationToken;
public RuntimeControllerAspNetDotnetFirstSignalR(
AspNetLifetimeAdapter aspNetLifetimeAdapter,
IServer server,
IHubContext<ElectronHub> hubContext,
IElectronAuthenticationService authenticationService)
: base(aspNetLifetimeAdapter)
{
this.server = server;
this.hubContext = hubContext;
this.authenticationService = authenticationService;
this.signalRFacade = new SignalRFacade(hubContext);
this.electronLaunched = false;
this.signalRFacade.BridgeConnected += this.SignalRFacade_Connected;
this.signalRFacade.BridgeDisconnected += this.SignalRFacade_Disconnected;
// Subscribe to ASP.NET ready event to launch Electron
aspNetLifetimeAdapter.Ready += this.OnAspNetReady;
}
internal override ElectronProcessBase ElectronProcess => this.electronProcess;
internal override SocketBridgeService SocketBridge => null;
internal override IFacade Socket
{
get
{
if (this.State == LifetimeState.Ready)
{
return this.signalRFacade;
}
throw new Exception("Cannot access SignalR facade. Runtime is not in 'Ready' state");
}
}
internal SignalRFacade SignalRSocket => this.signalRFacade;
protected override Task StartCore()
{
return Task.CompletedTask;
}
protected override Task StopCore()
{
this.electronProcess?.Stop();
this.signalRFacade?.DisposeSocket();
return Task.CompletedTask;
}
private void OnAspNetReady(object sender, EventArgs e)
{
if (!this.electronLaunched)
{
this.CapturePortAndLaunchElectron();
}
}
private void CapturePortAndLaunchElectron()
{
var addresses = this.server.Features.Get<IServerAddressesFeature>();
if (addresses == null || !addresses.Addresses.Any())
{
throw new Exception("Could not retrieve server addresses");
}
this.actualUrl = addresses.Addresses.First();
this.port = new Uri(this.actualUrl).Port;
// Update the runtime port so WindowManager uses the correct URL
ElectronNetRuntime.AspNetWebPort = this.port;
this.LaunchElectron();
this.electronLaunched = true;
}
private void LaunchElectron()
{
// Generate secure authentication token (128-bit cryptographic random GUID)
// This token protects against unauthorized connections from other users on the same machine
this.authenticationToken = Guid.NewGuid().ToString("N"); // 32 hex chars, no hyphens
// Register token with authentication service for validation
// The middleware will validate this token on all HTTP and SignalR requests
this.authenticationService.SetExpectedToken(this.authenticationToken);
var isUnPacked = ElectronNetRuntime.StartupMethod.IsUnpackaged();
var flag = isUnPacked ? "--unpackeddotnetsignalr" : "--dotnetpackedsignalr";
var args = $"{flag} --electronurl={this.actualUrl} --authtoken={this.authenticationToken}";
this.electronProcess = new ElectronProcessActive(isUnPacked, ElectronNetRuntime.ElectronExecutable, args, this.port.Value);
// Note: We do NOT subscribe to electronProcess.Ready in SignalR mode.
// The "ready" signal comes from the SignalR connection, not stdout.
this.electronProcess.Stopped += this.ElectronProcess_Stopped;
_ = this.electronProcess.Start();
}
private async void SignalRFacade_Connected(object sender, EventArgs e)
{
// Register handler for 'electron-host-ready' signal from Electron.
// This ensures API modules are fully loaded before calling the app ready callback.
this.signalRFacade.Once("electron-host-ready", () =>
{
this.OnElectronHostReady();
});
}
private async void OnElectronHostReady()
{
this.TransitionState(LifetimeState.Ready);
// Execute the app ready callback
if (ElectronNetRuntime.OnAppReadyCallback != null)
{
try
{
await ElectronNetRuntime.OnAppReadyCallback().ConfigureAwait(false);
}
catch (Exception ex)
{
Console.Error.WriteLine($"Exception in app ready callback: {ex}");
this.Stop();
}
}
}
private void SignalRFacade_Disconnected(object sender, EventArgs e)
{
// IMPORTANT: Do NOT call HandleStopped synchronously here!
// This event fires from within SignalR's OnDisconnectedAsync, and calling
// StopApplication() synchronously causes a deadlock: the host waits for
// OnDisconnectedAsync to complete, but we're waiting for the host to stop.
// Fire and forget to break the deadlock.
_ = Task.Run(() => this.HandleStopped());
}
private void ElectronProcess_Stopped(object sender, EventArgs e)
{
this.HandleStopped();
}
public void OnSignalRConnected(string connectionId)
{
this.signalRFacade.SetConnectionId(connectionId);
}
public void OnSignalRDisconnected()
{
this.signalRFacade.OnDisconnected();
}
}
}

View File

@@ -0,0 +1,53 @@
namespace ElectronNET.AspNet.Services
{
/// <summary>
/// Implementation of authentication service for Electron clients.
/// Stores and validates the authentication token to ensure only the spawned Electron process can connect.
/// </summary>
public class ElectronAuthenticationService : IElectronAuthenticationService
{
private string _expectedToken;
private readonly object _lock = new object();
/// <inheritdoc />
public void SetExpectedToken(string token)
{
lock (_lock)
{
_expectedToken = token;
}
}
/// <inheritdoc />
public bool ValidateToken(string token)
{
if (string.IsNullOrEmpty(token))
return false;
lock (_lock)
{
if (string.IsNullOrEmpty(_expectedToken))
return false;
// Constant-time comparison to prevent timing attacks
return ConstantTimeEquals(token, _expectedToken);
}
}
/// <summary>
/// Performs constant-time string comparison to prevent timing attacks.
/// </summary>
private static bool ConstantTimeEquals(string a, string b)
{
if (a == null || b == null || a.Length != b.Length)
return false;
var result = 0;
for (int i = 0; i < a.Length; i++)
{
result |= a[i] ^ b[i];
}
return result == 0;
}
}
}

View File

@@ -0,0 +1,24 @@
namespace ElectronNET.AspNet.Services
{
/// <summary>
/// Service for validating authentication tokens from Electron clients.
/// Used to ensure only the Electron process spawned by this .NET instance can connect.
/// </summary>
public interface IElectronAuthenticationService
{
/// <summary>
/// Sets the expected authentication token for this instance.
/// Should be called when launching Electron with the generated token.
/// </summary>
/// <param name="token">The authentication token</param>
void SetExpectedToken(string token);
/// <summary>
/// Validates an incoming token against the expected token.
/// Uses constant-time comparison to prevent timing attacks.
/// </summary>
/// <param name="token">The token to validate</param>
/// <returns>True if token is valid, false otherwise</returns>
bool ValidateToken(string token);
}
}

View File

@@ -70,7 +70,7 @@
<ProjectReference Include="..\ElectronNET.API\ElectronNET.API.csproj" Condition="$(ElectronNetDevMode)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.4.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core" Version="0.4.1" Condition="'$(ElectronNetDevMode)' != 'true'" />
</ItemGroup>
<Import Project="..\ElectronNET\build\ElectronNET.Core.targets" Condition="$(ElectronNetDevMode)" />

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/1.0.4110890">
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/1.0.3864779">
<ItemGroup>
<None Include=".vscode\tasks.json" />
</ItemGroup>

View File

@@ -1,13 +1,14 @@
"use strict";
let isQuitWindowAllClosed = true, electronSocket;
let isQuitWindowAllClosed = true;
let electronSocket;
let appWindowAllClosedEventId;
module.exports = (socket, app) => {
electronSocket = socket;
// By default, quit when all windows are closed
app.on('window-all-closed', () => {
app.on("window-all-closed", () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin' && isQuitWindowAllClosed) {
if (process.platform !== "darwin" && isQuitWindowAllClosed) {
app.quit();
}
else if (appWindowAllClosedEventId) {
@@ -15,220 +16,224 @@ module.exports = (socket, app) => {
// - OR -
// If the user has indicated NOT to quit when all windows are closed,
// emit the event.
electronSocket.emit('app-window-all-closed' + appWindowAllClosedEventId);
electronSocket.emit("app-window-all-closed" + appWindowAllClosedEventId);
}
});
socket.on('quit-app-window-all-closed', (quit) => {
socket.on("quit-app-window-all-closed", (quit) => {
isQuitWindowAllClosed = quit;
});
socket.on('register-app-window-all-closed', (id) => {
socket.on("register-app-window-all-closed", (id) => {
appWindowAllClosedEventId = id;
});
socket.on('register-app-before-quit', (id) => {
app.on('before-quit', (event) => {
socket.on("register-app-before-quit", (id) => {
app.on("before-quit", (event) => {
event.preventDefault();
electronSocket.emit('app-before-quit' + id);
electronSocket.emit("app-before-quit" + id);
});
});
socket.on('register-app-will-quit', (id) => {
app.on('will-quit', (event) => {
socket.on("register-app-will-quit", (id) => {
app.on("will-quit", (event) => {
event.preventDefault();
electronSocket.emit('app-will-quit' + id);
electronSocket.emit("app-will-quit" + id);
});
});
socket.on('register-app-browser-window-blur', (id) => {
app.on('browser-window-blur', () => {
electronSocket.emit('app-browser-window-blur' + id);
socket.on("register-app-browser-window-blur", (id) => {
app.on("browser-window-blur", () => {
electronSocket.emit("app-browser-window-blur" + id);
});
});
socket.on('register-app-browser-window-focus', (id) => {
app.on('browser-window-focus', () => {
electronSocket.emit('app-browser-window-focus' + id);
socket.on("register-app-browser-window-focus", (id) => {
app.on("browser-window-focus", () => {
electronSocket.emit("app-browser-window-focus" + id);
});
});
socket.on('register-app-browser-window-created', (id) => {
app.on('browser-window-created', () => {
electronSocket.emit('app-browser-window-created' + id);
socket.on("register-app-browser-window-created", (id) => {
app.on("browser-window-created", () => {
electronSocket.emit("app-browser-window-created" + id);
});
});
socket.on('register-app-web-contents-created', (id) => {
app.on('web-contents-created', () => {
electronSocket.emit('app-web-contents-created' + id);
socket.on("register-app-web-contents-created", (id) => {
app.on("web-contents-created", () => {
electronSocket.emit("app-web-contents-created" + id);
});
});
socket.on('register-app-accessibility-support-changed', (id) => {
app.on('accessibility-support-changed', (event, accessibilitySupportEnabled) => {
electronSocket.emit('app-accessibility-support-changed' + id, accessibilitySupportEnabled);
socket.on("register-app-accessibility-support-changed", (id) => {
app.on("accessibility-support-changed", (event, accessibilitySupportEnabled) => {
electronSocket.emit("app-accessibility-support-changed" + id, accessibilitySupportEnabled);
});
});
socket.on('appQuit', () => {
socket.on("appQuit", () => {
app.quit();
});
socket.on('appExit', (exitCode = 0) => {
socket.on("appExit", (exitCode = 0) => {
app.exit(exitCode);
});
socket.on('appRelaunch', (options) => {
socket.on("appRelaunch", (options) => {
app.relaunch(options);
});
socket.on('appFocus', (options) => {
socket.on("appFocus", (options) => {
app.focus(options);
});
socket.on('appHide', () => {
socket.on("appHide", () => {
app.hide();
});
socket.on('appShow', () => {
socket.on("appShow", () => {
app.show();
});
socket.on('appGetAppPath', () => {
socket.on("appGetAppPath", () => {
const path = app.getAppPath();
electronSocket.emit('appGetAppPathCompleted', path);
electronSocket.emit("appGetAppPathCompleted", path);
});
socket.on('appSetAppLogsPath', (path) => {
socket.on("appSetAppLogsPath", (path) => {
app.setAppLogsPath(path);
});
socket.on('appGetPath', (name) => {
socket.on("appGetPath", (name) => {
const path = app.getPath(name);
electronSocket.emit('appGetPathCompleted', path);
electronSocket.emit("appGetPathCompleted", path);
});
socket.on('appGetFileIcon', async (path, options) => {
socket.on("appGetFileIcon", async (path, options) => {
let error = {};
if (options) {
const nativeImage = await app.getFileIcon(path, options).catch((errorFileIcon) => error = errorFileIcon);
electronSocket.emit('appGetFileIconCompleted', [error, nativeImage]);
const nativeImage = await app
.getFileIcon(path, options)
.catch((errorFileIcon) => (error = errorFileIcon));
electronSocket.emit("appGetFileIconCompleted", [error, nativeImage]);
}
else {
const nativeImage = await app.getFileIcon(path).catch((errorFileIcon) => error = errorFileIcon);
electronSocket.emit('appGetFileIconCompleted', [error, nativeImage]);
const nativeImage = await app
.getFileIcon(path)
.catch((errorFileIcon) => (error = errorFileIcon));
electronSocket.emit("appGetFileIconCompleted", [error, nativeImage]);
}
});
socket.on('appSetPath', (name, path) => {
socket.on("appSetPath", (name, path) => {
app.setPath(name, path);
});
socket.on('appGetVersion', () => {
socket.on("appGetVersion", () => {
const version = app.getVersion();
electronSocket.emit('appGetVersionCompleted', version);
electronSocket.emit("appGetVersionCompleted", version);
});
socket.on('appGetName', () => {
electronSocket.emit('appGetNameCompleted', app.name);
socket.on("appGetName", () => {
electronSocket.emit("appGetNameCompleted", app.name);
});
socket.on('appSetName', (name) => {
socket.on("appSetName", (name) => {
app.name = name;
});
socket.on('appGetLocale', () => {
socket.on("appGetLocale", () => {
const locale = app.getLocale();
electronSocket.emit('appGetLocaleCompleted', locale);
electronSocket.emit("appGetLocaleCompleted", locale);
});
socket.on('appAddRecentDocument', (path) => {
socket.on("appAddRecentDocument", (path) => {
app.addRecentDocument(path);
});
socket.on('appClearRecentDocuments', () => {
socket.on("appClearRecentDocuments", () => {
app.clearRecentDocuments();
});
socket.on('appSetAsDefaultProtocolClient', (protocol, path, args) => {
socket.on("appSetAsDefaultProtocolClient", (protocol, path, args) => {
const success = app.setAsDefaultProtocolClient(protocol, path, args);
electronSocket.emit('appSetAsDefaultProtocolClientCompleted', success);
electronSocket.emit("appSetAsDefaultProtocolClientCompleted", success);
});
socket.on('appRemoveAsDefaultProtocolClient', (protocol, path, args) => {
socket.on("appRemoveAsDefaultProtocolClient", (protocol, path, args) => {
const success = app.removeAsDefaultProtocolClient(protocol, path, args);
electronSocket.emit('appRemoveAsDefaultProtocolClientCompleted', success);
electronSocket.emit("appRemoveAsDefaultProtocolClientCompleted", success);
});
socket.on('appIsDefaultProtocolClient', (protocol, path, args) => {
socket.on("appIsDefaultProtocolClient", (protocol, path, args) => {
const success = app.isDefaultProtocolClient(protocol, path, args);
electronSocket.emit('appIsDefaultProtocolClientCompleted', success);
electronSocket.emit("appIsDefaultProtocolClientCompleted", success);
});
socket.on('appSetUserTasks', (tasks) => {
socket.on("appSetUserTasks", (tasks) => {
const success = app.setUserTasks(tasks);
electronSocket.emit('appSetUserTasksCompleted', success);
electronSocket.emit("appSetUserTasksCompleted", success);
});
socket.on('appGetJumpListSettings', () => {
socket.on("appGetJumpListSettings", () => {
const jumpListSettings = app.getJumpListSettings();
electronSocket.emit('appGetJumpListSettingsCompleted', jumpListSettings);
electronSocket.emit("appGetJumpListSettingsCompleted", jumpListSettings);
});
socket.on('appSetJumpList', (categories) => {
socket.on("appSetJumpList", (categories) => {
app.setJumpList(categories);
});
socket.on('appRequestSingleInstanceLock', () => {
socket.on("appRequestSingleInstanceLock", () => {
const success = app.requestSingleInstanceLock();
electronSocket.emit('appRequestSingleInstanceLockCompleted', success);
app.on('second-instance', (event, args = [], workingDirectory = '') => {
electronSocket.emit('secondInstance', [args, workingDirectory]);
electronSocket.emit("appRequestSingleInstanceLockCompleted", success);
app.on("second-instance", (event, args = [], workingDirectory = "") => {
electronSocket.emit("secondInstance", [args, workingDirectory]);
});
});
socket.on('appHasSingleInstanceLock', () => {
socket.on("appHasSingleInstanceLock", () => {
const hasLock = app.hasSingleInstanceLock();
electronSocket.emit('appHasSingleInstanceLockCompleted', hasLock);
electronSocket.emit("appHasSingleInstanceLockCompleted", hasLock);
});
socket.on('appReleaseSingleInstanceLock', () => {
socket.on("appReleaseSingleInstanceLock", () => {
app.releaseSingleInstanceLock();
});
socket.on('appSetUserActivity', (type, userInfo, webpageUrl) => {
socket.on("appSetUserActivity", (type, userInfo, webpageUrl) => {
app.setUserActivity(type, userInfo, webpageUrl);
});
socket.on('appGetCurrentActivityType', () => {
socket.on("appGetCurrentActivityType", () => {
const activityType = app.getCurrentActivityType();
electronSocket.emit('appGetCurrentActivityTypeCompleted', activityType);
electronSocket.emit("appGetCurrentActivityTypeCompleted", activityType);
});
socket.on('appInvalidateCurrentActivity', () => {
socket.on("appInvalidateCurrentActivity", () => {
app.invalidateCurrentActivity();
});
socket.on('appResignCurrentActivity', () => {
socket.on("appResignCurrentActivity", () => {
app.resignCurrentActivity();
});
socket.on('appSetAppUserModelId', (id) => {
socket.on("appSetAppUserModelId", (id) => {
app.setAppUserModelId(id);
});
socket.on('appImportCertificate', (options) => {
socket.on("appImportCertificate", (options) => {
app.importCertificate(options, (result) => {
electronSocket.emit('appImportCertificateCompleted', result);
electronSocket.emit("appImportCertificateCompleted", result);
});
});
socket.on('appGetAppMetrics', () => {
socket.on("appGetAppMetrics", () => {
const processMetrics = app.getAppMetrics();
electronSocket.emit('appGetAppMetricsCompleted', processMetrics);
electronSocket.emit("appGetAppMetricsCompleted", processMetrics);
});
socket.on('appGetGpuFeatureStatus', () => {
socket.on("appGetGpuFeatureStatus", () => {
const gpuFeatureStatus = app.getGPUFeatureStatus();
electronSocket.emit('appGetGpuFeatureStatusCompleted', gpuFeatureStatus);
electronSocket.emit("appGetGpuFeatureStatusCompleted", gpuFeatureStatus);
});
socket.on('appSetBadgeCount', (count) => {
socket.on("appSetBadgeCount", (count) => {
const success = app.setBadgeCount(count);
electronSocket.emit('appSetBadgeCountCompleted', success);
electronSocket.emit("appSetBadgeCountCompleted", success);
});
socket.on('appGetBadgeCount', () => {
socket.on("appGetBadgeCount", () => {
const count = app.getBadgeCount();
electronSocket.emit('appGetBadgeCountCompleted', count);
electronSocket.emit("appGetBadgeCountCompleted", count);
});
socket.on('appIsUnityRunning', () => {
socket.on("appIsUnityRunning", () => {
const isUnityRunning = app.isUnityRunning();
electronSocket.emit('appIsUnityRunningCompleted', isUnityRunning);
electronSocket.emit("appIsUnityRunningCompleted", isUnityRunning);
});
socket.on('appGetLoginItemSettings', (options) => {
socket.on("appGetLoginItemSettings", (options) => {
const loginItemSettings = app.getLoginItemSettings(options);
electronSocket.emit('appGetLoginItemSettingsCompleted', loginItemSettings);
electronSocket.emit("appGetLoginItemSettingsCompleted", loginItemSettings);
});
socket.on('appSetLoginItemSettings', (settings) => {
socket.on("appSetLoginItemSettings", (settings) => {
app.setLoginItemSettings(settings);
});
socket.on('appIsAccessibilitySupportEnabled', () => {
socket.on("appIsAccessibilitySupportEnabled", () => {
const isAccessibilitySupportEnabled = app.isAccessibilitySupportEnabled();
electronSocket.emit('appIsAccessibilitySupportEnabledCompleted', isAccessibilitySupportEnabled);
electronSocket.emit("appIsAccessibilitySupportEnabledCompleted", isAccessibilitySupportEnabled);
});
socket.on('appSetAccessibilitySupportEnabled', (enabled) => {
socket.on("appSetAccessibilitySupportEnabled", (enabled) => {
app.setAccessibilitySupportEnabled(enabled);
});
socket.on('appShowAboutPanel', () => {
socket.on("appShowAboutPanel", () => {
app.showAboutPanel();
});
socket.on('appSetAboutPanelOptions', (options) => {
socket.on("appSetAboutPanelOptions", (options) => {
app.setAboutPanelOptions(options);
});
socket.on('appGetUserAgentFallback', () => {
electronSocket.emit('appGetUserAgentFallbackCompleted', app.userAgentFallback);
socket.on("appGetUserAgentFallback", () => {
electronSocket.emit("appGetUserAgentFallbackCompleted", app.userAgentFallback);
});
socket.on('appSetUserAgentFallback', (userAgent) => {
socket.on("appSetUserAgentFallback", (userAgent) => {
app.userAgentFallback = userAgent;
});
socket.on('register-app-on-event', (eventName, listenerName) => {
socket.on("register-app-on-event", (eventName, listenerName) => {
app.on(eventName, (...args) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
@@ -238,7 +243,7 @@ module.exports = (socket, app) => {
}
});
});
socket.on('register-app-once-event', (eventName, listenerName) => {
socket.on("register-app-once-event", (eventName, listenerName) => {
app.once(eventName, (...args) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);

File diff suppressed because one or more lines are too long

View File

@@ -1,313 +1,338 @@
import { RelaunchOptions, LoginItemSettingsOptions, Settings, AboutPanelOptionsOptions } from "electron";
import { Socket } from "net";
import type { Socket } from "net";
import {
RelaunchOptions,
LoginItemSettingsOptions,
Settings,
AboutPanelOptionsOptions,
} from "electron";
let isQuitWindowAllClosed = true;
let electronSocket: Socket;
let appWindowAllClosedEventId: string;
let isQuitWindowAllClosed = true, electronSocket;
let appWindowAllClosedEventId;
export = (socket: Socket, app: Electron.App) => {
electronSocket = socket;
electronSocket = socket;
// By default, quit when all windows are closed
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin' && isQuitWindowAllClosed) {
app.quit();
} else if (appWindowAllClosedEventId) {
// If the user is on macOS
// - OR -
// If the user has indicated NOT to quit when all windows are closed,
// emit the event.
electronSocket.emit('app-window-all-closed' + appWindowAllClosedEventId);
}
// By default, quit when all windows are closed
app.on("window-all-closed", () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== "darwin" && isQuitWindowAllClosed) {
app.quit();
} else if (appWindowAllClosedEventId) {
// If the user is on macOS
// - OR -
// If the user has indicated NOT to quit when all windows are closed,
// emit the event.
electronSocket.emit("app-window-all-closed" + appWindowAllClosedEventId);
}
});
socket.on("quit-app-window-all-closed", (quit) => {
isQuitWindowAllClosed = quit;
});
socket.on("register-app-window-all-closed", (id) => {
appWindowAllClosedEventId = id;
});
socket.on("register-app-before-quit", (id) => {
app.on("before-quit", (event) => {
event.preventDefault();
electronSocket.emit("app-before-quit" + id);
});
});
socket.on('quit-app-window-all-closed', (quit) => {
isQuitWindowAllClosed = quit;
socket.on("register-app-will-quit", (id) => {
app.on("will-quit", (event) => {
event.preventDefault();
electronSocket.emit("app-will-quit" + id);
});
});
socket.on('register-app-window-all-closed', (id) => {
appWindowAllClosedEventId = id;
socket.on("register-app-browser-window-blur", (id) => {
app.on("browser-window-blur", () => {
electronSocket.emit("app-browser-window-blur" + id);
});
});
socket.on('register-app-before-quit', (id) => {
app.on('before-quit', (event) => {
event.preventDefault();
electronSocket.emit('app-before-quit' + id);
});
socket.on("register-app-browser-window-focus", (id) => {
app.on("browser-window-focus", () => {
electronSocket.emit("app-browser-window-focus" + id);
});
});
socket.on('register-app-will-quit', (id) => {
app.on('will-quit', (event) => {
event.preventDefault();
electronSocket.emit('app-will-quit' + id);
});
socket.on("register-app-browser-window-created", (id) => {
app.on("browser-window-created", () => {
electronSocket.emit("app-browser-window-created" + id);
});
});
socket.on('register-app-browser-window-blur', (id) => {
app.on('browser-window-blur', () => {
electronSocket.emit('app-browser-window-blur' + id);
});
socket.on("register-app-web-contents-created", (id) => {
app.on("web-contents-created", () => {
electronSocket.emit("app-web-contents-created" + id);
});
});
socket.on('register-app-browser-window-focus', (id) => {
app.on('browser-window-focus', () => {
electronSocket.emit('app-browser-window-focus' + id);
});
socket.on("register-app-accessibility-support-changed", (id) => {
app.on(
"accessibility-support-changed",
(event, accessibilitySupportEnabled) => {
electronSocket.emit(
"app-accessibility-support-changed" + id,
accessibilitySupportEnabled,
);
},
);
});
socket.on("appQuit", () => {
app.quit();
});
socket.on("appExit", (exitCode = 0) => {
app.exit(exitCode);
});
socket.on("appRelaunch", (options) => {
app.relaunch(options as RelaunchOptions);
});
socket.on("appFocus", (options) => {
app.focus(options);
});
socket.on("appHide", () => {
app.hide();
});
socket.on("appShow", () => {
app.show();
});
socket.on("appGetAppPath", () => {
const path = app.getAppPath();
electronSocket.emit("appGetAppPathCompleted", path);
});
socket.on("appSetAppLogsPath", (path) => {
app.setAppLogsPath(path);
});
socket.on("appGetPath", (name) => {
const path = app.getPath(name);
electronSocket.emit("appGetPathCompleted", path);
});
socket.on("appGetFileIcon", async (path, options) => {
let error = {};
if (options) {
const nativeImage = await app
.getFileIcon(path, options)
.catch((errorFileIcon) => (error = errorFileIcon));
electronSocket.emit("appGetFileIconCompleted", [error, nativeImage]);
} else {
const nativeImage = await app
.getFileIcon(path)
.catch((errorFileIcon) => (error = errorFileIcon));
electronSocket.emit("appGetFileIconCompleted", [error, nativeImage]);
}
});
socket.on("appSetPath", (name, path) => {
app.setPath(name, path);
});
socket.on("appGetVersion", () => {
const version = app.getVersion();
electronSocket.emit("appGetVersionCompleted", version);
});
socket.on("appGetName", () => {
electronSocket.emit("appGetNameCompleted", app.name);
});
socket.on("appSetName", (name) => {
app.name = name;
});
socket.on("appGetLocale", () => {
const locale = app.getLocale();
electronSocket.emit("appGetLocaleCompleted", locale);
});
socket.on("appAddRecentDocument", (path) => {
app.addRecentDocument(path);
});
socket.on("appClearRecentDocuments", () => {
app.clearRecentDocuments();
});
socket.on("appSetAsDefaultProtocolClient", (protocol, path, args) => {
const success = app.setAsDefaultProtocolClient(protocol, path, args);
electronSocket.emit("appSetAsDefaultProtocolClientCompleted", success);
});
socket.on("appRemoveAsDefaultProtocolClient", (protocol, path, args) => {
const success = app.removeAsDefaultProtocolClient(protocol, path, args);
electronSocket.emit("appRemoveAsDefaultProtocolClientCompleted", success);
});
socket.on("appIsDefaultProtocolClient", (protocol, path, args) => {
const success = app.isDefaultProtocolClient(protocol, path, args);
electronSocket.emit("appIsDefaultProtocolClientCompleted", success);
});
socket.on("appSetUserTasks", (tasks) => {
const success = app.setUserTasks(tasks);
electronSocket.emit("appSetUserTasksCompleted", success);
});
socket.on("appGetJumpListSettings", () => {
const jumpListSettings = app.getJumpListSettings();
electronSocket.emit("appGetJumpListSettingsCompleted", jumpListSettings);
});
socket.on("appSetJumpList", (categories) => {
app.setJumpList(categories);
});
socket.on("appRequestSingleInstanceLock", () => {
const success = app.requestSingleInstanceLock();
electronSocket.emit("appRequestSingleInstanceLockCompleted", success);
app.on("second-instance", (event, args = [], workingDirectory = "") => {
electronSocket.emit("secondInstance", [args, workingDirectory]);
});
});
socket.on('register-app-browser-window-created', (id) => {
app.on('browser-window-created', () => {
electronSocket.emit('app-browser-window-created' + id);
});
socket.on("appHasSingleInstanceLock", () => {
const hasLock = app.hasSingleInstanceLock();
electronSocket.emit("appHasSingleInstanceLockCompleted", hasLock);
});
socket.on("appReleaseSingleInstanceLock", () => {
app.releaseSingleInstanceLock();
});
socket.on("appSetUserActivity", (type, userInfo, webpageUrl) => {
app.setUserActivity(type, userInfo, webpageUrl);
});
socket.on("appGetCurrentActivityType", () => {
const activityType = app.getCurrentActivityType();
electronSocket.emit("appGetCurrentActivityTypeCompleted", activityType);
});
socket.on("appInvalidateCurrentActivity", () => {
app.invalidateCurrentActivity();
});
socket.on("appResignCurrentActivity", () => {
app.resignCurrentActivity();
});
socket.on("appSetAppUserModelId", (id) => {
app.setAppUserModelId(id);
});
socket.on("appImportCertificate", (options) => {
app.importCertificate(options, (result) => {
electronSocket.emit("appImportCertificateCompleted", result);
});
});
socket.on('register-app-web-contents-created', (id) => {
app.on('web-contents-created', () => {
electronSocket.emit('app-web-contents-created' + id);
});
socket.on("appGetAppMetrics", () => {
const processMetrics = app.getAppMetrics();
electronSocket.emit("appGetAppMetricsCompleted", processMetrics);
});
socket.on("appGetGpuFeatureStatus", () => {
const gpuFeatureStatus = app.getGPUFeatureStatus();
electronSocket.emit("appGetGpuFeatureStatusCompleted", gpuFeatureStatus);
});
socket.on("appSetBadgeCount", (count) => {
const success = app.setBadgeCount(count);
electronSocket.emit("appSetBadgeCountCompleted", success);
});
socket.on("appGetBadgeCount", () => {
const count = app.getBadgeCount();
electronSocket.emit("appGetBadgeCountCompleted", count);
});
socket.on("appIsUnityRunning", () => {
const isUnityRunning = app.isUnityRunning();
electronSocket.emit("appIsUnityRunningCompleted", isUnityRunning);
});
socket.on("appGetLoginItemSettings", (options) => {
const loginItemSettings = app.getLoginItemSettings(
options as LoginItemSettingsOptions,
);
electronSocket.emit("appGetLoginItemSettingsCompleted", loginItemSettings);
});
socket.on("appSetLoginItemSettings", (settings) => {
app.setLoginItemSettings(settings as Settings);
});
socket.on("appIsAccessibilitySupportEnabled", () => {
const isAccessibilitySupportEnabled = app.isAccessibilitySupportEnabled();
electronSocket.emit(
"appIsAccessibilitySupportEnabledCompleted",
isAccessibilitySupportEnabled,
);
});
socket.on("appSetAccessibilitySupportEnabled", (enabled) => {
app.setAccessibilitySupportEnabled(enabled);
});
socket.on("appShowAboutPanel", () => {
app.showAboutPanel();
});
socket.on("appSetAboutPanelOptions", (options) => {
app.setAboutPanelOptions(options as AboutPanelOptionsOptions);
});
socket.on("appGetUserAgentFallback", () => {
electronSocket.emit(
"appGetUserAgentFallbackCompleted",
app.userAgentFallback,
);
});
socket.on("appSetUserAgentFallback", (userAgent) => {
app.userAgentFallback = userAgent;
});
socket.on("register-app-on-event", (eventName, listenerName) => {
app.on(eventName, (...args) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
} else {
electronSocket.emit(listenerName);
}
});
});
socket.on('register-app-accessibility-support-changed', (id) => {
app.on('accessibility-support-changed', (event, accessibilitySupportEnabled) => {
electronSocket.emit('app-accessibility-support-changed' + id, accessibilitySupportEnabled);
});
});
socket.on('appQuit', () => {
app.quit();
});
socket.on('appExit', (exitCode = 0) => {
app.exit(exitCode);
});
socket.on('appRelaunch', (options) => {
app.relaunch(options as RelaunchOptions);
});
socket.on('appFocus', (options) => {
app.focus(options);
});
socket.on('appHide', () => {
app.hide();
});
socket.on('appShow', () => {
app.show();
});
socket.on('appGetAppPath', () => {
const path = app.getAppPath();
electronSocket.emit('appGetAppPathCompleted', path);
});
socket.on('appSetAppLogsPath', (path) => {
app.setAppLogsPath(path);
});
socket.on('appGetPath', (name) => {
const path = app.getPath(name);
electronSocket.emit('appGetPathCompleted', path);
});
socket.on('appGetFileIcon', async (path, options) => {
let error = {};
if (options) {
const nativeImage = await app.getFileIcon(path, options).catch((errorFileIcon) => error = errorFileIcon);
electronSocket.emit('appGetFileIconCompleted', [error, nativeImage]);
} else {
const nativeImage = await app.getFileIcon(path).catch((errorFileIcon) => error = errorFileIcon);
electronSocket.emit('appGetFileIconCompleted', [error, nativeImage]);
}
});
socket.on('appSetPath', (name, path) => {
app.setPath(name, path);
});
socket.on('appGetVersion', () => {
const version = app.getVersion();
electronSocket.emit('appGetVersionCompleted', version);
});
socket.on('appGetName', () => {
electronSocket.emit('appGetNameCompleted', app.name);
});
socket.on('appSetName', (name) => {
app.name = name;
});
socket.on('appGetLocale', () => {
const locale = app.getLocale();
electronSocket.emit('appGetLocaleCompleted', locale);
});
socket.on('appAddRecentDocument', (path) => {
app.addRecentDocument(path);
});
socket.on('appClearRecentDocuments', () => {
app.clearRecentDocuments();
});
socket.on('appSetAsDefaultProtocolClient', (protocol, path, args) => {
const success = app.setAsDefaultProtocolClient(protocol, path, args);
electronSocket.emit('appSetAsDefaultProtocolClientCompleted', success);
});
socket.on('appRemoveAsDefaultProtocolClient', (protocol, path, args) => {
const success = app.removeAsDefaultProtocolClient(protocol, path, args);
electronSocket.emit('appRemoveAsDefaultProtocolClientCompleted', success);
});
socket.on('appIsDefaultProtocolClient', (protocol, path, args) => {
const success = app.isDefaultProtocolClient(protocol, path, args);
electronSocket.emit('appIsDefaultProtocolClientCompleted', success);
});
socket.on('appSetUserTasks', (tasks) => {
const success = app.setUserTasks(tasks);
electronSocket.emit('appSetUserTasksCompleted', success);
});
socket.on('appGetJumpListSettings', () => {
const jumpListSettings = app.getJumpListSettings();
electronSocket.emit('appGetJumpListSettingsCompleted', jumpListSettings);
});
socket.on('appSetJumpList', (categories) => {
app.setJumpList(categories);
});
socket.on('appRequestSingleInstanceLock', () => {
const success = app.requestSingleInstanceLock();
electronSocket.emit('appRequestSingleInstanceLockCompleted', success);
app.on('second-instance', (event, args = [], workingDirectory = '') => {
electronSocket.emit('secondInstance', [args, workingDirectory]);
});
});
socket.on('appHasSingleInstanceLock', () => {
const hasLock = app.hasSingleInstanceLock();
electronSocket.emit('appHasSingleInstanceLockCompleted', hasLock);
});
socket.on('appReleaseSingleInstanceLock', () => {
app.releaseSingleInstanceLock();
});
socket.on('appSetUserActivity', (type, userInfo, webpageUrl) => {
app.setUserActivity(type, userInfo, webpageUrl);
});
socket.on('appGetCurrentActivityType', () => {
const activityType = app.getCurrentActivityType();
electronSocket.emit('appGetCurrentActivityTypeCompleted', activityType);
});
socket.on('appInvalidateCurrentActivity', () => {
app.invalidateCurrentActivity();
});
socket.on('appResignCurrentActivity', () => {
app.resignCurrentActivity();
});
socket.on('appSetAppUserModelId', (id) => {
app.setAppUserModelId(id);
});
socket.on('appImportCertificate', (options) => {
app.importCertificate(options, (result) => {
electronSocket.emit('appImportCertificateCompleted', result);
});
});
socket.on('appGetAppMetrics', () => {
const processMetrics = app.getAppMetrics();
electronSocket.emit('appGetAppMetricsCompleted', processMetrics);
});
socket.on('appGetGpuFeatureStatus', () => {
const gpuFeatureStatus = app.getGPUFeatureStatus();
electronSocket.emit('appGetGpuFeatureStatusCompleted', gpuFeatureStatus);
});
socket.on('appSetBadgeCount', (count) => {
const success = app.setBadgeCount(count);
electronSocket.emit('appSetBadgeCountCompleted', success);
});
socket.on('appGetBadgeCount', () => {
const count = app.getBadgeCount();
electronSocket.emit('appGetBadgeCountCompleted', count);
});
socket.on('appIsUnityRunning', () => {
const isUnityRunning = app.isUnityRunning();
electronSocket.emit('appIsUnityRunningCompleted', isUnityRunning);
});
socket.on('appGetLoginItemSettings', (options) => {
const loginItemSettings = app.getLoginItemSettings(options as LoginItemSettingsOptions);
electronSocket.emit('appGetLoginItemSettingsCompleted', loginItemSettings);
});
socket.on('appSetLoginItemSettings', (settings) => {
app.setLoginItemSettings(settings as Settings);
});
socket.on('appIsAccessibilitySupportEnabled', () => {
const isAccessibilitySupportEnabled = app.isAccessibilitySupportEnabled();
electronSocket.emit('appIsAccessibilitySupportEnabledCompleted', isAccessibilitySupportEnabled);
});
socket.on('appSetAccessibilitySupportEnabled', (enabled) => {
app.setAccessibilitySupportEnabled(enabled);
});
socket.on('appShowAboutPanel', () => {
app.showAboutPanel();
});
socket.on('appSetAboutPanelOptions', (options) => {
app.setAboutPanelOptions(options as AboutPanelOptionsOptions);
});
socket.on('appGetUserAgentFallback', () => {
electronSocket.emit('appGetUserAgentFallbackCompleted', app.userAgentFallback);
});
socket.on('appSetUserAgentFallback', (userAgent) => {
app.userAgentFallback = userAgent;
});
socket.on('register-app-on-event', (eventName, listenerName) => {
app.on(eventName, (...args) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
} else {
electronSocket.emit(listenerName);
}
});
});
socket.on('register-app-once-event', (eventName, listenerName) => {
app.once(eventName, (...args) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
} else {
electronSocket.emit(listenerName);
}
});
socket.on("register-app-once-event", (eventName, listenerName) => {
app.once(eventName, (...args) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
} else {
electronSocket.emit(listenerName);
}
});
});
};

View File

@@ -3,112 +3,118 @@ const electron_updater_1 = require("electron-updater");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('register-autoUpdater-error', (id) => {
electron_updater_1.autoUpdater.on('error', (error) => {
electronSocket.emit('autoUpdater-error' + id, error.message);
socket.on("register-autoUpdater-error", (id) => {
electron_updater_1.autoUpdater.on("error", (error) => {
electronSocket.emit("autoUpdater-error" + id, error.message);
});
});
socket.on('register-autoUpdater-checking-for-update', (id) => {
electron_updater_1.autoUpdater.on('checking-for-update', () => {
electronSocket.emit('autoUpdater-checking-for-update' + id);
socket.on("register-autoUpdater-checking-for-update", (id) => {
electron_updater_1.autoUpdater.on("checking-for-update", () => {
electronSocket.emit("autoUpdater-checking-for-update" + id);
});
});
socket.on('register-autoUpdater-update-available', (id) => {
electron_updater_1.autoUpdater.on('update-available', (updateInfo) => {
electronSocket.emit('autoUpdater-update-available' + id, updateInfo);
socket.on("register-autoUpdater-update-available", (id) => {
electron_updater_1.autoUpdater.on("update-available", (updateInfo) => {
electronSocket.emit("autoUpdater-update-available" + id, updateInfo);
});
});
socket.on('register-autoUpdater-update-not-available', (id) => {
electron_updater_1.autoUpdater.on('update-not-available', (updateInfo) => {
electronSocket.emit('autoUpdater-update-not-available' + id, updateInfo);
socket.on("register-autoUpdater-update-not-available", (id) => {
electron_updater_1.autoUpdater.on("update-not-available", (updateInfo) => {
electronSocket.emit("autoUpdater-update-not-available" + id, updateInfo);
});
});
socket.on('register-autoUpdater-download-progress', (id) => {
electron_updater_1.autoUpdater.on('download-progress', (progressInfo) => {
electronSocket.emit('autoUpdater-download-progress' + id, progressInfo);
socket.on("register-autoUpdater-download-progress", (id) => {
electron_updater_1.autoUpdater.on("download-progress", (progressInfo) => {
electronSocket.emit("autoUpdater-download-progress" + id, progressInfo);
});
});
socket.on('register-autoUpdater-update-downloaded', (id) => {
electron_updater_1.autoUpdater.on('update-downloaded', (updateInfo) => {
electronSocket.emit('autoUpdater-update-downloaded' + id, updateInfo);
socket.on("register-autoUpdater-update-downloaded", (id) => {
electron_updater_1.autoUpdater.on("update-downloaded", (updateInfo) => {
electronSocket.emit("autoUpdater-update-downloaded" + id, updateInfo);
});
});
// Properties *****
socket.on('autoUpdater-autoDownload', () => {
electronSocket.emit('autoUpdater-autoDownload-completed', electron_updater_1.autoUpdater.autoDownload);
socket.on("autoUpdater-autoDownload", () => {
electronSocket.emit("autoUpdater-autoDownload-completed", electron_updater_1.autoUpdater.autoDownload);
});
socket.on('autoUpdater-autoDownload-set', (value) => {
socket.on("autoUpdater-autoDownload-set", (value) => {
electron_updater_1.autoUpdater.autoDownload = value;
});
socket.on('autoUpdater-autoInstallOnAppQuit', () => {
electronSocket.emit('autoUpdater-autoInstallOnAppQuit-completed', electron_updater_1.autoUpdater.autoInstallOnAppQuit);
socket.on("autoUpdater-autoInstallOnAppQuit", () => {
electronSocket.emit("autoUpdater-autoInstallOnAppQuit-completed", electron_updater_1.autoUpdater.autoInstallOnAppQuit);
});
socket.on('autoUpdater-autoInstallOnAppQuit-set', (value) => {
socket.on("autoUpdater-autoInstallOnAppQuit-set", (value) => {
electron_updater_1.autoUpdater.autoInstallOnAppQuit = value;
});
socket.on('autoUpdater-allowPrerelease', () => {
electronSocket.emit('autoUpdater-allowPrerelease-completed', electron_updater_1.autoUpdater.allowPrerelease);
socket.on("autoUpdater-allowPrerelease", () => {
electronSocket.emit("autoUpdater-allowPrerelease-completed", electron_updater_1.autoUpdater.allowPrerelease);
});
socket.on('autoUpdater-allowPrerelease-set', (value) => {
socket.on("autoUpdater-allowPrerelease-set", (value) => {
electron_updater_1.autoUpdater.allowPrerelease = value;
});
socket.on('autoUpdater-fullChangelog', () => {
electronSocket.emit('autoUpdater-fullChangelog-completed', electron_updater_1.autoUpdater.fullChangelog);
socket.on("autoUpdater-fullChangelog", () => {
electronSocket.emit("autoUpdater-fullChangelog-completed", electron_updater_1.autoUpdater.fullChangelog);
});
socket.on('autoUpdater-fullChangelog-set', (value) => {
socket.on("autoUpdater-fullChangelog-set", (value) => {
electron_updater_1.autoUpdater.fullChangelog = value;
});
socket.on('autoUpdater-allowDowngrade', () => {
electronSocket.emit('autoUpdater-allowDowngrade-completed', electron_updater_1.autoUpdater.allowDowngrade);
socket.on("autoUpdater-allowDowngrade", () => {
electronSocket.emit("autoUpdater-allowDowngrade-completed", electron_updater_1.autoUpdater.allowDowngrade);
});
socket.on('autoUpdater-allowDowngrade-set', (value) => {
socket.on("autoUpdater-allowDowngrade-set", (value) => {
electron_updater_1.autoUpdater.allowDowngrade = value;
});
socket.on('autoUpdater-updateConfigPath', () => {
electronSocket.emit('autoUpdater-updateConfigPath-completed', electron_updater_1.autoUpdater.updateConfigPath || '');
socket.on("autoUpdater-updateConfigPath", () => {
electronSocket.emit("autoUpdater-updateConfigPath-completed", electron_updater_1.autoUpdater.updateConfigPath || "");
});
socket.on('autoUpdater-updateConfigPath-set', (value) => {
socket.on("autoUpdater-updateConfigPath-set", (value) => {
electron_updater_1.autoUpdater.updateConfigPath = value;
});
socket.on('autoUpdater-currentVersion', () => {
electronSocket.emit('autoUpdater-currentVersion-completed', electron_updater_1.autoUpdater.currentVersion);
socket.on("autoUpdater-currentVersion", () => {
electronSocket.emit("autoUpdater-currentVersion-completed", electron_updater_1.autoUpdater.currentVersion);
});
socket.on('autoUpdater-channel', () => {
electronSocket.emit('autoUpdater-channel-completed', electron_updater_1.autoUpdater.channel || '');
socket.on("autoUpdater-channel", () => {
electronSocket.emit("autoUpdater-channel-completed", electron_updater_1.autoUpdater.channel || "");
});
socket.on('autoUpdater-channel-set', (value) => {
socket.on("autoUpdater-channel-set", (value) => {
electron_updater_1.autoUpdater.channel = value;
});
socket.on('autoUpdater-requestHeaders', () => {
electronSocket.emit('autoUpdater-requestHeaders-completed', electron_updater_1.autoUpdater.requestHeaders);
socket.on("autoUpdater-requestHeaders", () => {
electronSocket.emit("autoUpdater-requestHeaders-completed", electron_updater_1.autoUpdater.requestHeaders);
});
socket.on('autoUpdater-requestHeaders-set', (value) => {
socket.on("autoUpdater-requestHeaders-set", (value) => {
electron_updater_1.autoUpdater.requestHeaders = value;
});
socket.on('autoUpdater-checkForUpdatesAndNotify', async (guid) => {
electron_updater_1.autoUpdater.checkForUpdatesAndNotify().then((updateCheckResult) => {
electronSocket.emit('autoUpdater-checkForUpdatesAndNotify-completed' + guid, updateCheckResult);
}).catch((error) => {
electronSocket.emit('autoUpdater-checkForUpdatesAndNotifyError' + guid, error);
socket.on("autoUpdater-checkForUpdatesAndNotify", async (guid) => {
electron_updater_1.autoUpdater
.checkForUpdatesAndNotify()
.then((updateCheckResult) => {
electronSocket.emit("autoUpdater-checkForUpdatesAndNotify-completed" + guid, updateCheckResult);
})
.catch((error) => {
electronSocket.emit("autoUpdater-checkForUpdatesAndNotifyError" + guid, error);
});
});
socket.on('autoUpdater-checkForUpdates', async (guid) => {
electron_updater_1.autoUpdater.checkForUpdates().then((updateCheckResult) => {
electronSocket.emit('autoUpdater-checkForUpdates-completed' + guid, updateCheckResult);
}).catch((error) => {
electronSocket.emit('autoUpdater-checkForUpdatesError' + guid, error);
socket.on("autoUpdater-checkForUpdates", async (guid) => {
electron_updater_1.autoUpdater
.checkForUpdates()
.then((updateCheckResult) => {
electronSocket.emit("autoUpdater-checkForUpdates-completed" + guid, updateCheckResult);
})
.catch((error) => {
electronSocket.emit("autoUpdater-checkForUpdatesError" + guid, error);
});
});
socket.on('autoUpdater-quitAndInstall', async (isSilent, isForceRunAfter) => {
socket.on("autoUpdater-quitAndInstall", async (isSilent, isForceRunAfter) => {
electron_updater_1.autoUpdater.quitAndInstall(isSilent, isForceRunAfter);
});
socket.on('autoUpdater-downloadUpdate', async (guid) => {
socket.on("autoUpdater-downloadUpdate", async (guid) => {
const downloadedPath = await electron_updater_1.autoUpdater.downloadUpdate();
electronSocket.emit('autoUpdater-downloadUpdate-completed' + guid, downloadedPath);
electronSocket.emit("autoUpdater-downloadUpdate-completed" + guid, downloadedPath);
});
socket.on('autoUpdater-getFeedURL', async (guid) => {
socket.on("autoUpdater-getFeedURL", async (guid) => {
const feedUrl = await electron_updater_1.autoUpdater.getFeedURL();
electronSocket.emit('autoUpdater-getFeedURL-completed' + guid, feedUrl || '');
electronSocket.emit("autoUpdater-getFeedURL-completed" + guid, feedUrl || "");
});
};
//# sourceMappingURL=autoUpdater.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"autoUpdater.js","sourceRoot":"","sources":["autoUpdater.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"autoUpdater.js","sourceRoot":"","sources":["autoUpdater.ts"],"names":[],"mappings":";AACA,uDAA+C;AAE/C,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IAC1B,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,CAAC,EAAE,EAAE,EAAE;QAC7C,8BAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAChC,cAAc,CAAC,IAAI,CAAC,mBAAmB,GAAG,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,0CAA0C,EAAE,CAAC,EAAE,EAAE,EAAE;QAC3D,8BAAW,CAAC,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;YACzC,cAAc,CAAC,IAAI,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,uCAAuC,EAAE,CAAC,EAAE,EAAE,EAAE;QACxD,8BAAW,CAAC,EAAE,CAAC,kBAAkB,EAAE,CAAC,UAAU,EAAE,EAAE;YAChD,cAAc,CAAC,IAAI,CAAC,8BAA8B,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2CAA2C,EAAE,CAAC,EAAE,EAAE,EAAE;QAC5D,8BAAW,CAAC,EAAE,CAAC,sBAAsB,EAAE,CAAC,UAAU,EAAE,EAAE;YACpD,cAAc,CAAC,IAAI,CAAC,kCAAkC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,wCAAwC,EAAE,CAAC,EAAE,EAAE,EAAE;QACzD,8BAAW,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,YAAY,EAAE,EAAE;YACnD,cAAc,CAAC,IAAI,CAAC,+BAA+B,GAAG,EAAE,EAAE,YAAY,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,wCAAwC,EAAE,CAAC,EAAE,EAAE,EAAE;QACzD,8BAAW,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,UAAU,EAAE,EAAE;YACjD,cAAc,CAAC,IAAI,CAAC,+BAA+B,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,mBAAmB;IAEnB,MAAM,CAAC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACzC,cAAc,CAAC,IAAI,CACjB,oCAAoC,EACpC,8BAAW,CAAC,YAAY,CACzB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC,KAAK,EAAE,EAAE;QAClD,8BAAW,CAAC,YAAY,GAAG,KAAK,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QACjD,cAAc,CAAC,IAAI,CACjB,4CAA4C,EAC5C,8BAAW,CAAC,oBAAoB,CACjC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,sCAAsC,EAAE,CAAC,KAAK,EAAE,EAAE;QAC1D,8BAAW,CAAC,oBAAoB,GAAG,KAAK,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QAC5C,cAAc,CAAC,IAAI,CACjB,uCAAuC,EACvC,8BAAW,CAAC,eAAe,CAC5B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,iCAAiC,EAAE,CAAC,KAAK,EAAE,EAAE;QACrD,8BAAW,CAAC,eAAe,GAAG,KAAK,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QAC1C,cAAc,CAAC,IAAI,CACjB,qCAAqC,EACrC,8BAAW,CAAC,aAAa,CAC1B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,CAAC,KAAK,EAAE,EAAE;QACnD,8BAAW,CAAC,aAAa,GAAG,KAAK,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAC3C,cAAc,CAAC,IAAI,CACjB,sCAAsC,EACtC,8BAAW,CAAC,cAAc,CAC3B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gCAAgC,EAAE,CAAC,KAAK,EAAE,EAAE;QACpD,8BAAW,CAAC,cAAc,GAAG,KAAK,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC7C,cAAc,CAAC,IAAI,CACjB,wCAAwC,EACxC,8BAAW,CAAC,gBAAgB,IAAI,EAAE,CACnC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,kCAAkC,EAAE,CAAC,KAAK,EAAE,EAAE;QACtD,8BAAW,CAAC,gBAAgB,GAAG,KAAK,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAC3C,cAAc,CAAC,IAAI,CACjB,sCAAsC,EACtC,8BAAW,CAAC,cAAc,CAC3B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACpC,cAAc,CAAC,IAAI,CACjB,+BAA+B,EAC/B,8BAAW,CAAC,OAAO,IAAI,EAAE,CAC1B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,KAAK,EAAE,EAAE;QAC7C,8BAAW,CAAC,OAAO,GAAG,KAAK,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAC3C,cAAc,CAAC,IAAI,CACjB,sCAAsC,EACtC,8BAAW,CAAC,cAAc,CAC3B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gCAAgC,EAAE,CAAC,KAAK,EAAE,EAAE;QACpD,8BAAW,CAAC,cAAc,GAAG,KAAK,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,sCAAsC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC/D,8BAAW;aACR,wBAAwB,EAAE;aAC1B,IAAI,CAAC,CAAC,iBAAiB,EAAE,EAAE;YAC1B,cAAc,CAAC,IAAI,CACjB,gDAAgD,GAAG,IAAI,EACvD,iBAAiB,CAClB,CAAC;QACJ,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,cAAc,CAAC,IAAI,CACjB,2CAA2C,GAAG,IAAI,EAClD,KAAK,CACN,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,6BAA6B,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACtD,8BAAW;aACR,eAAe,EAAE;aACjB,IAAI,CAAC,CAAC,iBAAiB,EAAE,EAAE;YAC1B,cAAc,CAAC,IAAI,CACjB,uCAAuC,GAAG,IAAI,EAC9C,iBAAiB,CAClB,CAAC;QACJ,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,cAAc,CAAC,IAAI,CAAC,kCAAkC,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,EAAE;QAC1E,8BAAW,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,cAAc,GAAG,MAAM,8BAAW,CAAC,cAAc,EAAE,CAAC;QAC1D,cAAc,CAAC,IAAI,CACjB,sCAAsC,GAAG,IAAI,EAC7C,cAAc,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,wBAAwB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,MAAM,8BAAW,CAAC,UAAU,EAAE,CAAC;QAC/C,cAAc,CAAC,IAAI,CACjB,kCAAkC,GAAG,IAAI,EACzC,OAAO,IAAI,EAAE,CACd,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}

View File

@@ -1,143 +1,192 @@
import { Socket } from 'net';
import { autoUpdater } from 'electron-updater';
let electronSocket;
import type { Socket } from "net";
import { autoUpdater } from "electron-updater";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
electronSocket = socket;
socket.on('register-autoUpdater-error', (id) => {
autoUpdater.on('error', (error) => {
electronSocket.emit('autoUpdater-error' + id, error.message);
});
socket.on("register-autoUpdater-error", (id) => {
autoUpdater.on("error", (error) => {
electronSocket.emit("autoUpdater-error" + id, error.message);
});
});
socket.on('register-autoUpdater-checking-for-update', (id) => {
autoUpdater.on('checking-for-update', () => {
electronSocket.emit('autoUpdater-checking-for-update' + id);
});
socket.on("register-autoUpdater-checking-for-update", (id) => {
autoUpdater.on("checking-for-update", () => {
electronSocket.emit("autoUpdater-checking-for-update" + id);
});
});
socket.on('register-autoUpdater-update-available', (id) => {
autoUpdater.on('update-available', (updateInfo) => {
electronSocket.emit('autoUpdater-update-available' + id, updateInfo);
});
socket.on("register-autoUpdater-update-available", (id) => {
autoUpdater.on("update-available", (updateInfo) => {
electronSocket.emit("autoUpdater-update-available" + id, updateInfo);
});
});
socket.on('register-autoUpdater-update-not-available', (id) => {
autoUpdater.on('update-not-available', (updateInfo) => {
electronSocket.emit('autoUpdater-update-not-available' + id, updateInfo);
});
socket.on("register-autoUpdater-update-not-available", (id) => {
autoUpdater.on("update-not-available", (updateInfo) => {
electronSocket.emit("autoUpdater-update-not-available" + id, updateInfo);
});
});
socket.on('register-autoUpdater-download-progress', (id) => {
autoUpdater.on('download-progress', (progressInfo) => {
electronSocket.emit('autoUpdater-download-progress' + id, progressInfo);
});
socket.on("register-autoUpdater-download-progress", (id) => {
autoUpdater.on("download-progress", (progressInfo) => {
electronSocket.emit("autoUpdater-download-progress" + id, progressInfo);
});
});
socket.on('register-autoUpdater-update-downloaded', (id) => {
autoUpdater.on('update-downloaded', (updateInfo) => {
electronSocket.emit('autoUpdater-update-downloaded' + id, updateInfo);
});
socket.on("register-autoUpdater-update-downloaded", (id) => {
autoUpdater.on("update-downloaded", (updateInfo) => {
electronSocket.emit("autoUpdater-update-downloaded" + id, updateInfo);
});
});
// Properties *****
// Properties *****
socket.on('autoUpdater-autoDownload', () => {
electronSocket.emit('autoUpdater-autoDownload-completed', autoUpdater.autoDownload);
});
socket.on("autoUpdater-autoDownload", () => {
electronSocket.emit(
"autoUpdater-autoDownload-completed",
autoUpdater.autoDownload,
);
});
socket.on('autoUpdater-autoDownload-set', (value) => {
autoUpdater.autoDownload = value;
});
socket.on("autoUpdater-autoDownload-set", (value) => {
autoUpdater.autoDownload = value;
});
socket.on('autoUpdater-autoInstallOnAppQuit', () => {
electronSocket.emit('autoUpdater-autoInstallOnAppQuit-completed', autoUpdater.autoInstallOnAppQuit);
});
socket.on("autoUpdater-autoInstallOnAppQuit", () => {
electronSocket.emit(
"autoUpdater-autoInstallOnAppQuit-completed",
autoUpdater.autoInstallOnAppQuit,
);
});
socket.on('autoUpdater-autoInstallOnAppQuit-set', (value) => {
autoUpdater.autoInstallOnAppQuit = value;
});
socket.on("autoUpdater-autoInstallOnAppQuit-set", (value) => {
autoUpdater.autoInstallOnAppQuit = value;
});
socket.on('autoUpdater-allowPrerelease', () => {
electronSocket.emit('autoUpdater-allowPrerelease-completed', autoUpdater.allowPrerelease);
});
socket.on("autoUpdater-allowPrerelease", () => {
electronSocket.emit(
"autoUpdater-allowPrerelease-completed",
autoUpdater.allowPrerelease,
);
});
socket.on('autoUpdater-allowPrerelease-set', (value) => {
autoUpdater.allowPrerelease = value;
});
socket.on("autoUpdater-allowPrerelease-set", (value) => {
autoUpdater.allowPrerelease = value;
});
socket.on('autoUpdater-fullChangelog', () => {
electronSocket.emit('autoUpdater-fullChangelog-completed', autoUpdater.fullChangelog);
});
socket.on("autoUpdater-fullChangelog", () => {
electronSocket.emit(
"autoUpdater-fullChangelog-completed",
autoUpdater.fullChangelog,
);
});
socket.on('autoUpdater-fullChangelog-set', (value) => {
autoUpdater.fullChangelog = value;
});
socket.on("autoUpdater-fullChangelog-set", (value) => {
autoUpdater.fullChangelog = value;
});
socket.on('autoUpdater-allowDowngrade', () => {
electronSocket.emit('autoUpdater-allowDowngrade-completed', autoUpdater.allowDowngrade);
});
socket.on("autoUpdater-allowDowngrade", () => {
electronSocket.emit(
"autoUpdater-allowDowngrade-completed",
autoUpdater.allowDowngrade,
);
});
socket.on('autoUpdater-allowDowngrade-set', (value) => {
autoUpdater.allowDowngrade = value;
});
socket.on("autoUpdater-allowDowngrade-set", (value) => {
autoUpdater.allowDowngrade = value;
});
socket.on('autoUpdater-updateConfigPath', () => {
electronSocket.emit('autoUpdater-updateConfigPath-completed', autoUpdater.updateConfigPath || '');
});
socket.on("autoUpdater-updateConfigPath", () => {
electronSocket.emit(
"autoUpdater-updateConfigPath-completed",
autoUpdater.updateConfigPath || "",
);
});
socket.on('autoUpdater-updateConfigPath-set', (value) => {
autoUpdater.updateConfigPath = value;
});
socket.on("autoUpdater-updateConfigPath-set", (value) => {
autoUpdater.updateConfigPath = value;
});
socket.on('autoUpdater-currentVersion', () => {
electronSocket.emit('autoUpdater-currentVersion-completed', autoUpdater.currentVersion);
});
socket.on("autoUpdater-currentVersion", () => {
electronSocket.emit(
"autoUpdater-currentVersion-completed",
autoUpdater.currentVersion,
);
});
socket.on('autoUpdater-channel', () => {
electronSocket.emit('autoUpdater-channel-completed', autoUpdater.channel || '');
});
socket.on("autoUpdater-channel", () => {
electronSocket.emit(
"autoUpdater-channel-completed",
autoUpdater.channel || "",
);
});
socket.on('autoUpdater-channel-set', (value) => {
autoUpdater.channel = value;
});
socket.on("autoUpdater-channel-set", (value) => {
autoUpdater.channel = value;
});
socket.on('autoUpdater-requestHeaders', () => {
electronSocket.emit('autoUpdater-requestHeaders-completed', autoUpdater.requestHeaders);
});
socket.on("autoUpdater-requestHeaders", () => {
electronSocket.emit(
"autoUpdater-requestHeaders-completed",
autoUpdater.requestHeaders,
);
});
socket.on('autoUpdater-requestHeaders-set', (value) => {
autoUpdater.requestHeaders = value;
});
socket.on("autoUpdater-requestHeaders-set", (value) => {
autoUpdater.requestHeaders = value;
});
socket.on('autoUpdater-checkForUpdatesAndNotify', async (guid) => {
autoUpdater.checkForUpdatesAndNotify().then((updateCheckResult) => {
electronSocket.emit('autoUpdater-checkForUpdatesAndNotify-completed' + guid, updateCheckResult);
}).catch((error) => {
electronSocket.emit('autoUpdater-checkForUpdatesAndNotifyError' + guid, error);
});
});
socket.on("autoUpdater-checkForUpdatesAndNotify", async (guid) => {
autoUpdater
.checkForUpdatesAndNotify()
.then((updateCheckResult) => {
electronSocket.emit(
"autoUpdater-checkForUpdatesAndNotify-completed" + guid,
updateCheckResult,
);
})
.catch((error) => {
electronSocket.emit(
"autoUpdater-checkForUpdatesAndNotifyError" + guid,
error,
);
});
});
socket.on('autoUpdater-checkForUpdates', async (guid) => {
autoUpdater.checkForUpdates().then((updateCheckResult) => {
electronSocket.emit('autoUpdater-checkForUpdates-completed' + guid, updateCheckResult);
}).catch((error) => {
electronSocket.emit('autoUpdater-checkForUpdatesError' + guid, error);
});
});
socket.on("autoUpdater-checkForUpdates", async (guid) => {
autoUpdater
.checkForUpdates()
.then((updateCheckResult) => {
electronSocket.emit(
"autoUpdater-checkForUpdates-completed" + guid,
updateCheckResult,
);
})
.catch((error) => {
electronSocket.emit("autoUpdater-checkForUpdatesError" + guid, error);
});
});
socket.on('autoUpdater-quitAndInstall', async (isSilent, isForceRunAfter) => {
autoUpdater.quitAndInstall(isSilent, isForceRunAfter);
});
socket.on("autoUpdater-quitAndInstall", async (isSilent, isForceRunAfter) => {
autoUpdater.quitAndInstall(isSilent, isForceRunAfter);
});
socket.on('autoUpdater-downloadUpdate', async (guid) => {
const downloadedPath = await autoUpdater.downloadUpdate();
electronSocket.emit('autoUpdater-downloadUpdate-completed' + guid, downloadedPath);
});
socket.on("autoUpdater-downloadUpdate", async (guid) => {
const downloadedPath = await autoUpdater.downloadUpdate();
electronSocket.emit(
"autoUpdater-downloadUpdate-completed" + guid,
downloadedPath,
);
});
socket.on('autoUpdater-getFeedURL', async (guid) => {
const feedUrl = await autoUpdater.getFeedURL();
electronSocket.emit('autoUpdater-getFeedURL-completed' + guid, feedUrl || '');
});
socket.on("autoUpdater-getFeedURL", async (guid) => {
const feedUrl = await autoUpdater.getFeedURL();
electronSocket.emit(
"autoUpdater-getFeedURL-completed" + guid,
feedUrl || "",
);
});
};

View File

@@ -2,17 +2,22 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.browserViewMediateService = exports.browserViewApi = void 0;
const electron_1 = require("electron");
const browserViews = (global['browserViews'] = global['browserViews'] || []);
let browserView, electronSocket;
const proxyToCredentialsMap = (global['proxyToCredentialsMap'] = global['proxyToCredentialsMap'] || []);
const browserViews = (global["browserViews"] =
global["browserViews"] || []);
const proxyToCredentialsMap = (global["proxyToCredentialsMap"] = global["proxyToCredentialsMap"] || []);
let browserView;
let electronSocket;
const browserViewApi = (socket) => {
electronSocket = socket;
socket.on('createBrowserView', (options) => {
if (!hasOwnChildreen(options, 'webPreferences', 'nodeIntegration')) {
options = { ...options, webPreferences: { nodeIntegration: true, contextIsolation: false } };
socket.on("createBrowserView", (options) => {
if (!hasOwnChildreen(options, "webPreferences", "nodeIntegration")) {
options = {
...options,
webPreferences: { nodeIntegration: true, contextIsolation: false },
};
}
browserView = new electron_1.BrowserView(options);
browserView['id'] = browserViews.length + 1;
browserView["id"] = browserViews.length + 1;
if (options.proxy) {
browserView.webContents.session.setProxy({ proxyRules: options.proxy });
}
@@ -20,19 +25,19 @@ const browserViewApi = (socket) => {
proxyToCredentialsMap[options.proxy] = options.proxyCredentials;
}
browserViews.push(browserView);
electronSocket.emit('BrowserViewCreated', browserView['id']);
electronSocket.emit("BrowserViewCreated", browserView["id"]);
});
socket.on('browserView-bounds', (id) => {
socket.on("browserView-bounds", (id) => {
const bounds = getBrowserViewById(id).getBounds();
electronSocket.emit('browserView-bounds-completed', bounds);
electronSocket.emit("browserView-bounds-completed", bounds);
});
socket.on('browserView-bounds-set', (id, bounds) => {
socket.on("browserView-bounds-set", (id, bounds) => {
getBrowserViewById(id).setBounds(bounds);
});
socket.on('browserView-setAutoResize', (id, options) => {
socket.on("browserView-setAutoResize", (id, options) => {
getBrowserViewById(id).setAutoResize(options);
});
socket.on('browserView-setBackgroundColor', (id, color) => {
socket.on("browserView-setBackgroundColor", (id, color) => {
getBrowserViewById(id).setBackgroundColor(color);
});
function hasOwnChildreen(obj, ...childNames) {
@@ -53,7 +58,7 @@ exports.browserViewMediateService = browserViewMediateService;
function getBrowserViewById(id) {
for (let index = 0; index < browserViews.length; index++) {
const browserViewItem = browserViews[index];
if (browserViewItem['id'] === id) {
if (browserViewItem["id"] === id) {
return browserViewItem;
}
}

View File

@@ -1 +1 @@
{"version":3,"file":"browserView.js","sourceRoot":"","sources":["browserView.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"browserView.js","sourceRoot":"","sources":["browserView.ts"],"names":[],"mappings":"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"}

View File

@@ -1,74 +1,83 @@
import { Socket } from 'net';
import { BrowserView } from 'electron';
const browserViews: BrowserView[] = (global['browserViews'] = global['browserViews'] || []) as BrowserView[];
let browserView: BrowserView, electronSocket;
const proxyToCredentialsMap: { [proxy: string]: string } = (global['proxyToCredentialsMap'] = global['proxyToCredentialsMap'] || []) as { [proxy: string]: string };
import type { Socket } from "net";
import { BrowserView } from "electron";
const browserViews: BrowserView[] = (global["browserViews"] =
global["browserViews"] || []) as BrowserView[];
const proxyToCredentialsMap: { [proxy: string]: string } = (global[
"proxyToCredentialsMap"
] = global["proxyToCredentialsMap"] || []) as { [proxy: string]: string };
let browserView: BrowserView;
let electronSocket: Socket;
const browserViewApi = (socket: Socket) => {
electronSocket = socket;
electronSocket = socket;
socket.on('createBrowserView', (options) => {
if (!hasOwnChildreen(options, 'webPreferences', 'nodeIntegration')) {
options = { ...options, webPreferences: { nodeIntegration: true, contextIsolation: false } };
}
browserView = new BrowserView(options);
browserView['id'] = browserViews.length + 1;
if (options.proxy) {
browserView.webContents.session.setProxy({proxyRules: options.proxy});
}
if (options.proxy && options.proxyCredentials) {
proxyToCredentialsMap[options.proxy] = options.proxyCredentials;
}
browserViews.push(browserView);
electronSocket.emit('BrowserViewCreated', browserView['id']);
});
socket.on('browserView-bounds', (id) => {
const bounds = getBrowserViewById(id).getBounds();
electronSocket.emit('browserView-bounds-completed', bounds);
});
socket.on('browserView-bounds-set', (id, bounds) => {
getBrowserViewById(id).setBounds(bounds);
});
socket.on('browserView-setAutoResize', (id, options) => {
getBrowserViewById(id).setAutoResize(options);
});
socket.on('browserView-setBackgroundColor', (id, color) => {
getBrowserViewById(id).setBackgroundColor(color);
});
function hasOwnChildreen(obj, ...childNames) {
for (let i = 0; i < childNames.length; i++) {
if (!obj || !obj.hasOwnProperty(childNames[i])) {
return false;
}
obj = obj[childNames[i]];
}
return true;
socket.on("createBrowserView", (options) => {
if (!hasOwnChildreen(options, "webPreferences", "nodeIntegration")) {
options = {
...options,
webPreferences: { nodeIntegration: true, contextIsolation: false },
};
}
browserView = new BrowserView(options);
browserView["id"] = browserViews.length + 1;
if (options.proxy) {
browserView.webContents.session.setProxy({ proxyRules: options.proxy });
}
if (options.proxy && options.proxyCredentials) {
proxyToCredentialsMap[options.proxy] = options.proxyCredentials;
}
browserViews.push(browserView);
electronSocket.emit("BrowserViewCreated", browserView["id"]);
});
socket.on("browserView-bounds", (id) => {
const bounds = getBrowserViewById(id).getBounds();
electronSocket.emit("browserView-bounds-completed", bounds);
});
socket.on("browserView-bounds-set", (id, bounds) => {
getBrowserViewById(id).setBounds(bounds);
});
socket.on("browserView-setAutoResize", (id, options) => {
getBrowserViewById(id).setAutoResize(options);
});
socket.on("browserView-setBackgroundColor", (id, color) => {
getBrowserViewById(id).setBackgroundColor(color);
});
function hasOwnChildreen(obj, ...childNames) {
for (let i = 0; i < childNames.length; i++) {
if (!obj || !obj.hasOwnProperty(childNames[i])) {
return false;
}
obj = obj[childNames[i]];
}
return true;
}
};
const browserViewMediateService = (browserViewId: number): BrowserView => {
return getBrowserViewById(browserViewId);
return getBrowserViewById(browserViewId);
};
function getBrowserViewById(id: number) {
for (let index = 0; index < browserViews.length; index++) {
const browserViewItem = browserViews[index];
if (browserViewItem['id'] === id) {
return browserViewItem;
}
for (let index = 0; index < browserViews.length; index++) {
const browserViewItem = browserViews[index];
if (browserViewItem["id"] === id) {
return browserViewItem;
}
}
}
export { browserViewApi, browserViewMediateService };

View File

@@ -1,12 +1,46 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
const path = __importStar(require("path"));
const electron_1 = require("electron");
const browserView_1 = require("./browserView");
const path = require("path");
const windows = (global["browserWindows"] =
global["browserWindows"] || []);
let readyToShowWindowsIds = [];
let window, lastOptions, electronSocket;
let mainWindowURL;
let window;
let lastOptions;
let electronSocket;
const proxyToCredentialsMap = (global["proxyToCredentialsMap"] = global["proxyToCredentialsMap"] || []);
module.exports = (socket, app) => {
electronSocket = socket;
@@ -112,6 +146,12 @@ module.exports = (socket, app) => {
electronSocket.emit("browserWindow-move" + id);
});
});
socket.on("register-browserWindow-bounds-changed", (id) => {
const window = getWindowById(id);
const cb = () => electronSocket.emit("browserWindow-bounds-changed" + id, window.getBounds());
window.on("resize", cb);
window.on("move", cb);
});
socket.on("register-browserWindow-moved", (id) => {
getWindowById(id).on("moved", () => {
electronSocket.emit("browserWindow-moved" + id);
@@ -237,7 +277,15 @@ module.exports = (socket, app) => {
}
});
if (loadUrl) {
window.loadURL(loadUrl);
// Append authentication token to initial URL if available
const token = global["authToken"];
if (token) {
const separator = loadUrl.includes("?") ? "&" : "?";
window.loadURL(`${loadUrl}${separator}token=${token}`);
}
else {
window.loadURL(loadUrl);
}
}
if (app.commandLine.hasSwitch("clear-cache") &&
app.commandLine.getSwitchValue("clear-cache")) {

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,18 @@
import { Socket } from "net";
import { BrowserWindow, Menu, nativeImage } from "electron";
import * as path from "path";
import type { Socket } from "net";
import { BrowserWindow, Menu } from "electron";
import { browserViewMediateService } from "./browserView";
const path = require("path");
const windows: Electron.BrowserWindow[] = (global["browserWindows"] =
global["browserWindows"] || []) as Electron.BrowserWindow[];
let readyToShowWindowsIds: number[] = [];
let window, lastOptions, electronSocket;
let mainWindowURL;
let window;
let lastOptions;
let electronSocket;
const proxyToCredentialsMap: { [proxy: string]: string } = (global[
"proxyToCredentialsMap"
] = global["proxyToCredentialsMap"] || []) as { [proxy: string]: string };
@@ -32,7 +38,7 @@ export = (socket: Socket, app: Electron.App) => {
socket.on("register-browserWindow-ready-to-show", (id) => {
if (readyToShowWindowsIds.includes(id)) {
readyToShowWindowsIds = readyToShowWindowsIds.filter(
(value) => value !== id
(value) => value !== id,
);
electronSocket.emit("browserWindow-ready-to-show" + id);
}
@@ -139,6 +145,17 @@ export = (socket: Socket, app: Electron.App) => {
});
});
socket.on("register-browserWindow-bounds-changed", (id) => {
const window = getWindowById(id);
const cb = () =>
electronSocket.emit(
"browserWindow-bounds-changed" + id,
window.getBounds(),
);
window.on("resize", cb);
window.on("move", cb);
});
socket.on("register-browserWindow-moved", (id) => {
getWindowById(id).on("moved", () => {
electronSocket.emit("browserWindow-moved" + id);
@@ -224,7 +241,7 @@ export = (socket: Socket, app: Electron.App) => {
__dirname,
"..",
"scripts",
"blazor-preload.js"
"blazor-preload.js",
);
}
@@ -257,7 +274,7 @@ export = (socket: Socket, app: Electron.App) => {
window.on("ready-to-show", () => {
if (readyToShowWindowsIds.includes(window.id)) {
readyToShowWindowsIds = readyToShowWindowsIds.filter(
(value) => value !== window.id
(value) => value !== window.id,
);
} else {
readyToShowWindowsIds.push(window.id);
@@ -292,7 +309,15 @@ export = (socket: Socket, app: Electron.App) => {
});
if (loadUrl) {
window.loadURL(loadUrl);
// Append authentication token to initial URL if available
const token = global["authToken"];
if (token) {
const separator = loadUrl.includes("?") ? "&" : "?";
window.loadURL(`${loadUrl}${separator}token=${token}`);
} else {
window.loadURL(loadUrl);
}
}
if (
@@ -524,7 +549,7 @@ export = (socket: Socket, app: Electron.App) => {
electronSocket.emit(
"browserWindow-isFullScreenable-completed",
fullscreenable
fullscreenable,
);
});
@@ -609,7 +634,7 @@ export = (socket: Socket, app: Electron.App) => {
.toString(16);
electronSocket.emit(
"browserWindow-getNativeWindowHandle-completed",
nativeWindowHandle
nativeWindowHandle,
);
});
@@ -622,7 +647,7 @@ export = (socket: Socket, app: Electron.App) => {
} catch (e) {
console.warn(
"setRepresentedFilename failed (likely unsupported platform):",
e
e,
);
}
});
@@ -637,12 +662,12 @@ export = (socket: Socket, app: Electron.App) => {
} catch (e) {
console.warn(
"getRepresentedFilename failed (likely unsupported platform):",
e
e,
);
}
electronSocket.emit(
"browserWindow-getRepresentedFilename-completed",
pathname
pathname,
);
});
@@ -734,7 +759,7 @@ export = (socket: Socket, app: Electron.App) => {
imagePath = path.join(
__dirname.replace("api", ""),
"bin",
originalIconPath
originalIconPath,
);
}
const { nativeImage } = require("electron");
@@ -751,7 +776,7 @@ export = (socket: Socket, app: Electron.App) => {
const success = getWindowById(id).setThumbarButtons(thumbarButtons);
electronSocket.emit("browserWindowSetThumbarButtons-completed", success);
}
},
);
socket.on("browserWindowSetThumbnailClip", (id, rectangle) => {
@@ -779,7 +804,7 @@ export = (socket: Socket, app: Electron.App) => {
electronSocket.emit(
"browserWindow-isMenuBarAutoHide-completed",
isMenuBarAutoHide
isMenuBarAutoHide,
);
});
@@ -792,7 +817,7 @@ export = (socket: Socket, app: Electron.App) => {
electronSocket.emit(
"browserWindow-isMenuBarVisible-completed",
isMenuBarVisible
isMenuBarVisible,
);
});
@@ -806,7 +831,7 @@ export = (socket: Socket, app: Electron.App) => {
electronSocket.emit(
"browserWindow-isVisibleOnAllWorkspaces-completed",
isVisibleOnAllWorkspaces
isVisibleOnAllWorkspaces,
);
});
@@ -838,7 +863,7 @@ export = (socket: Socket, app: Electron.App) => {
electronSocket.emit(
"browserWindow-getParentWindow-completed",
browserWindow.id
browserWindow.id,
);
});

View File

@@ -3,63 +3,65 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('clipboard-readText', (type) => {
socket.on("clipboard-readText", (type) => {
const text = electron_1.clipboard.readText(type);
electronSocket.emit('clipboard-readText-completed', text);
electronSocket.emit("clipboard-readText-completed", text);
});
socket.on('clipboard-writeText', (text, type) => {
socket.on("clipboard-writeText", (text, type) => {
electron_1.clipboard.writeText(text, type);
});
socket.on('clipboard-readHTML', (type) => {
socket.on("clipboard-readHTML", (type) => {
const content = electron_1.clipboard.readHTML(type);
electronSocket.emit('clipboard-readHTML-completed', content);
electronSocket.emit("clipboard-readHTML-completed", content);
});
socket.on('clipboard-writeHTML', (markup, type) => {
socket.on("clipboard-writeHTML", (markup, type) => {
electron_1.clipboard.writeHTML(markup, type);
});
socket.on('clipboard-readRTF', (type) => {
socket.on("clipboard-readRTF", (type) => {
const content = electron_1.clipboard.readRTF(type);
electronSocket.emit('clipboard-readRTF-completed', content);
electronSocket.emit("clipboard-readRTF-completed", content);
});
socket.on('clipboard-writeRTF', (text, type) => {
socket.on("clipboard-writeRTF", (text, type) => {
electron_1.clipboard.writeHTML(text, type);
});
socket.on('clipboard-readBookmark', () => {
socket.on("clipboard-readBookmark", () => {
const bookmark = electron_1.clipboard.readBookmark();
electronSocket.emit('clipboard-readBookmark-completed', bookmark);
electronSocket.emit("clipboard-readBookmark-completed", bookmark);
});
socket.on('clipboard-writeBookmark', (title, url, type) => {
socket.on("clipboard-writeBookmark", (title, url, type) => {
electron_1.clipboard.writeBookmark(title, url, type);
});
socket.on('clipboard-readFindText', () => {
socket.on("clipboard-readFindText", () => {
const content = electron_1.clipboard.readFindText();
electronSocket.emit('clipboard-readFindText-completed', content);
electronSocket.emit("clipboard-readFindText-completed", content);
});
socket.on('clipboard-writeFindText', (text) => {
socket.on("clipboard-writeFindText", (text) => {
electron_1.clipboard.writeFindText(text);
});
socket.on('clipboard-clear', (type) => {
socket.on("clipboard-clear", (type) => {
electron_1.clipboard.clear(type);
});
socket.on('clipboard-availableFormats', (type) => {
socket.on("clipboard-availableFormats", (type) => {
const formats = electron_1.clipboard.availableFormats(type);
electronSocket.emit('clipboard-availableFormats-completed', formats);
electronSocket.emit("clipboard-availableFormats-completed", formats);
});
socket.on('clipboard-write', (data, type) => {
socket.on("clipboard-write", (data, type) => {
electron_1.clipboard.write(data, type);
});
socket.on('clipboard-readImage', (type) => {
socket.on("clipboard-readImage", (type) => {
const image = electron_1.clipboard.readImage(type);
electronSocket.emit('clipboard-readImage-completed', { 1: image.toPNG().toString('base64') });
electronSocket.emit("clipboard-readImage-completed", {
1: image.toPNG().toString("base64"),
});
});
socket.on('clipboard-writeImage', (data, type) => {
socket.on("clipboard-writeImage", (data, type) => {
const dataContent = JSON.parse(data);
const image = electron_1.nativeImage.createEmpty();
// tslint:disable-next-line: forin
for (const key in dataContent) {
const scaleFactor = key;
const bytes = data[key];
const buffer = Buffer.from(bytes, 'base64');
const buffer = Buffer.from(bytes, "base64");
image.addRepresentation({ scaleFactor: +scaleFactor, buffer: buffer });
}
electron_1.clipboard.writeImage(image, type);

View File

@@ -1 +1 @@
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["clipboard.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["clipboard.ts"],"names":[],"mappings":"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"}

View File

@@ -1,84 +1,87 @@
import { Socket } from 'net';
import { clipboard, nativeImage } from 'electron';
let electronSocket;
import type { Socket } from "net";
import { clipboard, nativeImage } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('clipboard-readText', (type) => {
const text = clipboard.readText(type);
electronSocket.emit('clipboard-readText-completed', text);
electronSocket = socket;
socket.on("clipboard-readText", (type) => {
const text = clipboard.readText(type);
electronSocket.emit("clipboard-readText-completed", text);
});
socket.on("clipboard-writeText", (text, type) => {
clipboard.writeText(text, type);
});
socket.on("clipboard-readHTML", (type) => {
const content = clipboard.readHTML(type);
electronSocket.emit("clipboard-readHTML-completed", content);
});
socket.on("clipboard-writeHTML", (markup, type) => {
clipboard.writeHTML(markup, type);
});
socket.on("clipboard-readRTF", (type) => {
const content = clipboard.readRTF(type);
electronSocket.emit("clipboard-readRTF-completed", content);
});
socket.on("clipboard-writeRTF", (text, type) => {
clipboard.writeHTML(text, type);
});
socket.on("clipboard-readBookmark", () => {
const bookmark = clipboard.readBookmark();
electronSocket.emit("clipboard-readBookmark-completed", bookmark);
});
socket.on("clipboard-writeBookmark", (title, url, type) => {
clipboard.writeBookmark(title, url, type);
});
socket.on("clipboard-readFindText", () => {
const content = clipboard.readFindText();
electronSocket.emit("clipboard-readFindText-completed", content);
});
socket.on("clipboard-writeFindText", (text) => {
clipboard.writeFindText(text);
});
socket.on("clipboard-clear", (type) => {
clipboard.clear(type);
});
socket.on("clipboard-availableFormats", (type) => {
const formats = clipboard.availableFormats(type);
electronSocket.emit("clipboard-availableFormats-completed", formats);
});
socket.on("clipboard-write", (data, type) => {
clipboard.write(data, type);
});
socket.on("clipboard-readImage", (type) => {
const image = clipboard.readImage(type);
electronSocket.emit("clipboard-readImage-completed", {
1: image.toPNG().toString("base64"),
});
});
socket.on('clipboard-writeText', (text, type) => {
clipboard.writeText(text, type);
});
socket.on("clipboard-writeImage", (data, type) => {
const dataContent = JSON.parse(data);
const image = nativeImage.createEmpty();
socket.on('clipboard-readHTML', (type) => {
const content = clipboard.readHTML(type);
electronSocket.emit('clipboard-readHTML-completed', content);
});
// tslint:disable-next-line: forin
for (const key in dataContent) {
const scaleFactor = key;
const bytes = data[key];
const buffer = Buffer.from(bytes, "base64");
image.addRepresentation({ scaleFactor: +scaleFactor, buffer: buffer });
}
socket.on('clipboard-writeHTML', (markup, type) => {
clipboard.writeHTML(markup, type);
});
socket.on('clipboard-readRTF', (type) => {
const content = clipboard.readRTF(type);
electronSocket.emit('clipboard-readRTF-completed', content);
});
socket.on('clipboard-writeRTF', (text, type) => {
clipboard.writeHTML(text, type);
});
socket.on('clipboard-readBookmark', () => {
const bookmark = clipboard.readBookmark();
electronSocket.emit('clipboard-readBookmark-completed', bookmark);
});
socket.on('clipboard-writeBookmark', (title, url, type) => {
clipboard.writeBookmark(title, url, type);
});
socket.on('clipboard-readFindText', () => {
const content = clipboard.readFindText();
electronSocket.emit('clipboard-readFindText-completed', content);
});
socket.on('clipboard-writeFindText', (text) => {
clipboard.writeFindText(text);
});
socket.on('clipboard-clear', (type) => {
clipboard.clear(type);
});
socket.on('clipboard-availableFormats', (type) => {
const formats = clipboard.availableFormats(type);
electronSocket.emit('clipboard-availableFormats-completed', formats);
});
socket.on('clipboard-write', (data, type) => {
clipboard.write(data, type);
});
socket.on('clipboard-readImage', (type) => {
const image = clipboard.readImage(type);
electronSocket.emit('clipboard-readImage-completed', { 1: image.toPNG().toString('base64') });
});
socket.on('clipboard-writeImage', (data, type) => {
const dataContent = JSON.parse(data);
const image = nativeImage.createEmpty();
// tslint:disable-next-line: forin
for (const key in dataContent) {
const scaleFactor = key;
const bytes = data[key];
const buffer = Buffer.from(bytes, 'base64');
image.addRepresentation({ scaleFactor: +scaleFactor, buffer: buffer });
}
clipboard.writeImage(image, type);
});
clipboard.writeImage(image, type);
});
};

View File

@@ -2,19 +2,19 @@
let electronSocket;
module.exports = (socket, app) => {
electronSocket = socket;
socket.on('appCommandLineAppendSwitch', (the_switch, value) => {
socket.on("appCommandLineAppendSwitch", (the_switch, value) => {
app.commandLine.appendSwitch(the_switch, value);
});
socket.on('appCommandLineAppendArgument', (value) => {
socket.on("appCommandLineAppendArgument", (value) => {
app.commandLine.appendArgument(value);
});
socket.on('appCommandLineHasSwitch', (value) => {
socket.on("appCommandLineHasSwitch", (value) => {
const hasSwitch = app.commandLine.hasSwitch(value);
electronSocket.emit('appCommandLineHasSwitchCompleted', hasSwitch);
electronSocket.emit("appCommandLineHasSwitchCompleted", hasSwitch);
});
socket.on('appCommandLineGetSwitchValue', (the_switch) => {
socket.on("appCommandLineGetSwitchValue", (the_switch) => {
const value = app.commandLine.getSwitchValue(the_switch);
electronSocket.emit('appCommandLineGetSwitchValueCompleted', value);
electronSocket.emit("appCommandLineGetSwitchValueCompleted", value);
});
};
//# sourceMappingURL=commandLine.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"commandLine.js","sourceRoot":"","sources":["commandLine.ts"],"names":[],"mappings":";AACA,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,GAAiB,EAAE,EAAE;IAC3C,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,CAAC,UAAkB,EAAE,KAAa,EAAE,EAAE;QAC1E,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC,KAAa,EAAE,EAAE;QACxD,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,KAAa,EAAE,EAAE;QACnD,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnD,cAAc,CAAC,IAAI,CAAC,kCAAkC,EAAE,SAAS,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC,UAAkB,EAAE,EAAE;QAC7D,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACzD,cAAc,CAAC,IAAI,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"commandLine.js","sourceRoot":"","sources":["commandLine.ts"],"names":[],"mappings":";AAEA,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,GAAiB,EAAE,EAAE;IAC7C,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CACP,4BAA4B,EAC5B,CAAC,UAAkB,EAAE,KAAa,EAAE,EAAE;QACpC,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC,KAAa,EAAE,EAAE;QAC1D,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,KAAa,EAAE,EAAE;QACrD,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnD,cAAc,CAAC,IAAI,CAAC,kCAAkC,EAAE,SAAS,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC,UAAkB,EAAE,EAAE;QAC/D,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACzD,cAAc,CAAC,IAAI,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}

View File

@@ -1,24 +1,28 @@
import { Socket } from 'net';
let electronSocket;
import type { Socket } from "net";
let electronSocket: Socket;
export = (socket: Socket, app: Electron.App) => {
electronSocket = socket;
electronSocket = socket;
socket.on('appCommandLineAppendSwitch', (the_switch: string, value: string) => {
app.commandLine.appendSwitch(the_switch, value);
});
socket.on(
"appCommandLineAppendSwitch",
(the_switch: string, value: string) => {
app.commandLine.appendSwitch(the_switch, value);
},
);
socket.on('appCommandLineAppendArgument', (value: string) => {
app.commandLine.appendArgument(value);
});
socket.on("appCommandLineAppendArgument", (value: string) => {
app.commandLine.appendArgument(value);
});
socket.on('appCommandLineHasSwitch', (value: string) => {
const hasSwitch = app.commandLine.hasSwitch(value);
electronSocket.emit('appCommandLineHasSwitchCompleted', hasSwitch);
});
socket.on("appCommandLineHasSwitch", (value: string) => {
const hasSwitch = app.commandLine.hasSwitch(value);
electronSocket.emit("appCommandLineHasSwitchCompleted", hasSwitch);
});
socket.on('appCommandLineGetSwitchValue', (the_switch: string) => {
const value = app.commandLine.getSwitchValue(the_switch);
electronSocket.emit('appCommandLineGetSwitchValueCompleted', value);
});
socket.on("appCommandLineGetSwitchValue", (the_switch: string) => {
const value = app.commandLine.getSwitchValue(the_switch);
electronSocket.emit("appCommandLineGetSwitchValueCompleted", value);
});
};

View File

@@ -3,35 +3,41 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('showMessageBox', async (browserWindow, options, guid) => {
if ('id' in browserWindow) {
socket.on("showMessageBox", async (browserWindow, options, guid) => {
if ("id" in browserWindow) {
const window = electron_1.BrowserWindow.fromId(browserWindow.id);
const messageBoxReturnValue = await electron_1.dialog.showMessageBox(window, options);
electronSocket.emit('showMessageBoxComplete' + guid, [messageBoxReturnValue.response, messageBoxReturnValue.checkboxChecked]);
electronSocket.emit("showMessageBoxComplete" + guid, [
messageBoxReturnValue.response,
messageBoxReturnValue.checkboxChecked,
]);
}
else {
const id = guid || options;
const messageBoxReturnValue = await electron_1.dialog.showMessageBox(browserWindow);
electronSocket.emit('showMessageBoxComplete' + id, [messageBoxReturnValue.response, messageBoxReturnValue.checkboxChecked]);
electronSocket.emit("showMessageBoxComplete" + id, [
messageBoxReturnValue.response,
messageBoxReturnValue.checkboxChecked,
]);
}
});
socket.on('showOpenDialog', async (browserWindow, options, guid) => {
socket.on("showOpenDialog", async (browserWindow, options, guid) => {
const window = electron_1.BrowserWindow.fromId(browserWindow.id);
const openDialogReturnValue = await electron_1.dialog.showOpenDialog(window, options);
electronSocket.emit('showOpenDialogComplete' + guid, openDialogReturnValue.filePaths || []);
electronSocket.emit("showOpenDialogComplete" + guid, openDialogReturnValue.filePaths || []);
});
socket.on('showSaveDialog', async (browserWindow, options, guid) => {
socket.on("showSaveDialog", async (browserWindow, options, guid) => {
const window = electron_1.BrowserWindow.fromId(browserWindow.id);
const saveDialogReturnValue = await electron_1.dialog.showSaveDialog(window, options);
electronSocket.emit('showSaveDialogComplete' + guid, saveDialogReturnValue.filePath || '');
electronSocket.emit("showSaveDialogComplete" + guid, saveDialogReturnValue.filePath || "");
});
socket.on('showErrorBox', (title, content) => {
socket.on("showErrorBox", (title, content) => {
electron_1.dialog.showErrorBox(title, content);
});
socket.on('showCertificateTrustDialog', async (browserWindow, options, guid) => {
socket.on("showCertificateTrustDialog", async (browserWindow, options, guid) => {
const window = electron_1.BrowserWindow.fromId(browserWindow.id);
await electron_1.dialog.showCertificateTrustDialog(window, options);
electronSocket.emit('showCertificateTrustDialogComplete' + guid);
electronSocket.emit("showCertificateTrustDialogComplete" + guid);
});
};
//# sourceMappingURL=dialog.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"dialog.js","sourceRoot":"","sources":["dialog.ts"],"names":[],"mappings":";AACA,uCAAiD;AACjD,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,IAAI,IAAI,IAAI,aAAa,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAEtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,CAAC,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC,CAAC;QAClI,CAAC;aAAM,CAAC;YACJ,MAAM,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC;YAC3B,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAEzE,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,EAAE,EAAE,CAAC,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC,CAAC;QAChI,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,qBAAqB,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,qBAAqB,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACzC,iBAAM,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC3E,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,iBAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEzD,cAAc,CAAC,IAAI,CAAC,oCAAoC,GAAG,IAAI,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"dialog.js","sourceRoot":"","sources":["dialog.ts"],"names":[],"mappings":";AACA,uCAAiD;AAEjD,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IAC1B,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACjE,IAAI,IAAI,IAAI,aAAa,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAEtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CACvD,MAAM,EACN,OAAO,CACR,CAAC;YACF,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE;gBACnD,qBAAqB,CAAC,QAAQ;gBAC9B,qBAAqB,CAAC,eAAe;aACtC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC;YAC3B,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAEzE,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,EAAE,EAAE;gBACjD,qBAAqB,CAAC,QAAQ;gBAC9B,qBAAqB,CAAC,eAAe;aACtC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACjE,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE3E,cAAc,CAAC,IAAI,CACjB,wBAAwB,GAAG,IAAI,EAC/B,qBAAqB,CAAC,SAAS,IAAI,EAAE,CACtC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACjE,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE3E,cAAc,CAAC,IAAI,CACjB,wBAAwB,GAAG,IAAI,EAC/B,qBAAqB,CAAC,QAAQ,IAAI,EAAE,CACrC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QAC3C,iBAAM,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CACP,4BAA4B,EAC5B,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,iBAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEzD,cAAc,CAAC,IAAI,CAAC,oCAAoC,GAAG,IAAI,CAAC,CAAC;IACnE,CAAC,CACF,CAAC;AACJ,CAAC,CAAC"}

View File

@@ -1,45 +1,64 @@
import { Socket } from 'net';
import { BrowserWindow, dialog } from 'electron';
import type { Socket } from "net";
import { BrowserWindow, dialog } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('showMessageBox', async (browserWindow, options, guid) => {
if ('id' in browserWindow) {
const window = BrowserWindow.fromId(browserWindow.id);
electronSocket = socket;
socket.on("showMessageBox", async (browserWindow, options, guid) => {
if ("id" in browserWindow) {
const window = BrowserWindow.fromId(browserWindow.id);
const messageBoxReturnValue = await dialog.showMessageBox(window, options);
electronSocket.emit('showMessageBoxComplete' + guid, [messageBoxReturnValue.response, messageBoxReturnValue.checkboxChecked]);
} else {
const id = guid || options;
const messageBoxReturnValue = await dialog.showMessageBox(browserWindow);
const messageBoxReturnValue = await dialog.showMessageBox(
window,
options,
);
electronSocket.emit("showMessageBoxComplete" + guid, [
messageBoxReturnValue.response,
messageBoxReturnValue.checkboxChecked,
]);
} else {
const id = guid || options;
const messageBoxReturnValue = await dialog.showMessageBox(browserWindow);
electronSocket.emit('showMessageBoxComplete' + id, [messageBoxReturnValue.response, messageBoxReturnValue.checkboxChecked]);
}
});
electronSocket.emit("showMessageBoxComplete" + id, [
messageBoxReturnValue.response,
messageBoxReturnValue.checkboxChecked,
]);
}
});
socket.on('showOpenDialog', async (browserWindow, options, guid) => {
const window = BrowserWindow.fromId(browserWindow.id);
const openDialogReturnValue = await dialog.showOpenDialog(window, options);
socket.on("showOpenDialog", async (browserWindow, options, guid) => {
const window = BrowserWindow.fromId(browserWindow.id);
const openDialogReturnValue = await dialog.showOpenDialog(window, options);
electronSocket.emit('showOpenDialogComplete' + guid, openDialogReturnValue.filePaths || []);
});
electronSocket.emit(
"showOpenDialogComplete" + guid,
openDialogReturnValue.filePaths || [],
);
});
socket.on('showSaveDialog', async (browserWindow, options, guid) => {
const window = BrowserWindow.fromId(browserWindow.id);
const saveDialogReturnValue = await dialog.showSaveDialog(window, options);
socket.on("showSaveDialog", async (browserWindow, options, guid) => {
const window = BrowserWindow.fromId(browserWindow.id);
const saveDialogReturnValue = await dialog.showSaveDialog(window, options);
electronSocket.emit('showSaveDialogComplete' + guid, saveDialogReturnValue.filePath || '');
});
electronSocket.emit(
"showSaveDialogComplete" + guid,
saveDialogReturnValue.filePath || "",
);
});
socket.on('showErrorBox', (title, content) => {
dialog.showErrorBox(title, content);
});
socket.on("showErrorBox", (title, content) => {
dialog.showErrorBox(title, content);
});
socket.on('showCertificateTrustDialog', async (browserWindow, options, guid) => {
const window = BrowserWindow.fromId(browserWindow.id);
await dialog.showCertificateTrustDialog(window, options);
socket.on(
"showCertificateTrustDialog",
async (browserWindow, options, guid) => {
const window = BrowserWindow.fromId(browserWindow.id);
await dialog.showCertificateTrustDialog(window, options);
electronSocket.emit('showCertificateTrustDialogComplete' + guid);
});
electronSocket.emit("showCertificateTrustDialogComplete" + guid);
},
);
};

View File

@@ -3,49 +3,49 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('dock-bounce', (type) => {
socket.on("dock-bounce", (type) => {
const id = electron_1.app.dock.bounce(type);
electronSocket.emit('dock-bounce-completed', id);
electronSocket.emit("dock-bounce-completed", id);
});
socket.on('dock-cancelBounce', (id) => {
socket.on("dock-cancelBounce", (id) => {
electron_1.app.dock.cancelBounce(id);
});
socket.on('dock-downloadFinished', (filePath) => {
socket.on("dock-downloadFinished", (filePath) => {
electron_1.app.dock.downloadFinished(filePath);
});
socket.on('dock-setBadge', (text) => {
socket.on("dock-setBadge", (text) => {
electron_1.app.dock.setBadge(text);
});
socket.on('dock-getBadge', () => {
socket.on("dock-getBadge", () => {
const text = electron_1.app.dock.getBadge();
electronSocket.emit('dock-getBadge-completed', text);
electronSocket.emit("dock-getBadge-completed", text);
});
socket.on('dock-hide', () => {
socket.on("dock-hide", () => {
electron_1.app.dock.hide();
});
socket.on('dock-show', () => {
socket.on("dock-show", () => {
electron_1.app.dock.show();
});
socket.on('dock-isVisible', () => {
socket.on("dock-isVisible", () => {
const isVisible = electron_1.app.dock.isVisible();
electronSocket.emit('dock-isVisible-completed', isVisible);
electronSocket.emit("dock-isVisible-completed", isVisible);
});
socket.on('dock-setMenu', (menuItems) => {
socket.on("dock-setMenu", (menuItems) => {
let menu = null;
if (menuItems) {
menu = electron_1.Menu.buildFromTemplate(menuItems);
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit('dockMenuItemClicked', id);
electronSocket.emit("dockMenuItemClicked", id);
});
}
electron_1.app.dock.setMenu(menu);
});
// TODO: Menu (macOS) still to be implemented
socket.on('dock-getMenu', () => {
socket.on("dock-getMenu", () => {
const menu = electron_1.app.dock.getMenu();
electronSocket.emit('dock-getMenu-completed', menu);
electronSocket.emit("dock-getMenu-completed", menu);
});
socket.on('dock-setIcon', (image) => {
socket.on("dock-setIcon", (image) => {
electron_1.app.dock.setIcon(image);
});
function addMenuItemClickConnector(menuItems, callback) {
@@ -53,8 +53,10 @@ module.exports = (socket) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
if ('id' in item && item.id) {
item.click = () => { callback(item.id); };
if ("id" in item && item.id) {
item.click = () => {
callback(item.id);
};
}
});
}

View File

@@ -1 +1 @@
{"version":3,"file":"dock.js","sourceRoot":"","sources":["dock.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"dock.js","sourceRoot":"","sources":["dock.ts"],"names":[],"mappings":"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"}

View File

@@ -1,78 +1,81 @@
import { Socket } from 'net';
import { app, Menu } from 'electron';
let electronSocket;
import type { Socket } from "net";
import { app, Menu } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
electronSocket = socket;
socket.on('dock-bounce', (type) => {
const id = app.dock.bounce(type);
electronSocket.emit('dock-bounce-completed', id);
});
socket.on("dock-bounce", (type) => {
const id = app.dock.bounce(type);
electronSocket.emit("dock-bounce-completed", id);
});
socket.on('dock-cancelBounce', (id) => {
app.dock.cancelBounce(id);
});
socket.on("dock-cancelBounce", (id) => {
app.dock.cancelBounce(id);
});
socket.on('dock-downloadFinished', (filePath) => {
app.dock.downloadFinished(filePath);
});
socket.on("dock-downloadFinished", (filePath) => {
app.dock.downloadFinished(filePath);
});
socket.on('dock-setBadge', (text) => {
app.dock.setBadge(text);
});
socket.on("dock-setBadge", (text) => {
app.dock.setBadge(text);
});
socket.on('dock-getBadge', () => {
const text = app.dock.getBadge();
electronSocket.emit('dock-getBadge-completed', text);
});
socket.on("dock-getBadge", () => {
const text = app.dock.getBadge();
electronSocket.emit("dock-getBadge-completed", text);
});
socket.on('dock-hide', () => {
app.dock.hide();
});
socket.on("dock-hide", () => {
app.dock.hide();
});
socket.on('dock-show', () => {
app.dock.show();
});
socket.on("dock-show", () => {
app.dock.show();
});
socket.on('dock-isVisible', () => {
const isVisible = app.dock.isVisible();
electronSocket.emit('dock-isVisible-completed', isVisible);
});
socket.on("dock-isVisible", () => {
const isVisible = app.dock.isVisible();
electronSocket.emit("dock-isVisible-completed", isVisible);
});
socket.on('dock-setMenu', (menuItems) => {
let menu = null;
socket.on("dock-setMenu", (menuItems) => {
let menu = null;
if (menuItems) {
menu = Menu.buildFromTemplate(menuItems);
if (menuItems) {
menu = Menu.buildFromTemplate(menuItems);
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit('dockMenuItemClicked', id);
});
}
app.dock.setMenu(menu);
});
// TODO: Menu (macOS) still to be implemented
socket.on('dock-getMenu', () => {
const menu = app.dock.getMenu();
electronSocket.emit('dock-getMenu-completed', menu);
});
socket.on('dock-setIcon', (image) => {
app.dock.setIcon(image);
});
function addMenuItemClickConnector(menuItems, callback) {
menuItems.forEach((item) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
if ('id' in item && item.id) {
item.click = () => { callback(item.id); };
}
});
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit("dockMenuItemClicked", id);
});
}
app.dock.setMenu(menu);
});
// TODO: Menu (macOS) still to be implemented
socket.on("dock-getMenu", () => {
const menu = app.dock.getMenu();
electronSocket.emit("dock-getMenu-completed", menu);
});
socket.on("dock-setIcon", (image) => {
app.dock.setIcon(image);
});
function addMenuItemClickConnector(menuItems, callback) {
menuItems.forEach((item) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
if ("id" in item && item.id) {
item.click = () => {
callback(item.id);
};
}
});
}
};

View File

@@ -3,19 +3,19 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('globalShortcut-register', (accelerator) => {
socket.on("globalShortcut-register", (accelerator) => {
electron_1.globalShortcut.register(accelerator, () => {
electronSocket.emit('globalShortcut-pressed', accelerator);
electronSocket.emit("globalShortcut-pressed", accelerator);
});
});
socket.on('globalShortcut-isRegistered', (accelerator) => {
socket.on("globalShortcut-isRegistered", (accelerator) => {
const isRegistered = electron_1.globalShortcut.isRegistered(accelerator);
electronSocket.emit('globalShortcut-isRegisteredCompleted', isRegistered);
electronSocket.emit("globalShortcut-isRegisteredCompleted", isRegistered);
});
socket.on('globalShortcut-unregister', (accelerator) => {
socket.on("globalShortcut-unregister", (accelerator) => {
electron_1.globalShortcut.unregister(accelerator);
});
socket.on('globalShortcut-unregisterAll', () => {
socket.on("globalShortcut-unregisterAll", () => {
try {
electron_1.globalShortcut.unregisterAll();
}

View File

@@ -1 +1 @@
{"version":3,"file":"globalShortcut.js","sourceRoot":"","sources":["globalShortcut.ts"],"names":[],"mappings":";AAAA,uCAA0C;AAE1C,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,WAAW,EAAE,EAAE;QACjD,yBAAc,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;YACtC,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,WAAW,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,6BAA6B,EAAE,CAAC,WAAW,EAAE,EAAE;QACrD,MAAM,YAAY,GAAG,yBAAc,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAE9D,cAAc,CAAC,IAAI,CAAC,sCAAsC,EAAE,YAAY,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2BAA2B,EAAE,CAAC,WAAW,EAAE,EAAE;QACnD,yBAAc,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC3C,IAAI,CAAC;YACD,yBAAc,CAAC,aAAa,EAAE,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"globalShortcut.js","sourceRoot":"","sources":["globalShortcut.ts"],"names":[],"mappings":";AACA,uCAA0C;AAE1C,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IAC1B,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,WAAW,EAAE,EAAE;QACnD,yBAAc,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;YACxC,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,WAAW,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,6BAA6B,EAAE,CAAC,WAAW,EAAE,EAAE;QACvD,MAAM,YAAY,GAAG,yBAAc,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAE9D,cAAc,CAAC,IAAI,CAAC,sCAAsC,EAAE,YAAY,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2BAA2B,EAAE,CAAC,WAAW,EAAE,EAAE;QACrD,yBAAc,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC7C,IAAI,CAAC;YACH,yBAAc,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC,CAAA,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}

View File

@@ -1,28 +1,29 @@
import { globalShortcut } from 'electron';
import { Socket } from 'net';
let electronSocket;
import type { Socket } from "net";
import { globalShortcut } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('globalShortcut-register', (accelerator) => {
globalShortcut.register(accelerator, () => {
electronSocket.emit('globalShortcut-pressed', accelerator);
});
electronSocket = socket;
socket.on("globalShortcut-register", (accelerator) => {
globalShortcut.register(accelerator, () => {
electronSocket.emit("globalShortcut-pressed", accelerator);
});
});
socket.on('globalShortcut-isRegistered', (accelerator) => {
const isRegistered = globalShortcut.isRegistered(accelerator);
socket.on("globalShortcut-isRegistered", (accelerator) => {
const isRegistered = globalShortcut.isRegistered(accelerator);
electronSocket.emit('globalShortcut-isRegisteredCompleted', isRegistered);
});
electronSocket.emit("globalShortcut-isRegisteredCompleted", isRegistered);
});
socket.on('globalShortcut-unregister', (accelerator) => {
globalShortcut.unregister(accelerator);
});
socket.on("globalShortcut-unregister", (accelerator) => {
globalShortcut.unregister(accelerator);
});
socket.on('globalShortcut-unregisterAll', () => {
try {
globalShortcut.unregisterAll();
} catch (error) { }
});
socket.on("globalShortcut-unregisterAll", () => {
try {
globalShortcut.unregisterAll();
} catch (error) {}
});
};

View File

@@ -3,40 +3,41 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('registerIpcMainChannel', (channel) => {
socket.on("registerIpcMainChannel", (channel) => {
electron_1.ipcMain.on(channel, (event, args) => {
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
socket.on('registerSyncIpcMainChannel', (channel) => {
socket.on("registerSyncIpcMainChannel", (channel) => {
electron_1.ipcMain.on(channel, (event, args) => {
const x = socket;
x.removeAllListeners(channel + 'Sync');
socket.on(channel + 'Sync', (result) => {
x.removeAllListeners(channel + "Sync");
socket.on(channel + "Sync", (result) => {
event.returnValue = result;
});
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
socket.on('registerOnceIpcMainChannel', (channel) => {
socket.on("registerOnceIpcMainChannel", (channel) => {
electron_1.ipcMain.once(channel, (event, args) => {
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
socket.on('removeAllListenersIpcMainChannel', (channel) => {
socket.on("removeAllListenersIpcMainChannel", (channel) => {
electron_1.ipcMain.removeAllListeners(channel);
});
socket.on('sendToIpcRenderer', (browserWindow, channel, data) => {
socket.on("sendToIpcRenderer", (browserWindow, channel, data) => {
const window = electron_1.BrowserWindow.fromId(browserWindow.id);
if (window) {
window.webContents.send(channel, ...data);
}
});
socket.on('sendToIpcRendererBrowserView', (id, channel, data) => {
const browserViews = (global['browserViews'] = global['browserViews'] || []);
socket.on("sendToIpcRendererBrowserView", (id, channel, data) => {
const browserViews = (global["browserViews"] =
global["browserViews"] || []);
let view = null;
for (let i = 0; i < browserViews.length; i++) {
if (browserViews[i]['id'] === id) {
if (browserViews[i]["id"] === id) {
view = browserViews[i];
break;
}
@@ -45,29 +46,58 @@ module.exports = (socket) => {
view.webContents.send(channel, ...data);
}
});
socket.on("registerHandleIpcMainChannel", (channel) => {
electron_1.ipcMain.handle(channel, (event, args) => {
return new Promise((resolve, _reject) => {
socket.removeAllListeners(channel + "Handle");
socket.on(channel + "Handle", (result) => {
resolve(result);
});
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
});
socket.on("registerHandleOnceIpcMainChannel", (channel) => {
electron_1.ipcMain.handleOnce(channel, (event, args) => {
return new Promise((resolve, _reject) => {
socket.removeAllListeners(channel + "HandleOnce");
socket.once(channel + "HandleOnce", (result) => {
resolve(result);
});
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
});
socket.on("removeHandlerIpcMainChannel", (channel) => {
electron_1.ipcMain.removeHandler(channel);
});
// Integration helpers: programmatically click menu items from renderer tests
electron_1.ipcMain.on('integration-click-application-menu', (event, id) => {
electron_1.ipcMain.on("integration-click-application-menu", (event, id) => {
try {
const menu = electron_1.Menu.getApplicationMenu();
const mi = menu ? menu.getMenuItemById(id) : null;
if (mi && typeof mi.click === 'function') {
if (mi && typeof mi.click === "function") {
const bw = electron_1.BrowserWindow.fromWebContents(event.sender);
mi.click(undefined, bw, undefined);
}
}
catch { /* ignore */ }
catch {
/* ignore */
}
});
electron_1.ipcMain.on('integration-click-context-menu', (event, windowId, id) => {
electron_1.ipcMain.on("integration-click-context-menu", (event, windowId, id) => {
try {
const entries = global['contextMenuItems'] || [];
const entries = global["contextMenuItems"] || [];
const entry = entries.find((x) => x.browserWindowId === windowId);
const mi = entry?.menu?.items?.find((i) => i.id === id);
if (mi && typeof mi.click === 'function') {
if (mi && typeof mi.click === "function") {
const bw = electron_1.BrowserWindow.fromId(windowId);
mi.click(undefined, bw, undefined);
}
}
catch { /* ignore */ }
catch {
/* ignore */
}
});
};
//# sourceMappingURL=ipc.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"ipc.js","sourceRoot":"","sources":["ipc.ts"],"names":[],"mappings":";AAAA,uCAAqE;AAErE,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,wBAAwB,EAAE,CAAC,OAAO,EAAE,EAAE;QAC5C,kBAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAChC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,CAAC,OAAO,EAAE,EAAE;QAChD,kBAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAChC,MAAM,CAAC,GAAQ,MAAM,CAAC;YACtB,CAAC,CAAC,kBAAkB,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,OAAO,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;gBACnC,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC;YAC/B,CAAC,CAAC,CAAC;YAEH,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,CAAC,OAAO,EAAE,EAAE;QAChD,kBAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAClC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,kCAAkC,EAAE,CAAC,OAAO,EAAE,EAAE;QACtD,kBAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC5D,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAEtD,IAAI,MAAM,EAAE,CAAC;YACT,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC5D,MAAM,YAAY,GAAkB,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,CAAkB,CAAC;QAC7G,IAAI,IAAI,GAAgB,IAAI,CAAC;QAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC/B,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;gBACvB,MAAM;YACV,CAAC;QACL,CAAC;QAED,IAAI,IAAI,EAAE,CAAC;YACP,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QAC5C,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,kBAAO,CAAC,EAAE,CAAC,oCAAoC,EAAE,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;QACnE,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,eAAI,CAAC,kBAAkB,EAAE,CAAC;YACvC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAClD,IAAI,EAAE,IAAI,OAAQ,EAAU,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;gBAChD,MAAM,EAAE,GAAG,wBAAa,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACtD,EAAU,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;YAChD,CAAC;QACL,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,kBAAO,CAAC,EAAE,CAAC,gCAAgC,EAAE,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAU,EAAE,EAAE;QACjF,IAAI,CAAC;YACD,MAAM,OAAO,GAAI,MAAc,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC;YAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC;YACvE,MAAM,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YAC7D,IAAI,EAAE,IAAI,OAAQ,EAAU,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;gBAChD,MAAM,EAAE,GAAG,wBAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACzC,EAAU,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;YAChD,CAAC;QACL,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"ipc.js","sourceRoot":"","sources":["ipc.ts"],"names":[],"mappings":"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"}

View File

@@ -1,81 +1,118 @@
import { ipcMain, BrowserWindow, BrowserView, Menu } from 'electron';
import { Socket } from 'net';
let electronSocket;
import type { Socket } from "net";
import { ipcMain, BrowserWindow, BrowserView, Menu } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('registerIpcMainChannel', (channel) => {
ipcMain.on(channel, (event, args) => {
electronSocket.emit(channel, [event.preventDefault(), args]);
electronSocket = socket;
socket.on("registerIpcMainChannel", (channel) => {
ipcMain.on(channel, (event, args) => {
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
socket.on("registerSyncIpcMainChannel", (channel) => {
ipcMain.on(channel, (event, args) => {
const x = <any>socket;
x.removeAllListeners(channel + "Sync");
socket.on(channel + "Sync", (result) => {
event.returnValue = result;
});
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
socket.on("registerOnceIpcMainChannel", (channel) => {
ipcMain.once(channel, (event, args) => {
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
socket.on("removeAllListenersIpcMainChannel", (channel) => {
ipcMain.removeAllListeners(channel);
});
socket.on("sendToIpcRenderer", (browserWindow, channel, data) => {
const window = BrowserWindow.fromId(browserWindow.id);
if (window) {
window.webContents.send(channel, ...data);
}
});
socket.on("sendToIpcRendererBrowserView", (id, channel, data) => {
const browserViews: BrowserView[] = (global["browserViews"] =
global["browserViews"] || []) as BrowserView[];
let view: BrowserView = null;
for (let i = 0; i < browserViews.length; i++) {
if (browserViews[i]["id"] === id) {
view = browserViews[i];
break;
}
}
if (view) {
view.webContents.send(channel, ...data);
}
});
socket.on("registerHandleIpcMainChannel", (channel) => {
ipcMain.handle(channel, (event, args) => {
return new Promise((resolve, _reject) => {
socket.removeAllListeners(channel + "Handle");
socket.on(channel + "Handle", (result) => {
resolve(result);
});
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
});
socket.on('registerSyncIpcMainChannel', (channel) => {
ipcMain.on(channel, (event, args) => {
const x = <any>socket;
x.removeAllListeners(channel + 'Sync');
socket.on(channel + 'Sync', (result) => {
event.returnValue = result;
});
electronSocket.emit(channel, [event.preventDefault(), args]);
socket.on("registerHandleOnceIpcMainChannel", (channel) => {
ipcMain.handleOnce(channel, (event, args) => {
return new Promise((resolve, _reject) => {
socket.removeAllListeners(channel + "HandleOnce");
socket.once(channel + "HandleOnce", (result) => {
resolve(result);
});
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
});
socket.on('registerOnceIpcMainChannel', (channel) => {
ipcMain.once(channel, (event, args) => {
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
socket.on("removeHandlerIpcMainChannel", (channel) => {
ipcMain.removeHandler(channel);
});
socket.on('removeAllListenersIpcMainChannel', (channel) => {
ipcMain.removeAllListeners(channel);
});
// Integration helpers: programmatically click menu items from renderer tests
ipcMain.on("integration-click-application-menu", (event, id: string) => {
try {
const menu = Menu.getApplicationMenu();
const mi = menu ? menu.getMenuItemById(id) : null;
if (mi && typeof (mi as any).click === "function") {
const bw = BrowserWindow.fromWebContents(event.sender);
(mi as any).click(undefined, bw, undefined);
}
} catch {
/* ignore */
}
});
socket.on('sendToIpcRenderer', (browserWindow, channel, data) => {
const window = BrowserWindow.fromId(browserWindow.id);
if (window) {
window.webContents.send(channel, ...data);
ipcMain.on(
"integration-click-context-menu",
(event, windowId: number, id: string) => {
try {
const entries = (global as any)["contextMenuItems"] || [];
const entry = entries.find((x: any) => x.browserWindowId === windowId);
const mi = entry?.menu?.items?.find((i: any) => i.id === id);
if (mi && typeof (mi as any).click === "function") {
const bw = BrowserWindow.fromId(windowId);
(mi as any).click(undefined, bw, undefined);
}
});
socket.on('sendToIpcRendererBrowserView', (id, channel, data) => {
const browserViews: BrowserView[] = (global['browserViews'] = global['browserViews'] || []) as BrowserView[];
let view: BrowserView = null;
for (let i = 0; i < browserViews.length; i++) {
if (browserViews[i]['id'] === id) {
view = browserViews[i];
break;
}
}
if (view) {
view.webContents.send(channel, ...data);
}
});
// Integration helpers: programmatically click menu items from renderer tests
ipcMain.on('integration-click-application-menu', (event, id: string) => {
try {
const menu = Menu.getApplicationMenu();
const mi = menu ? menu.getMenuItemById(id) : null;
if (mi && typeof (mi as any).click === 'function') {
const bw = BrowserWindow.fromWebContents(event.sender);
(mi as any).click(undefined, bw, undefined);
}
} catch { /* ignore */ }
});
ipcMain.on('integration-click-context-menu', (event, windowId: number, id: string) => {
try {
const entries = (global as any)['contextMenuItems'] || [];
const entry = entries.find((x: any) => x.browserWindowId === windowId);
const mi = entry?.menu?.items?.find((i: any) => i.id === id);
if (mi && typeof (mi as any).click === 'function') {
const bw = BrowserWindow.fromId(windowId);
(mi as any).click(undefined, bw, undefined);
}
} catch { /* ignore */ }
});
} catch {
/* ignore */
}
},
);
};

View File

@@ -1,18 +1,19 @@
"use strict";
const electron_1 = require("electron");
const contextMenuItems = (global['contextMenuItems'] = global['contextMenuItems'] || []);
const contextMenuItems = (global["contextMenuItems"] =
global["contextMenuItems"] || []);
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('menu-setContextMenu', (browserWindowId, menuItems) => {
socket.on("menu-setContextMenu", (browserWindowId, menuItems) => {
const menu = electron_1.Menu.buildFromTemplate(menuItems);
addContextMenuItemClickConnector(menu.items, browserWindowId, (id, windowId) => {
electronSocket.emit('contextMenuItemClicked', [id, windowId]);
electronSocket.emit("contextMenuItemClicked", [id, windowId]);
});
const index = contextMenuItems.findIndex(contextMenu => contextMenu.browserWindowId === browserWindowId);
const index = contextMenuItems.findIndex((contextMenu) => contextMenu.browserWindowId === browserWindowId);
const contextMenuItem = {
menu: menu,
browserWindowId: browserWindowId
browserWindowId: browserWindowId,
};
if (index === -1) {
contextMenuItems.push(contextMenuItem);
@@ -26,23 +27,25 @@ module.exports = (socket) => {
if (item.submenu && item.submenu.items.length > 0) {
addContextMenuItemClickConnector(item.submenu.items, browserWindowId, callback);
}
if ('id' in item && item.id) {
item.click = () => { callback(item.id, browserWindowId); };
if ("id" in item && item.id) {
item.click = () => {
callback(item.id, browserWindowId);
};
}
});
}
socket.on('menu-contextMenuPopup', (browserWindowId) => {
contextMenuItems.forEach(x => {
socket.on("menu-contextMenuPopup", (browserWindowId) => {
contextMenuItems.forEach((x) => {
if (x.browserWindowId === browserWindowId) {
const browserWindow = electron_1.BrowserWindow.fromId(browserWindowId);
x.menu.popup(browserWindow);
}
});
});
socket.on('menu-setApplicationMenu', (menuItems) => {
socket.on("menu-setApplicationMenu", (menuItems) => {
const menu = electron_1.Menu.buildFromTemplate(menuItems);
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit('menuItemClicked', id);
electronSocket.emit("menuItemClicked", id);
});
electron_1.Menu.setApplicationMenu(menu);
});
@@ -51,8 +54,10 @@ module.exports = (socket) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
if ('id' in item && item.id) {
item.click = () => { callback(item.id); };
if ("id" in item && item.id) {
item.click = () => {
callback(item.id);
};
}
});
}

View File

@@ -1 +1 @@
{"version":3,"file":"menu.js","sourceRoot":"","sources":["menu.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"menu.js","sourceRoot":"","sources":["menu.ts"],"names":[],"mappings":"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"}

View File

@@ -1,71 +1,92 @@
import { Socket } from 'net';
import { Menu, BrowserWindow } from 'electron';
const contextMenuItems = (global['contextMenuItems'] = global['contextMenuItems'] || []);
let electronSocket;
import type { Socket } from "net";
import { Menu, BrowserWindow } from "electron";
const contextMenuItems = (global["contextMenuItems"] =
global["contextMenuItems"] || []);
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('menu-setContextMenu', (browserWindowId, menuItems) => {
const menu = Menu.buildFromTemplate(menuItems);
electronSocket = socket;
socket.on("menu-setContextMenu", (browserWindowId, menuItems) => {
const menu = Menu.buildFromTemplate(menuItems);
addContextMenuItemClickConnector(menu.items, browserWindowId, (id, windowId) => {
electronSocket.emit('contextMenuItemClicked', [id, windowId]);
});
addContextMenuItemClickConnector(
menu.items,
browserWindowId,
(id, windowId) => {
electronSocket.emit("contextMenuItemClicked", [id, windowId]);
},
);
const index = contextMenuItems.findIndex(contextMenu => contextMenu.browserWindowId === browserWindowId);
const index = contextMenuItems.findIndex(
(contextMenu) => contextMenu.browserWindowId === browserWindowId,
);
const contextMenuItem = {
menu: menu,
browserWindowId: browserWindowId
const contextMenuItem = {
menu: menu,
browserWindowId: browserWindowId,
};
if (index === -1) {
contextMenuItems.push(contextMenuItem);
} else {
contextMenuItems[index] = contextMenuItem;
}
});
function addContextMenuItemClickConnector(
menuItems,
browserWindowId,
callback,
) {
menuItems.forEach((item) => {
if (item.submenu && item.submenu.items.length > 0) {
addContextMenuItemClickConnector(
item.submenu.items,
browserWindowId,
callback,
);
}
if ("id" in item && item.id) {
item.click = () => {
callback(item.id, browserWindowId);
};
}
});
}
if (index === -1) {
contextMenuItems.push(contextMenuItem);
} else {
contextMenuItems[index] = contextMenuItem;
}
socket.on("menu-contextMenuPopup", (browserWindowId) => {
contextMenuItems.forEach((x) => {
if (x.browserWindowId === browserWindowId) {
const browserWindow = BrowserWindow.fromId(browserWindowId);
x.menu.popup(browserWindow);
}
});
});
socket.on("menu-setApplicationMenu", (menuItems) => {
const menu = Menu.buildFromTemplate(menuItems);
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit("menuItemClicked", id);
});
function addContextMenuItemClickConnector(menuItems, browserWindowId, callback) {
menuItems.forEach((item) => {
if (item.submenu && item.submenu.items.length > 0) {
addContextMenuItemClickConnector(item.submenu.items, browserWindowId, callback);
}
Menu.setApplicationMenu(menu);
});
if ('id' in item && item.id) {
item.click = () => { callback(item.id, browserWindowId); };
}
});
}
function addMenuItemClickConnector(menuItems, callback) {
menuItems.forEach((item) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
socket.on('menu-contextMenuPopup', (browserWindowId) => {
contextMenuItems.forEach(x => {
if (x.browserWindowId === browserWindowId) {
const browserWindow = BrowserWindow.fromId(browserWindowId);
x.menu.popup(browserWindow);
}
});
if ("id" in item && item.id) {
item.click = () => {
callback(item.id);
};
}
});
socket.on('menu-setApplicationMenu', (menuItems) => {
const menu = Menu.buildFromTemplate(menuItems);
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit('menuItemClicked', id);
});
Menu.setApplicationMenu(menu);
});
function addMenuItemClickConnector(menuItems, callback) {
menuItems.forEach((item) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
if ('id' in item && item.id) {
item.click = () => { callback(item.id); };
}
});
}
}
};

View File

@@ -3,28 +3,28 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('nativeTheme-shouldUseDarkColors', () => {
socket.on("nativeTheme-shouldUseDarkColors", () => {
const shouldUseDarkColors = electron_1.nativeTheme.shouldUseDarkColors;
electronSocket.emit('nativeTheme-shouldUseDarkColors-completed', shouldUseDarkColors);
electronSocket.emit("nativeTheme-shouldUseDarkColors-completed", shouldUseDarkColors);
});
socket.on('nativeTheme-shouldUseHighContrastColors', () => {
socket.on("nativeTheme-shouldUseHighContrastColors", () => {
const shouldUseHighContrastColors = electron_1.nativeTheme.shouldUseHighContrastColors;
electronSocket.emit('nativeTheme-shouldUseHighContrastColors-completed', shouldUseHighContrastColors);
electronSocket.emit("nativeTheme-shouldUseHighContrastColors-completed", shouldUseHighContrastColors);
});
socket.on('nativeTheme-shouldUseInvertedColorScheme', () => {
socket.on("nativeTheme-shouldUseInvertedColorScheme", () => {
const shouldUseInvertedColorScheme = electron_1.nativeTheme.shouldUseInvertedColorScheme;
electronSocket.emit('nativeTheme-shouldUseInvertedColorScheme-completed', shouldUseInvertedColorScheme);
electronSocket.emit("nativeTheme-shouldUseInvertedColorScheme-completed", shouldUseInvertedColorScheme);
});
socket.on('nativeTheme-getThemeSource', () => {
socket.on("nativeTheme-getThemeSource", () => {
const themeSource = electron_1.nativeTheme.themeSource;
electronSocket.emit('nativeTheme-getThemeSource-completed', themeSource);
electronSocket.emit("nativeTheme-getThemeSource-completed", themeSource);
});
socket.on('nativeTheme-themeSource', (themeSource) => {
socket.on("nativeTheme-themeSource", (themeSource) => {
electron_1.nativeTheme.themeSource = themeSource;
});
socket.on('register-nativeTheme-updated', (id) => {
electron_1.nativeTheme.on('updated', () => {
electronSocket.emit('nativeTheme-updated' + id);
socket.on("register-nativeTheme-updated", (id) => {
electron_1.nativeTheme.on("updated", () => {
electronSocket.emit("nativeTheme-updated" + id);
});
});
};

View File

@@ -1 +1 @@
{"version":3,"file":"nativeTheme.js","sourceRoot":"","sources":["nativeTheme.ts"],"names":[],"mappings":";AACA,uCAAuC;AACvC,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC9C,MAAM,mBAAmB,GAAG,sBAAW,CAAC,mBAAmB,CAAC;QAE5D,cAAc,CAAC,IAAI,CAAC,2CAA2C,EAAE,mBAAmB,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACtD,MAAM,2BAA2B,GAAG,sBAAW,CAAC,2BAA2B,CAAC;QAE5E,cAAc,CAAC,IAAI,CAAC,mDAAmD,EAAE,2BAA2B,CAAC,CAAC;IAC1G,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACvD,MAAM,4BAA4B,GAAG,sBAAW,CAAC,4BAA4B,CAAC;QAE9E,cAAc,CAAC,IAAI,CAAC,oDAAoD,EAAE,4BAA4B,CAAC,CAAC;IAC5G,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACzC,MAAM,WAAW,GAAG,sBAAW,CAAC,WAAW,CAAC;QAE5C,cAAc,CAAC,IAAI,CAAC,sCAAsC,EAAE,WAAW,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,WAAW,EAAE,EAAE;QACjD,sBAAW,CAAC,WAAW,GAAG,WAAW,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC,EAAE,EAAE,EAAE;QAC7C,sBAAW,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YAC3B,cAAc,CAAC,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"nativeTheme.js","sourceRoot":"","sources":["nativeTheme.ts"],"names":[],"mappings":";AACA,uCAAuC;AAEvC,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IAC1B,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAChD,MAAM,mBAAmB,GAAG,sBAAW,CAAC,mBAAmB,CAAC;QAE5D,cAAc,CAAC,IAAI,CACjB,2CAA2C,EAC3C,mBAAmB,CACpB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACxD,MAAM,2BAA2B,GAAG,sBAAW,CAAC,2BAA2B,CAAC;QAE5E,cAAc,CAAC,IAAI,CACjB,mDAAmD,EACnD,2BAA2B,CAC5B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACzD,MAAM,4BAA4B,GAChC,sBAAW,CAAC,4BAA4B,CAAC;QAE3C,cAAc,CAAC,IAAI,CACjB,oDAAoD,EACpD,4BAA4B,CAC7B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAC3C,MAAM,WAAW,GAAG,sBAAW,CAAC,WAAW,CAAC;QAE5C,cAAc,CAAC,IAAI,CAAC,sCAAsC,EAAE,WAAW,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,WAAW,EAAE,EAAE;QACnD,sBAAW,CAAC,WAAW,GAAG,WAAW,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC,EAAE,EAAE,EAAE;QAC/C,sBAAW,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YAC7B,cAAc,CAAC,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}

View File

@@ -1,41 +1,52 @@
import { Socket } from 'net';
import { nativeTheme } from 'electron';
let electronSocket;
import type { Socket } from "net";
import { nativeTheme } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
electronSocket = socket;
socket.on('nativeTheme-shouldUseDarkColors', () => {
const shouldUseDarkColors = nativeTheme.shouldUseDarkColors;
socket.on("nativeTheme-shouldUseDarkColors", () => {
const shouldUseDarkColors = nativeTheme.shouldUseDarkColors;
electronSocket.emit('nativeTheme-shouldUseDarkColors-completed', shouldUseDarkColors);
});
socket.on('nativeTheme-shouldUseHighContrastColors', () => {
const shouldUseHighContrastColors = nativeTheme.shouldUseHighContrastColors;
electronSocket.emit('nativeTheme-shouldUseHighContrastColors-completed', shouldUseHighContrastColors);
});
socket.on('nativeTheme-shouldUseInvertedColorScheme', () => {
const shouldUseInvertedColorScheme = nativeTheme.shouldUseInvertedColorScheme;
electronSocket.emit('nativeTheme-shouldUseInvertedColorScheme-completed', shouldUseInvertedColorScheme);
});
socket.on('nativeTheme-getThemeSource', () => {
const themeSource = nativeTheme.themeSource;
electronSocket.emit('nativeTheme-getThemeSource-completed', themeSource);
});
socket.on('nativeTheme-themeSource', (themeSource) => {
nativeTheme.themeSource = themeSource;
});
socket.on('register-nativeTheme-updated', (id) => {
nativeTheme.on('updated', () => {
electronSocket.emit('nativeTheme-updated' + id);
});
electronSocket.emit(
"nativeTheme-shouldUseDarkColors-completed",
shouldUseDarkColors,
);
});
socket.on("nativeTheme-shouldUseHighContrastColors", () => {
const shouldUseHighContrastColors = nativeTheme.shouldUseHighContrastColors;
electronSocket.emit(
"nativeTheme-shouldUseHighContrastColors-completed",
shouldUseHighContrastColors,
);
});
socket.on("nativeTheme-shouldUseInvertedColorScheme", () => {
const shouldUseInvertedColorScheme =
nativeTheme.shouldUseInvertedColorScheme;
electronSocket.emit(
"nativeTheme-shouldUseInvertedColorScheme-completed",
shouldUseInvertedColorScheme,
);
});
socket.on("nativeTheme-getThemeSource", () => {
const themeSource = nativeTheme.themeSource;
electronSocket.emit("nativeTheme-getThemeSource-completed", themeSource);
});
socket.on("nativeTheme-themeSource", (themeSource) => {
nativeTheme.themeSource = themeSource;
});
socket.on("register-nativeTheme-updated", (id) => {
nativeTheme.on("updated", () => {
electronSocket.emit("nativeTheme-updated" + id);
});
});
};

View File

@@ -1,40 +1,44 @@
"use strict";
const electron_1 = require("electron");
const notifications = (global['notifications'] = global['notifications'] || []);
const notifications = (global["notifications"] =
global["notifications"] || []);
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('createNotification', (options) => {
socket.on("createNotification", (options) => {
const notification = new electron_1.Notification(options);
let haveEvent = false;
if (options.showID) {
haveEvent = true;
notification.on('show', () => {
electronSocket.emit('NotificationEventShow', options.showID);
notification.on("show", () => {
electronSocket.emit("NotificationEventShow", options.showID);
});
}
if (options.clickID) {
haveEvent = true;
notification.on('click', () => {
electronSocket.emit('NotificationEventClick', options.clickID);
notification.on("click", () => {
electronSocket.emit("NotificationEventClick", options.clickID);
});
}
if (options.closeID) {
haveEvent = true;
notification.on('close', () => {
electronSocket.emit('NotificationEventClose', options.closeID);
notification.on("close", () => {
electronSocket.emit("NotificationEventClose", options.closeID);
});
}
if (options.replyID) {
haveEvent = true;
notification.on('reply', (event, value) => {
electronSocket.emit('NotificationEventReply', [options.replyID, value]);
notification.on("reply", (event, value) => {
electronSocket.emit("NotificationEventReply", [options.replyID, value]);
});
}
if (options.actionID) {
haveEvent = true;
notification.on('action', (event, value) => {
electronSocket.emit('NotificationEventAction', [options.actionID, value]);
notification.on("action", (event, value) => {
electronSocket.emit("NotificationEventAction", [
options.actionID,
value,
]);
});
}
if (haveEvent) {
@@ -42,9 +46,9 @@ module.exports = (socket) => {
}
notification.show();
});
socket.on('notificationIsSupported', () => {
socket.on("notificationIsSupported", () => {
const isSupported = electron_1.Notification.isSupported();
electronSocket.emit('notificationIsSupportedCompleted', isSupported);
electronSocket.emit("notificationIsSupportedCompleted", isSupported);
});
};
//# sourceMappingURL=notification.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"notification.js","sourceRoot":"","sources":["notification.ts"],"names":[],"mappings":";AACA,uCAAwC;AACxC,MAAM,aAAa,GAA4B,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAA4B,CAAC;AACpI,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,OAAO,EAAE,EAAE;QACxC,MAAM,YAAY,GAAG,IAAI,uBAAY,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACjB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;gBACzB,cAAc,CAAC,IAAI,CAAC,uBAAuB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACjE,CAAC,CAAC,CAAC;QACP,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC1B,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YACnE,CAAC,CAAC,CAAC;QACP,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC1B,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YACnE,CAAC,CAAC,CAAC;QACP,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACtC,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;YAC5E,CAAC,CAAC,CAAC;QACP,CAAC;QAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACvC,cAAc,CAAC,IAAI,CAAC,yBAAyB,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;YAC9E,CAAC,CAAC,CAAC;QACP,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACZ,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrC,CAAC;QAED,YAAY,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACtC,MAAM,WAAW,GAAG,uBAAY,CAAC,WAAW,EAAE,CAAC;QAC/C,cAAc,CAAC,IAAI,CAAC,kCAAkC,EAAE,WAAW,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"notification.js","sourceRoot":"","sources":["notification.ts"],"names":[],"mappings":";AACA,uCAAwC;AAExC,MAAM,aAAa,GAA4B,CAAC,MAAM,CAAC,eAAe,CAAC;IACrE,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAA4B,CAAC;AAE5D,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IAC1B,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,OAAO,EAAE,EAAE;QAC1C,MAAM,YAAY,GAAG,IAAI,uBAAY,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;gBAC3B,cAAc,CAAC,IAAI,CAAC,uBAAuB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC/D,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC5B,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YACjE,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC5B,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YACjE,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACxC,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;YAC1E,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACzC,cAAc,CAAC,IAAI,CAAC,yBAAyB,EAAE;oBAC7C,OAAO,CAAC,QAAQ;oBAChB,KAAK;iBACN,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACnC,CAAC;QAED,YAAY,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACxC,MAAM,WAAW,GAAG,uBAAY,CAAC,WAAW,EAAE,CAAC;QAC/C,cAAc,CAAC,IAAI,CAAC,kCAAkC,EAAE,WAAW,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}

View File

@@ -1,58 +1,64 @@
import { Socket } from 'net';
import { Notification } from 'electron';
const notifications: Electron.Notification[] = (global['notifications'] = global['notifications'] || []) as Electron.Notification[];
let electronSocket;
import type { Socket } from "net";
import { Notification } from "electron";
const notifications: Electron.Notification[] = (global["notifications"] =
global["notifications"] || []) as Electron.Notification[];
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('createNotification', (options) => {
const notification = new Notification(options);
let haveEvent = false;
electronSocket = socket;
socket.on("createNotification", (options) => {
const notification = new Notification(options);
let haveEvent = false;
if (options.showID) {
haveEvent = true;
notification.on('show', () => {
electronSocket.emit('NotificationEventShow', options.showID);
});
}
if (options.showID) {
haveEvent = true;
notification.on("show", () => {
electronSocket.emit("NotificationEventShow", options.showID);
});
}
if (options.clickID) {
haveEvent = true;
notification.on('click', () => {
electronSocket.emit('NotificationEventClick', options.clickID);
});
}
if (options.clickID) {
haveEvent = true;
notification.on("click", () => {
electronSocket.emit("NotificationEventClick", options.clickID);
});
}
if (options.closeID) {
haveEvent = true;
notification.on('close', () => {
electronSocket.emit('NotificationEventClose', options.closeID);
});
}
if (options.closeID) {
haveEvent = true;
notification.on("close", () => {
electronSocket.emit("NotificationEventClose", options.closeID);
});
}
if (options.replyID) {
haveEvent = true;
notification.on('reply', (event, value) => {
electronSocket.emit('NotificationEventReply', [options.replyID, value]);
});
}
if (options.replyID) {
haveEvent = true;
notification.on("reply", (event, value) => {
electronSocket.emit("NotificationEventReply", [options.replyID, value]);
});
}
if (options.actionID) {
haveEvent = true;
notification.on('action', (event, value) => {
electronSocket.emit('NotificationEventAction', [options.actionID, value]);
});
}
if (options.actionID) {
haveEvent = true;
notification.on("action", (event, value) => {
electronSocket.emit("NotificationEventAction", [
options.actionID,
value,
]);
});
}
if (haveEvent) {
notifications.push(notification);
}
if (haveEvent) {
notifications.push(notification);
}
notification.show();
});
notification.show();
});
socket.on('notificationIsSupported', () => {
const isSupported = Notification.isSupported();
electronSocket.emit('notificationIsSupportedCompleted', isSupported);
});
socket.on("notificationIsSupported", () => {
const isSupported = Notification.isSupported();
electronSocket.emit("notificationIsSupportedCompleted", isSupported);
});
};

View File

@@ -3,39 +3,39 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('register-powerMonitor-lock-screen', () => {
electron_1.powerMonitor.on('lock-screen', () => {
electronSocket.emit('powerMonitor-lock-screen');
socket.on("register-powerMonitor-lock-screen", () => {
electron_1.powerMonitor.on("lock-screen", () => {
electronSocket.emit("powerMonitor-lock-screen");
});
});
socket.on('register-powerMonitor-unlock-screen', () => {
electron_1.powerMonitor.on('unlock-screen', () => {
electronSocket.emit('powerMonitor-unlock-screen');
socket.on("register-powerMonitor-unlock-screen", () => {
electron_1.powerMonitor.on("unlock-screen", () => {
electronSocket.emit("powerMonitor-unlock-screen");
});
});
socket.on('register-powerMonitor-suspend', () => {
electron_1.powerMonitor.on('suspend', () => {
electronSocket.emit('powerMonitor-suspend');
socket.on("register-powerMonitor-suspend", () => {
electron_1.powerMonitor.on("suspend", () => {
electronSocket.emit("powerMonitor-suspend");
});
});
socket.on('register-powerMonitor-resume', () => {
electron_1.powerMonitor.on('resume', () => {
electronSocket.emit('powerMonitor-resume');
socket.on("register-powerMonitor-resume", () => {
electron_1.powerMonitor.on("resume", () => {
electronSocket.emit("powerMonitor-resume");
});
});
socket.on('register-powerMonitor-ac', () => {
electron_1.powerMonitor.on('on-ac', () => {
electronSocket.emit('powerMonitor-ac');
socket.on("register-powerMonitor-ac", () => {
electron_1.powerMonitor.on("on-ac", () => {
electronSocket.emit("powerMonitor-ac");
});
});
socket.on('register-powerMonitor-battery', () => {
electron_1.powerMonitor.on('on-battery', () => {
electronSocket.emit('powerMonitor-battery');
socket.on("register-powerMonitor-battery", () => {
electron_1.powerMonitor.on("on-battery", () => {
electronSocket.emit("powerMonitor-battery");
});
});
socket.on('register-powerMonitor-shutdown', () => {
electron_1.powerMonitor.on('shutdown', () => {
electronSocket.emit('powerMonitor-shutdown');
socket.on("register-powerMonitor-shutdown", () => {
electron_1.powerMonitor.on("shutdown", () => {
electronSocket.emit("powerMonitor-shutdown");
});
});
};

View File

@@ -1 +1 @@
{"version":3,"file":"powerMonitor.js","sourceRoot":"","sources":["powerMonitor.ts"],"names":[],"mappings":";AACA,uCAAwC;AACxC,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAChD,uBAAY,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;YAChC,cAAc,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAClD,uBAAY,CAAC,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;YAClC,cAAc,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC5C,uBAAY,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YAC5B,cAAc,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC3C,uBAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC3B,cAAc,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACvC,uBAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAC1B,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC5C,uBAAY,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;YAC/B,cAAc,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAC7C,uBAAY,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;YAC7B,cAAc,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"powerMonitor.js","sourceRoot":"","sources":["powerMonitor.ts"],"names":[],"mappings":";AACA,uCAAwC;AAExC,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IAC1B,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAClD,uBAAY,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;YAClC,cAAc,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QACpD,uBAAY,CAAC,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;YACpC,cAAc,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC9C,uBAAY,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YAC9B,cAAc,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC7C,uBAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC7B,cAAc,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACzC,uBAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAC5B,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC9C,uBAAY,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;YACjC,cAAc,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAC/C,uBAAY,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;YAC/B,cAAc,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}

View File

@@ -1,42 +1,43 @@
import { Socket } from 'net';
import { powerMonitor } from 'electron';
let electronSocket;
import type { Socket } from "net";
import { powerMonitor } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('register-powerMonitor-lock-screen', () => {
powerMonitor.on('lock-screen', () => {
electronSocket.emit('powerMonitor-lock-screen');
});
electronSocket = socket;
socket.on("register-powerMonitor-lock-screen", () => {
powerMonitor.on("lock-screen", () => {
electronSocket.emit("powerMonitor-lock-screen");
});
socket.on('register-powerMonitor-unlock-screen', () => {
powerMonitor.on('unlock-screen', () => {
electronSocket.emit('powerMonitor-unlock-screen');
});
});
socket.on("register-powerMonitor-unlock-screen", () => {
powerMonitor.on("unlock-screen", () => {
electronSocket.emit("powerMonitor-unlock-screen");
});
socket.on('register-powerMonitor-suspend', () => {
powerMonitor.on('suspend', () => {
electronSocket.emit('powerMonitor-suspend');
});
});
socket.on("register-powerMonitor-suspend", () => {
powerMonitor.on("suspend", () => {
electronSocket.emit("powerMonitor-suspend");
});
socket.on('register-powerMonitor-resume', () => {
powerMonitor.on('resume', () => {
electronSocket.emit('powerMonitor-resume');
});
});
socket.on("register-powerMonitor-resume", () => {
powerMonitor.on("resume", () => {
electronSocket.emit("powerMonitor-resume");
});
socket.on('register-powerMonitor-ac', () => {
powerMonitor.on('on-ac', () => {
electronSocket.emit('powerMonitor-ac');
});
});
socket.on("register-powerMonitor-ac", () => {
powerMonitor.on("on-ac", () => {
electronSocket.emit("powerMonitor-ac");
});
socket.on('register-powerMonitor-battery', () => {
powerMonitor.on('on-battery', () => {
electronSocket.emit('powerMonitor-battery');
});
});
socket.on("register-powerMonitor-battery", () => {
powerMonitor.on("on-battery", () => {
electronSocket.emit("powerMonitor-battery");
});
socket.on('register-powerMonitor-shutdown', () => {
powerMonitor.on('shutdown', () => {
electronSocket.emit('powerMonitor-shutdown');
});
});
socket.on("register-powerMonitor-shutdown", () => {
powerMonitor.on("shutdown", () => {
electronSocket.emit("powerMonitor-shutdown");
});
});
};

View File

@@ -2,61 +2,61 @@
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('process-execPath', () => {
socket.on("process-execPath", () => {
const value = process.execPath;
electronSocket.emit('process-execPath-completed', value);
electronSocket.emit("process-execPath-completed", value);
});
socket.on('process-argv', () => {
socket.on("process-argv", () => {
const value = process.argv;
electronSocket.emit('process-argv-completed', value);
electronSocket.emit("process-argv-completed", value);
});
socket.on('process-type', () => {
socket.on("process-type", () => {
const value = process.type;
electronSocket.emit('process-type-completed', value);
electronSocket.emit("process-type-completed", value);
});
socket.on('process-versions', () => {
socket.on("process-versions", () => {
const value = process.versions;
electronSocket.emit('process-versions-completed', value);
electronSocket.emit("process-versions-completed", value);
});
socket.on('process-defaultApp', () => {
socket.on("process-defaultApp", () => {
if (process.defaultApp === undefined) {
electronSocket.emit('process-defaultApp-completed', false);
electronSocket.emit("process-defaultApp-completed", false);
return;
}
electronSocket.emit('process-defaultApp-completed', process.defaultApp);
electronSocket.emit("process-defaultApp-completed", process.defaultApp);
});
socket.on('process-isMainFrame', () => {
socket.on("process-isMainFrame", () => {
if (process.isMainFrame === undefined) {
electronSocket.emit('process-isMainFrame-completed', false);
electronSocket.emit("process-isMainFrame-completed", false);
return;
}
electronSocket.emit('process-isMainFrame-completed', process.isMainFrame);
electronSocket.emit("process-isMainFrame-completed", process.isMainFrame);
});
socket.on('process-resourcesPath', () => {
socket.on("process-resourcesPath", () => {
const value = process.resourcesPath;
electronSocket.emit('process-resourcesPath-completed', value);
electronSocket.emit("process-resourcesPath-completed", value);
});
socket.on('process-upTime', () => {
socket.on("process-upTime", () => {
let value = process.uptime();
if (value === undefined) {
value = -1;
}
electronSocket.emit('process-upTime-completed', value);
electronSocket.emit("process-upTime-completed", value);
});
socket.on('process-pid', () => {
socket.on("process-pid", () => {
if (process.pid === undefined) {
electronSocket.emit('process-pid-completed', -1);
electronSocket.emit("process-pid-completed", -1);
return;
}
electronSocket.emit('process-pid-completed', process.pid);
electronSocket.emit("process-pid-completed", process.pid);
});
socket.on('process-arch', () => {
socket.on("process-arch", () => {
const value = process.arch;
electronSocket.emit('process-arch-completed', value);
electronSocket.emit("process-arch-completed", value);
});
socket.on('process-platform', () => {
socket.on("process-platform", () => {
const value = process.platform;
electronSocket.emit('process-platform-completed', value);
electronSocket.emit("process-platform-completed", value);
});
};
//# sourceMappingURL=process.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"process.js","sourceRoot":"","sources":["process.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"process.js","sourceRoot":"","sources":["process.ts"],"names":[],"mappings":"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"}

View File

@@ -1,73 +1,74 @@
import { Socket } from 'net';
let electronSocket;
import type { Socket } from "net";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
electronSocket = socket;
socket.on('process-execPath', () => {
const value = process.execPath;
electronSocket.emit('process-execPath-completed', value);
});
socket.on("process-execPath", () => {
const value = process.execPath;
electronSocket.emit("process-execPath-completed", value);
});
socket.on('process-argv', () => {
const value = process.argv;
electronSocket.emit('process-argv-completed', value);
});
socket.on("process-argv", () => {
const value = process.argv;
electronSocket.emit("process-argv-completed", value);
});
socket.on('process-type', () => {
const value = process.type;
electronSocket.emit('process-type-completed', value);
});
socket.on("process-type", () => {
const value = process.type;
electronSocket.emit("process-type-completed", value);
});
socket.on('process-versions', () => {
const value = process.versions;
electronSocket.emit('process-versions-completed', value);
});
socket.on("process-versions", () => {
const value = process.versions;
electronSocket.emit("process-versions-completed", value);
});
socket.on('process-defaultApp', () => {
if (process.defaultApp === undefined) {
electronSocket.emit('process-defaultApp-completed', false);
return;
}
electronSocket.emit('process-defaultApp-completed', process.defaultApp);
});
socket.on("process-defaultApp", () => {
if (process.defaultApp === undefined) {
electronSocket.emit("process-defaultApp-completed", false);
return;
}
electronSocket.emit("process-defaultApp-completed", process.defaultApp);
});
socket.on('process-isMainFrame', () => {
if (process.isMainFrame === undefined) {
electronSocket.emit('process-isMainFrame-completed', false);
return;
}
electronSocket.emit('process-isMainFrame-completed', process.isMainFrame);
});
socket.on("process-isMainFrame", () => {
if (process.isMainFrame === undefined) {
electronSocket.emit("process-isMainFrame-completed", false);
return;
}
electronSocket.emit("process-isMainFrame-completed", process.isMainFrame);
});
socket.on('process-resourcesPath', () => {
const value = process.resourcesPath;
electronSocket.emit('process-resourcesPath-completed', value);
});
socket.on("process-resourcesPath", () => {
const value = process.resourcesPath;
electronSocket.emit("process-resourcesPath-completed", value);
});
socket.on('process-upTime', () => {
let value = process.uptime();
if (value === undefined) {
value = -1;
}
electronSocket.emit('process-upTime-completed', value);
});
socket.on("process-upTime", () => {
let value = process.uptime();
if (value === undefined) {
value = -1;
}
electronSocket.emit("process-upTime-completed", value);
});
socket.on('process-pid', () => {
if (process.pid === undefined) {
electronSocket.emit('process-pid-completed', -1);
return;
}
electronSocket.emit('process-pid-completed', process.pid);
});
socket.on("process-pid", () => {
if (process.pid === undefined) {
electronSocket.emit("process-pid-completed", -1);
return;
}
electronSocket.emit("process-pid-completed", process.pid);
});
socket.on('process-arch', () => {
const value = process.arch;
electronSocket.emit('process-arch-completed', value);
});
socket.on("process-arch", () => {
const value = process.arch;
electronSocket.emit("process-arch-completed", value);
});
socket.on('process-platform', () => {
const value = process.platform;
electronSocket.emit('process-platform-completed', value);
})
socket.on("process-platform", () => {
const value = process.platform;
electronSocket.emit("process-platform-completed", value);
});
};

View File

@@ -3,44 +3,47 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('register-screen-display-added', (id) => {
electron_1.screen.on('display-added', (event, display) => {
electronSocket.emit('screen-display-added' + id, display);
socket.on("register-screen-display-added", (id) => {
electron_1.screen.on("display-added", (event, display) => {
electronSocket.emit("screen-display-added" + id, display);
});
});
socket.on('register-screen-display-removed', (id) => {
electron_1.screen.on('display-removed', (event, display) => {
electronSocket.emit('screen-display-removed' + id, display);
socket.on("register-screen-display-removed", (id) => {
electron_1.screen.on("display-removed", (event, display) => {
electronSocket.emit("screen-display-removed" + id, display);
});
});
socket.on('register-screen-display-metrics-changed', (id) => {
electron_1.screen.on('display-metrics-changed', (event, display, changedMetrics) => {
electronSocket.emit('screen-display-metrics-changed' + id, [display, changedMetrics]);
socket.on("register-screen-display-metrics-changed", (id) => {
electron_1.screen.on("display-metrics-changed", (event, display, changedMetrics) => {
electronSocket.emit("screen-display-metrics-changed" + id, [
display,
changedMetrics,
]);
});
});
socket.on('screen-getCursorScreenPoint', () => {
socket.on("screen-getCursorScreenPoint", () => {
const point = electron_1.screen.getCursorScreenPoint();
electronSocket.emit('screen-getCursorScreenPoint-completed', point);
electronSocket.emit("screen-getCursorScreenPoint-completed", point);
});
socket.on('screen-getMenuBarWorkArea', () => {
socket.on("screen-getMenuBarWorkArea", () => {
const height = electron_1.screen.getPrimaryDisplay().workArea;
electronSocket.emit('screen-getMenuBarWorkArea-completed', height);
electronSocket.emit("screen-getMenuBarWorkArea-completed", height);
});
socket.on('screen-getPrimaryDisplay', () => {
socket.on("screen-getPrimaryDisplay", () => {
const display = electron_1.screen.getPrimaryDisplay();
electronSocket.emit('screen-getPrimaryDisplay-completed', display);
electronSocket.emit("screen-getPrimaryDisplay-completed", display);
});
socket.on('screen-getAllDisplays', () => {
socket.on("screen-getAllDisplays", () => {
const display = electron_1.screen.getAllDisplays();
electronSocket.emit('screen-getAllDisplays-completed', display);
electronSocket.emit("screen-getAllDisplays-completed", display);
});
socket.on('screen-getDisplayNearestPoint', (point) => {
socket.on("screen-getDisplayNearestPoint", (point) => {
const display = electron_1.screen.getDisplayNearestPoint(point);
electronSocket.emit('screen-getDisplayNearestPoint-completed', display);
electronSocket.emit("screen-getDisplayNearestPoint-completed", display);
});
socket.on('screen-getDisplayMatching', (rectangle) => {
socket.on("screen-getDisplayMatching", (rectangle) => {
const display = electron_1.screen.getDisplayMatching(rectangle);
electronSocket.emit('screen-getDisplayMatching-completed', display);
electronSocket.emit("screen-getDisplayMatching-completed", display);
});
};
//# sourceMappingURL=screen.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"screen.js","sourceRoot":"","sources":["screen.ts"],"names":[],"mappings":";AACA,uCAAkC;AAClC,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,CAAC,EAAE,EAAE,EAAE;QAC9C,iBAAM,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC1C,cAAc,CAAC,IAAI,CAAC,sBAAsB,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,iCAAiC,EAAE,CAAC,EAAE,EAAE,EAAE;QAChD,iBAAM,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC5C,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yCAAyC,EAAE,CAAC,EAAE,EAAE,EAAE;QACxD,iBAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE;YACpE,cAAc,CAAC,IAAI,CAAC,gCAAgC,GAAG,EAAE,EAAE,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;QAC1F,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QAC1C,MAAM,KAAK,GAAG,iBAAM,CAAC,oBAAoB,EAAE,CAAC;QAC5C,cAAc,CAAC,IAAI,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACxC,MAAM,MAAM,GAAG,iBAAM,CAAC,iBAAiB,EAAE,CAAC,QAAQ,CAAC;QACnD,cAAc,CAAC,IAAI,CAAC,qCAAqC,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACvC,MAAM,OAAO,GAAG,iBAAM,CAAC,iBAAiB,EAAE,CAAC;QAC3C,cAAc,CAAC,IAAI,CAAC,oCAAoC,EAAE,OAAO,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACpC,MAAM,OAAO,GAAG,iBAAM,CAAC,cAAc,EAAE,CAAC;QACxC,cAAc,CAAC,IAAI,CAAC,iCAAiC,EAAE,OAAO,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,CAAC,KAAK,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,iBAAM,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QACrD,cAAc,CAAC,IAAI,CAAC,yCAAyC,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2BAA2B,EAAE,CAAC,SAAS,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,iBAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACrD,cAAc,CAAC,IAAI,CAAC,qCAAqC,EAAE,OAAO,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"screen.js","sourceRoot":"","sources":["screen.ts"],"names":[],"mappings":";AACA,uCAAkC;AAElC,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IAC1B,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,CAAC,EAAE,EAAE,EAAE;QAChD,iBAAM,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC5C,cAAc,CAAC,IAAI,CAAC,sBAAsB,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,iCAAiC,EAAE,CAAC,EAAE,EAAE,EAAE;QAClD,iBAAM,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC9C,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yCAAyC,EAAE,CAAC,EAAE,EAAE,EAAE;QAC1D,iBAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE;YACtE,cAAc,CAAC,IAAI,CAAC,gCAAgC,GAAG,EAAE,EAAE;gBACzD,OAAO;gBACP,cAAc;aACf,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QAC5C,MAAM,KAAK,GAAG,iBAAM,CAAC,oBAAoB,EAAE,CAAC;QAC5C,cAAc,CAAC,IAAI,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QAC1C,MAAM,MAAM,GAAG,iBAAM,CAAC,iBAAiB,EAAE,CAAC,QAAQ,CAAC;QACnD,cAAc,CAAC,IAAI,CAAC,qCAAqC,EAAE,MAAM,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACzC,MAAM,OAAO,GAAG,iBAAM,CAAC,iBAAiB,EAAE,CAAC;QAC3C,cAAc,CAAC,IAAI,CAAC,oCAAoC,EAAE,OAAO,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACtC,MAAM,OAAO,GAAG,iBAAM,CAAC,cAAc,EAAE,CAAC;QACxC,cAAc,CAAC,IAAI,CAAC,iCAAiC,EAAE,OAAO,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,+BAA+B,EAAE,CAAC,KAAK,EAAE,EAAE;QACnD,MAAM,OAAO,GAAG,iBAAM,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QACrD,cAAc,CAAC,IAAI,CAAC,yCAAyC,EAAE,OAAO,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2BAA2B,EAAE,CAAC,SAAS,EAAE,EAAE;QACnD,MAAM,OAAO,GAAG,iBAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACrD,cAAc,CAAC,IAAI,CAAC,qCAAqC,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}

View File

@@ -1,55 +1,59 @@
import { Socket } from 'net';
import { screen } from 'electron';
let electronSocket;
import type { Socket } from "net";
import { screen } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
electronSocket = socket;
socket.on('register-screen-display-added', (id) => {
screen.on('display-added', (event, display) => {
electronSocket.emit('screen-display-added' + id, display);
});
socket.on("register-screen-display-added", (id) => {
screen.on("display-added", (event, display) => {
electronSocket.emit("screen-display-added" + id, display);
});
});
socket.on('register-screen-display-removed', (id) => {
screen.on('display-removed', (event, display) => {
electronSocket.emit('screen-display-removed' + id, display);
});
socket.on("register-screen-display-removed", (id) => {
screen.on("display-removed", (event, display) => {
electronSocket.emit("screen-display-removed" + id, display);
});
});
socket.on('register-screen-display-metrics-changed', (id) => {
screen.on('display-metrics-changed', (event, display, changedMetrics) => {
electronSocket.emit('screen-display-metrics-changed' + id, [display, changedMetrics]);
});
socket.on("register-screen-display-metrics-changed", (id) => {
screen.on("display-metrics-changed", (event, display, changedMetrics) => {
electronSocket.emit("screen-display-metrics-changed" + id, [
display,
changedMetrics,
]);
});
});
socket.on('screen-getCursorScreenPoint', () => {
const point = screen.getCursorScreenPoint();
electronSocket.emit('screen-getCursorScreenPoint-completed', point);
});
socket.on("screen-getCursorScreenPoint", () => {
const point = screen.getCursorScreenPoint();
electronSocket.emit("screen-getCursorScreenPoint-completed", point);
});
socket.on('screen-getMenuBarWorkArea', () => {
const height = screen.getPrimaryDisplay().workArea;
electronSocket.emit('screen-getMenuBarWorkArea-completed', height);
});
socket.on("screen-getMenuBarWorkArea", () => {
const height = screen.getPrimaryDisplay().workArea;
electronSocket.emit("screen-getMenuBarWorkArea-completed", height);
});
socket.on('screen-getPrimaryDisplay', () => {
const display = screen.getPrimaryDisplay();
electronSocket.emit('screen-getPrimaryDisplay-completed', display);
});
socket.on("screen-getPrimaryDisplay", () => {
const display = screen.getPrimaryDisplay();
electronSocket.emit("screen-getPrimaryDisplay-completed", display);
});
socket.on('screen-getAllDisplays', () => {
const display = screen.getAllDisplays();
electronSocket.emit('screen-getAllDisplays-completed', display);
});
socket.on("screen-getAllDisplays", () => {
const display = screen.getAllDisplays();
electronSocket.emit("screen-getAllDisplays-completed", display);
});
socket.on('screen-getDisplayNearestPoint', (point) => {
const display = screen.getDisplayNearestPoint(point);
electronSocket.emit('screen-getDisplayNearestPoint-completed', display);
});
socket.on("screen-getDisplayNearestPoint", (point) => {
const display = screen.getDisplayNearestPoint(point);
electronSocket.emit("screen-getDisplayNearestPoint-completed", display);
});
socket.on('screen-getDisplayMatching', (rectangle) => {
const display = screen.getDisplayMatching(rectangle);
electronSocket.emit('screen-getDisplayMatching-completed', display);
});
socket.on("screen-getDisplayMatching", (rectangle) => {
const display = screen.getDisplayMatching(rectangle);
electronSocket.emit("screen-getDisplayMatching-completed", display);
});
};

View File

@@ -3,18 +3,18 @@ const electron_1 = require("electron");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('shell-showItemInFolder', (fullPath) => {
socket.on("shell-showItemInFolder", (fullPath) => {
electron_1.shell.showItemInFolder(fullPath);
electronSocket.emit('shell-showItemInFolderCompleted');
electronSocket.emit("shell-showItemInFolderCompleted");
});
socket.on('shell-openPath', async (path) => {
socket.on("shell-openPath", async (path) => {
const errorMessage = await electron_1.shell.openPath(path);
electronSocket.emit('shell-openPathCompleted', errorMessage);
electronSocket.emit("shell-openPathCompleted", errorMessage);
});
socket.on('shell-openExternal', async (url, options) => {
let result = '';
socket.on("shell-openExternal", async (url, options) => {
let result = "";
if (options) {
await electron_1.shell.openExternal(url, options).catch(e => {
await electron_1.shell.openExternal(url, options).catch((e) => {
result = e.message;
});
}
@@ -23,9 +23,9 @@ module.exports = (socket) => {
result = e.message;
});
}
electronSocket.emit('shell-openExternalCompleted', result);
electronSocket.emit("shell-openExternalCompleted", result);
});
socket.on('shell-trashItem', async (fullPath, deleteOnFail) => {
socket.on("shell-trashItem", async (fullPath, deleteOnFail) => {
let success = false;
try {
await electron_1.shell.trashItem(fullPath);
@@ -34,18 +34,18 @@ module.exports = (socket) => {
catch (error) {
success = false;
}
electronSocket.emit('shell-trashItem-completed', success);
electronSocket.emit("shell-trashItem-completed", success);
});
socket.on('shell-beep', () => {
socket.on("shell-beep", () => {
electron_1.shell.beep();
});
socket.on('shell-writeShortcutLink', (shortcutPath, operation, options) => {
socket.on("shell-writeShortcutLink", (shortcutPath, operation, options) => {
const success = electron_1.shell.writeShortcutLink(shortcutPath, operation, options);
electronSocket.emit('shell-writeShortcutLinkCompleted', success);
electronSocket.emit("shell-writeShortcutLinkCompleted", success);
});
socket.on('shell-readShortcutLink', (shortcutPath) => {
socket.on("shell-readShortcutLink", (shortcutPath) => {
const shortcutDetails = electron_1.shell.readShortcutLink(shortcutPath);
electronSocket.emit('shell-readShortcutLinkCompleted', shortcutDetails);
electronSocket.emit("shell-readShortcutLinkCompleted", shortcutDetails);
});
};
//# sourceMappingURL=shell.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"shell.js","sourceRoot":"","sources":["shell.ts"],"names":[],"mappings":";AACA,uCAAiC;AACjC,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,wBAAwB,EAAE,CAAC,QAAQ,EAAE,EAAE;QAC7C,gBAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAEjC,cAAc,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACvC,MAAM,YAAY,GAAG,MAAM,gBAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEhD,cAAc,CAAC,IAAI,CAAC,yBAAyB,EAAE,YAAY,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,oBAAoB,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE;QACnD,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,IAAI,OAAO,EAAE,CAAC;YACV,MAAM,gBAAK,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;gBAC7C,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC;YACvB,CAAC,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACJ,MAAM,gBAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACtC,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC;YACvB,CAAC,CAAC,CAAC;QACP,CAAC;QAED,cAAc,CAAC,IAAI,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,iBAAiB,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE;QAC1D,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,IAAI,CAAC;YACD,MAAM,gBAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAChC,OAAO,GAAG,IAAI,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,GAAG,KAAK,CAAC;QACpB,CAAC;QAED,cAAc,CAAC,IAAI,CAAC,2BAA2B,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;QACzB,gBAAK,CAAC,IAAI,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;QACtE,MAAM,OAAO,GAAG,gBAAK,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAE1E,cAAc,CAAC,IAAI,CAAC,kCAAkC,EAAE,OAAO,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,wBAAwB,EAAE,CAAC,YAAY,EAAE,EAAE;QACjD,MAAM,eAAe,GAAG,gBAAK,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAE7D,cAAc,CAAC,IAAI,CAAC,iCAAiC,EAAE,eAAe,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"shell.js","sourceRoot":"","sources":["shell.ts"],"names":[],"mappings":";AACA,uCAAiC;AAEjC,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IAC1B,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,wBAAwB,EAAE,CAAC,QAAQ,EAAE,EAAE;QAC/C,gBAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAEjC,cAAc,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACzC,MAAM,YAAY,GAAG,MAAM,gBAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEhD,cAAc,CAAC,IAAI,CAAC,yBAAyB,EAAE,YAAY,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,oBAAoB,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE;QACrD,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,gBAAK,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACjD,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC;YACrB,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,gBAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACxC,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC;YACrB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,cAAc,CAAC,IAAI,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,iBAAiB,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE;QAC5D,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,IAAI,CAAC;YACH,MAAM,gBAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAChC,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;QAED,cAAc,CAAC,IAAI,CAAC,2BAA2B,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;QAC3B,gBAAK,CAAC,IAAI,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;QACxE,MAAM,OAAO,GAAG,gBAAK,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAE1E,cAAc,CAAC,IAAI,CAAC,kCAAkC,EAAE,OAAO,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,wBAAwB,EAAE,CAAC,YAAY,EAAE,EAAE;QACnD,MAAM,eAAe,GAAG,gBAAK,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAE7D,cAAc,CAAC,IAAI,CAAC,iCAAiC,EAAE,eAAe,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}

View File

@@ -1,63 +1,64 @@
import { Socket } from 'net';
import { shell } from 'electron';
let electronSocket;
import type { Socket } from "net";
import { shell } from "electron";
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('shell-showItemInFolder', (fullPath) => {
shell.showItemInFolder(fullPath);
electronSocket = socket;
socket.on("shell-showItemInFolder", (fullPath) => {
shell.showItemInFolder(fullPath);
electronSocket.emit('shell-showItemInFolderCompleted');
});
electronSocket.emit("shell-showItemInFolderCompleted");
});
socket.on('shell-openPath', async (path) => {
const errorMessage = await shell.openPath(path);
socket.on("shell-openPath", async (path) => {
const errorMessage = await shell.openPath(path);
electronSocket.emit('shell-openPathCompleted', errorMessage);
});
electronSocket.emit("shell-openPathCompleted", errorMessage);
});
socket.on('shell-openExternal', async (url, options) => {
let result = '';
socket.on("shell-openExternal", async (url, options) => {
let result = "";
if (options) {
await shell.openExternal(url, options).catch(e => {
result = e.message;
});
} else {
await shell.openExternal(url).catch((e) => {
result = e.message;
});
}
if (options) {
await shell.openExternal(url, options).catch((e) => {
result = e.message;
});
} else {
await shell.openExternal(url).catch((e) => {
result = e.message;
});
}
electronSocket.emit('shell-openExternalCompleted', result);
});
electronSocket.emit("shell-openExternalCompleted", result);
});
socket.on('shell-trashItem', async (fullPath, deleteOnFail) => {
let success = false;
socket.on("shell-trashItem", async (fullPath, deleteOnFail) => {
let success = false;
try {
await shell.trashItem(fullPath);
success = true;
} catch (error) {
success = false;
}
try {
await shell.trashItem(fullPath);
success = true;
} catch (error) {
success = false;
}
electronSocket.emit('shell-trashItem-completed', success);
});
electronSocket.emit("shell-trashItem-completed", success);
});
socket.on('shell-beep', () => {
shell.beep();
});
socket.on("shell-beep", () => {
shell.beep();
});
socket.on('shell-writeShortcutLink', (shortcutPath, operation, options) => {
const success = shell.writeShortcutLink(shortcutPath, operation, options);
socket.on("shell-writeShortcutLink", (shortcutPath, operation, options) => {
const success = shell.writeShortcutLink(shortcutPath, operation, options);
electronSocket.emit('shell-writeShortcutLinkCompleted', success);
});
electronSocket.emit("shell-writeShortcutLinkCompleted", success);
});
socket.on('shell-readShortcutLink', (shortcutPath) => {
const shortcutDetails = shell.readShortcutLink(shortcutPath);
socket.on("shell-readShortcutLink", (shortcutPath) => {
const shortcutDetails = shell.readShortcutLink(shortcutPath);
electronSocket.emit('shell-readShortcutLinkCompleted', shortcutDetails);
});
electronSocket.emit("shell-readShortcutLinkCompleted", shortcutDetails);
});
};

View File

@@ -0,0 +1,214 @@
/**
* 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");
const { app } = require("electron");
const { logger } = require("../logger");
// Flag to track if we've already initiated shutdown due to EPIPE
let isShuttingDownFromEPIPE = false;
// Handle EPIPE errors at the process stdout/stderr level
// When the pipe breaks (e.g., .NET process terminates), quit Electron gracefully
const handlePipeError = (err) => {
if (err.code === "EPIPE" || err.code === "ERR_STREAM_WRITE_AFTER_END") {
// Pipe is broken - the .NET process has terminated
if (!isShuttingDownFromEPIPE) {
isShuttingDownFromEPIPE = true;
// Give a brief moment for any pending operations, then quit
setImmediate(() => {
if (app && app.quit) {
app.quit();
}
});
}
return;
}
// Re-throw other errors
throw err;
};
// Suppress EPIPE errors at the process stdout/stderr level
if (process.stdout && !process.stdout.listenerCount("error")) {
process.stdout.on("error", handlePipeError);
}
if (process.stderr && !process.stderr.listenerCount("error")) {
process.stderr.on("error", handlePipeError);
}
// Custom logger for SignalR that uses environment-aware logging
class SafeLogger {
constructor(minLevel) {
this.minLevel = minLevel || signalR.LogLevel.Warning;
}
log(logLevel, message) {
// Skip if below minimum level
if (logLevel < this.minLevel) {
return;
}
switch (logLevel) {
case signalR.LogLevel.Critical:
case signalR.LogLevel.Error:
logger.error(`[SignalR] ${message}`);
break;
case signalR.LogLevel.Warning:
logger.warn(`[SignalR] ${message}`);
break;
case signalR.LogLevel.Information:
logger.info(`[SignalR] ${message}`);
break;
case signalR.LogLevel.Debug:
case signalR.LogLevel.Trace:
logger.debug(`[SignalR] ${message}`);
break;
}
}
}
class SignalRBridge {
constructor(hubUrl, authToken) {
this.hubUrl = hubUrl;
this.authToken = authToken;
this.connection = null;
this.isConnected = false;
this.eventHandlers = new Map(); // For socket.io-style .on() handlers
this.callIdCounter = 0;
}
async connect() {
// Append authentication token to the SignalR connection URL
const connectionUrl = this.authToken
? `${this.hubUrl}?token=${this.authToken}`
: this.hubUrl;
// Determine SignalR log level based on environment
// Warning level suppresses verbose packet-level logging
const { getLogLevel, LogLevel: AppLogLevel } = require("../logger");
let signalRLogLevel;
if (getLogLevel() <= AppLogLevel.DEBUG) {
// Debug mode: show Info level (connection events without packet details)
signalRLogLevel = signalR.LogLevel.Information;
} else {
// Development/Production: only warnings and errors
signalRLogLevel = signalR.LogLevel.Warning;
}
this.connection = new signalR.HubConnectionBuilder()
.withUrl(connectionUrl)
.withAutomaticReconnect()
.configureLogging(new SafeLogger(signalRLogLevel))
.build();
// Handle reconnection
this.connection.onreconnecting((error) => {
logger.error(`[SignalRBridge] Connection lost. Reconnecting...`, error);
this.isConnected = false;
});
this.connection.onreconnected((connectionId) => {
this.isConnected = true;
});
this.connection.onclose((error) => {
if (error) {
logger.error(`[SignalRBridge] Connection closed:`, error);
}
this.isConnected = false;
});
// Set up handlers for messages from .NET
this.setupMessageHandlers();
try {
await this.connection.start();
this.isConnected = true;
// Register with the hub
await this.connection.invoke("RegisterElectronClient");
return true;
} catch (err) {
// Check if this is an authentication error
if (err.message && err.message.includes("401")) {
logger.error(
`[SignalRBridge] Authentication failed: The authentication token is invalid or missing.`,
);
logger.error(
`[SignalRBridge] Please ensure the --authtoken parameter is correctly passed to Electron.`,
);
} else {
logger.error(`[SignalRBridge] Connection failed:`, err);
}
this.isConnected = false;
return false;
}
}
setupMessageHandlers() {
// Handle generic events from .NET - this is where .NET's Emit() calls arrive
this.connection.on("event", (eventName, args) => {
// args is an array from .NET - spread it when calling handlers
const argsArray = Array.isArray(args) ? args : [args];
// Check if we have handlers registered for this event
if (this.eventHandlers.has(eventName)) {
const handlers = this.eventHandlers.get(eventName);
handlers.forEach((handler) => {
try {
handler(...argsArray);
} catch (err) {
logger.error(
`[SignalRBridge] Error in event handler for ${eventName}:`,
err,
);
}
});
}
});
}
// Socket.io compatibility: register event handler
on(eventName, callback) {
if (!this.eventHandlers.has(eventName)) {
this.eventHandlers.set(eventName, []);
}
this.eventHandlers.get(eventName).push(callback);
}
// Socket.io compatibility: emit event (send to .NET)
async emit(eventName, ...args) {
if (!this.isConnected) {
logger.warn(`[SignalRBridge] Cannot emit ${eventName} - not connected`);
return;
}
try {
// Always pass args as an array to match C# method signature
await this.connection.invoke("ElectronEvent", eventName, args);
} catch (err) {
logger.error(`[SignalRBridge] Error emitting ${eventName}:`, err);
throw err;
}
}
async disconnect() {
if (this.connection) {
await this.connection.stop();
this.isConnected = false;
}
}
}
module.exports = { SignalRBridge };

View File

@@ -1,101 +1,112 @@
"use strict";
const electron_1 = require("electron");
let tray = (global['$tray'] = global['tray'] || { value: null });
let tray = (global["$tray"] = global["tray"] || {
value: null,
});
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
socket.on('register-tray-click', (id) => {
socket.on("register-tray-click", (id) => {
if (tray.value) {
tray.value.on('click', (event, bounds) => {
electronSocket.emit('tray-click' + id, [event.__proto__, bounds]);
tray.value.on("click", (event, bounds) => {
electronSocket.emit("tray-click" + id, [
event.__proto__,
bounds,
]);
});
}
});
socket.on('register-tray-right-click', (id) => {
socket.on("register-tray-right-click", (id) => {
if (tray.value) {
tray.value.on('right-click', (event, bounds) => {
electronSocket.emit('tray-right-click' + id, [event.__proto__, bounds]);
tray.value.on("right-click", (event, bounds) => {
electronSocket.emit("tray-right-click" + id, [
event.__proto__,
bounds,
]);
});
}
});
socket.on('register-tray-double-click', (id) => {
socket.on("register-tray-double-click", (id) => {
if (tray.value) {
tray.value.on('double-click', (event, bounds) => {
electronSocket.emit('tray-double-click' + id, [event.__proto__, bounds]);
tray.value.on("double-click", (event, bounds) => {
electronSocket.emit("tray-double-click" + id, [
event.__proto__,
bounds,
]);
});
}
});
socket.on('register-tray-balloon-show', (id) => {
socket.on("register-tray-balloon-show", (id) => {
if (tray.value) {
tray.value.on('balloon-show', () => {
electronSocket.emit('tray-balloon-show' + id);
tray.value.on("balloon-show", () => {
electronSocket.emit("tray-balloon-show" + id);
});
}
});
socket.on('register-tray-balloon-click', (id) => {
socket.on("register-tray-balloon-click", (id) => {
if (tray.value) {
tray.value.on('balloon-click', () => {
electronSocket.emit('tray-balloon-click' + id);
tray.value.on("balloon-click", () => {
electronSocket.emit("tray-balloon-click" + id);
});
}
});
socket.on('register-tray-balloon-closed', (id) => {
socket.on("register-tray-balloon-closed", (id) => {
if (tray.value) {
tray.value.on('balloon-closed', () => {
electronSocket.emit('tray-balloon-closed' + id);
tray.value.on("balloon-closed", () => {
electronSocket.emit("tray-balloon-closed" + id);
});
}
});
socket.on('create-tray', (image, menuItems) => {
socket.on("create-tray", (image, menuItems) => {
const trayIcon = electron_1.nativeImage.createFromPath(image);
tray.value = new electron_1.Tray(trayIcon);
if (menuItems) {
applyContextMenu(menuItems);
}
});
socket.on('tray-destroy', () => {
socket.on("tray-destroy", () => {
if (tray.value) {
tray.value.destroy();
}
});
socket.on('set-contextMenu', (menuItems) => {
socket.on("set-contextMenu", (menuItems) => {
if (menuItems && tray.value) {
applyContextMenu(menuItems);
}
});
socket.on('tray-setImage', (image) => {
socket.on("tray-setImage", (image) => {
if (tray.value) {
tray.value.setImage(image);
}
});
socket.on('tray-setPressedImage', (image) => {
socket.on("tray-setPressedImage", (image) => {
if (tray.value) {
const img = electron_1.nativeImage.createFromPath(image);
tray.value.setPressedImage(img);
}
});
socket.on('tray-setToolTip', (toolTip) => {
socket.on("tray-setToolTip", (toolTip) => {
if (tray.value) {
tray.value.setToolTip(toolTip);
}
});
socket.on('tray-setTitle', (title) => {
socket.on("tray-setTitle", (title) => {
if (tray.value) {
tray.value.setTitle(title);
}
});
socket.on('tray-displayBalloon', (options) => {
socket.on("tray-displayBalloon", (options) => {
if (tray.value) {
tray.value.displayBalloon(options);
}
});
socket.on('tray-isDestroyed', () => {
socket.on("tray-isDestroyed", () => {
if (tray.value) {
const isDestroyed = tray.value.isDestroyed();
electronSocket.emit('tray-isDestroyedCompleted', isDestroyed);
electronSocket.emit("tray-isDestroyedCompleted", isDestroyed);
}
});
socket.on('register-tray-on-event', (eventName, listenerName) => {
socket.on("register-tray-on-event", (eventName, listenerName) => {
if (tray.value) {
tray.value.on(eventName, (...args) => {
if (args.length > 1) {
@@ -107,7 +118,7 @@ module.exports = (socket) => {
});
}
});
socket.on('register-tray-once-event', (eventName, listenerName) => {
socket.on("register-tray-once-event", (eventName, listenerName) => {
if (tray.value) {
tray.value.once(eventName, (...args) => {
if (args.length > 1) {
@@ -122,7 +133,7 @@ module.exports = (socket) => {
function applyContextMenu(menuItems) {
const menu = electron_1.Menu.buildFromTemplate(menuItems);
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit('trayMenuItemClicked', id);
electronSocket.emit("trayMenuItemClicked", id);
});
tray.value.setContextMenu(menu);
}
@@ -131,8 +142,10 @@ module.exports = (socket) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
if ('id' in item && item.id) {
item.click = () => { callback(item.id); };
if ("id" in item && item.id) {
item.click = () => {
callback(item.id);
};
}
});
}

File diff suppressed because one or more lines are too long

View File

@@ -1,159 +1,174 @@
import { Socket } from 'net';
import { Menu, Tray, nativeImage } from 'electron';
let tray: { value: Electron.Tray } = (global['$tray'] = global['tray'] || { value: null });
let electronSocket;
import type { Socket } from "net";
import { Menu, Tray, nativeImage } from "electron";
let tray: { value: Electron.Tray } = (global["$tray"] = global["tray"] || {
value: null,
});
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('register-tray-click', (id) => {
if (tray.value) {
tray.value.on('click', (event, bounds) => {
electronSocket.emit('tray-click' + id, [(<any>event).__proto__, bounds]);
});
}
});
socket.on('register-tray-right-click', (id) => {
if (tray.value) {
tray.value.on('right-click', (event, bounds) => {
electronSocket.emit('tray-right-click' + id, [(<any>event).__proto__, bounds]);
});
}
});
socket.on('register-tray-double-click', (id) => {
if (tray.value) {
tray.value.on('double-click', (event, bounds) => {
electronSocket.emit('tray-double-click' + id, [(<any>event).__proto__, bounds]);
});
}
});
socket.on('register-tray-balloon-show', (id) => {
if (tray.value) {
tray.value.on('balloon-show', () => {
electronSocket.emit('tray-balloon-show' + id);
});
}
});
socket.on('register-tray-balloon-click', (id) => {
if (tray.value) {
tray.value.on('balloon-click', () => {
electronSocket.emit('tray-balloon-click' + id);
});
}
});
socket.on('register-tray-balloon-closed', (id) => {
if (tray.value) {
tray.value.on('balloon-closed', () => {
electronSocket.emit('tray-balloon-closed' + id);
});
}
});
socket.on('create-tray', (image, menuItems) => {
const trayIcon = nativeImage.createFromPath(image);
tray.value = new Tray(trayIcon);
if (menuItems) {
applyContextMenu(menuItems);
}
});
socket.on('tray-destroy', () => {
if (tray.value) {
tray.value.destroy();
}
});
socket.on('set-contextMenu', (menuItems) => {
if (menuItems && tray.value) {
applyContextMenu(menuItems);
}
});
socket.on('tray-setImage', (image) => {
if (tray.value) {
tray.value.setImage(image);
}
});
socket.on('tray-setPressedImage', (image) => {
if (tray.value) {
const img = nativeImage.createFromPath(image);
tray.value.setPressedImage(img);
}
});
socket.on('tray-setToolTip', (toolTip) => {
if (tray.value) {
tray.value.setToolTip(toolTip);
}
});
socket.on('tray-setTitle', (title) => {
if (tray.value) {
tray.value.setTitle(title);
}
});
socket.on('tray-displayBalloon', (options) => {
if (tray.value) {
tray.value.displayBalloon(options);
}
});
socket.on('tray-isDestroyed', () => {
if (tray.value) {
const isDestroyed = tray.value.isDestroyed();
electronSocket.emit('tray-isDestroyedCompleted', isDestroyed);
}
});
socket.on('register-tray-on-event', (eventName, listenerName) => {
if (tray.value){
tray.value.on(eventName, (...args: any[]) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
} else {
electronSocket.emit(listenerName);
}
});
}
});
socket.on('register-tray-once-event', (eventName, listenerName) => {
if (tray.value){
tray.value.once(eventName, (...args: any[]) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
} else {
electronSocket.emit(listenerName);
}
});
}
});
function applyContextMenu(menuItems) {
const menu = Menu.buildFromTemplate(menuItems);
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit('trayMenuItemClicked', id);
});
tray.value.setContextMenu(menu);
electronSocket = socket;
socket.on("register-tray-click", (id) => {
if (tray.value) {
tray.value.on("click", (event, bounds) => {
electronSocket.emit("tray-click" + id, [
(<any>event).__proto__,
bounds,
]);
});
}
});
function addMenuItemClickConnector(menuItems, callback) {
menuItems.forEach((item) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
if ('id' in item && item.id) {
item.click = () => { callback(item.id); };
}
});
socket.on("register-tray-right-click", (id) => {
if (tray.value) {
tray.value.on("right-click", (event, bounds) => {
electronSocket.emit("tray-right-click" + id, [
(<any>event).__proto__,
bounds,
]);
});
}
});
socket.on("register-tray-double-click", (id) => {
if (tray.value) {
tray.value.on("double-click", (event, bounds) => {
electronSocket.emit("tray-double-click" + id, [
(<any>event).__proto__,
bounds,
]);
});
}
});
socket.on("register-tray-balloon-show", (id) => {
if (tray.value) {
tray.value.on("balloon-show", () => {
electronSocket.emit("tray-balloon-show" + id);
});
}
});
socket.on("register-tray-balloon-click", (id) => {
if (tray.value) {
tray.value.on("balloon-click", () => {
electronSocket.emit("tray-balloon-click" + id);
});
}
});
socket.on("register-tray-balloon-closed", (id) => {
if (tray.value) {
tray.value.on("balloon-closed", () => {
electronSocket.emit("tray-balloon-closed" + id);
});
}
});
socket.on("create-tray", (image, menuItems) => {
const trayIcon = nativeImage.createFromPath(image);
tray.value = new Tray(trayIcon);
if (menuItems) {
applyContextMenu(menuItems);
}
});
socket.on("tray-destroy", () => {
if (tray.value) {
tray.value.destroy();
}
});
socket.on("set-contextMenu", (menuItems) => {
if (menuItems && tray.value) {
applyContextMenu(menuItems);
}
});
socket.on("tray-setImage", (image) => {
if (tray.value) {
tray.value.setImage(image);
}
});
socket.on("tray-setPressedImage", (image) => {
if (tray.value) {
const img = nativeImage.createFromPath(image);
tray.value.setPressedImage(img);
}
});
socket.on("tray-setToolTip", (toolTip) => {
if (tray.value) {
tray.value.setToolTip(toolTip);
}
});
socket.on("tray-setTitle", (title) => {
if (tray.value) {
tray.value.setTitle(title);
}
});
socket.on("tray-displayBalloon", (options) => {
if (tray.value) {
tray.value.displayBalloon(options);
}
});
socket.on("tray-isDestroyed", () => {
if (tray.value) {
const isDestroyed = tray.value.isDestroyed();
electronSocket.emit("tray-isDestroyedCompleted", isDestroyed);
}
});
socket.on("register-tray-on-event", (eventName, listenerName) => {
if (tray.value) {
tray.value.on(eventName, (...args: any[]) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
} else {
electronSocket.emit(listenerName);
}
});
}
});
socket.on("register-tray-once-event", (eventName, listenerName) => {
if (tray.value) {
tray.value.once(eventName, (...args: any[]) => {
if (args.length > 1) {
electronSocket.emit(listenerName, args[1]);
} else {
electronSocket.emit(listenerName);
}
});
}
});
function applyContextMenu(menuItems) {
const menu = Menu.buildFromTemplate(menuItems);
addMenuItemClickConnector(menu.items, (id) => {
electronSocket.emit("trayMenuItemClicked", id);
});
tray.value.setContextMenu(menu);
}
function addMenuItemClickConnector(menuItems, callback) {
menuItems.forEach((item) => {
if (item.submenu && item.submenu.items.length > 0) {
addMenuItemClickConnector(item.submenu.items, callback);
}
if ("id" in item && item.id) {
item.click = () => {
callback(item.id);
};
}
});
}
};

View File

@@ -1,7 +1,40 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
const fs = __importStar(require("fs"));
const electron_1 = require("electron");
const browserView_1 = require("./browserView");
const fs = require("fs");
let electronSocket;
module.exports = (socket) => {
electronSocket = socket;
@@ -315,28 +348,28 @@ module.exports = (socket) => {
const extension = await browserWindow.webContents.session.loadExtension(path, { allowFileAccess: allowFileAccess });
electronSocket.emit("webContents-session-loadExtension-completed", extension);
});
socket.on('webContents-getZoomFactor', (id) => {
socket.on("webContents-getZoomFactor", (id) => {
const browserWindow = getWindowById(id);
const text = browserWindow.webContents.getZoomFactor();
electronSocket.emit('webContents-getZoomFactor-completed', text);
electronSocket.emit("webContents-getZoomFactor-completed", text);
});
socket.on('webContents-setZoomFactor', (id, factor) => {
socket.on("webContents-setZoomFactor", (id, factor) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.setZoomFactor(factor);
});
socket.on('webContents-getZoomLevel', (id) => {
socket.on("webContents-getZoomLevel", (id) => {
const browserWindow = getWindowById(id);
const content = browserWindow.webContents.getZoomLevel();
electronSocket.emit('webContents-getZoomLevel-completed', content);
electronSocket.emit("webContents-getZoomLevel-completed", content);
});
socket.on('webContents-setZoomLevel', (id, level) => {
socket.on("webContents-setZoomLevel", (id, level) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.setZoomLevel(level);
});
socket.on('webContents-setVisualZoomLevelLimits', async (id, minimumLevel, maximumLevel) => {
socket.on("webContents-setVisualZoomLevelLimits", async (id, minimumLevel, maximumLevel) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.setVisualZoomLevelLimits(minimumLevel, maximumLevel);
electronSocket.emit('webContents-setVisualZoomLevelLimits-completed');
electronSocket.emit("webContents-setVisualZoomLevelLimits-completed");
});
socket.on("webContents-toggleDevTools", (id) => {
getWindowById(id).webContents.toggleDevTools();
@@ -346,26 +379,26 @@ module.exports = (socket) => {
});
socket.on("webContents-isDevToolsOpened", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-isDevToolsOpened-completed', browserWindow.webContents.isDevToolsOpened());
electronSocket.emit("webContents-isDevToolsOpened-completed", browserWindow.webContents.isDevToolsOpened());
});
socket.on("webContents-isDevToolsFocused", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-isDevToolsFocused-completed', browserWindow.webContents.isDevToolsFocused());
electronSocket.emit("webContents-isDevToolsFocused-completed", browserWindow.webContents.isDevToolsFocused());
});
socket.on("webContents-setAudioMuted", (id, muted) => {
getWindowById(id).webContents.setAudioMuted(muted);
});
socket.on("webContents-isAudioMuted", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-isAudioMuted-completed', browserWindow.webContents.isAudioMuted());
electronSocket.emit("webContents-isAudioMuted-completed", browserWindow.webContents.isAudioMuted());
});
socket.on("webContents-isCurrentlyAudible", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-isCurrentlyAudible-completed', browserWindow.webContents.isCurrentlyAudible());
electronSocket.emit("webContents-isCurrentlyAudible-completed", browserWindow.webContents.isCurrentlyAudible());
});
socket.on("webContents-getUserAgent", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-getUserAgent-completed', browserWindow.webContents.getUserAgent());
electronSocket.emit("webContents-getUserAgent-completed", browserWindow.webContents.getUserAgent());
});
socket.on("webContents-setUserAgent", (id, userAgent) => {
getWindowById(id).webContents.setUserAgent(userAgent);

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,10 @@
import { Socket } from "net";
import {BrowserWindow, BrowserView} from "electron";
import * as fs from "fs";
import type { Socket } from "net";
import { BrowserWindow, BrowserView } from "electron";
import { browserViewMediateService } from "./browserView";
const fs = require("fs");
let electronSocket;
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;
@@ -68,7 +70,7 @@ export = (socket: Socket) => {
errorCode,
validatedUrl,
});
}
},
);
});
@@ -136,17 +138,17 @@ export = (socket: Socket) => {
async (id, code, userGesture = false) => {
const result = await getWindowById(id).webContents.executeJavaScript(
code,
userGesture
userGesture,
);
electronSocket.emit("webContents-executeJavaScript-completed", result);
}
},
);
socket.on("webContents-getUrl", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit(
"webContents-getUrl" + id,
browserWindow.webContents.getURL()
browserWindow.webContents.getURL(),
);
});
@@ -155,7 +157,7 @@ export = (socket: Socket) => {
(id, domains) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.allowNTLMCredentialsForDomains(domains);
}
},
);
socket.on("webContents-session-clearAuthCache", async (...args) => {
@@ -194,7 +196,7 @@ export = (socket: Socket) => {
await browserWindow.webContents.session.clearHostResolverCache();
electronSocket.emit(
"webContents-session-clearHostResolverCache-completed" + guid
"webContents-session-clearHostResolverCache-completed" + guid,
);
});
@@ -203,7 +205,7 @@ export = (socket: Socket) => {
await browserWindow.webContents.session.clearStorageData({});
electronSocket.emit(
"webContents-session-clearStorageData-completed" + guid
"webContents-session-clearStorageData-completed" + guid,
);
});
@@ -214,9 +216,9 @@ export = (socket: Socket) => {
await browserWindow.webContents.session.clearStorageData(options);
electronSocket.emit(
"webContents-session-clearStorageData-options-completed" + guid
"webContents-session-clearStorageData-options-completed" + guid,
);
}
},
);
socket.on("webContents-session-createInterruptedDownload", (id, options) => {
@@ -241,13 +243,12 @@ export = (socket: Socket) => {
socket.on("webContents-session-getBlobData", async (id, identifier, guid) => {
const browserWindow = getWindowById(id);
const buffer = await browserWindow.webContents.session.getBlobData(
identifier
);
const buffer =
await browserWindow.webContents.session.getBlobData(identifier);
electronSocket.emit(
"webContents-session-getBlobData-completed" + guid,
buffer.buffer
buffer.buffer,
);
});
@@ -257,7 +258,7 @@ export = (socket: Socket) => {
electronSocket.emit(
"webContents-session-getCacheSize-completed" + guid,
size
size,
);
});
@@ -267,7 +268,7 @@ export = (socket: Socket) => {
electronSocket.emit(
"webContents-session-getPreloads-completed" + guid,
preloads
preloads,
);
});
@@ -277,7 +278,7 @@ export = (socket: Socket) => {
electronSocket.emit(
"webContents-session-getUserAgent-completed" + guid,
userAgent
userAgent,
);
});
@@ -287,7 +288,7 @@ export = (socket: Socket) => {
electronSocket.emit(
"webContents-session-resolveProxy-completed" + guid,
proxy
proxy,
);
});
@@ -314,9 +315,9 @@ export = (socket: Socket) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.setUserAgent(
userAgent,
acceptLanguages
acceptLanguages,
);
}
},
);
socket.on(
@@ -328,17 +329,17 @@ export = (socket: Socket) => {
session.webRequest.onBeforeRequest(filter, (details, callback) => {
socket.emit(
`webContents-session-webRequest-onBeforeRequest${id}`,
details
details,
);
// Listen for a response from C# to continue the request
electronSocket.once(
`webContents-session-webRequest-onBeforeRequest-response${id}`,
(response) => {
callback(response);
}
},
);
});
}
},
);
socket.on("register-webContents-session-cookies-changed", (id) => {
@@ -353,7 +354,7 @@ export = (socket: Socket) => {
cause,
removed,
]);
}
},
);
});
@@ -363,7 +364,7 @@ export = (socket: Socket) => {
electronSocket.emit(
"webContents-session-cookies-get-completed" + guid,
cookies
cookies,
);
});
@@ -381,9 +382,9 @@ export = (socket: Socket) => {
await browserWindow.webContents.session.cookies.remove(url, name);
electronSocket.emit(
"webContents-session-cookies-remove-completed" + guid
"webContents-session-cookies-remove-completed" + guid,
);
}
},
);
socket.on("webContents-session-cookies-flushStore", async (id, guid) => {
@@ -391,7 +392,7 @@ export = (socket: Socket) => {
await browserWindow.webContents.session.cookies.flushStore();
electronSocket.emit(
"webContents-session-cookies-flushStore-completed" + guid
"webContents-session-cookies-flushStore-completed" + guid,
);
});
@@ -441,7 +442,7 @@ export = (socket: Socket) => {
electronSocket.emit(
"webContents-session-getAllExtensions-completed",
chromeExtensionInfo
chromeExtensionInfo,
);
});
@@ -456,87 +457,108 @@ export = (socket: Socket) => {
const browserWindow = getWindowById(id);
const extension = await browserWindow.webContents.session.loadExtension(
path,
{ allowFileAccess: allowFileAccess }
{ allowFileAccess: allowFileAccess },
);
electronSocket.emit(
"webContents-session-loadExtension-completed",
extension
extension,
);
}
},
);
socket.on('webContents-getZoomFactor', (id) => {
const browserWindow = getWindowById(id);
const text = browserWindow.webContents.getZoomFactor();
electronSocket.emit('webContents-getZoomFactor-completed', text);
});
socket.on("webContents-getZoomFactor", (id) => {
const browserWindow = getWindowById(id);
const text = browserWindow.webContents.getZoomFactor();
electronSocket.emit("webContents-getZoomFactor-completed", text);
});
socket.on('webContents-setZoomFactor', (id, factor) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.setZoomFactor(factor);
});
socket.on("webContents-setZoomFactor", (id, factor) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.setZoomFactor(factor);
});
socket.on('webContents-getZoomLevel', (id) => {
const browserWindow = getWindowById(id);
const content = browserWindow.webContents.getZoomLevel();
electronSocket.emit('webContents-getZoomLevel-completed', content);
});
socket.on("webContents-getZoomLevel", (id) => {
const browserWindow = getWindowById(id);
const content = browserWindow.webContents.getZoomLevel();
electronSocket.emit("webContents-getZoomLevel-completed", content);
});
socket.on('webContents-setZoomLevel', (id, level) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.setZoomLevel(level);
});
socket.on("webContents-setZoomLevel", (id, level) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.setZoomLevel(level);
});
socket.on('webContents-setVisualZoomLevelLimits', async (id, minimumLevel, maximumLevel) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.setVisualZoomLevelLimits(minimumLevel, maximumLevel);
electronSocket.emit('webContents-setVisualZoomLevelLimits-completed');
});
socket.on(
"webContents-setVisualZoomLevelLimits",
async (id, minimumLevel, maximumLevel) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.setVisualZoomLevelLimits(
minimumLevel,
maximumLevel,
);
electronSocket.emit("webContents-setVisualZoomLevelLimits-completed");
},
);
socket.on("webContents-toggleDevTools", (id) => {
getWindowById(id).webContents.toggleDevTools();
});
socket.on("webContents-toggleDevTools", (id) => {
getWindowById(id).webContents.toggleDevTools();
});
socket.on("webContents-closeDevTools", (id) => {
getWindowById(id).webContents.closeDevTools();
});
socket.on("webContents-closeDevTools", (id) => {
getWindowById(id).webContents.closeDevTools();
});
socket.on("webContents-isDevToolsOpened", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-isDevToolsOpened-completed', browserWindow.webContents.isDevToolsOpened());
});
socket.on("webContents-isDevToolsOpened", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit(
"webContents-isDevToolsOpened-completed",
browserWindow.webContents.isDevToolsOpened(),
);
});
socket.on("webContents-isDevToolsFocused", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-isDevToolsFocused-completed', browserWindow.webContents.isDevToolsFocused());
});
socket.on("webContents-isDevToolsFocused", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit(
"webContents-isDevToolsFocused-completed",
browserWindow.webContents.isDevToolsFocused(),
);
});
socket.on("webContents-setAudioMuted", (id, muted) => {
getWindowById(id).webContents.setAudioMuted(muted);
});
socket.on("webContents-setAudioMuted", (id, muted) => {
getWindowById(id).webContents.setAudioMuted(muted);
});
socket.on("webContents-isAudioMuted", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-isAudioMuted-completed', browserWindow.webContents.isAudioMuted());
});
socket.on("webContents-isAudioMuted", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit(
"webContents-isAudioMuted-completed",
browserWindow.webContents.isAudioMuted(),
);
});
socket.on("webContents-isCurrentlyAudible", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-isCurrentlyAudible-completed', browserWindow.webContents.isCurrentlyAudible());
});
socket.on("webContents-isCurrentlyAudible", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit(
"webContents-isCurrentlyAudible-completed",
browserWindow.webContents.isCurrentlyAudible(),
);
});
socket.on("webContents-getUserAgent", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-getUserAgent-completed', browserWindow.webContents.getUserAgent());
});
socket.on("webContents-getUserAgent", function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit(
"webContents-getUserAgent-completed",
browserWindow.webContents.getUserAgent(),
);
});
socket.on("webContents-setUserAgent", (id, userAgent) => {
getWindowById(id).webContents.setUserAgent(userAgent);
});
socket.on("webContents-setUserAgent", (id, userAgent) => {
getWindowById(id).webContents.setUserAgent(userAgent);
});
function getWindowById(
id: number
function getWindowById(
id: number,
): Electron.BrowserWindow | Electron.BrowserView {
if (id >= 1000) {
return browserViewMediateService(id - 1000);

View File

@@ -0,0 +1,199 @@
/**
* Environment-aware logging utility for Electron.NET
*
* Provides structured logging with log levels that respect the environment.
* Preserves console.time/timeEnd for performance measurements.
*/
// Log levels
const LogLevel = {
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3,
SILENT: 4,
};
/**
* Detect the current environment based on various indicators
* @returns {'development'|'production'|'debug'} The detected environment
*/
function detectEnvironment() {
// Check for unpacked/development mode flags
const args = process.argv.join(" ").toLowerCase();
if (
args.includes("--unpackeddotnet") ||
args.includes("--unpackedelectron") ||
args.includes("--unpackeddotnetsignalr")
) {
return "development";
}
// Check NODE_ENV
const nodeEnv = process.env.NODE_ENV?.toLowerCase();
if (nodeEnv === "development" || nodeEnv === "dev") {
return "development";
}
// Check for debugger
if (
process.execArgv.some(
(arg) => arg.includes("inspect") || arg.includes("debug"),
)
) {
return "debug";
}
// Default to production for packaged apps
return "production";
}
// Determine current environment and default log level
const environment = detectEnvironment();
const defaultLogLevels = {
debug: LogLevel.DEBUG,
development: LogLevel.INFO,
production: LogLevel.WARN,
};
let currentLogLevel = defaultLogLevels[environment];
/**
* Set the current log level
* @param {number} level - LogLevel enum value
*/
function setLogLevel(level) {
currentLogLevel = level;
}
/**
* Get the current log level
* @returns {number} Current LogLevel
*/
function getLogLevel() {
return currentLogLevel;
}
/**
* Get the current environment
* @returns {string} Current environment name
*/
function getEnvironment() {
return environment;
}
/**
* Check if a log level should be output
* @param {number} level - LogLevel to check
* @returns {boolean} True if the level should be logged
*/
function shouldLog(level) {
return level >= currentLogLevel;
}
/**
* Safe wrapper for console methods that catches EPIPE errors
*/
const safeConsole = {
log: (...args) => {
try {
console.log(...args);
} catch (e) {
// Ignore EPIPE errors when console is detached
}
},
warn: (...args) => {
try {
console.warn(...args);
} catch (e) {
// Ignore EPIPE errors when console is detached
}
},
error: (...args) => {
try {
console.error(...args);
} catch (e) {
// Ignore EPIPE errors when console is detached
}
},
// Preserve timing functions as-is
time: (label) => {
try {
console.time(label);
} catch (e) {
// Ignore EPIPE errors
}
},
timeEnd: (label) => {
try {
console.timeEnd(label);
} catch (e) {
// Ignore EPIPE errors
}
},
};
/**
* Logger with environment-aware log levels
*/
const logger = {
/**
* Log a debug message (only in debug mode)
*/
debug: (...args) => {
if (shouldLog(LogLevel.DEBUG)) {
safeConsole.log("[DEBUG]", ...args);
}
},
/**
* Log an info message
*/
info: (...args) => {
if (shouldLog(LogLevel.INFO)) {
safeConsole.log("[INFO]", ...args);
}
},
/**
* Log a warning message
*/
warn: (...args) => {
if (shouldLog(LogLevel.WARN)) {
safeConsole.warn("[WARN]", ...args);
}
},
/**
* Log an error message
*/
error: (...args) => {
if (shouldLog(LogLevel.ERROR)) {
safeConsole.error("[ERROR]", ...args);
}
},
/**
* Start a timing measurement (always logged)
*/
time: (label) => {
safeConsole.time(label);
},
/**
* End a timing measurement (always logged)
*/
timeEnd: (label) => {
safeConsole.timeEnd(label);
},
};
module.exports = {
logger,
safeConsole,
LogLevel,
setLogLevel,
getLogLevel,
getEnvironment,
shouldLog,
};

View File

@@ -5,6 +5,8 @@ const path = require('path');
const cProcess = require('child_process').spawn;
const portscanner = require('portscanner');
const { imageSize } = require('image-size');
const { logger } = require('./logger');
let io, server, browserWindows, ipc, apiProcess, loadURL;
let appApi, menu, dialogApi, notification, tray, webContents;
let globalShortcut, shellApi, screen, clipboard, autoUpdater;
@@ -14,6 +16,9 @@ let processInfo;
let splashScreen;
let nativeTheme;
let dock;
let desktopCapturer;
let electronHostHook;
let touchBar;
let launchFile;
let launchUrl;
let processApi;
@@ -22,15 +27,24 @@ let manifestJsonFileName = 'package.json';
let unpackedelectron = false;
let unpackeddotnet = false;
let dotnetpacked = false;
let unpackeddotnetsignalr = false;
let dotnetpackedsignalr = false;
let electronforcedport;
let electronUrl;
if (app.commandLine.hasSwitch('manifest')) {
manifestJsonFileName = app.commandLine.getSwitchValue('manifest');
}
console.log('Entry!!!: ');
if (app.commandLine.hasSwitch('unpackedelectron')) {
// Check for SignalR modes first (these take precedence)
if (app.commandLine.hasSwitch('unpackeddotnetsignalr')) {
unpackeddotnetsignalr = true;
}
else if (app.commandLine.hasSwitch('dotnetpackedsignalr')) {
dotnetpackedsignalr = true;
}
// Then check legacy modes
else if (app.commandLine.hasSwitch('unpackedelectron')) {
unpackedelectron = true;
}
else if (app.commandLine.hasSwitch('unpackeddotnet')) {
@@ -44,6 +58,17 @@ if (app.commandLine.hasSwitch('electronforcedport')) {
electronforcedport = app.commandLine.getSwitchValue('electronforcedport');
}
let authToken;
if (app.commandLine.hasSwitch('authtoken')) {
authToken = app.commandLine.getSwitchValue('authtoken');
// Store in global for access by browser windows
global.authToken = authToken;
}
if (app.commandLine.hasSwitch('electronurl')) {
electronUrl = app.commandLine.getSwitchValue('electronurl');
}
// Custom startup hook: look for custom_main.js and invoke its onStartup(host) if present.
// If the hook returns false, abort Electron startup.
try {
@@ -60,11 +85,11 @@ try {
try { app.exit(0); } catch (err) { process.exit(0); }
}
} else {
console.warn('custom_main.js found but no onStartup function exported.');
logger.warn('custom_main.js found but no onStartup function exported.');
}
}
} catch (err) {
console.error('Error while executing custom_main.js:', err);
logger.error('Error while executing custom_main.js:', err);
}
const currentPath = __dirname;
@@ -73,7 +98,7 @@ let manifestJsonFilePath = path.join(currentPath, manifestJsonFileName);
// if running unpackedelectron, lets change the path
if (unpackedelectron || unpackeddotnet) {
console.log('unpackedelectron! dir: ' + currentPath);
logger.debug('Running in unpacked mode, dir: ' + currentPath);
manifestJsonFilePath = path.join(currentPath, manifestJsonFileName);
currentBinPath = path.join(currentPath, '../'); // go to project directory
@@ -140,7 +165,10 @@ function getForwardedArgs() {
const forwardedArgs = getForwardedArgs();
app.on('ready', () => {
app.on('ready', async () => {
// Start overall startup timer
logger.time('[Startup] Total Electron Startup');
// Fix ERR_UNKNOWN_URL_SCHEME using file protocol
// https://github.com/electron/electron/issues/23757
////protocol.registerFileProtocol('file', (request, callback) => {
@@ -152,8 +180,41 @@ app.on('ready', () => {
startSplashScreen();
}
// 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) {
logger.error('[Electron] ERROR: SignalR mode requires --electronUrl parameter');
app.quit();
return;
}
// 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({
show: false,
width: 1,
height: 1
});
// Destroy the keep-alive window when the first real window is created
app.once('browser-window-created', (event, window) => {
if (keepAliveWindow && !keepAliveWindow.isDestroyed()) {
keepAliveWindow.destroy();
}
});
await startSignalRApiBridge(electronUrl);
logger.timeEnd('[Startup] Total Electron Startup');
return;
}
// Legacy socket.io startup
if (electronforcedport) {
console.log('Electron Socket IO (forced) Port: ' + electronforcedport);
logger.info('Electron Socket IO (forced) Port: ' + electronforcedport);
startSocketApiBridge(electronforcedport);
return;
}
@@ -166,31 +227,47 @@ app.on('ready', () => {
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(defaultElectronPort, 65535, 'localhost', function (error, port) {
console.log('Electron Socket IO Port: ' + port);
logger.info('Electron Socket IO Port: ' + port);
startSocketApiBridge(port);
});
});
app.on('quit', async (event, exitCode) => {
try {
server.close();
server.closeAllConnections();
} catch (e) {
console.error(e);
}
try {
apiProcess?.kill();
} catch (e) {
console.error(e);
}
try {
if (io && typeof io.close === 'function') {
io.close();
// Clean up Socket.IO resources (legacy mode only)
if (typeof server !== 'undefined' && server) {
try {
server.close();
server.closeAllConnections();
} catch (e) {
logger.error('Error closing Socket.IO server:', e);
}
}
// Clean up API process (Socket.IO mode only)
if (typeof apiProcess !== 'undefined' && apiProcess) {
try {
apiProcess.kill();
} catch (e) {
logger.error('Error killing API process:', e);
}
}
// Clean up Socket.IO connection (legacy mode only)
if (typeof io !== 'undefined' && io && typeof io.close === 'function') {
try {
io.close();
} catch (e) {
logger.error('Error closing Socket.IO connection:', e);
}
}
// Clean up SignalR connection (SignalR mode only)
if (global['electronsignalr'] && typeof global['electronsignalr'].connection !== 'undefined') {
try {
await global['electronsignalr'].connection.stop();
} catch (e) {
logger.error('Error closing SignalR connection:', e);
}
} catch (e) {
console.error(e);
}
});
@@ -246,9 +323,7 @@ function startSplashScreen() {
// it's an image, so we can compute the desired splash screen size
imageSize(imageFile, (error, dimensions) => {
if (error) {
console.log(`load splashscreen error:`);
console.error(error);
logger.error(`load splashscreen error:`, error);
throw new Error(error.message);
}
@@ -259,7 +334,7 @@ function startSplashScreen() {
function startSocketApiBridge(port) {
// instead of 'require('socket.io')(port);' we need to use this workaround
// otherwise the Windows Firewall will be triggered
console.log('Electron Socket: starting...');
logger.debug('Electron Socket: starting...');
server = require('http').createServer();
const { Server } = require('socket.io');
let hostHook;
@@ -271,7 +346,7 @@ function startSocketApiBridge(port) {
server.listen(port, 'localhost');
server.on('listening', function () {
console.log('Electron Socket: listening on port %s at %s', server.address().port, server.address().address);
logger.info('Electron Socket: listening on port %s at %s', server.address().port, server.address().address);
// Now that socket connection is established, we can guarantee port will not be open for portscanner
if (unpackedelectron) {
startAspCoreBackendUnpackaged(port);
@@ -286,9 +361,9 @@ function startSocketApiBridge(port) {
// @ts-ignore
io.on('connection', (socket) => {
console.log('Electron Socket: connected!');
logger.info('Electron Socket: connected!');
socket.on('disconnect', function (reason) {
console.log('Got disconnect! Reason: ' + reason);
logger.debug('Got disconnect! Reason: ' + reason);
try {
////console.log('requireCache');
////console.log(require.cache['electron-host-hook']);
@@ -299,7 +374,7 @@ function startSocketApiBridge(port) {
hostHook = undefined;
}
} catch (err) {
console.error(err.message);
logger.error(err.message);
}
});
@@ -308,7 +383,7 @@ function startSocketApiBridge(port) {
global['electronsocket'].setMaxListeners(0);
}
console.log('Electron Socket: loading components...');
logger.debug('Electron Socket: loading components...');
if (appApi === undefined) appApi = require('./api/app')(socket, app);
if (browserWindows === undefined) browserWindows = require('./api/browserWindows')(socket, app);
@@ -366,13 +441,123 @@ function startSocketApiBridge(port) {
hostHook.onHostReady();
}
} catch (error) {
console.error(error.message);
logger.error(error.message);
}
console.log('Electron Socket: startup complete.');
logger.info('Electron Socket: startup complete.');
});
}
/**
* 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`;
// Pass the authentication token to the SignalR bridge
const signalRBridge = new SignalRBridge(hubUrl, global.authToken);
try {
logger.time('[Startup] SignalR Connection');
const connected = await signalRBridge.connect();
logger.timeEnd('[Startup] SignalR Connection');
if (!connected) {
logger.error('[SignalRBridge] Failed to connect to SignalR hub');
app.quit();
return;
}
// Store the bridge globally for API access
global['electronsignalr'] = signalRBridge;
// Load API modules in parallel for faster startup
logger.time('[Startup] Module Loading');
// Define module loaders - each returns the initialized module
const loadModules = () => {
const modules = {};
// Load all modules in parallel using Promise.all
return Promise.all([
// Critical modules (always needed)
Promise.resolve().then(() => modules.appApi = require('./api/app')(signalRBridge, app)),
Promise.resolve().then(() => modules.browserWindows = require('./api/browserWindows')(signalRBridge, app)),
Promise.resolve().then(() => modules.commandLine = require('./api/commandLine')(signalRBridge, app)),
Promise.resolve().then(() => modules.webContents = require('./api/webContents')(signalRBridge)),
Promise.resolve().then(() => modules.ipc = require('./api/ipc')(signalRBridge)),
Promise.resolve().then(() => modules.menu = require('./api/menu')(signalRBridge)),
// Secondary modules (commonly used)
Promise.resolve().then(() => modules.dialogApi = require('./api/dialog')(signalRBridge)),
Promise.resolve().then(() => modules.notification = require('./api/notification')(signalRBridge)),
Promise.resolve().then(() => modules.shellApi = require('./api/shell')(signalRBridge)),
Promise.resolve().then(() => modules.clipboard = require('./api/clipboard')(signalRBridge)),
Promise.resolve().then(() => modules.screen = require('./api/screen')(signalRBridge)),
// Utility modules (less frequently used)
Promise.resolve().then(() => modules.autoUpdater = require('./api/autoUpdater')(signalRBridge)),
Promise.resolve().then(() => modules.tray = require('./api/tray')(signalRBridge)),
Promise.resolve().then(() => modules.globalShortcut = require('./api/globalShortcut')(signalRBridge)),
Promise.resolve().then(() => modules.nativeTheme = require('./api/nativeTheme')(signalRBridge)),
Promise.resolve().then(() => modules.powerMonitor = require('./api/powerMonitor')(signalRBridge)),
Promise.resolve().then(() => modules.processApi = require('./api/process')(signalRBridge)),
// Platform-specific modules
Promise.resolve().then(() => {
if (process.platform === 'darwin') {
modules.dock = require('./api/dock')(signalRBridge, app);
}
})
]).then(() => modules);
};
const modules = await loadModules();
// Assign to global variables (for backward compatibility)
if (appApi === undefined) appApi = modules.appApi;
if (browserWindows === undefined) browserWindows = modules.browserWindows;
if (commandLine === undefined) commandLine = modules.commandLine;
if (autoUpdater === undefined) autoUpdater = modules.autoUpdater;
if (ipc === undefined) ipc = modules.ipc;
if (menu === undefined) menu = modules.menu;
if (dialogApi === undefined) dialogApi = modules.dialogApi;
if (notification === undefined) notification = modules.notification;
if (tray === undefined) tray = modules.tray;
if (webContents === undefined) webContents = modules.webContents;
if (globalShortcut === undefined) globalShortcut = modules.globalShortcut;
if (clipboard === undefined) clipboard = modules.clipboard;
if (screen === undefined) screen = modules.screen;
if (shellApi === undefined) shellApi = modules.shellApi;
if (nativeTheme === undefined) nativeTheme = modules.nativeTheme;
if (powerMonitor === undefined) powerMonitor = modules.powerMonitor;
if (dock === undefined && modules.dock) dock = modules.dock;
if (processApi === undefined) processApi = modules.processApi;
logger.timeEnd('[Startup] Module Loading');
// Signal to .NET that Electron is fully ready (API modules loaded)
logger.time('[Startup] Host Ready Signal');
await signalRBridge.emit('electron-host-ready');
logger.timeEnd('[Startup] Host Ready Signal');
} catch (error) {
logger.error('[SignalRBridge] Error during startup:', error);
logger.error('[SignalRBridge] Stack:', error.stack);
app.quit();
}
}
function startAspCoreBackend(electronPort) {
startBackend();
@@ -395,11 +580,11 @@ function startAspCoreBackend(electronPort) {
let binFilePath = path.join(currentBinPath, binaryFile);
var options = { cwd: currentBinPath };
console.log('Starting backend with parameters:', parameters.join(' '));
logger.debug('Starting backend with parameters:', parameters.join(' '));
apiProcess = cProcess(binFilePath, parameters, options);
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
logger.debug(`stdout: ${data.toString()}`);
});
}
}
@@ -425,11 +610,11 @@ function startAspCoreBackendUnpackaged(electronPort) {
let binFilePath = path.join(currentBinPath, binaryFile);
var options = { cwd: currentBinPath };
console.log('Starting backend (unpackaged) with parameters:', parameters.join(' '));
logger.debug('Starting backend (unpackaged) with parameters:', parameters.join(' '));
apiProcess = cProcess(binFilePath, parameters, options);
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
logger.debug(`stdout: ${data.toString()}`);
});
}
}

View File

@@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@microsoft/signalr": "^8.0.7",
"dasherize": "^2.0.0",
"electron-host-hook": "file:./ElectronHostHook",
"electron-updater": "^6.6.2",
@@ -57,9 +58,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
"integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
"integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -140,9 +141,9 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
"integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -152,7 +153,7 @@
"globals": "^14.0.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"js-yaml": "^4.1.1",
"minimatch": "^3.1.2",
"strip-json-comments": "^3.1.1"
},
@@ -164,9 +165,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.39.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz",
"integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==",
"version": "9.39.2",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
"integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -252,6 +253,40 @@
"url": "https://github.com/sponsors/nzakas"
}
},
"node_modules/@microsoft/signalr": {
"version": "8.0.17",
"resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-8.0.17.tgz",
"integrity": "sha512-5pM6xPtKZNJLO0Tq5nQasVyPFwi/WBY3QB5uc/v3dIPTpS1JXQbaXAQAPxFoQ5rTBFE094w8bbqkp17F9ReQvA==",
"license": "MIT",
"dependencies": {
"abort-controller": "^3.0.0",
"eventsource": "^2.0.2",
"fetch-cookie": "^2.0.3",
"node-fetch": "^2.6.7",
"ws": "^7.5.10"
}
},
"node_modules/@microsoft/signalr/node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/@sindresorhus/is": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
@@ -314,9 +349,9 @@
"license": "MIT"
},
"node_modules/@types/http-cache-semantics": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
"integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
"integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==",
"dev": true,
"license": "MIT"
},
@@ -338,9 +373,9 @@
}
},
"node_modules/@types/node": {
"version": "22.19.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.1.tgz",
"integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==",
"version": "22.19.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.8.tgz",
"integrity": "sha512-ebO/Yl+EAvVe8DnMfi+iaAyIqYdK0q/q0y0rw82INWEKJOBe6b/P3YWE8NW7oOlF/nXFNrHwhARrN/hdgDkraA==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
@@ -367,6 +402,18 @@
"@types/node": "*"
}
},
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"license": "MIT",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -498,9 +545,9 @@
}
},
"node_modules/builder-util-runtime": {
"version": "9.3.1",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz",
"integrity": "sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==",
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz",
"integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.3.4",
@@ -616,9 +663,9 @@
}
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
"integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
@@ -626,6 +673,10 @@
},
"engines": {
"node": ">= 0.10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/cross-spawn": {
@@ -782,18 +833,18 @@
"link": true
},
"node_modules/electron-updater": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.6.2.tgz",
"integrity": "sha512-Cr4GDOkbAUqRHP5/oeOmH/L2Bn6+FQPxVLZtPbcmKZC63a1F3uu5EefYOssgZXG3u/zBlubbJ5PJdITdMVggbw==",
"version": "6.7.3",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.7.3.tgz",
"integrity": "sha512-EgkT8Z9noqXKbwc3u5FkJA+r48jwZ5DTUiOkJMOTEEH//n5Am6wfQGz7nvSFEA2oIAMv9jRzn5JKTyWeSKOPgg==",
"license": "MIT",
"dependencies": {
"builder-util-runtime": "9.3.1",
"builder-util-runtime": "9.5.1",
"fs-extra": "^10.1.0",
"js-yaml": "^4.1.0",
"lazy-val": "^1.0.5",
"lodash.escaperegexp": "^4.1.2",
"lodash.isequal": "^4.5.0",
"semver": "^7.6.3",
"semver": "~7.7.3",
"tiny-typed-emitter": "^2.1.0"
}
},
@@ -845,9 +896,9 @@
}
},
"node_modules/electron/node_modules/@types/node": {
"version": "20.19.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz",
"integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==",
"version": "20.19.31",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.31.tgz",
"integrity": "sha512-5jsi0wpncvTD33Sh1UCgacK37FFwDn+EG7wCmEvs62fCvBL+n8/76cAYDok21NF6+jaVWIqKwCZyX7Vbu8eB3A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -865,9 +916,9 @@
}
},
"node_modules/engine.io": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
"version": "6.6.5",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz",
"integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
@@ -876,9 +927,9 @@
"base64id": "2.0.0",
"cookie": "~0.7.2",
"cors": "~2.8.5",
"debug": "~4.3.1",
"debug": "~4.4.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1"
"ws": "~8.18.3"
},
"engines": {
"node": ">=10.2.0"
@@ -893,23 +944,6 @@
"node": ">=10.0.0"
}
},
"node_modules/engine.io/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -964,9 +998,9 @@
}
},
"node_modules/eslint": {
"version": "9.39.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"version": "9.39.2",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -976,7 +1010,7 @@
"@eslint/config-helpers": "^0.4.2",
"@eslint/core": "^0.17.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.39.1",
"@eslint/js": "9.39.2",
"@eslint/plugin-kit": "^0.4.1",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -1072,9 +1106,9 @@
}
},
"node_modules/esquery": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
"integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -1117,6 +1151,24 @@
"node": ">=0.10.0"
}
},
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/eventsource": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
"integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/extract-zip": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
@@ -1169,6 +1221,16 @@
"pend": "~1.2.0"
}
},
"node_modules/fetch-cookie": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.2.0.tgz",
"integrity": "sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==",
"license": "Unlicense",
"dependencies": {
"set-cookie-parser": "^2.4.8",
"tough-cookie": "^4.0.0"
}
},
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -1614,9 +1676,9 @@
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
"node_modules/lodash.escaperegexp": {
@@ -1735,6 +1797,26 @@
"node": ">= 0.6"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
@@ -1912,6 +1994,18 @@
"node": ">=0.4.0"
}
},
"node_modules/psl": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
"integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
"license": "MIT",
"dependencies": {
"punycode": "^2.3.1"
},
"funding": {
"url": "https://github.com/sponsors/lupomontero"
}
},
"node_modules/pump": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
@@ -1927,12 +2021,17 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"license": "MIT"
},
"node_modules/queue": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
@@ -1955,6 +2054,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"license": "MIT"
},
"node_modules/resolve-alpn": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
@@ -2005,10 +2110,13 @@
}
},
"node_modules/sax": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz",
"integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==",
"license": "BlueOak-1.0.0"
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz",
"integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==",
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=11.0.0"
}
},
"node_modules/semver": {
"version": "6.3.1",
@@ -2045,6 +2153,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/set-cookie-parser": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
"license": "MIT"
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -2069,15 +2183,15 @@
}
},
"node_modules/socket.io": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz",
"integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"cors": "~2.8.5",
"debug": "~4.3.2",
"debug": "~4.4.1",
"engine.io": "~6.6.0",
"socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.4"
@@ -2087,79 +2201,28 @@
}
},
"node_modules/socket.io-adapter": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
"version": "2.5.6",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz",
"integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==",
"license": "MIT",
"dependencies": {
"debug": "~4.3.4",
"ws": "~8.17.1"
}
},
"node_modules/socket.io-adapter/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
"debug": "~4.4.1",
"ws": "~8.18.3"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz",
"integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
"debug": "~4.4.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
@@ -2213,6 +2276,36 @@
"integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==",
"license": "MIT"
},
"node_modules/tough-cookie": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"license": "BSD-3-Clause",
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tough-cookie/node_modules/universalify": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -2280,6 +2373,16 @@
"punycode": "^2.1.0"
}
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"license": "MIT",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -2289,6 +2392,22 @@
"node": ">= 0.8"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -2323,9 +2442,9 @@
"license": "ISC"
},
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"

View File

@@ -16,6 +16,7 @@
"author": "Gregor Biswanger, Florian Rappl",
"license": "MIT",
"dependencies": {
"@microsoft/signalr": "^8.0.7",
"dasherize": "^2.0.0",
"electron-host-hook": "file:./ElectronHostHook",
"image-size": "^1.2.1",

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