Compare commits

...

94 Commits

Author SHA1 Message Date
Florian Rappl
672ff6c40d Implemented #1003 2026-09-04 14:29:38 +02:00
Florian Rappl
7cd552a78f Finished #1106 2026-09-04 14:05:36 +02:00
Florian Rappl
042d8e6c70 Infra enhancements 2026-09-04 13:26:27 +02:00
Florian Rappl
0140749753 Fixed #1103 2026-09-04 11:52:21 +02:00
Florian Rappl
7af2e954c7 Fixed 1040 2026-09-04 11:37:42 +02:00
Florian Rappl
da0e1f17db Fixes #1097 2026-09-03 17:04:21 +02:00
Florian Rappl
9cb210040d Fixed #1105 2026-09-03 16:25:47 +02:00
Florian Rappl
7e8f45b16d Updated changelog 2026-09-03 16:17:19 +02:00
Florian Rappl
76dc687269 Merged 2026-09-03 11:28:37 +02:00
Florian Rappl
dcf4585510 Merge pull request #1108 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/humanfs/node-0.16.8
Bump @humanfs/node from 0.16.7 to 0.16.8 in /src/ElectronNET.WebApp/ElectronHostHook
2026-09-03 08:54:37 +02:00
dependabot[bot]
a6d7434adf Bump @humanfs/node in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [@humanfs/node](https://github.com/humanwhocodes/humanfs/tree/HEAD/packages/node) from 0.16.7 to 0.16.8.
- [Release notes](https://github.com/humanwhocodes/humanfs/releases)
- [Changelog](https://github.com/humanwhocodes/humanfs/blob/main/packages/node/CHANGELOG.md)
- [Commits](https://github.com/humanwhocodes/humanfs/commits/node-v0.16.8/packages/node)

---
updated-dependencies:
- dependency-name: "@humanfs/node"
  dependency-version: 0.16.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-03 00:19:56 +00:00
Florian Rappl
76ff44f67e Merge pull request #1104 from epsitec-sa/feat/#1095
chore(build): allow customization of target framwork version in dev mode (#1095)
2026-08-14 13:07:48 +02:00
Samuel Nussbaum
20ab82b16d chore(build): fix error when props file is missing 2026-08-14 11:25:19 +02:00
Samuel Nussbaum
b27f705a6a chore(build): Change import barriere 2026-08-14 10:52:10 +02:00
Samuel Nussbaum
8697c4de44 chore(build): passthrough props barriere 2026-08-14 10:07:58 +02:00
Florian Rappl
376a791e48 Merge pull request #1099 from epsitec-sa/bug/#1096
chore(build): fix #1096 by depends on resolve unrelated target
2026-08-11 09:45:16 +02:00
Florian Rappl
195a29052e Merge pull request #1100 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/js-yaml-4.3.1
Bump js-yaml from 4.3.0 to 4.3.1 in /src/ElectronNET.WebApp/ElectronHostHook
2026-08-11 09:31:59 +02:00
Florian Rappl
f577a53227 Merge pull request #1102 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.Host/electron-39.8.10
Bump electron from 30.5.1 to 39.8.10 in /src/ElectronNET.Host
2026-08-11 08:52:04 +02:00
Florian Rappl
382d544468 Merge pull request #1101 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/brace-expansion-1.1.18
Bump brace-expansion from 1.1.14 to 1.1.18 in /src/ElectronNET.WebApp/ElectronHostHook
2026-08-11 08:51:42 +02:00
dependabot[bot]
18f08f9aff Bump electron from 30.5.1 to 39.8.10 in /src/ElectronNET.Host
Bumps [electron](https://github.com/electron/electron) from 30.5.1 to 39.8.10.
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v30.5.1...v39.8.10)

---
updated-dependencies:
- dependency-name: electron
  dependency-version: 39.8.10
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 23:17:12 +00:00
dependabot[bot]
def289ab54 Bump brace-expansion in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.14 to 1.1.18.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.14...v1.1.18)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.18
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 23:17:02 +00:00
dependabot[bot]
4011f3d30b Bump js-yaml in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.3.0 to 4.3.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/4.3.1/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.3.0...4.3.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 23:17:01 +00:00
Samuel Nussbaum
26b9d86ee4 chore(build): target frameworks customization 2026-08-10 10:33:00 +02:00
Florian Rappl
3b57de976a Merge pull request #1098 from epsitec-sa/bug/#1097
fix(packaging): Restore cross-compile on same platform and packaging dir name behavior
2026-08-10 10:19:45 +02:00
Samuel Nussbaum
d9e9b3d2e6 fix(packaging): Architecture must be defined in electron-builder compile args in order to allow cross-compile on same platform. Enforce default-arch to be the default arch in order to avoid arch in package directory name. 2026-08-10 09:22:21 +02:00
Samuel Nussbaum
1ec1fde3c6 chore(build): fix #1096 by depends on not resolve related target 2026-08-07 14:37:13 +02:00
Florian Rappl
e5ccf75c9f Merge pull request #1094 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.Host/ElectronHostHook/socket.io-parser-4.2.7
Bump socket.io-parser from 4.2.6 to 4.2.7 in /src/ElectronNET.Host/ElectronHostHook
2026-08-05 09:08:03 +02:00
dependabot[bot]
819e643ab8 Bump socket.io-parser in /src/ElectronNET.Host/ElectronHostHook
Bumps [socket.io-parser](https://github.com/socketio/socket.io) from 4.2.6 to 4.2.7.
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.6...socket.io-parser@4.2.7)

---
updated-dependencies:
- dependency-name: socket.io-parser
  dependency-version: 4.2.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-05 05:07:46 +00:00
Florian Rappl
7fe3f9b5b6 Merge pull request #1093 from ElectronNET/develop
Release 0.5.2
2026-08-03 14:53:48 +02:00
Florian Rappl
16cbc5f2a4 Improved platform agnostic for test 2026-08-03 14:36:20 +02:00
Florian Rappl
3a2c997e6a Ensure windows are not retained after being destroyed #1008 2026-08-03 14:25:47 +02:00
Florian Rappl
f88f5f8b18 Added tests, improved icon implementation 2026-08-03 14:19:25 +02:00
Florian Rappl
4e39f5f377 Added support for MacOS modern app icon #1047 2026-08-03 14:12:09 +02:00
Florian Rappl
7fa5ec5b0b Fixed #1050 2026-08-03 14:09:01 +02:00
Florian Rappl
2f8f717dbb Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-03 11:13:32 +02:00
Florian Rappl
525d6185fb Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-03 11:13:08 +02:00
Florian Rappl
73703819be Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-03 11:12:56 +02:00
Florian Rappl
09249f74c6 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-03 11:12:41 +02:00
Florian Rappl
cfd8be36f3 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-03 11:12:19 +02:00
Florian Rappl
6055635eb5 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-03 11:11:15 +02:00
Florian Rappl
74a734ae58 Merge pull request #1092 from epsitec-sa/bug/#1091
Bug/#1091 - Fix CA1416 on AspNet project
2026-07-29 11:05:29 +02:00
Samuel Nussbaum
d4402d1040 chore(build): Apply same NoWarn regardless of current runtime, platform or architecture in order to avoid compile issue when used in development mode 2026-07-29 09:47:00 +02:00
Florian Rappl
4b65ed26a4 Merge pull request #1089 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/flatted-3.4.3
Bump flatted from 3.3.3 to 3.4.3 in /src/ElectronNET.WebApp/ElectronHostHook
2026-07-28 09:07:22 +02:00
Florian Rappl
e12145004e Merge pull request #1090 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.Host/socket.io-parser-4.2.7
Bump socket.io-parser from 4.2.5 to 4.2.7 in /src/ElectronNET.Host
2026-07-28 09:07:11 +02:00
Florian Rappl
3e8ebde05b Merge pull request #1088 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.Host/multi-32449639ce
Bump builder-util-runtime and electron-updater in /src/ElectronNET.Host
2026-07-28 09:06:58 +02:00
Florian Rappl
820d7bbcec Merge pull request #1087 from epsitec-sa/bug/#1084
Bug/#1084 - Visual studio loading issue
2026-07-28 09:05:52 +02:00
Samuel Nussbaum
5eeab1bd24 fix(warning): remove warining CS4014 2026-07-28 06:54:48 +02:00
Roger Vuistiner
1fff688098 chore: consolidate MSBuild configuration barriers
- Moved Directory.Build.* barriers from nuke to root folder to cover all projects.
- Added a Directory.Packages.props barrier to stop central package management.
- Removed obsolete 'ManagePackageVersionsCentrally' properties.
2026-07-28 06:54:43 +02:00
dependabot[bot]
9b701f5258 Bump socket.io-parser from 4.2.5 to 4.2.7 in /src/ElectronNET.Host
Bumps [socket.io-parser](https://github.com/socketio/socket.io) from 4.2.5 to 4.2.7.
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.5...socket.io-parser@4.2.7)

---
updated-dependencies:
- dependency-name: socket.io-parser
  dependency-version: 4.2.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 03:41:41 +00:00
dependabot[bot]
b41c7e51b1 Bump flatted in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.3.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.3)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 03:41:32 +00:00
dependabot[bot]
1d24067f4b Bump builder-util-runtime and electron-updater in /src/ElectronNET.Host
Bumps [builder-util-runtime](https://github.com/electron-userland/electron-builder/tree/HEAD/packages/builder-util-runtime) to 9.7.0 and updates ancestor dependency [electron-updater](https://github.com/electron-userland/electron-builder/tree/HEAD/packages/electron-updater). These dependencies need to be updated together.


Updates `builder-util-runtime` from 9.5.1 to 9.7.0
- [Release notes](https://github.com/electron-userland/electron-builder/releases)
- [Changelog](https://github.com/electron-userland/electron-builder/blob/master/packages/builder-util-runtime/CHANGELOG.md)
- [Commits](https://github.com/electron-userland/electron-builder/commits/HEAD/packages/builder-util-runtime)

Updates `electron-updater` from 6.8.3 to 6.8.9
- [Release notes](https://github.com/electron-userland/electron-builder/releases)
- [Changelog](https://github.com/electron-userland/electron-builder/blob/master/packages/electron-updater/CHANGELOG.md)
- [Commits](https://github.com/electron-userland/electron-builder/commits/electron-updater@6.8.9/packages/electron-updater)

---
updated-dependencies:
- dependency-name: builder-util-runtime
  dependency-version: 9.7.0
  dependency-type: indirect
- dependency-name: electron-updater
  dependency-version: 6.8.9
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 03:41:30 +00:00
Samuel Nussbaum
44e5c4e230 chore(build): runtime identifier is not required anymore 2026-07-27 16:45:52 +02:00
Samuel Nussbaum
0b3053477d chore(dx): visual studio load regression, let electron choose the required runtime. 2026-07-27 16:45:52 +02:00
Samuel Nussbaum
3fecc0ee1b fix: Visual studio load issue 2026-07-27 16:45:51 +02:00
Florian Rappl
95089e1721 Merge pull request #1085 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/js-yaml-4.3.0
Bump js-yaml from 4.1.1 to 4.3.0 in /src/ElectronNET.WebApp/ElectronHostHook
2026-07-22 07:12:18 +02:00
Florian Rappl
cec178cf50 Merge pull request #1086 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.Host/brace-expansion-1.1.16
Bump brace-expansion from 1.1.12 to 1.1.16 in /src/ElectronNET.Host
2026-07-22 07:12:07 +02:00
dependabot[bot]
20af8a692c Bump brace-expansion from 1.1.12 to 1.1.16 in /src/ElectronNET.Host
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.16.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.16)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.16
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 02:19:22 +00:00
dependabot[bot]
4e69bcf030 Bump js-yaml in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.3.0.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.1...4.3.0)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 02:19:18 +00:00
Florian Rappl
5ae5bf0df7 Merge pull request #1083 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.Host/js-yaml-4.3.0
Bump js-yaml from 4.1.1 to 4.3.0 in /src/ElectronNET.Host
2026-07-15 07:12:13 +02:00
dependabot[bot]
5da5d1c618 Bump js-yaml from 4.1.1 to 4.3.0 in /src/ElectronNET.Host
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.3.0.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.1...4.3.0)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-14 22:27:36 +00:00
Florian Rappl
b6e496b2c6 Merge pull request #1082 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/js-yaml-4.3.0
Bump js-yaml from 4.1.1 to 4.3.0 in /src/ElectronNET.WebApp/ElectronHostHook
2026-07-09 15:33:25 +02:00
Florian Rappl
5974cb9e43 Merge branch 'develop' into dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/js-yaml-4.3.0 2026-07-09 10:42:03 +02:00
dependabot[bot]
d4d4e9dddd Bump js-yaml in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.3.0.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.1...4.3.0)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-08 23:02:16 +00:00
Florian Rappl
3b5f21c724 Merge pull request #1081 from epsitec-sa/bug/default-runtime
chore: use default sdk runtime identifier
2026-07-06 15:17:02 +02:00
Samuel Nussbaum
5aebe807c3 change to less brittle solution 2026-07-06 11:02:48 +02:00
Samuel Nussbaum
bdee008cc8 use default sdk runtime identifier 2026-07-06 10:44:05 +02:00
Florian Rappl
7fc5c9b611 Merge pull request #1080 from epsitec-sa/bug/#1058
fix(shore): bloated asar and corrupted packaged directory
2026-07-05 11:08:43 +02:00
Samuel Nussbaum
86e5d74c03 dump to latest version 2026-07-03 15:24:49 +02:00
Samuel Nussbaum
e79b029e16 Fix scoped css naming issue 2026-07-03 15:09:49 +02:00
Samuel Nussbaum
5bdf6230b9 fix examples build and publish 2026-07-03 15:08:57 +02:00
Samuel Nussbaum
8c2382a05c Split packaging to avoid duplication in .asar archive 2026-07-03 11:28:52 +02:00
Florian Rappl
10b1b686cb Merge pull request #1079 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/js-yaml-4.2.0
Bump js-yaml from 4.1.1 to 4.2.0 in /src/ElectronNET.WebApp/ElectronHostHook
2026-06-24 14:51:00 +02:00
Florian Rappl
d7d2521d0c Merge pull request #1078 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.Host/multi-5f1280885e
Bump ws, engine.io and socket.io-adapter in /src/ElectronNET.Host
2026-06-24 14:50:35 +02:00
Florian Rappl
392419e5a7 Merge branch 'develop' into dependabot/npm_and_yarn/src/ElectronNET.Host/multi-5f1280885e 2026-06-24 14:50:10 +02:00
dependabot[bot]
f92f07a378 Bump js-yaml in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.2.0.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.1...4.2.0)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.2.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-24 07:11:36 +00:00
dependabot[bot]
9b045cbf01 Bump ws, engine.io and socket.io-adapter in /src/ElectronNET.Host
Bumps [ws](https://github.com/websockets/ws), [engine.io](https://github.com/socketio/socket.io) and [socket.io-adapter](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `ws` from 8.20.1 to 8.21.0
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.20.1...8.21.0)

Updates `engine.io` from 6.6.8 to 6.6.9
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/engine.io@6.6.8...engine.io@6.6.9)

Updates `socket.io-adapter` from 2.5.7 to 2.5.8
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.7...socket.io-adapter@2.5.8)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.21.0
  dependency-type: indirect
- dependency-name: engine.io
  dependency-version: 6.6.9
  dependency-type: indirect
- dependency-name: socket.io-adapter
  dependency-version: 2.5.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-24 03:30:33 +00:00
Florian Rappl
94ff3c1c4d Updated token usage 2026-06-22 23:23:44 +02:00
Florian Rappl
773937448d Updated version 2026-06-22 23:23:34 +02:00
Florian Rappl
b094051dcb Merge pull request #1077 from AeonSake/1076-add-overloads-for-useelectron
Add Overloads for `UseElectron`
2026-06-21 21:46:56 +02:00
Aeon
3a10e7e98d Add missing null-check 2026-06-20 01:38:58 +02:00
Aeon
056661028b Remove unused property 2026-06-20 01:26:55 +02:00
Aeon
27a8c69a9a Add missing extension method overloads 2026-06-20 01:26:25 +02:00
Aeon
8e900655b9 Replace static property with resolver service 2026-06-20 01:26:00 +02:00
Aeon
066efa80e2 Add service for resolving on-app-ready callback 2026-06-20 01:24:30 +02:00
Florian Rappl
18944fe222 Release 0.5.1 (#1074)
* Bump ws, engine.io and socket.io-adapter

Bumps [ws](https://github.com/websockets/ws), [engine.io](https://github.com/socketio/socket.io) and [socket.io-adapter](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `ws` from 8.17.1 to 8.20.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.17.1...8.20.1)

Updates `engine.io` from 6.6.4 to 6.6.8
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/engine.io@6.6.4...engine.io@6.6.8)

Updates `socket.io-adapter` from 2.5.5 to 2.5.7
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.5...socket.io-adapter@2.5.7)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.20.1
  dependency-type: indirect
- dependency-name: engine.io
  dependency-version: 6.6.8
  dependency-type: indirect
- dependency-name: socket.io-adapter
  dependency-version: 2.5.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump tmp and exceljs in /src/ElectronNET.WebApp/ElectronHostHook

Bumps [tmp](https://github.com/raszi/node-tmp) to 0.2.7 and updates ancestor dependency [exceljs](https://github.com/exceljs/exceljs). These dependencies need to be updated together.


Updates `tmp` from 0.1.0 to 0.2.7
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.1.0...v0.2.7)

Updates `exceljs` from 1.15.0 to 4.4.0
- [Release notes](https://github.com/exceljs/exceljs/releases)
- [Commits](https://github.com/exceljs/exceljs/compare/v1.15.0...v4.4.0)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.7
  dependency-type: indirect
- dependency-name: exceljs
  dependency-version: 4.4.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ws, engine.io and socket.io-adapter in /src/ElectronNET.Host

Bumps [ws](https://github.com/websockets/ws), [engine.io](https://github.com/socketio/socket.io) and [socket.io-adapter](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `ws` from 8.18.3 to 8.20.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.18.3...8.20.1)

Updates `engine.io` from 6.6.5 to 6.6.8
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/engine.io@6.6.5...engine.io@6.6.8)

Updates `socket.io-adapter` from 2.5.6 to 2.5.7
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.6...socket.io-adapter@2.5.7)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.20.1
  dependency-type: indirect
- dependency-name: engine.io
  dependency-version: 6.6.8
  dependency-type: indirect
- dependency-name: socket.io-adapter
  dependency-version: 2.5.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ws, engine.io and socket.io-adapter

Bumps [ws](https://github.com/websockets/ws), [engine.io](https://github.com/socketio/socket.io) and [socket.io-adapter](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `ws` from 8.18.3 to 8.20.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.18.3...8.20.1)

Updates `engine.io` from 6.6.5 to 6.6.8
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/engine.io@6.6.5...engine.io@6.6.8)

Updates `socket.io-adapter` from 2.5.6 to 2.5.7
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.6...socket.io-adapter@2.5.7)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.20.1
  dependency-type: indirect
- dependency-name: engine.io
  dependency-version: 6.6.8
  dependency-type: indirect
- dependency-name: socket.io-adapter
  dependency-version: 2.5.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Improved argument forwarding

* Added support for Electron 42+

* Removed wrongly placed line

* Use path directly

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-08 21:28:22 +02:00
Florian Rappl
0e83af032c Merge branch 'develop' of https://github.com/ElectronNET/Electron.NET into develop 2026-06-07 14:48:15 +02:00
Florian Rappl
1ec84cfef0 Use path directly 2026-06-07 14:48:07 +02:00
Florian Rappl
1620c50627 Merge pull request #1071 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/multi-8c9a216550
Bump ws, engine.io and socket.io-adapter in /src/ElectronNET.WebApp/ElectronHostHook
2026-06-07 13:44:13 +02:00
Florian Rappl
295b250e58 Merge pull request #1070 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.Host/multi-8c9a216550
Bump ws, engine.io and socket.io-adapter in /src/ElectronNET.Host
2026-06-07 13:44:04 +02:00
Florian Rappl
644628c803 Merge pull request #1069 from ElectronNET/dependabot/npm_and_yarn/src/ElectronNET.WebApp/ElectronHostHook/multi-19724e71a7
Bump tmp and exceljs in /src/ElectronNET.WebApp/ElectronHostHook
2026-06-07 13:43:45 +02:00
Florian Rappl
a18944d4a4 Removed wrongly placed line 2026-06-07 13:41:21 +02:00
dependabot[bot]
e44927a655 Bump ws, engine.io and socket.io-adapter
Bumps [ws](https://github.com/websockets/ws), [engine.io](https://github.com/socketio/socket.io) and [socket.io-adapter](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `ws` from 8.18.3 to 8.20.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.18.3...8.20.1)

Updates `engine.io` from 6.6.5 to 6.6.8
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/engine.io@6.6.5...engine.io@6.6.8)

Updates `socket.io-adapter` from 2.5.6 to 2.5.7
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.6...socket.io-adapter@2.5.7)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.20.1
  dependency-type: indirect
- dependency-name: engine.io
  dependency-version: 6.6.8
  dependency-type: indirect
- dependency-name: socket.io-adapter
  dependency-version: 2.5.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-29 21:29:26 +00:00
dependabot[bot]
ed9a24bb5e Bump ws, engine.io and socket.io-adapter in /src/ElectronNET.Host
Bumps [ws](https://github.com/websockets/ws), [engine.io](https://github.com/socketio/socket.io) and [socket.io-adapter](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `ws` from 8.18.3 to 8.20.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.18.3...8.20.1)

Updates `engine.io` from 6.6.5 to 6.6.8
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/engine.io@6.6.5...engine.io@6.6.8)

Updates `socket.io-adapter` from 2.5.6 to 2.5.7
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.6...socket.io-adapter@2.5.7)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.20.1
  dependency-type: indirect
- dependency-name: engine.io
  dependency-version: 6.6.8
  dependency-type: indirect
- dependency-name: socket.io-adapter
  dependency-version: 2.5.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-28 03:59:46 +00:00
dependabot[bot]
94df47efa6 Bump tmp and exceljs in /src/ElectronNET.WebApp/ElectronHostHook
Bumps [tmp](https://github.com/raszi/node-tmp) to 0.2.7 and updates ancestor dependency [exceljs](https://github.com/exceljs/exceljs). These dependencies need to be updated together.


Updates `tmp` from 0.1.0 to 0.2.7
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.1.0...v0.2.7)

Updates `exceljs` from 1.15.0 to 4.4.0
- [Release notes](https://github.com/exceljs/exceljs/releases)
- [Commits](https://github.com/exceljs/exceljs/compare/v1.15.0...v4.4.0)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.7
  dependency-type: indirect
- dependency-name: exceljs
  dependency-version: 4.4.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-28 00:35:30 +00:00
54 changed files with 1825 additions and 551 deletions

View File

@@ -1,3 +1,32 @@
# 0.6.0
## ElectronNET.Core
- Updated dependencies
- Fixed single instance handling on macOS (#1040)
- Fixed slow socket bridge startup by binding to an explicit loopback address (#1103)
- Fixed socket bridge connection when a system proxy is configured (#1105)
- Fixed electron-builder using the host RID instead of the target RID (#1097)
- Fixed cross-compilation behavior on same platform (#1098) @epsnm
- Fixed resolution of unrelated target (#1099) @epsnm
- Added target framework customization (#1095) @epsnm
- Added configurable Electron root directory for custom packaging layouts (#1106) @DYH1319
- Added `ElectronExecutableName` to separate the product name from the executable name (#1003) @AeonSake
- Added build extensibility properties `ElectronSkipExecCommands` and `ElectronIntermediatePublishDir` (#1106) @DYH1319
# 0.5.2
## ElectronNET.Core
- Fixed token param being appended to external URLs (#1075)
- Fixed startup mode discriminator in case of existing `wwwroot` (#1050)
- Fixed CA1416 on ASP.NET project (#1091) @epsnm
- Fixed loading issue in plain Visual Studio (#1084) @epsnm
- Fixed bloated ASAR file (#1080) @epsnm
- Improved selection of runtime identifier (#1081) @epsnm
- Added more variants for `UseElectron` (#1076) @AeonSake
- Added support for modern MacOS app icon (#1047)
# 0.5.1
## ElectronNET.Core

15
Directory.Build.props Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This file prevents unintended imports of unrelated MSBuild files -->
<!-- Uncomment to include parent Directory.Build.props file -->
<!--<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />-->
<PropertyGroup>
<ElectronNetBuildProps>$([MSBuild]::GetPathOfFileAbove('ElectronNet.Build.props', '$(MSBuildThisFileDirectory)../'))</ElectronNetBuildProps>
</PropertyGroup>
<!-- Only import specific project related MSBuild file -->
<Import Project="$(ElectronNetBuildProps)" Condition=" '$(ElectronNetBuildProps)' != '' " />
</Project>

View File

@@ -2,7 +2,7 @@
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This file prevents unintended imports of unrelated MSBuild files -->
<!-- Uncomment to include parent Directory.Build.props file -->
<!--<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />-->
<!-- Uncomment to include parent Directory.Packages.props file -->
<!--<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Packages.props', '$(MSBuildThisFileDirectory)../'))" />-->
</Project>

View File

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

View File

@@ -28,9 +28,77 @@ These are the current default values when you don't make any changes:
<ElectronPackageId>$(MSBuildProjectName.Replace(".", "-").ToLower())</ElectronPackageId>
<ElectronBuilderJson>electron-builder.json</ElectronBuilderJson>
<Title>$(MSBuildProjectName)</Title>
<ElectronExecutableName></ElectronExecutableName>
<ElectronRootDir>../..</ElectronRootDir>
<ElectronSkipExecCommands>false</ElectronSkipExecCommands>
</PropertyGroup>
```
### Product Name and Executable Name
`Title` is the product name of the application. It is used for the window title, the installer, the macOS app bundle and the Linux desktop entry, and it may contain spaces and other characters that are awkward in a file name.
`ElectronExecutableName` controls the name of the executable inside the package (electron-builder's `executableName`). When it is not set, it defaults to the following behavior:
| Target | Default |
| --- | --- |
| Windows | `$(Title)` |
| Linux / macOS | `$(ElectronPackageId)` |
So to ship a product called `My Great App` with a `mygreatapp` binary on every platform:
```xml
<PropertyGroup>
<Title>My Great App</Title>
<ElectronExecutableName>mygreatapp</ElectronExecutableName>
</PropertyGroup>
```
> [!NOTE]
> `ElectronExecutable` is a separate, advanced setting: it is the binary Electron.NET launches when the .NET app starts first. It defaults to `ElectronExecutableName` and only needs to be changed when the package contains a launcher stub (for example added by an electron-builder hook) that should be started instead of the Electron binary.
### Custom Packaging Layout
`ElectronRootDir` tells the .NET app where to find the Electron binary when it is started first (DotNet-First startup of a packaged app). The path is resolved relative to the directory of the .NET executable; absolute paths are used as-is.
The default `../..` matches the standard Electron-First packaging layout produced by `dotnet publish`, where the .NET app is placed in `resources/bin` of the Electron package:
```
<install-root>/
MyApp # Electron executable
resources/
bin/
MyApp # .NET executable
```
If your own packaging pipeline places the .NET executable at the package root and Electron in a subdirectory, set `ElectronRootDir` accordingly:
```xml
<ElectronRootDir>electron</ElectronRootDir>
```
```
<install-root>/
MyApp # .NET executable
electron/
MyApp # Electron executable
resources/
locales/
```
The property is also used to detect whether the app runs packaged or unpackaged, so it must point to the directory that actually contains the Electron binary.
### Build Extensibility
These properties are useful when Electron.NET is embedded into a custom build or CI pipeline:
| Property | Default | Description |
| --- | --- | --- |
| `ElectronSkipExecCommands` | `false` | Skips all `npm`/`npx` invocations of the Electron build and publish targets. Use it when the dependencies and the Electron distribution are provided by the pipeline itself (for example from a cache or an offline mirror). |
| `ElectronIntermediatePublishDir` | `$(IntermediateOutputPath)PubTmp\` | Overrides the intermediate directory the .NET app is published to before it is assembled into the Electron package. |
`ElectronPackageId` and `Title` only fall back to the project name when they are not already set, so both can be defined by a `Directory.Build.props` or passed on the command line.
### Relation to package.json
ElectronNET.Core does not work with an `electron-manifest.json` file anymore.
@@ -42,11 +110,17 @@ Since electron builder still expects a `package.json` file to exist, ElectronNET
"productName": "$(ElectronTitle)",
"build": {
"appId": "$(ElectronPackageId)",
"win": {
"executableName": "$(ElectronExecutableName)"
},
"mac": {
"executableName": "$(ElectronExecutableName)"
},
"linux": {
"desktop": {
"entry": { "Name": "$(Title)" }
},
"executableName": "$(ElectronPackageId)"
"executableName": "$(ElectronExecutableName)"
},
"deb": {
"desktop": {
@@ -70,6 +144,12 @@ Since electron builder still expects a `package.json` file to exist, ElectronNET
}
```
### App Icon Path
The `ElectronIcon` property supports classic icon files (such as `.ico` and `.icns`) and modern macOS `.icon` app icon packages.
For `.icon`, provide the folder path (for example `Assets/MyApp.icon`). During build/publish, Electron.NET copies the full directory into the Electron output so `electron-builder.json` can reference it (for example `"mac": { "icon": "MyApp.icon" }`).
### Node.js Integration
Electron.NET requires Node.js integration to be enabled for IPC to function. If you are not using the IPC functionality you can disable Node.js integration like so:

View File

@@ -222,6 +222,15 @@ The publish process will:
> macOS builds can't be created on Windows machines because they require symlinks that aren't supported on Windows (per [this Electron issue](https://github.com/electron-userland/electron-packager/issues/71)). macOS builds can be produced on either Linux or macOS machines.
## Custom Packaging Pipelines
The default layout is Electron-First: electron-builder produces the Electron package and the .NET app is placed in `resources/bin`. If you assemble the package yourself and put the .NET executable at the package root with Electron in a subdirectory, set `ElectronRootDir` so the .NET app can locate the Electron binary at runtime.
For pipelines that provide the npm dependencies themselves, `ElectronSkipExecCommands` suppresses all `npm`/`npx` invocations, and `ElectronIntermediatePublishDir` redirects the intermediate publish output.
See [Configuration](Configuration.md#custom-packaging-layout) for details.
## 🚀 Next Steps
- **[Startup Methods](Startup-Methods.md)** - Understanding different launch modes for packaged apps

View File

@@ -19,6 +19,7 @@ namespace ElectronNET.API
internal WindowManager()
{
EnsureBrowserWindowClosedSubscription();
}
internal static WindowManager Instance
@@ -106,17 +107,6 @@ namespace ElectronNET.API
tcs.SetResult(browserWindow);
});
BridgeConnector.Socket.Once<int[]>("BrowserWindowClosed", (ids) =>
{
for (int index = 0; index < _browserWindows.Count; index++)
{
if (!ids.Contains(_browserWindows[index].Id))
{
_browserWindows.RemoveAt(index);
}
}
});
if (loadUrl.Equals("http://localhost", StringComparison.OrdinalIgnoreCase) && ElectronNetRuntime.AspNetWebPort.HasValue)
{
loadUrl = $"{loadUrl}:{ElectronNetRuntime.AspNetWebPort}";
@@ -149,6 +139,49 @@ namespace ElectronNET.API
return await tcs.Task.ConfigureAwait(false);
}
private readonly object _browserWindowSubscriptionSync = new();
private bool _browserWindowClosedSubscribed;
private void EnsureBrowserWindowClosedSubscription()
{
if (_browserWindowClosedSubscribed)
{
return;
}
lock (_browserWindowSubscriptionSync)
{
if (_browserWindowClosedSubscribed)
{
return;
}
BridgeConnector.Socket.On<int[]>("BrowserWindowClosed", HandleBrowserWindowClosed);
BridgeConnector.Socket.On<int>("BrowserWindowRecreated", HandleBrowserWindowRecreated);
_browserWindowClosedSubscribed = true;
}
}
private void HandleBrowserWindowRecreated(int id)
{
if (_browserWindows.All(window => window.Id != id))
{
_browserWindows.Add(new BrowserWindow(id));
}
}
private void HandleBrowserWindowClosed(int[] ids)
{
if (ids == null || ids.Length == 0)
{
_browserWindows.Clear();
return;
}
var existingIds = ids.ToHashSet();
_browserWindows.RemoveAll(window => !existingIds.Contains(window.Id));
}
private bool IsWindows10()
{
return RuntimeInformation.OSDescription.Contains("Windows 10");

View File

@@ -4,6 +4,7 @@ namespace ElectronNET.API;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using ElectronNET.API.Serialization;
using SocketIO.Serializer.SystemTextJson;
@@ -18,13 +19,21 @@ internal class SocketIOConnection : ISocketConnection
public SocketIOConnection(string uri, string authorization)
{
var opts = string.IsNullOrEmpty(authorization) ? new SocketIOOptions() : new SocketIOOptions
var opts = new SocketIOOptions
{
ExtraHeaders = new Dictionary<string, string>
// The bridge is a loopback IPC channel, so it must never go through a
// (system) proxy - otherwise the handshake never reaches the socket server.
Proxy = DirectProxy.Instance,
};
if (!string.IsNullOrEmpty(authorization))
{
opts.ExtraHeaders = new Dictionary<string, string>
{
["authorization"] = authorization
},
};
};
}
_socket = new SocketIO(uri, opts);
_socket.Serializer = new SystemTextJsonSerializer(ElectronJson.Options);
// Use default System.Text.Json serializer from SocketIOClient.
@@ -152,4 +161,15 @@ internal class SocketIOConnection : ISocketConnection
throw new ObjectDisposedException(nameof(SocketIOConnection));
}
}
private sealed class DirectProxy : IWebProxy
{
public static readonly DirectProxy Instance = new DirectProxy();
public ICredentials Credentials { get; set; }
public Uri GetProxy(Uri destination) => destination;
public bool IsBypassed(Uri host) => true;
}
}

View File

@@ -37,10 +37,18 @@
public ProcessRunner(string name)
{
this.Name = name;
this.ExitWaitTimeout = DefaultExitWaitTimeout;
}
public event EventHandler<EventArgs> ProcessExited;
/// <summary>Gets or sets the value <see cref="ExitWaitTimeout"/> is initialized with.</summary>
public static int DefaultExitWaitTimeout { get; set; } = 5000;
/// <summary>Gets or sets the time in milliseconds to wait for the process and its I/O to finish
/// after the exited event has been raised. Values of zero or less wait indefinitely.</summary>
public int ExitWaitTimeout { get; set; }
public bool IsDisposed { get; private set; }
private Process Process
@@ -498,8 +506,17 @@
{
try
{
var timeout = this.ExitWaitTimeout;
// This shouldn't throw here, but the mono process implementation doesn't always behave as it should.
this.process.WaitForExit();
if (timeout > 0)
{
this.process.WaitForExit(timeout);
}
else
{
this.process.WaitForExit();
}
}
catch (Exception ex)
{

View File

@@ -3,7 +3,7 @@
<Import Project="..\common.props" />
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>
<TargetFrameworks>$(ElectronNetTargetFrameworks)</TargetFrameworks>
<PackageOutputPath>..\..\artifacts</PackageOutputPath>
<PackageId>$(PackageNamePrefix).API</PackageId>
<Title>$(PackageId)</Title>
@@ -29,7 +29,7 @@
</PackageReference>
<PackageReference Include="SocketIOClient" Version="3.1.2" />
<PackageReference Include="System.Drawing.Common" Version="8.0.22" />
<PackageReference Include="System.Text.Json" Version="8.0.6" />
<PackageReference Include="System.Text.Json" Version="8.0.6" Condition=" '$(TargetFramework)' == 'net6.0' " />
</ItemGroup>
<ItemGroup>

View File

@@ -15,6 +15,7 @@
internal const int DefaultSocketPort = 8000;
internal const int DefaultWebPort = 8001;
internal const string ElectronPortArgumentName = "electronPort";
internal const string ElectronHostArgumentName = "electronHost";
internal const string ElectronPidArgumentName = "electronPID";
internal const string ElectronAuthTokenArgumentName = "electronAuthToken";
@@ -31,6 +32,11 @@
public static int? ElectronSocketPort { get; internal set; }
/// <summary>
/// The loopback address the Electron socket bridge is listening on.
/// </summary>
public static string ElectronSocketHost { get; internal set; }
public static int? AspNetWebPort { get; internal set; }
public static StartupMethod StartupMethod { get; internal set; }
@@ -50,8 +56,6 @@
internal static int? ElectronProcessId { get; set; }
internal static Func<Task> OnAppReadyCallback { get; set; }
internal static ISocketConnection GetSocket()
{
return RuntimeControllerCore?.Socket;

View File

@@ -6,6 +6,8 @@
public string ElectronVersion { get; internal set; }
public string ElectronRootDir { get; internal set; }
public string RuntimeIdentifier { get; internal set; }
public bool ElectronSingleInstance { get; internal set; }

View File

@@ -0,0 +1,31 @@
namespace ElectronNET.Runtime.Helpers
{
using System;
using System.IO;
/// <summary>
/// Resolves the directory that contains the Electron binary of a packaged application.
/// </summary>
internal static class ElectronRootDirResolver
{
/// <summary>The location of the Electron binary relative to the .NET application directory in the
/// default (Electron-first) layout, where the .NET application is placed in 'resources/bin'.</summary>
internal const string DefaultElectronRootDir = "../..";
/// <summary>Resolves the Electron root directory relative to the given .NET application directory.</summary>
/// <param name="baseDirectory">The directory containing the .NET application.</param>
/// <returns>The directory containing the Electron binary.</returns>
public static DirectoryInfo Resolve(DirectoryInfo baseDirectory)
{
var rootDir = ElectronNetRuntime.BuildInfo?.ElectronRootDir;
if (string.IsNullOrWhiteSpace(rootDir))
{
rootDir = DefaultElectronRootDir;
}
// An absolute ElectronRootDir is used as-is by Path.Combine.
return new DirectoryInfo(Path.GetFullPath(Path.Combine(baseDirectory.FullName, rootDir)));
}
}
}

View File

@@ -69,6 +69,15 @@
return false;
}
// Packaged, if the Electron binary is found where ElectronRootDir points to.
var electronExecutable = ElectronNetRuntime.ElectronExecutable;
if (!string.IsNullOrEmpty(electronExecutable) &&
File.Exists(Path.Combine(ElectronRootDirResolver.Resolve(dir).FullName, electronExecutable)))
{
return false;
}
if (dir.GetDirectories().Any(e => e.Name == ".electron"))
{
return true;

View File

@@ -11,6 +11,7 @@
using System.Threading.Tasks;
using ElectronNET.Common;
using ElectronNET.Runtime.Data;
using ElectronNET.Runtime.Helpers;
/// <summary>
/// Launches and manages the Electron app process.
@@ -18,7 +19,7 @@
[Localizable(false)]
internal class ElectronProcessActive : ElectronProcessBase
{
private readonly Regex extractor = new Regex("^Electron Socket: listening on port (\\d+) at .* using ([a-f0-9]+)$");
private readonly Regex extractor = new Regex("^Electron Socket: listening on port (\\d+) at (\\S+) using ([a-f0-9]+)$");
private readonly bool isUnpackaged;
private readonly string electronBinaryName;
@@ -87,7 +88,7 @@
}
else
{
dir = dir.Parent!.Parent!;
dir = ElectronRootDirResolver.Resolve(dir);
startCmd = Path.Combine(dir.FullName, this.electronBinaryName);
args = $"-dotnetpacked -electronforcedport={this.socketPort:D} " + this.extraArguments;
workingDir = dir.FullName;
@@ -179,11 +180,13 @@
if (match?.Success ?? false)
{
var port = int.Parse(match.Groups[1].Value);
var token = match.Groups[2].Value;
var host = match.Groups[2].Value;
var token = match.Groups[3].Value;
this.process.LineReceived -= Read_SocketIO_Parameters;
ElectronNetRuntime.ElectronAuthToken = token;
ElectronNetRuntime.ElectronSocketPort = port;
ElectronNetRuntime.ElectronSocketHost = host;
tcs.SetResult();
}
}

View File

@@ -16,7 +16,19 @@
{
this.socketPort = socketPort;
this.authorization = authorization;
this.socketUrl = $"http://localhost:{this.socketPort}";
this.socketUrl = $"http://{FormatHost(ElectronNetRuntime.ElectronSocketHost)}:{this.socketPort}";
}
// The Electron host reports the loopback address it is actually listening on; only
// when it is unknown we have to fall back to the ambiguous hostname.
private static string FormatHost(string socketHost)
{
if (string.IsNullOrWhiteSpace(socketHost))
{
return "localhost";
}
return socketHost.Contains(':') ? $"[{socketHost}]" : socketHost;
}
public int SocketPort => this.socketPort;

View File

@@ -94,8 +94,20 @@
}
}
var pidArg = argsList.FirstOrDefault(e => e.Contains(ElectronNetRuntime.ElectronPidArgumentName, StringComparison.OrdinalIgnoreCase));
var hostArg = argsList.FirstOrDefault(e => e.Contains(ElectronNetRuntime.ElectronHostArgumentName, StringComparison.OrdinalIgnoreCase));
if (hostArg != null)
{
var parts = hostArg.Split('=', StringSplitOptions.TrimEntries);
if (parts.Length > 1 && !string.IsNullOrWhiteSpace(parts[1]))
{
ElectronNetRuntime.ElectronSocketHost = parts[1];
Console.WriteLine("Use Electron Host: " + parts[1]);
}
}
var pidArg = argsList.FirstOrDefault(e => e.Contains(ElectronNetRuntime.ElectronPidArgumentName, StringComparison.OrdinalIgnoreCase));
if (pidArg != null)
{
var parts = pidArg.Split('=', StringSplitOptions.TrimEntries);
@@ -166,6 +178,7 @@
{
buildInfo.ElectronExecutable = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.ElectronExecutable))?.Value;
buildInfo.ElectronVersion = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.ElectronVersion))?.Value;
buildInfo.ElectronRootDir = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.ElectronRootDir))?.Value;
buildInfo.RuntimeIdentifier = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.RuntimeIdentifier))?.Value;
buildInfo.Title = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.Title))?.Value;
buildInfo.Version = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.Version))?.Value;

View File

@@ -44,5 +44,98 @@
return builder;
}
/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process, forwarded to Electron.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="WebApplicationBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// var builder = WebApplication.CreateBuilder(args)
/// .UseElectron(args, async (processArgs) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
///
/// var app = builder.Build();
/// app.MapRazorPages();
/// app.Run();
/// </code>
/// </example>
public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func<string[], Task> onAppReadyCallback)
{
builder.WebHost.UseElectron(args, onAppReadyCallback);
return builder;
}
/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process, forwarded to Electron.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="WebApplicationBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// var builder = WebApplication.CreateBuilder(args)
/// .UseElectron(args, async (serviceProvider) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
///
/// var app = builder.Build();
/// app.MapRazorPages();
/// app.Run();
/// </code>
/// </example>
public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func<IServiceProvider, Task> onAppReadyCallback)
{
builder.WebHost.UseElectron(args, onAppReadyCallback);
return builder;
}
/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process, forwarded to Electron.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="WebApplicationBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// var builder = WebApplication.CreateBuilder(args)
/// .UseElectron(args, async (serviceProvider, processArgs) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
///
/// var app = builder.Build();
/// app.MapRazorPages();
/// app.Run();
/// </code>
/// </example>
public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func<IServiceProvider, string[], Task> onAppReadyCallback)
{
builder.WebHost.UseElectron(args, onAppReadyCallback);
return builder;
}
}
}

View File

@@ -61,8 +61,154 @@
/// </example>
public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<Task> onAppReadyCallback)
{
ElectronNetRuntime.OnAppReadyCallback = onAppReadyCallback;
builder.ConfigureServices(services =>
{
services.AddSingleton<IAppReadyCallbackResolver>(_ => new AppReadyCallbackResolver(onAppReadyCallback));
});
return UseElectronCore(builder, args);
}
/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="IWebHostBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// using Microsoft.AspNetCore.Hosting;
/// using Microsoft.Extensions.Hosting;
/// using ElectronNET.API;
///
/// public class Program
/// {
/// public static void Main(string[] args)
/// {
/// Host.CreateDefaultBuilder(args)
/// .ConfigureWebHostDefaults(webBuilder =>
/// {
/// webBuilder.UseStartup&lt;Startup&gt;();
/// webBuilder.UseElectron(args, async (processArgs) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
/// })
/// .Build()
/// .Run();
/// }
/// }
/// </code>
/// </example>
public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<string[], Task> onAppReadyCallback)
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IAppReadyCallbackResolver>(_ => new AppReadyCallbackResolver(args, onAppReadyCallback));
});
return UseElectronCore(builder, args);
}
/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="IWebHostBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// using Microsoft.AspNetCore.Hosting;
/// using Microsoft.Extensions.Hosting;
/// using ElectronNET.API;
///
/// public class Program
/// {
/// public static void Main(string[] args)
/// {
/// Host.CreateDefaultBuilder(args)
/// .ConfigureWebHostDefaults(webBuilder =>
/// {
/// webBuilder.UseStartup&lt;Startup&gt;();
/// webBuilder.UseElectron(args, async (serviceProvider) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
/// })
/// .Build()
/// .Run();
/// }
/// }
/// </code>
/// </example>
public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<IServiceProvider, Task> onAppReadyCallback)
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IAppReadyCallbackResolver>(provider => new AppReadyCallbackResolver(provider, onAppReadyCallback));
});
return UseElectronCore(builder, args);
}
/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="IWebHostBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// using Microsoft.AspNetCore.Hosting;
/// using Microsoft.Extensions.Hosting;
/// using ElectronNET.API;
///
/// public class Program
/// {
/// public static void Main(string[] args)
/// {
/// Host.CreateDefaultBuilder(args)
/// .ConfigureWebHostDefaults(webBuilder =>
/// {
/// webBuilder.UseStartup&lt;Startup&gt;();
/// webBuilder.UseElectron(args, async (serviceProvider, processArgs) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
/// })
/// .Build()
/// .Run();
/// }
/// }
/// </code>
/// </example>
public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<IServiceProvider, string[], Task> onAppReadyCallback)
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IAppReadyCallbackResolver>(provider => new AppReadyCallbackResolver(provider, args, onAppReadyCallback));
});
return UseElectronCore(builder, args);
}
private static IWebHostBuilder UseElectronCore(IWebHostBuilder builder, string[] args)
{
// no matter how this is set - let's unset to prevent Electron not starting as expected
// e.g., VS Code sets this env variable, but this will cause `require("electron")` to not
// work as expected, see issue #952
@@ -70,14 +216,16 @@
var webPort = ElectronNetRuntime.AspNetWebPort ?? 0;
// 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.
// In packaged mode, static content is deployed alongside the app binaries, so we must
// point content root to the process base directory. In unpackaged/watch scenarios we
// keep the default project content root to preserve live reload behavior.
var isPackagedStartup = ElectronNetRuntime.StartupMethod == StartupMethod.PackagedElectronFirst ||
ElectronNetRuntime.StartupMethod == StartupMethod.PackagedDotnetFirst;
// For port 0 (dynamic port assignment), Kestrel requires binding to specific IP (127.0.0.1) not localhost
var host = webPort == 0 ? "127.0.0.1" : "localhost";
if (Directory.Exists($"{AppDomain.CurrentDomain.BaseDirectory}\\wwwroot"))
if (isPackagedStartup)
{
builder = builder.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
.UseUrls($"http://{host}:{webPort}");

View File

@@ -3,7 +3,7 @@
<Import Project="..\common.props" />
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>
<TargetFrameworks>$(ElectronNetTargetFrameworks)</TargetFrameworks>
<PackageOutputPath>..\..\artifacts</PackageOutputPath>
<PackageId>$(PackageNamePrefix).AspNet</PackageId>
<Title>$(PackageId)</Title>
@@ -13,23 +13,6 @@
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<Nullable>disable</Nullable>
<RootNamespace>ElectronNET</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net10.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net10.0|AnyCPU'">
<NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>
</PropertyGroup>
<ItemGroup>

View File

@@ -17,13 +17,15 @@
{
private readonly IServer server;
private readonly AspNetLifetimeAdapter aspNetLifetimeAdapter;
private readonly IAppReadyCallbackResolver callbackResolver;
private readonly IElectronAuthenticationService authenticationService;
private SocketBridgeService socketBridge;
protected RuntimeControllerAspNetBase(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null)
protected RuntimeControllerAspNetBase(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IAppReadyCallbackResolver callbackResolver, IElectronAuthenticationService authenticationService = null)
{
this.server = server;
this.aspNetLifetimeAdapter = aspNetLifetimeAdapter;
this.callbackResolver = callbackResolver;
this.authenticationService = authenticationService;
this.aspNetLifetimeAdapter.Ready += this.AspNetLifetimeAdapter_Ready;
this.aspNetLifetimeAdapter.Stopping += this.AspNetLifetimeAdapter_Stopping;
@@ -130,20 +132,20 @@
private async Task RunReadyCallback()
{
if (ElectronNetRuntime.OnAppReadyCallback == null)
if (!callbackResolver.HasCallback)
{
Console.WriteLine("Warning: Non OnReadyCallback provided in UseElectron() setup.");
Console.WriteLine("Warning: No OnReadyCallback provided in UseElectron() setup.");
return;
}
try
{
await ElectronNetRuntime.OnAppReadyCallback().ConfigureAwait(false);
await callbackResolver.Invoke().ConfigureAwait(false);
}
catch (Exception ex)
{
Console.WriteLine("Exception while executing OnAppReadyCallback. Stopping...\n" + ex);
this.Stop();
_ = this.Stop();
}
}
}

View File

@@ -14,7 +14,7 @@
{
private ElectronProcessBase electronProcess;
public RuntimeControllerAspNetDotnetFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, authenticationService)
public RuntimeControllerAspNetDotnetFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IAppReadyCallbackResolver callbackResolver, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, callbackResolver, authenticationService)
{
}

View File

@@ -11,7 +11,7 @@
{
private ElectronProcessBase electronProcess;
public RuntimeControllerAspNetElectronFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, authenticationService)
public RuntimeControllerAspNetElectronFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IAppReadyCallbackResolver callbackResolver, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, callbackResolver, authenticationService)
{
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Threading.Tasks;
namespace ElectronNET.AspNet.Runtime
{
internal class AppReadyCallbackResolver : IAppReadyCallbackResolver
{
private readonly Func<Task> _callback;
public AppReadyCallbackResolver()
{ }
public AppReadyCallbackResolver(Func<Task> callback)
{
_callback = callback;
}
public AppReadyCallbackResolver(string[] args, Func<string[], Task> callback)
{
if (callback != null)
{
_callback = () => callback.Invoke(args);
}
}
public AppReadyCallbackResolver(IServiceProvider serviceProvider, Func<IServiceProvider, Task> callback)
{
if (callback != null)
{
_callback = () => callback.Invoke(serviceProvider);
}
}
public AppReadyCallbackResolver(IServiceProvider serviceProvider, string[] args, Func<IServiceProvider, string[], Task> callback)
{
if (callback != null)
{
_callback = () => callback.Invoke(serviceProvider, args);
}
}
public bool HasCallback => _callback != null;
public Task Invoke() => _callback?.Invoke() ?? Task.CompletedTask;
}
}

View File

@@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace ElectronNET.AspNet.Runtime
{
internal interface IAppReadyCallbackResolver
{
public bool HasCallback { get; }
public Task Invoke();
}
}

View File

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

View File

@@ -247,9 +247,9 @@
}
},
"node_modules/socket.io-parser": {
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz",
"integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==",
"version": "4.2.7",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.7.tgz",
"integrity": "sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",

View File

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

View File

@@ -39,7 +39,6 @@ const windows = (global["browserWindows"] =
global["browserWindows"] || []);
let readyToShowWindowsIds = [];
let window;
let lastOptions;
let electronSocket;
const proxyToCredentialsMap = (global["proxyToCredentialsMap"] = global["proxyToCredentialsMap"] || []);
module.exports = (socket, app) => {
@@ -203,6 +202,18 @@ module.exports = (socket, app) => {
});
});
socket.on("createBrowserWindow", (options, loadUrl) => {
createWindow(options, loadUrl, "BrowserWindowCreated");
});
// Allows the host (main.js) to bring the main window back when the app is activated
// again on macOS after all windows have been closed.
global["recreateMainWindow"] = () => {
if (electron_1.BrowserWindow.getAllWindows().length > 0 || !app["mainWindowOptions"]) {
return false;
}
createWindow(app["mainWindowOptions"], app["mainWindowURL"], "BrowserWindowRecreated");
return true;
};
function createWindow(options, loadUrl, createdEventName) {
if (options.webPreferences &&
!("nodeIntegration" in options.webPreferences)) {
options = {
@@ -226,18 +237,19 @@ module.exports = (socket, app) => {
delete options.isRunningBlazor;
// we dont want to recreate the window when watch is ready.
if (app.commandLine.hasSwitch("watch") &&
app["mainWindowURL"] === loadUrl) {
app["mainWindowURL"] === loadUrl &&
app["mainWindow"] &&
!app["mainWindow"].isDestroyed()) {
window = app["mainWindow"];
if (window) {
window.reload();
window.reload();
synchronizeWindowRegistry();
if (!windows.some((entry) => tryGetWindowId(entry) === window.id)) {
windows.push(window);
electronSocket.emit("BrowserWindowCreated", window.id);
return;
}
electronSocket.emit(createdEventName, window.id);
return;
}
else {
window = new electron_1.BrowserWindow(options);
}
window = new electron_1.BrowserWindow(options);
if (options.proxy) {
window.webContents.session.setProxy({ proxyRules: options.proxy });
}
@@ -252,36 +264,28 @@ module.exports = (socket, app) => {
readyToShowWindowsIds.push(window.id);
}
});
lastOptions = options;
window.on("closed", (sender) => {
for (let index = 0; index < windows.length; index++) {
const windowItem = windows[index];
try {
windowItem.id;
}
catch (error) {
if (error.message === "Object has been destroyed") {
windows.splice(index, 1);
const ids = [];
windows.forEach((x) => ids.push(x.id));
electronSocket.emit("BrowserWindowClosed", ids);
}
}
}
});
app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (window === null && lastOptions) {
window = new electron_1.BrowserWindow(lastOptions);
}
window.on("closed", () => {
synchronizeWindowRegistry();
emitBrowserWindowClosed();
});
if (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}`);
try {
const url = new URL(loadUrl);
const isLocal = url.hostname === "localhost" ||
url.hostname === "127.0.0.1" ||
url.hostname === "::1";
if (isLocal) {
url.searchParams.set("token", token);
}
window.loadURL(url.toString());
}
catch {
// Handle invalid URLs or file:// URLs if needed
window.loadURL(loadUrl);
}
}
else {
window.loadURL(loadUrl);
@@ -296,10 +300,14 @@ module.exports = (socket, app) => {
if (app["mainWindowURL"] == undefined || app["mainWindowURL"] == "") {
app["mainWindowURL"] = loadUrl;
app["mainWindow"] = window;
app["mainWindowOptions"] = options;
}
else if (app["mainWindowURL"] === loadUrl) {
app["mainWindow"] = window;
}
windows.push(window);
electronSocket.emit("BrowserWindowCreated", window.id);
});
electronSocket.emit(createdEventName, window.id);
}
socket.on("browserWindowDestroy", (id) => {
getWindowById(id).destroy();
});
@@ -691,12 +699,47 @@ module.exports = (socket, app) => {
getWindowById(id).setBrowserView((0, browserView_1.browserViewMediateService)(browserViewId));
});
function getWindowById(id) {
const runtimeWindow = electron_1.BrowserWindow.fromId(id);
if (runtimeWindow) {
return runtimeWindow;
}
synchronizeWindowRegistry();
for (let index = 0; index < windows.length; index++) {
const element = windows[index];
if (element.id === id) {
if (tryGetWindowId(element) === id) {
return element;
}
}
throw new Error(`BrowserWindow with id '${id}' was not found.`);
}
function tryGetWindowId(element) {
try {
return element.id;
}
catch {
return null;
}
}
function synchronizeWindowRegistry() {
const runtimeWindows = electron_1.BrowserWindow.getAllWindows();
const runtimeWindowIds = new Set(runtimeWindows.map((entry) => entry.id));
for (let index = windows.length - 1; index >= 0; index--) {
const windowId = tryGetWindowId(windows[index]);
if (windowId === null || !runtimeWindowIds.has(windowId)) {
windows.splice(index, 1);
}
}
readyToShowWindowsIds = readyToShowWindowsIds.filter((entryId) => runtimeWindowIds.has(entryId));
}
function emitBrowserWindowClosed() {
const ids = [];
for (const entry of windows) {
const windowId = tryGetWindowId(entry);
if (windowId !== null) {
ids.push(windowId);
}
}
electronSocket.emit("BrowserWindowClosed", ids);
}
};
//# sourceMappingURL=browserWindows.js.map

File diff suppressed because one or more lines are too long

View File

@@ -10,7 +10,6 @@ const windows: Electron.BrowserWindow[] = (global["browserWindows"] =
let readyToShowWindowsIds: number[] = [];
let window;
let lastOptions;
let electronSocket;
const proxyToCredentialsMap: { [proxy: string]: string } = (global[
@@ -217,6 +216,26 @@ export = (socket: Socket, app: Electron.App) => {
});
socket.on("createBrowserWindow", (options, loadUrl) => {
createWindow(options, loadUrl, "BrowserWindowCreated");
});
// Allows the host (main.js) to bring the main window back when the app is activated
// again on macOS after all windows have been closed.
global["recreateMainWindow"] = () => {
if (BrowserWindow.getAllWindows().length > 0 || !app["mainWindowOptions"]) {
return false;
}
createWindow(
app["mainWindowOptions"],
app["mainWindowURL"],
"BrowserWindowRecreated",
);
return true;
};
function createWindow(options, loadUrl, createdEventName: string) {
if (
options.webPreferences &&
!("nodeIntegration" in options.webPreferences)
@@ -250,19 +269,24 @@ export = (socket: Socket, app: Electron.App) => {
// we dont want to recreate the window when watch is ready.
if (
app.commandLine.hasSwitch("watch") &&
app["mainWindowURL"] === loadUrl
app["mainWindowURL"] === loadUrl &&
app["mainWindow"] &&
!app["mainWindow"].isDestroyed()
) {
window = app["mainWindow"];
if (window) {
window.reload();
window.reload();
synchronizeWindowRegistry();
if (!windows.some((entry) => tryGetWindowId(entry) === window.id)) {
windows.push(window);
electronSocket.emit("BrowserWindowCreated", window.id);
return;
}
} else {
window = new BrowserWindow(options);
electronSocket.emit(createdEventName, window.id);
return;
}
window = new BrowserWindow(options);
if (options.proxy) {
window.webContents.session.setProxy({ proxyRules: options.proxy });
}
@@ -281,31 +305,9 @@ export = (socket: Socket, app: Electron.App) => {
}
});
lastOptions = options;
window.on("closed", (sender) => {
for (let index = 0; index < windows.length; index++) {
const windowItem = windows[index];
try {
windowItem.id;
} catch (error) {
if (error.message === "Object has been destroyed") {
windows.splice(index, 1);
const ids = [];
windows.forEach((x) => ids.push(x.id));
electronSocket.emit("BrowserWindowClosed", ids);
}
}
}
});
app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (window === null && lastOptions) {
window = new BrowserWindow(lastOptions);
}
window.on("closed", () => {
synchronizeWindowRegistry();
emitBrowserWindowClosed();
});
if (loadUrl) {
@@ -313,8 +315,23 @@ export = (socket: Socket, app: Electron.App) => {
const token = global["authToken"];
if (token) {
const separator = loadUrl.includes("?") ? "&" : "?";
window.loadURL(`${loadUrl}${separator}token=${token}`);
try {
const url = new URL(loadUrl);
const isLocal =
url.hostname === "localhost" ||
url.hostname === "127.0.0.1" ||
url.hostname === "::1";
if (isLocal) {
url.searchParams.set("token", token);
}
window.loadURL(url.toString());
} catch {
// Handle invalid URLs or file:// URLs if needed
window.loadURL(loadUrl);
}
} else {
window.loadURL(loadUrl);
}
@@ -332,11 +349,14 @@ export = (socket: Socket, app: Electron.App) => {
if (app["mainWindowURL"] == undefined || app["mainWindowURL"] == "") {
app["mainWindowURL"] = loadUrl;
app["mainWindow"] = window;
app["mainWindowOptions"] = options;
} else if (app["mainWindowURL"] === loadUrl) {
app["mainWindow"] = window;
}
windows.push(window);
electronSocket.emit("BrowserWindowCreated", window.id);
});
electronSocket.emit(createdEventName, window.id);
}
socket.on("browserWindowDestroy", (id) => {
getWindowById(id).destroy();
@@ -892,11 +912,57 @@ export = (socket: Socket, app: Electron.App) => {
});
function getWindowById(id: number): Electron.BrowserWindow {
const runtimeWindow = BrowserWindow.fromId(id);
if (runtimeWindow) {
return runtimeWindow;
}
synchronizeWindowRegistry();
for (let index = 0; index < windows.length; index++) {
const element = windows[index];
if (element.id === id) {
if (tryGetWindowId(element) === id) {
return element;
}
}
throw new Error(`BrowserWindow with id '${id}' was not found.`);
}
function tryGetWindowId(element: Electron.BrowserWindow): number | null {
try {
return element.id;
} catch {
return null;
}
}
function synchronizeWindowRegistry(): void {
const runtimeWindows = BrowserWindow.getAllWindows();
const runtimeWindowIds = new Set(runtimeWindows.map((entry) => entry.id));
for (let index = windows.length - 1; index >= 0; index--) {
const windowId = tryGetWindowId(windows[index]);
if (windowId === null || !runtimeWindowIds.has(windowId)) {
windows.splice(index, 1);
}
}
readyToShowWindowsIds = readyToShowWindowsIds.filter((entryId) =>
runtimeWindowIds.has(entryId),
);
}
function emitBrowserWindowClosed(): void {
const ids: number[] = [];
for (const entry of windows) {
const windowId = tryGetWindowId(entry);
if (windowId !== null) {
ids.push(windowId);
}
}
electronSocket.emit("BrowserWindowClosed", ids);
}
};

View File

@@ -103,9 +103,44 @@ app.on('will-finish-launching', () => {
const manifestJsonFile = require(manifestJsonFilePath);
// Brings the app back to the foreground: focuses an already existing window or - if
// all windows have been closed (which keeps the app alive on macOS) - recreates the
// main window.
function activateApp() {
const windows = BrowserWindow.getAllWindows().filter((window) => !window.isDestroyed());
if (!windows.length) {
return typeof global.recreateMainWindow === 'function' && global.recreateMainWindow();
}
const target = windows.find((window) => window.isVisible()) || windows[0];
if (target.isMinimized()) {
target.restore();
}
if (!target.isVisible()) {
target.show();
}
target.focus();
if (platform() === 'darwin') {
// On macOS focusing a window does not necessarily bring the app itself to the front
app.focus({ steal: true });
}
return true;
}
if (manifestJsonFile.singleInstance) {
const mainInstance = app.requestSingleInstanceLock();
app.on('second-instance', (events, args = []) => {
if (!app.requestSingleInstanceLock()) {
// Another instance already owns the lock. Exit right away so that neither the
// socket bridge nor the .NET backend process of this instance is started.
app.exit(0);
}
app.on('second-instance', (event, args = []) => {
args.forEach((parameter) => {
const words = parameter.split('=');
@@ -116,20 +151,16 @@ if (manifestJsonFile.singleInstance) {
}
});
const windows = BrowserWindow.getAllWindows();
if (windows.length) {
if (windows[0].isMinimized()) {
windows[0].restore();
}
windows[0].focus();
}
activateApp();
});
if (!mainInstance) {
app.quit();
}
}
// On macOS launching an already running app (or clicking its dock icon) does not
// start a second instance - the 'activate' event is raised instead.
app.on('activate', () => {
activateApp();
});
// Collect user supplied command line args (excluding those handled by Electron host itself)
function getForwardedArgs() {
const skipSwitches = new Set(['unpackedelectron', 'unpackeddotnet', 'dotnetpacked']);
@@ -144,6 +175,7 @@ function getForwardedArgs() {
if (cleaned.startsWith('remote-debugging-port')) return false;
// We add /electronPort ourselves later
if (cleaned.startsWith('electronPort=')) return false;
if (cleaned.startsWith('electronHost=')) return false;
if (cleaned.startsWith('electronWebPort=')) return false;
return true;
});
@@ -264,7 +296,6 @@ function startSocketApiBridge(port) {
// otherwise the Windows Firewall will be triggered
console.debug('Electron Socket: starting...');
server = createServer();
const host = !port ? '127.0.0.1' : 'localhost';
let hostHook;
io = new Server({
pingTimeout: 60000, // in ms, default is 5000
@@ -272,16 +303,35 @@ function startSocketApiBridge(port) {
});
io.attach(server);
server.listen(port, host);
// Never bind to the 'localhost' hostname: it may resolve to ::1 and 127.0.0.1 in any
// order, so server and client can end up on different stacks - which costs a failed
// connection attempt (or a DNS lookup) on every startup.
const hostCandidates = ['127.0.0.1', '::1'];
let hostIndex = 0;
server.on('error', (error) => {
const isUnavailable = error.code === 'EADDRNOTAVAIL' || error.code === 'EAFNOSUPPORT' || error.code === 'EINVAL';
if (isUnavailable && hostIndex + 1 < hostCandidates.length) {
console.warn(`Electron Socket: cannot bind to ${hostCandidates[hostIndex]} (${error.code}), falling back to ${hostCandidates[hostIndex + 1]}.`);
hostIndex++;
server.listen(port, hostCandidates[hostIndex]);
return;
}
console.error('Electron Socket: ' + error.message);
});
server.listen(port, hostCandidates[hostIndex]);
server.on('listening', function () {
const addr = server.address();
console.info(`Electron Socket: listening on port ${addr.port} at ${addr.address} using ${authToken}`);
// Now that socket connection is established, we can guarantee port will not be open for portscanner
if (unpackedelectron) {
startAspCoreBackendUnpackaged(addr.port);
startAspCoreBackendUnpackaged(addr.port, addr.address);
} else if (!unpackeddotnet && !dotnetpacked) {
startAspCoreBackend(addr.port);
startAspCoreBackend(addr.port, addr.address);
}
});
@@ -385,7 +435,7 @@ function startSocketApiBridge(port) {
});
}
function startAspCoreBackend(electronPort) {
function startAspCoreBackend(electronPort, electronHost) {
startBackend();
function startBackend() {
@@ -394,6 +444,7 @@ function startAspCoreBackend(electronPort) {
const parameters = [
envParam,
`/electronPort=${electronPort}`,
`/electronHost=${electronHost}`,
`/electronPID=${process.pid}`,
`/electronAuthToken=${authToken}`,
// forward user supplied args (avoid duplicate environment)
@@ -416,7 +467,7 @@ function startAspCoreBackend(electronPort) {
}
}
function startAspCoreBackendUnpackaged(electronPort) {
function startAspCoreBackendUnpackaged(electronPort, electronHost) {
startBackend();
function startBackend() {
@@ -425,6 +476,7 @@ function startAspCoreBackendUnpackaged(electronPort) {
const parameters = [
envParam,
`/electronPort=${electronPort}`,
`/electronHost=${electronHost}`,
`/electronPID=${process.pid}`,
`/electronAuthToken=${authToken}`,
...forwardedArgs.filter(a => !(envParam && a.startsWith('--environment=')))

View File

@@ -11,14 +11,13 @@
"dependencies": {
"dasherize": "^2.0.0",
"electron-host-hook": "file:./ElectronHostHook",
"electron-updater": "^6.6.2",
"electron-updater": "^6.8.9",
"image-size": "^1.2.1",
"portscanner": "^2.2.0",
"socket.io": "^4.8.1"
},
"devDependencies": {
"@types/node": "^22.18",
"electron": "^30.0.3",
"electron": "^39.8.10",
"eslint": "^9.39.1",
"typescript": "^5.9.3"
}
@@ -356,6 +355,15 @@
"@types/node": "*"
}
},
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/yauzl": {
"version": "2.10.3",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
@@ -442,15 +450,6 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/async": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"license": "MIT",
"dependencies": {
"lodash": "^4.17.14"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -477,9 +476,9 @@
"optional": true
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -498,9 +497,9 @@
}
},
"node_modules/builder-util-runtime": {
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz",
"integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==",
"version": "9.7.0",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.7.0.tgz",
"integrity": "sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw==",
"license": "MIT",
"dependencies": {
"debug": "^4.3.4",
@@ -763,15 +762,15 @@
"optional": true
},
"node_modules/electron": {
"version": "30.5.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-30.5.1.tgz",
"integrity": "sha512-AhL7+mZ8Lg14iaNfoYTkXQ2qee8mmsQyllKdqxlpv/zrKgfxz6jNVtcRRbQtLxtF8yzcImWdfTQROpYiPumdbw==",
"version": "39.8.10",
"resolved": "https://registry.npmjs.org/electron/-/electron-39.8.10.tgz",
"integrity": "sha512-zbYtGPYUI7PzqLAzkk21Rk6j67WN0hxn0Mq/njErZo1d0HSf33is4f8ICI5fMLy5vYe0JtCtM5sYunNOaochSQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@electron/get": "^2.0.0",
"@types/node": "^20.9.0",
"@types/node": "^22.7.7",
"extract-zip": "^2.0.1"
},
"bin": {
@@ -786,12 +785,12 @@
"link": true
},
"node_modules/electron-updater": {
"version": "6.8.3",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.3.tgz",
"integrity": "sha512-Z6sgw3jgbikWKXei1ENdqFOxBP0WlXg3TtKfz0rgw2vIZFJUyI4pD7ZN7jrkm7EoMK+tcm/qTnPUdqfZukBlBQ==",
"version": "6.8.9",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.9.tgz",
"integrity": "sha512-ZhVxM9iGONUpZGI1FxdMRgJjUFXi7AYGVa5PwKlO1tV1/4zDxQmfKpXOHVztKrd6L9rLcFjERvi1Mf2vxyTkig==",
"license": "MIT",
"dependencies": {
"builder-util-runtime": "9.5.1",
"builder-util-runtime": "9.7.0",
"fs-extra": "^10.1.0",
"js-yaml": "^4.1.0",
"lazy-val": "^1.0.5",
@@ -848,16 +847,6 @@
"node": ">= 10.0.0"
}
},
"node_modules/electron/node_modules/@types/node": {
"version": "20.19.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz",
"integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/end-of-stream": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
@@ -869,20 +858,21 @@
}
},
"node_modules/engine.io": {
"version": "6.6.5",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz",
"integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==",
"version": "6.6.9",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.9.tgz",
"integrity": "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"@types/ws": "^8.5.12",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.7.2",
"cors": "~2.8.5",
"debug": "~4.4.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.18.3"
"ws": "~8.21.0"
},
"engines": {
"node": ">=10.2.0"
@@ -1487,15 +1477,6 @@
"node": ">=0.10.0"
}
},
"node_modules/is-number-like": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz",
"integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==",
"license": "ISC",
"dependencies": {
"lodash.isfinite": "^3.3.2"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1504,9 +1485,19 @@
"license": "ISC"
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
"integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@@ -1600,12 +1591,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash": {
"version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT"
},
"node_modules/lodash.escaperegexp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
@@ -1619,12 +1604,6 @@
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
"license": "MIT"
},
"node_modules/lodash.isfinite": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz",
"integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==",
"license": "MIT"
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -1865,20 +1844,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/portscanner": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz",
"integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==",
"license": "MIT",
"dependencies": {
"async": "^2.6.0",
"is-number-like": "^1.0.3"
},
"engines": {
"node": ">=0.4",
"npm": ">=1.0.0"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -1992,9 +1957,9 @@
}
},
"node_modules/sax": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz",
"integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==",
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz",
"integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==",
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=11.0.0"
@@ -2077,19 +2042,19 @@
}
},
"node_modules/socket.io-adapter": {
"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==",
"version": "2.5.8",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz",
"integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==",
"license": "MIT",
"dependencies": {
"debug": "~4.4.1",
"ws": "~8.18.3"
"ws": "~8.21.0"
}
},
"node_modules/socket.io-parser": {
"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==",
"version": "4.2.7",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.7.tgz",
"integrity": "sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
@@ -2262,9 +2227,9 @@
"license": "ISC"
},
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"

View File

@@ -19,12 +19,12 @@
"dasherize": "^2.0.0",
"electron-host-hook": "file:./ElectronHostHook",
"image-size": "^1.2.1",
"electron-updater": "^6.6.2",
"electron-updater": "^6.8.9",
"socket.io": "^4.8.1"
},
"devDependencies": {
"@types/node": "^22.18",
"electron": "^30.0.3",
"electron": "^39.8.10",
"eslint": "^9.39.1",
"typescript": "^5.9.3"
}

View File

@@ -3,6 +3,7 @@
<PropertyGroup>
<!-- When this is enabled, the project will be switched from nuget packages to consuming the ElectronNet orchestration directly -->
<ElectronNetDevMode>true</ElectronNetDevMode>
<IsTest>True</IsTest>
</PropertyGroup>
<Import Project="..\ElectronNET\build\ElectronNET.Core.props" Condition="$(ElectronNetDevMode)" />

View File

@@ -0,0 +1,108 @@
using System.Diagnostics;
namespace ElectronNET.IntegrationTests.Tests;
/// <summary>
/// Tests for the Electron clean targets.
/// Covers GitHub issue #1096: cleaning must not require a restore, so the clean targets
/// must not depend on targets that need the assets file (NETSDK1004).
/// </summary>
public class ElectronCleanTargetsTests
{
private static readonly string CorePropsPath = FindBuildFile("src/ElectronNET/build/ElectronNET.Core.props", "ElectronNET/build/ElectronNET.Core.props");
private static readonly string CoreTargetsPath = FindBuildFile("src/ElectronNET/build/ElectronNET.Core.targets", "ElectronNET/build/ElectronNET.Core.targets");
[Fact]
public async Task ElectronCleanTargets_WithoutRestore_ShouldSucceed()
{
var tempDir = CreateTempProjectDirectory();
try
{
await WriteMinimalCsprojAsync(tempDir);
var (exitCode, output) = await RunDotnetMsBuildAsync(tempDir, "Clean");
output.Should().NotContain("NETSDK1004",
$"cleaning must not require the assets file of a previous restore. Full output:\n{output}");
exitCode.Should().Be(0,
$"cleaning an unrestored project must succeed. Full output:\n{output}");
}
finally
{
Directory.Delete(tempDir, recursive: true);
}
}
private static string FindBuildFile(string relativeFromRepoRoot, string relativeFromSrc)
{
var dir = new DirectoryInfo(AppContext.BaseDirectory);
while (dir != null)
{
var fromRepoRoot = Path.Combine(dir.FullName, relativeFromRepoRoot);
if (File.Exists(fromRepoRoot))
{
return Path.GetFullPath(fromRepoRoot);
}
var fromSrc = Path.Combine(dir.FullName, relativeFromSrc);
if (File.Exists(fromSrc))
{
return Path.GetFullPath(fromSrc);
}
dir = dir.Parent;
}
throw new FileNotFoundException(
$"Could not locate '{relativeFromRepoRoot}' by walking up from '{AppContext.BaseDirectory}'.");
}
private static string CreateTempProjectDirectory()
{
var tempDir = Path.Combine(Path.GetTempPath(), $"electron-net-clean-test-{Guid.NewGuid():N}");
Directory.CreateDirectory(tempDir);
Directory.CreateDirectory(Path.Combine(tempDir, "Properties"));
return tempDir;
}
private static Task WriteMinimalCsprojAsync(string tempDir)
{
var propsPathEscaped = CorePropsPath.Replace("'", "&apos;");
var targetsPathEscaped = CoreTargetsPath.Replace("'", "&apos;");
return File.WriteAllTextAsync(
Path.Combine(tempDir, "TestApp.csproj"),
$$"""
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<Import Project="{{propsPathEscaped}}" />
<Import Project="{{targetsPathEscaped}}" />
</Project>
""");
}
private static async Task<(int ExitCode, string Output)> RunDotnetMsBuildAsync(string workingDirectory, string target)
{
// Deliberately without /restore - that is what issue #1096 is about.
var psi = new ProcessStartInfo("dotnet", $"msbuild TestApp.csproj --nologo -v:minimal /t:{target}")
{
WorkingDirectory = workingDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
};
using var process = Process.Start(psi)!;
var stdOut = await process.StandardOutput.ReadToEndAsync();
var stdErr = await process.StandardError.ReadToEndAsync();
await process.WaitForExitAsync();
return (process.ExitCode, stdOut + stdErr);
}
}

View File

@@ -0,0 +1,133 @@
using System.Diagnostics;
namespace ElectronNET.IntegrationTests.Tests;
/// <summary>
/// Tests for ElectronNET.Core.targets icon copy behavior.
/// Covers GitHub issue #1047: modern macOS .icon app-icon packages are folders
/// and must be copied recursively, not treated as a single file.
/// </summary>
public class ElectronIconTargetsTests
{
private static readonly string CorePropsPath = FindBuildFile("src/ElectronNET/build/ElectronNET.Core.props", "ElectronNET/build/ElectronNET.Core.props");
private static readonly string CoreTargetsPath = FindBuildFile("src/ElectronNET/build/ElectronNET.Core.targets", "ElectronNET/build/ElectronNET.Core.targets");
[Fact]
public async Task ElectronCoreTargets_ElectronIconDirectory_ShouldBeMappedIntoElectronOutput()
{
var tempDir = CreateTempProjectDirectory();
try
{
var iconPackageDir = Path.Combine(tempDir, "Assets", "MyApp.icon");
Directory.CreateDirectory(Path.Combine(iconPackageDir, "layers"));
await File.WriteAllTextAsync(Path.Combine(iconPackageDir, "manifest.json"), "{}");
await File.WriteAllTextAsync(Path.Combine(iconPackageDir, "layers", "foreground.png"), "not-a-real-png");
await WriteMinimalCsprojAsync(tempDir);
var (exitCode, output) = await RunDotnetMsBuildAsync(tempDir, "DumpElectronIconCopyItems");
var normalizedOutput = NormalizePathSeparators(output);
exitCode.Should().Be(0,
$"MSBuild target evaluation must succeed. Full output:\n{output}");
normalizedOutput.Should().Contain(
".electron/MyApp.icon/manifest.json",
$"the icon package root file must be mapped into .electron/MyApp.icon. Full output:\n{output}");
normalizedOutput.Should().Contain(
".electron/MyApp.icon/layers/foreground.png",
$"nested files in .icon package must preserve structure in .electron output. Full output:\n{output}");
}
finally
{
Directory.Delete(tempDir, recursive: true);
}
}
private static string FindBuildFile(string relativeFromRepoRoot, string relativeFromSrc)
{
var dir = new DirectoryInfo(AppContext.BaseDirectory);
while (dir != null)
{
var fromRepoRoot = Path.Combine(dir.FullName, relativeFromRepoRoot);
if (File.Exists(fromRepoRoot))
{
return Path.GetFullPath(fromRepoRoot);
}
var fromSrc = Path.Combine(dir.FullName, relativeFromSrc);
if (File.Exists(fromSrc))
{
return Path.GetFullPath(fromSrc);
}
dir = dir.Parent;
}
throw new FileNotFoundException(
$"Could not locate '{relativeFromRepoRoot}' by walking up from '{AppContext.BaseDirectory}'.");
}
private static string CreateTempProjectDirectory()
{
var tempDir = Path.Combine(Path.GetTempPath(), $"electron-net-icon-test-{Guid.NewGuid():N}");
Directory.CreateDirectory(tempDir);
Directory.CreateDirectory(Path.Combine(tempDir, "Properties"));
return tempDir;
}
private static Task WriteMinimalCsprojAsync(string tempDir)
{
var propsPathEscaped = CorePropsPath.Replace("'", "&apos;");
var targetsPathEscaped = CoreTargetsPath.Replace("'", "&apos;");
return File.WriteAllTextAsync(
Path.Combine(tempDir, "TestApp.csproj"),
$$"""
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<Import Project="{{propsPathEscaped}}" />
<PropertyGroup Label="ElectronNetCommon">
<ElectronIcon>Assets/MyApp.icon</ElectronIcon>
</PropertyGroup>
<Import Project="{{targetsPathEscaped}}" />
<Target Name="DumpElectronIconCopyItems"
DependsOnTargets="ElectronResolvePaths;ElectronGetCopyToOutputDirectoryItems">
<Message Importance="High"
Text="ELECTRON_COPY_ITEMS: @(_ElectronFilesToCopyWithTargetPath->'%(TargetPath)')" />
</Target>
</Project>
""");
}
private static async Task<(int ExitCode, string Output)> RunDotnetMsBuildAsync(string workingDirectory, string target)
{
var psi = new ProcessStartInfo("dotnet", $"msbuild TestApp.csproj --nologo -v:minimal /restore /t:{target}")
{
WorkingDirectory = workingDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
};
using var process = Process.Start(psi)!;
var stdOut = await process.StandardOutput.ReadToEndAsync();
var stdErr = await process.StandardError.ReadToEndAsync();
await process.WaitForExitAsync();
return (process.ExitCode, stdOut + stdErr);
}
private static string NormalizePathSeparators(string value)
{
return value.Replace('\\', '/');
}
}

View File

@@ -0,0 +1,55 @@
namespace ElectronNET.IntegrationTests.Tests;
/// <summary>
/// Regression checks for BrowserWindow lifecycle cleanup in WindowManager.
/// Covers GitHub issue #1008.
/// </summary>
public class WindowManagerLifecycleTests
{
private static readonly string WindowManagerFilePath = FindWindowManagerFile();
[Fact]
public void WindowManager_ShouldUsePersistentBrowserWindowClosedSubscription()
{
File.Exists(WindowManagerFilePath).Should().BeTrue(
$"WindowManager source must exist at '{WindowManagerFilePath}'.");
var content = File.ReadAllText(WindowManagerFilePath);
content.Should().Contain(
"Socket.On<int[]>(\"BrowserWindowClosed\"",
"closed-window cleanup must be wired for every close event, not just the first one.");
content.Should().NotContain(
"Socket.Once<int[]>(\"BrowserWindowClosed\"",
"a one-shot subscription causes stale BrowserWindow references after subsequent closes (issue #1008).");
}
private static string FindWindowManagerFile()
{
const string RelativeFromRepoRoot = "src/ElectronNET.API/API/WindowManager.cs";
const string RelativeFromSrc = "ElectronNET.API/API/WindowManager.cs";
var dir = new DirectoryInfo(AppContext.BaseDirectory);
while (dir != null)
{
var fromRepoRoot = Path.Combine(dir.FullName, RelativeFromRepoRoot);
if (File.Exists(fromRepoRoot))
{
return Path.GetFullPath(fromRepoRoot);
}
var fromSrc = Path.Combine(dir.FullName, RelativeFromSrc);
if (File.Exists(fromSrc))
{
return Path.GetFullPath(fromSrc);
}
dir = dir.Parent;
}
throw new FileNotFoundException(
"Could not locate WindowManager.cs by walking up from " +
$"'{AppContext.BaseDirectory}'.");
}
}

View File

@@ -8,7 +8,7 @@
<ResourcePreloader />
<link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" />
<link rel="stylesheet" href="@Assets["app.css"]" />
<link rel="stylesheet" href="@Assets["electronnet-samples-blazorsignalr.styles.css"]" />
<link rel="stylesheet" href="@Assets["electronnet-samples-authmiddleware.styles.css"]" />
<ImportMap />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />

View File

@@ -1,6 +1,6 @@
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">ElectronNET.Samples.BlazorSignalR</a>
<a class="navbar-brand" href="">ElectronNET.Samples.AuthMiddleware</a>
</div>
</div>

View File

@@ -14,7 +14,7 @@
<TypeScriptUseNodeJS>true</TypeScriptUseNodeJS>
<TypeScriptTSConfig>ElectronHostHook/tsconfig.json</TypeScriptTSConfig>
<TypeScriptCompileOnSaveEnabled>true</TypeScriptCompileOnSaveEnabled>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptCompileBlocked>false</TypeScriptCompileBlocked>
</PropertyGroup>
<ItemGroup>
@@ -27,8 +27,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.5.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core.AspNet" Version="0.5.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core" Version="0.6.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core.AspNet" Version="0.6.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="5.9.3" />
</ItemGroup>

View File

@@ -10,7 +10,7 @@
"license": "MIT",
"dependencies": {
"archiver-utils": "^2.1.0",
"exceljs": "^1.10.0",
"exceljs": "^4.4.0",
"socket.io": "^4.8.1"
},
"devDependencies": {
@@ -162,30 +162,85 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@fast-csv/format": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz",
"integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==",
"license": "MIT",
"dependencies": {
"@types/node": "^14.0.1",
"lodash.escaperegexp": "^4.1.2",
"lodash.isboolean": "^3.0.3",
"lodash.isequal": "^4.5.0",
"lodash.isfunction": "^3.0.9",
"lodash.isnil": "^4.0.0"
}
},
"node_modules/@fast-csv/format/node_modules/@types/node": {
"version": "14.18.63",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz",
"integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==",
"license": "MIT"
},
"node_modules/@fast-csv/parse": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz",
"integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==",
"license": "MIT",
"dependencies": {
"@types/node": "^14.0.1",
"lodash.escaperegexp": "^4.1.2",
"lodash.groupby": "^4.6.0",
"lodash.isfunction": "^3.0.9",
"lodash.isnil": "^4.0.0",
"lodash.isundefined": "^3.0.1",
"lodash.uniq": "^4.5.0"
}
},
"node_modules/@fast-csv/parse/node_modules/@types/node": {
"version": "14.18.63",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz",
"integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==",
"license": "MIT"
},
"node_modules/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
"integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
"integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@humanfs/types": "^0.15.0"
},
"engines": {
"node": ">=18.18.0"
}
},
"node_modules/@humanfs/node": {
"version": "0.16.7",
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
"integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
"integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@humanfs/core": "^0.19.1",
"@humanfs/core": "^0.19.2",
"@humanfs/types": "^0.15.0",
"@humanwhocodes/retry": "^0.4.0"
},
"engines": {
"node": ">=18.18.0"
}
},
"node_modules/@humanfs/types": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
"integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=18.18.0"
}
},
"node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
@@ -252,6 +307,15 @@
"undici-types": "~7.18.0"
}
},
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -322,21 +386,21 @@
}
},
"node_modules/archiver": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-3.1.1.tgz",
"integrity": "sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==",
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz",
"integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==",
"license": "MIT",
"dependencies": {
"archiver-utils": "^2.1.0",
"async": "^2.6.3",
"async": "^3.2.4",
"buffer-crc32": "^0.2.1",
"glob": "^7.1.4",
"readable-stream": "^3.4.0",
"tar-stream": "^2.1.0",
"zip-stream": "^2.1.2"
"readable-stream": "^3.6.0",
"readdir-glob": "^1.1.2",
"tar-stream": "^2.2.0",
"zip-stream": "^4.1.0"
},
"engines": {
"node": ">= 6"
"node": ">= 10"
}
},
"node_modules/archiver-utils": {
@@ -381,35 +445,11 @@
"dev": true,
"license": "Python-2.0"
},
"node_modules/arguments-extended": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/arguments-extended/-/arguments-extended-0.0.3.tgz",
"integrity": "sha512-MNYdPKgCiywbgHAmNsYr1tSNLtfbSdwE1akZV+33hU9A8RG0lO5HAK9oMnw7y7bjYUhc04dJpcIBMUaPPYYtXg==",
"license": "MIT",
"dependencies": {
"extended": "~0.0.3",
"is-extended": "~0.0.8"
}
},
"node_modules/array-extended": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/array-extended/-/array-extended-0.0.11.tgz",
"integrity": "sha512-Fe4Ti2YgM1onQgrcCD8dUhFuZgHQxzqylSl1C5IDJVVVqY5D07h8RghIXL9sZ6COZ0e+oTL5IusTv5eXABJ9Kw==",
"license": "MIT",
"dependencies": {
"arguments-extended": "~0.0.3",
"extended": "~0.0.3",
"is-extended": "~0.0.3"
}
},
"node_modules/async": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"license": "MIT",
"dependencies": {
"lodash": "^4.17.14"
}
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
"license": "MIT"
},
"node_modules/balanced-match": {
"version": "1.0.2",
@@ -500,9 +540,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
"integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -619,15 +659,29 @@
"license": "MIT"
},
"node_modules/compress-commons": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-2.1.1.tgz",
"integrity": "sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz",
"integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==",
"license": "MIT",
"dependencies": {
"buffer-crc32": "^0.2.13",
"crc32-stream": "^3.0.1",
"crc32-stream": "^4.0.2",
"normalize-path": "^3.0.0",
"readable-stream": "^2.3.6"
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">= 10"
}
},
"node_modules/compress-commons/node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
@@ -671,26 +725,29 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/crc": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
"integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
"license": "MIT",
"dependencies": {
"buffer": "^5.1.0"
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"license": "Apache-2.0",
"bin": {
"crc32": "bin/crc32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/crc32-stream": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-3.0.1.tgz",
"integrity": "sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz",
"integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==",
"license": "MIT",
"dependencies": {
"crc": "^3.4.4",
"crc-32": "^1.2.0",
"readable-stream": "^3.4.0"
},
"engines": {
"node": ">= 6.9.0"
"node": ">= 10"
}
},
"node_modules/crc32-stream/node_modules/readable-stream": {
@@ -722,16 +779,11 @@
"node": ">= 8"
}
},
"node_modules/date-extended": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/date-extended/-/date-extended-0.0.6.tgz",
"integrity": "sha512-v9a2QLTVn1GQGXf02TQaSvNfeXA/V1FL2Tr0OQYqjI5+L9T5jEtCpLYG01sxFk+m1OtwMxydkKa8NKcflANAoQ==",
"license": "MIT",
"dependencies": {
"array-extended": "~0.0.3",
"extended": "~0.0.3",
"is-extended": "~0.0.3"
}
"node_modules/dayjs": {
"version": "1.11.21",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz",
"integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==",
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
@@ -750,12 +802,6 @@
}
}
},
"node_modules/declare.js": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/declare.js/-/declare.js-0.0.8.tgz",
"integrity": "sha512-O659hy1gcHef7JnwtqdQlrj2c5DAEgtxm8pgFXofW7eUE1L4FjsSLlziovWcrOJAOFlEPaOJshY+0hBWCG/AnA==",
"license": "MIT"
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -782,20 +828,21 @@
}
},
"node_modules/engine.io": {
"version": "6.6.5",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz",
"integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==",
"version": "6.6.8",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.8.tgz",
"integrity": "sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"@types/ws": "^8.5.12",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.7.2",
"cors": "~2.8.5",
"debug": "~4.4.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.18.3"
"ws": "~8.20.1"
},
"engines": {
"node": ">=10.2.0"
@@ -810,12 +857,6 @@
"node": ">=10.0.0"
}
},
"node_modules/es6-promise": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
"integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==",
"license": "MIT"
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -984,56 +1025,50 @@
}
},
"node_modules/exceljs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/exceljs/-/exceljs-1.15.0.tgz",
"integrity": "sha512-72CySYLU1oBIixpBkWV0mR6YM+X8v2GyyWgKBovS9Hso0Ul7S3FtlWGeAifxB+lpzznokWMRDLMZ8EyS2tX6xg==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz",
"integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==",
"license": "MIT",
"dependencies": {
"archiver": "^3.0.0",
"fast-csv": "^2.4.1",
"jszip": "^3.1.5",
"moment": "^2.22.2",
"promish": "^5.1.1",
"sax": "^1.2.4",
"tmp": "^0.1.0",
"unzipper": "^0.9.12"
"archiver": "^5.0.0",
"dayjs": "^1.8.34",
"fast-csv": "^4.3.1",
"jszip": "^3.10.1",
"readable-stream": "^3.6.0",
"saxes": "^5.0.1",
"tmp": "^0.2.0",
"unzipper": "^0.10.11",
"uuid": "^8.3.0"
},
"engines": {
"node": ">=6.0.0"
"node": ">=8.3.0"
}
},
"node_modules/extended": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/extended/-/extended-0.0.6.tgz",
"integrity": "sha512-rvAV3BDGsV1SYGzUOu7aO0k82quhfl0QAyZudYhAcTeIr1rPbBnyOhOlkCLwLpDfP7HyKAWAPNSjRb9p7lE3rg==",
"node_modules/exceljs/node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"extender": "~0.0.5"
}
},
"node_modules/extender": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/extender/-/extender-0.0.10.tgz",
"integrity": "sha512-iPLUHZJaNW6RuOShQX33ZpewEUIlijFBcsXnKWyiYERKWPsFxfKgx8J0xRz29hKQWPFFPACgBW6cHM7Ke1pfaA==",
"license": "MIT",
"dependencies": {
"declare.js": "~0.0.4"
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fast-csv": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-2.5.0.tgz",
"integrity": "sha512-M/9ezLU9/uDwvDZTt9sNFJa0iLDUsbhYJwPtnE0D9MjeuB6DY9wRCyUPZta9iI6cSz5wBWGaUPL61QH8h92cNA==",
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz",
"integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==",
"license": "MIT",
"dependencies": {
"extended": "0.0.6",
"is-extended": "0.0.10",
"object-extended": "0.0.7",
"safer-buffer": "^2.1.2",
"string-extended": "0.0.8"
"@fast-csv/format": "4.3.5",
"@fast-csv/parse": "4.3.6"
},
"engines": {
"node": ">=4.0.0"
"node": ">=10.0.0"
}
},
"node_modules/fast-deep-equal": {
@@ -1102,9 +1137,9 @@
}
},
"node_modules/flatted": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz",
"integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==",
"dev": true,
"license": "ISC"
},
@@ -1279,15 +1314,6 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/is-extended": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/is-extended/-/is-extended-0.0.10.tgz",
"integrity": "sha512-qp+HR+L9QXbgFurvqiVgD+JiGyUboRgICNzCXmbiLtZBFVSNFbxRsI4q7Be9mCWTO5PoO1IxoWp5sl+j5b83FA==",
"license": "MIT",
"dependencies": {
"extended": "~0.0.3"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -1325,10 +1351,20 @@
"license": "ISC"
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
"integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@@ -1437,12 +1473,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash": {
"version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT"
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
@@ -1455,18 +1485,61 @@
"integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==",
"license": "MIT"
},
"node_modules/lodash.escaperegexp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
"integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==",
"license": "MIT"
},
"node_modules/lodash.flatten": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
"integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
"license": "MIT"
},
"node_modules/lodash.groupby": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
"integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
"license": "MIT"
},
"node_modules/lodash.isfunction": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
"integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==",
"license": "MIT"
},
"node_modules/lodash.isnil": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz",
"integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isundefined": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz",
"integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==",
"license": "MIT"
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -1480,6 +1553,12 @@
"integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==",
"license": "MIT"
},
"node_modules/lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
"integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
"license": "MIT"
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -1534,15 +1613,6 @@
"mkdirp": "bin/cmd.js"
}
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -1583,17 +1653,6 @@
"node": ">=0.10.0"
}
},
"node_modules/object-extended": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/object-extended/-/object-extended-0.0.7.tgz",
"integrity": "sha512-2LJYIacEXoZ1glGkAZuvA/4pfJM4Y1ShReAo9jWpBSuz89TiUCdiPqhGJJ6m97F3WjhCSRwrbgaxYEAm9dRYBw==",
"license": "MIT",
"dependencies": {
"array-extended": "~0.0.4",
"extended": "~0.0.3",
"is-extended": "~0.0.3"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -1717,18 +1776,6 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/promish": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/promish/-/promish-5.1.1.tgz",
"integrity": "sha512-37xEzvSas6JIYI/BcKh5TwhaqWepI44u/hC+tQStkX1sxMf+L756beESPgSWirxRCPqtXHzosoNzpjLnTnP8FA==",
"license": "MIT",
"dependencies": {
"es6-promise": "^3.0.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -1754,6 +1801,36 @@
"util-deprecate": "~1.0.1"
}
},
"node_modules/readdir-glob": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
"integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
"license": "Apache-2.0",
"dependencies": {
"minimatch": "^5.1.0"
}
},
"node_modules/readdir-glob/node_modules/brace-expansion": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
"integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/readdir-glob/node_modules/minimatch": {
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -1783,19 +1860,16 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/sax": {
"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",
"node_modules/saxes": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
"integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
"license": "ISC",
"dependencies": {
"xmlchars": "^2.2.0"
},
"engines": {
"node": ">=11.0.0"
"node": ">=10"
}
},
"node_modules/setimmediate": {
@@ -1846,13 +1920,13 @@
}
},
"node_modules/socket.io-adapter": {
"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==",
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.7.tgz",
"integrity": "sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==",
"license": "MIT",
"dependencies": {
"debug": "~4.4.1",
"ws": "~8.18.3"
"ws": "~8.20.1"
}
},
"node_modules/socket.io-parser": {
@@ -1877,18 +1951,6 @@
"safe-buffer": "~5.1.0"
}
},
"node_modules/string-extended": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/string-extended/-/string-extended-0.0.8.tgz",
"integrity": "sha512-CK46p3AxBvBhJbBi6WrF9bCcaWH20E4NwlLSzpooG2nXWvcP2gy2YR8VN6fSwZyrbcvL4S4zoNKbR0QG52X4rw==",
"license": "MIT",
"dependencies": {
"array-extended": "~0.0.5",
"date-extended": "~0.0.3",
"extended": "~0.0.3",
"is-extended": "~0.0.3"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -1946,15 +2008,12 @@
}
},
"node_modules/tmp": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz",
"integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==",
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz",
"integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
"license": "MIT",
"dependencies": {
"rimraf": "^2.6.3"
},
"engines": {
"node": ">=6"
"node": ">=14.14"
}
},
"node_modules/traverse": {
@@ -2000,9 +2059,9 @@
"license": "MIT"
},
"node_modules/unzipper": {
"version": "0.9.15",
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.9.15.tgz",
"integrity": "sha512-2aaUvO4RAeHDvOCuEtth7jrHFaCKTSXPqUkXwADaLBzGbgZGzUDccoEdJ5lW+3RmfpOZYNx0Rw6F6PUzM6caIA==",
"version": "0.10.14",
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz",
"integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==",
"license": "MIT",
"dependencies": {
"big-integer": "^1.6.17",
@@ -2011,6 +2070,7 @@
"buffer-indexof-polyfill": "~1.0.0",
"duplexer2": "~0.1.4",
"fstream": "^1.0.12",
"graceful-fs": "^4.2.2",
"listenercount": "~1.0.1",
"readable-stream": "~2.3.6",
"setimmediate": "~1.0.4"
@@ -2032,6 +2092,16 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).",
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -2074,9 +2144,9 @@
"license": "ISC"
},
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"version": "8.20.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@@ -2094,6 +2164,12 @@
}
}
},
"node_modules/xmlchars": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"license": "MIT"
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -2108,17 +2184,38 @@
}
},
"node_modules/zip-stream": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.3.tgz",
"integrity": "sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz",
"integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==",
"license": "MIT",
"dependencies": {
"archiver-utils": "^2.1.0",
"compress-commons": "^2.1.1",
"readable-stream": "^3.4.0"
"archiver-utils": "^3.0.4",
"compress-commons": "^4.1.2",
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">= 6"
"node": ">= 10"
}
},
"node_modules/zip-stream/node_modules/archiver-utils": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz",
"integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==",
"license": "MIT",
"dependencies": {
"glob": "^7.2.3",
"graceful-fs": "^4.2.0",
"lazystream": "^1.0.0",
"lodash.defaults": "^4.2.0",
"lodash.difference": "^4.5.0",
"lodash.flatten": "^4.4.0",
"lodash.isplainobject": "^4.0.6",
"lodash.union": "^4.6.0",
"normalize-path": "^3.0.0",
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">= 10"
}
},
"node_modules/zip-stream/node_modules/readable-stream": {

View File

@@ -19,6 +19,6 @@
"dependencies": {
"archiver-utils": "^2.1.0",
"socket.io": "^4.8.1",
"exceljs": "^1.10.0"
"exceljs": "^4.4.0"
}
}

View File

@@ -34,7 +34,6 @@
<ElectronSplashScreen>wwwroot\assets\img\about@2x.png</ElectronSplashScreen>
<License>MIT</License>
<ElectronSingleInstance>false</ElectronSingleInstance>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ElectronBuilderVersion>26.0</ElectronBuilderVersion>
</PropertyGroup>
<PropertyGroup>
@@ -76,8 +75,8 @@
<ProjectReference Include="..\ElectronNET.AspNet\ElectronNET.AspNet.csproj" Condition="$(ElectronNetDevMode)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.5.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core.AspNet" Version="0.5.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core" Version="0.6.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core.AspNet" Version="0.6.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="5.9.3" />
</ItemGroup>

View File

@@ -3,7 +3,7 @@
<Import Project="..\common.props" />
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>
<TargetFrameworks>$(ElectronNetTargetFrameworks)</TargetFrameworks>
<PackageOutputPath>..\..\artifacts</PackageOutputPath>
<PackageId>$(PackageNamePrefix)</PackageId>
<Title>$(PackageId)</Title>

View File

@@ -4,14 +4,21 @@
<PropertyGroup Label="ElectronNetCommon">
<ElectronVersion>30.4.0</ElectronVersion>
<ElectronBuilderVersion>26.0</ElectronBuilderVersion>
<RuntimeIdentifier Condition="'$(RuntimeIdentifier)' == ''">win-x64</RuntimeIdentifier>
<!-- ElectronRuntimeIdentifier may be set explicitly here; it is otherwise resolved from
RuntimeIdentifier (or the host) in ElectronResolveRuntimeIdentifier, which runs late
enough to also see RIDs coming from the project file or a publish profile. -->
<ElectronSingleInstance>true</ElectronSingleInstance>
<ElectronSplashScreen></ElectronSplashScreen>
<ElectronIcon></ElectronIcon>
<PackageIcon></PackageIcon>
<ElectronPackageId>$(MSBuildProjectName.Replace(".", "-").ToLower())</ElectronPackageId>
<ElectronPackageId Condition="'$(ElectronPackageId)' == ''">$(MSBuildProjectName.Replace(".", "-").ToLower())</ElectronPackageId>
<ElectronBuilderJson>electron-builder.json</ElectronBuilderJson>
<Title>$(MSBuildProjectName)</Title>
<Title Condition="'$(Title)' == ''">$(MSBuildProjectName)</Title>
<!-- Location of the Electron binary relative to the .NET application directory of a packaged app.
The default matches the standard layout, where the .NET app is placed in 'resources/bin'. -->
<ElectronRootDir Condition="'$(ElectronRootDir)' == ''">../..</ElectronRootDir>
<!-- Set to true to suppress the npm/npx invocations of the Electron build and publish targets. -->
<ElectronSkipExecCommands Condition="'$(ElectronSkipExecCommands)' == ''">false</ElectronSkipExecCommands>
</PropertyGroup>
<PropertyGroup>

View File

@@ -1,10 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(ElectronExecutable)' == ''">
<PropertyGroup Condition="'$(ElectronExecutableName)' == ''">
<WinPrefix>win</WinPrefix>
<ElectronExecutable Condition="'$(RuntimeIdentifier.StartsWith($(WinPrefix)))' == 'true'">$(Title)</ElectronExecutable>
<ElectronExecutable Condition="'$(RuntimeIdentifier.StartsWith($(WinPrefix)))' != 'true'">$(ElectronPackageId)</ElectronExecutable>
<ElectronExecutableName Condition="'$(RuntimeIdentifier.StartsWith($(WinPrefix)))' == 'true'">$(Title)</ElectronExecutableName>
<ElectronExecutableName Condition="'$(RuntimeIdentifier.StartsWith($(WinPrefix)))' != 'true'">$(ElectronPackageId)</ElectronExecutableName>
</PropertyGroup>
<PropertyGroup>
<!-- The binary Electron.NET launches. It only differs from the packaged executable in advanced
scenarios, e.g. when a build hook adds a launcher stub to the package. -->
<ElectronExecutable Condition="'$(ElectronExecutable)' == ''">$(ElectronExecutableName)</ElectronExecutable>
</PropertyGroup>
<PropertyGroup>
@@ -19,6 +25,7 @@
<ItemGroup>
<AssemblyMetadata Include="ElectronExecutable" Value="$(ElectronExecutable)" />
<AssemblyMetadata Include="ElectronVersion" Value="$(ElectronVersion)" />
<AssemblyMetadata Include="ElectronRootDir" Value="$(ElectronRootDir)" />
<AssemblyMetadata Include="RuntimeIdentifier" Value="$(RuntimeIdentifier)" />
<AssemblyMetadata Include="ElectronSingleInstance" Value="$(ElectronSingleInstance)" />
<AssemblyMetadata Include="Title" Value="$(Title)" />

View File

@@ -52,7 +52,7 @@
<!-- Targets -->
<Target Name="ElectronBeforeClean" AfterTargets="BeforeClean" DependsOnTargets="ElectronResolvePaths">
<Target Name="ElectronBeforeClean" AfterTargets="BeforeClean" DependsOnTargets="ElectronSetPaths">
<ItemGroup>
<Clean Include="$(ElectronOutDir)**" />
</ItemGroup>
@@ -60,7 +60,7 @@
<!--<Message Text="ElectronBeforeClean - Clean Files: @(Clean)" Importance="High" />-->
</Target>
<Target Name="ElectronClean" AfterTargets="CoreClean" DependsOnTargets="ElectronResolvePaths">
<Target Name="ElectronClean" AfterTargets="CoreClean" DependsOnTargets="ElectronSetPaths">
<RemoveDir Directories="$(ElectronOutDir)" />
@@ -95,8 +95,24 @@
</Target>
<!-- Resolved at execution time, so that a RuntimeIdentifier coming from the project file,
a publish profile or the CLI wins over the host RID. -->
<Target Name="ElectronResolveRuntimeIdentifier">
<PropertyGroup>
<ElectronRuntimeIdentifier Condition="'$(ElectronRuntimeIdentifier)' == '' AND '$(RuntimeIdentifier)' != ''">$(RuntimeIdentifier)</ElectronRuntimeIdentifier>
<!-- When using the dotnet CLI (Core MSBuild), infer the current RID as a default -->
<ElectronRuntimeIdentifier Condition="'$(ElectronRuntimeIdentifier)' == '' AND '$(MSBuildRuntimeType)' == 'Core'">$([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier)</ElectronRuntimeIdentifier>
<!-- Otherwise, Full MSBuild runs only on Windows, so infer a Windows RID from OSArchitecture -->
<ElectronRuntimeIdentifier Condition="'$(ElectronRuntimeIdentifier)' == '' AND '$(MSBuildRuntimeType)' == 'Full'">win-$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLower())</ElectronRuntimeIdentifier>
</PropertyGroup>
<Message Text="ElectronRuntimeIdentifier: $(ElectronRuntimeIdentifier)" Importance="High" />
</Target>
<!-- This is also run at design time, each time when a property of the project is changed -->
<Target Name="ElectronCreatePackageJson" DependsOnTargets="ResolveProjectReferences;ElectronSetPaths">
<Target Name="ElectronCreatePackageJson" DependsOnTargets="ResolveProjectReferences;ElectronSetPaths;ElectronResolveRuntimeIdentifier">
<Message Text="Creating package.json from template..." Importance="High" />
<Message Text="OutDir: $(OutDir)" Importance="High" />
@@ -121,7 +137,7 @@
<!-- Electron Builder uses title for the installation dir on Linux, but it should not have spaces -->
<LinuxPrefix>linux</LinuxPrefix>
<ElectronTitle>$(Title)</ElectronTitle>
<ElectronTitle Condition="'$(RuntimeIdentifier.StartsWith($(LinuxPrefix)))' == 'true'">$(Title.Replace(' ', '-'))</ElectronTitle>
<ElectronTitle Condition="'$(ElectronRuntimeIdentifier.StartsWith($(LinuxPrefix)))' == 'true'">$(Title.Replace(' ', '-'))</ElectronTitle>
</PropertyGroup>
<ItemGroup>
@@ -154,7 +170,9 @@
<PropertyGroup Condition="'$(UsingMicrosoftNETSdkWeb)' != 'true'">
<_NonIntermediatePublishDir>$(PublishDir)</_NonIntermediatePublishDir>
<PublishUrl>$(PublishDir)</PublishUrl>
<PublishDir>$(IntermediateOutputPath)PubTmp\</PublishDir>
<!-- ElectronIntermediatePublishDir allows overriding the intermediate publish directory -->
<PublishDir Condition="'$(ElectronIntermediatePublishDir)' != ''">$(ElectronIntermediatePublishDir)</PublishDir>
<PublishDir Condition="'$(ElectronIntermediatePublishDir)' == ''">$(IntermediateOutputPath)PubTmp\</PublishDir>
</PropertyGroup>
<RemoveDir Directories="$(PublishDir);$(PublishUrl)" Condition="'$(UsingMicrosoftNETSdkWeb)' != 'true'" />
@@ -177,9 +195,12 @@
</PropertyGroup>
<ItemGroup>
<!-- tsconfig.json is a build-time config, not a runtime file. Excluding it also stops
Microsoft.TypeScript.MSBuild from discovering and compiling the host's tsconfig
(types:["node"]) in the consumer project when hook TypeScript compilation is enabled. -->
<ElectronSourceFiles
Include="$(ElectronSourceFilesPath)\**\*.js;$(ElectronSourceFilesPath)\**\*.json;$(ElectronSourceFilesPath)\**\*.html"
Exclude="$(ElectronSourceFilesPath)\**\build-helper.js" />
Exclude="$(ElectronSourceFilesPath)\**\build-helper.js;$(ElectronSourceFilesPath)\**\tsconfig.json" />
</ItemGroup>
<ItemGroup>
@@ -213,6 +234,35 @@
</ElectronCustomHookPackageJson>
</ItemGroup>
<!-- Committed-JS mode (TypeScriptCompileBlocked=true): the hook TypeScript is not compiled
during the build, so the committed ElectronHostHook JavaScript (and source maps) are
packaged as-is. Reclassify them from None into .electron\ElectronHostHook content
(mirroring ElectronSourceFiles) so they reach the build output and, at publish, are swept
into app\ -> app.asar. When compilation is enabled (TypeScriptCompileBlocked!=true) this
is skipped: Microsoft.TypeScript.MSBuild compiles the hook and ElectronAdjustHostHookOutput
routes the output, so reclassifying would duplicate .electron\ElectronHostHook items.
Without one of these, require('electron-host-hook') fails ('Cannot find module .../index.js'). -->
<ItemGroup Condition="'$(ElectronHasCustomHookCode)' == 'true' AND '$(TypeScriptCompileBlocked)' == 'true'">
<None Remove="ElectronHostHook\**\*.js;ElectronHostHook\**\*.js.map" />
<ElectronCustomHookJsFiles Include="ElectronHostHook\**\*.js;ElectronHostHook\**\*.js.map"
Exclude="ElectronHostHook\node_modules\**" />
<ElectronCustomHookJsFiles Update="@(ElectronCustomHookJsFiles)">
<Link>$(ElectronDirName)\ElectronHostHook\%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</ElectronCustomHookJsFiles>
</ItemGroup>
<AssignTargetPath Files="@(ElectronCustomHookJsFiles)" RootFolder="$(MSBuildProjectDirectory)"
Condition="'$(ElectronHasCustomHookCode)' == 'true' AND '$(TypeScriptCompileBlocked)' == 'true'">
<Output TaskParameter="AssignedFiles" ItemName="ElectronCustomHookJsFilesWithTargetPath" />
</AssignTargetPath>
<ItemGroup Condition="'$(ElectronHasCustomHookCode)' == 'true' AND '$(TypeScriptCompileBlocked)' == 'true'">
<FilesForPackagingFromProject Include="@(ElectronCustomHookJsFilesWithTargetPath->'%(Identity)')" />
<ContentWithTargetPath Include="@(ElectronCustomHookJsFilesWithTargetPath->'%(Identity)')" />
<Content Include="@(ElectronCustomHookJsFiles->'%(Identity)')" />
</ItemGroup>
<ItemGroup>
<ElectronIntermediatePackageJson Include="$(ElectronIntermediatePackageJson)" />
</ItemGroup>
@@ -231,13 +281,45 @@
</Target>
<!-- When hook TypeScript compilation is enabled (TypeScriptCompileBlocked!=true), restore the
hook's npm dependencies into ElectronHostHook\node_modules before tsc runs so its imports
(e.g. socket.io) resolve. Incremental: only re-runs when the hook package.json changes or
node_modules is missing. Skipped in committed-JS mode and at design time. -->
<Target Name="ElectronRestoreHostHookDependencies"
BeforeTargets="CompileTypeScriptWithTSConfig;CompileTypeScript"
Condition="'@(ElectronCustomHookTsFiles->Count())' &gt; 0 AND Exists('$(MSBuildProjectDirectory)\ElectronHostHook\package.json') AND '$(TypeScriptCompileBlocked)' != 'true' AND '$(DesignTimeBuild)' != 'true'"
Inputs="$(MSBuildProjectDirectory)\ElectronHostHook\package.json"
Outputs="$(MSBuildProjectDirectory)\ElectronHostHook\node_modules\.package-lock.json">
<PropertyGroup>
<IsLinuxWsl>false</IsLinuxWsl>
<IsLinuxWsl Condition="'$(ElectronPlatform)' == 'linux' AND $([MSBuild]::IsOSPlatform('Windows'))">true</IsLinuxWsl>
<_NpmCmd>npm install</_NpmCmd>
<_NpmCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpmCmd)'</_NpmCmd>
</PropertyGroup>
<Message Importance="High" Text="Restoring ElectronHostHook npm dependencies for TypeScript compilation..." />
<Exec Command="$(_NpmCmd)"
WorkingDirectory="$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', 'ElectronHostHook'))"
Timeout="600000" StandardOutputImportance="Low" StandardErrorImportance="High" ContinueOnError="false" />
</Target>
<!-- Run before GetTypeScriptOutputForPublishing to adjust the target directory -->
<Target Name="ElectronAdjustHostHookOutput" BeforeTargets="GetTypeScriptOutputForPublishing" DependsOnTargets="CompileTypeScriptWithTSConfig">
<ItemGroup>
<!-- Route the compiled hook JS to .electron\ElectronHostHook. Do NOT reuse
%(DestinationRelativePath): with no outDir in the hook tsconfig, VsTsc leaves it as
an absolute path, which would produce .electron\<absolute-path>. Derive the target
from the file name instead (hook files are flat). Link is set because
GetTypeScriptOutputForPublishing re-runs AssignTargetPath, which honors Link for the
publish TargetPath. -->
<GeneratedJavascript Update="@(GeneratedJavascript)">
<DestinationRelativePath>$(ElectronDirName)\%(DestinationRelativePath)</DestinationRelativePath>
<TargetPath>$(ElectronDirName)\%(DestinationRelativePath)</TargetPath>
<DestinationRelativePath>$(ElectronDirName)\ElectronHostHook\%(Filename)%(Extension)</DestinationRelativePath>
<TargetPath>$(ElectronDirName)\ElectronHostHook\%(Filename)%(Extension)</TargetPath>
<Link>$(ElectronDirName)\ElectronHostHook\%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</GeneratedJavascript>
</ItemGroup>
@@ -249,7 +331,10 @@
<ItemGroup>
<!--<_ElectronFiles Include="$(ElectronIntermediatePackageJson)" />-->
<_ElectronFiles Include="$(ElectronSplashScreen)" Condition="'$(ElectronSplashScreen)'!=''" />
<_ElectronFiles Include="$(ElectronIcon)" Condition="'$(ElectronIcon)'!=''" />
<_ElectronFiles Include="$(ElectronIcon)"
Condition="'$(ElectronIcon)'!='' AND ( !Exists('$(ElectronIcon)') OR !$([System.IO.Directory]::Exists('$(ElectronIcon)') ) )" />
<_ElectronIconDirectoryFiles Include="$(ElectronIcon)\**\*"
Condition="'$(ElectronIcon)'!='' AND Exists('$(ElectronIcon)') AND $([System.IO.Directory]::Exists('$(ElectronIcon)') )" />
</ItemGroup>
<ItemGroup>
@@ -265,11 +350,16 @@
</ItemGroup>
<Message Importance="High" Text="_ElectronFilesToCopy: @(_ElectronFilesToCopy)" />
<Message Importance="High" Text="_ElectronIconDirectoryFiles: @(_ElectronIconDirectoryFiles)" />
<ItemGroup>
<_ElectronFilesToCopyWithTargetPath Include="@(_ElectronFilesToCopy)">
<TargetPath>$(ElectronDirName)\%(FileName)%(Extension)</TargetPath>
</_ElectronFilesToCopyWithTargetPath>
<_ElectronFilesToCopyWithTargetPath Include="@(_ElectronIconDirectoryFiles)">
<TargetPath>$(ElectronDirName)\$(ElectronIconFileName)\%(RecursiveDir)%(FileName)%(Extension)</TargetPath>
</_ElectronFilesToCopyWithTargetPath>
</ItemGroup>
<Message Text="_ElectronFilesToCopyWithTargetPath: @(_ElectronFilesToCopyWithTargetPath)" />
@@ -298,21 +388,21 @@
<RemoveDir Directories="$(ElectronHookTargetModuleDir)" Condition="Exists($(ElectronHookTargetModuleDir))" />
</Target>
<Target Name="ElectronCheckVersionMismatch">
<Target Name="ElectronCheckVersionMismatch" DependsOnTargets="ElectronResolveRuntimeIdentifier">
<PropertyGroup>
<ElectronArch Condition="'$(RuntimeIdentifier)' == 'win-x64'">x64</ElectronArch>
<ElectronArch Condition="'$(RuntimeIdentifier)' == 'win-x86'">ia32</ElectronArch>
<ElectronArch Condition="'$(RuntimeIdentifier)' == 'win-arm64'">arm64</ElectronArch>
<ElectronArch Condition="'$(RuntimeIdentifier)' == 'linux-x64'">x64</ElectronArch>
<ElectronArch Condition="'$(RuntimeIdentifier)' == 'linux-arm'">armv7l</ElectronArch>
<ElectronArch Condition="'$(RuntimeIdentifier)' == 'linux-arm64'">arm64</ElectronArch>
<ElectronArch Condition="'$(RuntimeIdentifier)' == 'osx-x64'">x64</ElectronArch>
<ElectronArch Condition="'$(RuntimeIdentifier)' == 'osx-arm64'">arm64</ElectronArch>
<ElectronArch Condition="'$(ElectronRuntimeIdentifier)' == 'win-x64'">x64</ElectronArch>
<ElectronArch Condition="'$(ElectronRuntimeIdentifier)' == 'win-x86'">ia32</ElectronArch>
<ElectronArch Condition="'$(ElectronRuntimeIdentifier)' == 'win-arm64'">arm64</ElectronArch>
<ElectronArch Condition="'$(ElectronRuntimeIdentifier)' == 'linux-x64'">x64</ElectronArch>
<ElectronArch Condition="'$(ElectronRuntimeIdentifier)' == 'linux-arm'">armv7l</ElectronArch>
<ElectronArch Condition="'$(ElectronRuntimeIdentifier)' == 'linux-arm64'">arm64</ElectronArch>
<ElectronArch Condition="'$(ElectronRuntimeIdentifier)' == 'osx-x64'">x64</ElectronArch>
<ElectronArch Condition="'$(ElectronRuntimeIdentifier)' == 'osx-arm64'">arm64</ElectronArch>
<ElectronPlatform Condition="'$(RuntimeIdentifier)' == 'win-x64' OR '$(RuntimeIdentifier)' == 'win-x86' OR '$(RuntimeIdentifier)' == 'win-arm64'">win</ElectronPlatform>
<ElectronPlatform Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm' OR '$(RuntimeIdentifier)' == 'linux-arm64'">linux</ElectronPlatform>
<ElectronPlatform Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64'">mac</ElectronPlatform>
<ElectronPlatform Condition="'$(ElectronRuntimeIdentifier)' == 'win-x64' OR '$(ElectronRuntimeIdentifier)' == 'win-x86' OR '$(ElectronRuntimeIdentifier)' == 'win-arm64'">win</ElectronPlatform>
<ElectronPlatform Condition="'$(ElectronRuntimeIdentifier)' == 'linux-x64' OR '$(ElectronRuntimeIdentifier)' == 'linux-arm' OR '$(ElectronRuntimeIdentifier)' == 'linux-arm64'">linux</ElectronPlatform>
<ElectronPlatform Condition="'$(ElectronRuntimeIdentifier)' == 'osx-x64' OR '$(ElectronRuntimeIdentifier)' == 'osx-arm64'">mac</ElectronPlatform>
<!-- npm uses different OS names than Electron -->
<NpmOs Condition="'$(ElectronPlatform)' == 'win'">win32</NpmOs>
@@ -321,7 +411,7 @@
<!-- npm CPU is same as ElectronArch except for linux-arm -->
<NpmCpu>$(ElectronArch)</NpmCpu>
<NpmCpu Condition="'$(RuntimeIdentifier)' == 'linux-arm'">arm</NpmCpu>
<NpmCpu Condition="'$(ElectronRuntimeIdentifier)' == 'linux-arm'">arm</NpmCpu>
<_CurrentOSPlatform Condition="$([MSBuild]::IsOSPlatform('Windows'))">win</_CurrentOSPlatform>
<_CurrentOSPlatform Condition="$([MSBuild]::IsOSPlatform('Linux'))">linux</_CurrentOSPlatform>
@@ -364,7 +454,6 @@
<PropertyGroup>
<ElectronOutputPath>$([System.IO.Path]::GetFullPath('$(ElectronOutDir)'))</ElectronOutputPath>
<_NpmCmd>npm install --no-bin-links</_NpmCmd>
<_NpmCmd Condition="$(ElectronMajor) &gt;= 42">npx install-electron</_NpmCmd>
<!-- Add cross-platform parameters when there's a platform mismatch (for remote debugging preparation) -->
<_NpmCmd Condition="'$(_IsPlatformMismatch)' == 'true'">$(_NpmCmd) --os=$(NpmOs) --cpu=$(NpmCpu) --arch=$(NpmCpu) --platform=$(NpmOs)</_NpmCmd>
<_NpmCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpmCmd)'</_NpmCmd>
@@ -372,28 +461,28 @@
<!--<Message Importance="High" Text="ElectronConfigureApp: CopiedFiles - @(_CopiedFiles)" />-->
<Message Importance="High" Text="Running command: $(_NpmCmd) in folder: $(ElectronOutputPath)" Condition="@(_CopiedFiles->Count()) > 0" />
<Message Importance="High" Text="Running command: $(_NpmCmd) in folder: $(ElectronOutputPath)" Condition="'$(ElectronSkipExecCommands)' != 'true' AND @(_CopiedFiles->Count()) > 0" />
<Exec Command="$(_NpmCmd)" WorkingDirectory="$(ElectronOutputPath)" Timeout="600000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="@(_CopiedFiles->Count()) > 0">
<Exec Command="$(_NpmCmd)" WorkingDirectory="$(ElectronOutputPath)" Timeout="600000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="'$(ElectronSkipExecCommands)' != 'true' AND @(_CopiedFiles->Count()) > 0">
<Output TaskParameter="ExitCode" PropertyName="ExecExitCode"/>
</Exec>
<Message Importance="High" Text="Electron setup failed!" Condition="'$(ExecExitCode)' != '0'" />
<Message Importance="High" Text="Electron setup failed!" Condition="'$(ExecExitCode)' != '' AND '$(ExecExitCode)' != '0'" />
<PropertyGroup>
<_NpmCmd>npx install-electron</_NpmCmd>
<_NpmCmd>node node_modules/electron/install.js</_NpmCmd>
<!-- Add cross-platform parameters when there's a platform mismatch (for remote debugging preparation) -->
<_NpmCmd Condition="'$(_IsPlatformMismatch)' == 'true'">$(_NpmCmd) --os=$(NpmOs) --cpu=$(NpmCpu) --arch=$(NpmCpu) --platform=$(NpmOs)</_NpmCmd>
<_NpmCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpmCmd)'</_NpmCmd>
</PropertyGroup>
<Message Importance="High" Text="Running command: $(_NpmCmd) in folder: $(ElectronOutputPath)" Condition="$(ElectronMajor) &gt;= 42 AND @(_CopiedFiles->Count()) > 0" />
<Message Importance="High" Text="Running command: $(_NpmCmd) in folder: $(ElectronOutputPath)" Condition="'$(ElectronSkipExecCommands)' != 'true' AND $(ElectronMajor) &gt;= 42 AND @(_CopiedFiles->Count()) > 0" />
<Exec Command="$(_NpmCmd)" WorkingDirectory="$(ElectronOutputPath)" Timeout="600000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="$(ElectronMajor) &gt;= 42 AND @(_CopiedFiles->Count()) > 0">
<Exec Command="$(_NpmCmd)" WorkingDirectory="$(ElectronOutputPath)" Timeout="600000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="'$(ElectronSkipExecCommands)' != 'true' AND $(ElectronMajor) &gt;= 42 AND @(_CopiedFiles->Count()) > 0">
<Output TaskParameter="ExitCode" PropertyName="ExecExitCode"/>
</Exec>
<Message Importance="High" Text="Electron installation failed!" Condition="'$(ExecExitCode)' != '0'" />
<Message Importance="High" Text="Electron installation failed!" Condition="'$(ExecExitCode)' != '' AND '$(ExecExitCode)' != '0'" />
<!-- Fix up incorrect symlinks created by npm on Windows when targeting macOS -->
<PropertyGroup>
@@ -450,12 +539,16 @@
<PublishDir>$(_OriginalPublishDir)</PublishDir>
<PublishDir Condition="'$(_NonIntermediatePublishDir)' != ''">$(_NonIntermediatePublishDir)</PublishDir>
<ElectronPublishDir>$(_OriginalPublishDir)</ElectronPublishDir>
<!-- The Electron host files (main.js, package.json, runtime node_modules, ...) are packed
into app.asar. They live in a dedicated 'app' subfolder so the .NET app in 'bin' is NOT
swept into the asar by electron-builder's default 'files' glob. See directories.app below. -->
<ElectronAppDir>$(ElectronPublishDir)app\</ElectronAppDir>
</PropertyGroup>
<Error Condition="'$(_IsPlatformMismatch)' == 'true'"
Code="ELECTRON100"
Text="The target RuntimeIdentifier '$(RuntimeIdentifier)' (platform: $(ElectronPlatform)) does not match the current operating system ($(_CurrentOSPlatform)).
Text="The target RuntimeIdentifier '$(ElectronRuntimeIdentifier)' (platform: $(ElectronPlatform)) does not match the current operating system ($(_CurrentOSPlatform)).
Electron applications must be built on the target operating system:
- Windows targets (win-x64, win-x86, win-arm64) must be built on Windows
@@ -490,7 +583,7 @@ For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migr
<ItemGroup>
<ElectronPublishFilesToMove Update="@(ElectronPublishFilesToMove)" >
<MoveTargetPath>$(ElectronPublishDir)%(RecursiveDir)%(FileName)%(Extension)</MoveTargetPath>
<MoveTargetPath>$(ElectronAppDir)%(RecursiveDir)%(FileName)%(Extension)</MoveTargetPath>
</ElectronPublishFilesToMove>
</ItemGroup>
@@ -504,20 +597,62 @@ For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migr
<ElectronPublishUrlFullPath>$([System.IO.Path]::GetFullPath('$(PublishUrl.TrimEnd(&quot;\&quot;))'))</ElectronPublishUrlFullPath>
</PropertyGroup>
<PropertyGroup>
<ElectronAppDirFullPath>$([System.IO.Path]::GetFullPath('$(ElectronAppDir)'))</ElectronAppDirFullPath>
</PropertyGroup>
<PropertyGroup>
<IsLinuxWsl>false</IsLinuxWsl>
<IsLinuxWsl Condition="'$(ElectronPlatform)' == 'linux' AND $([MSBuild]::IsOSPlatform('Windows'))">true</IsLinuxWsl>
<_NpmCmd>npm install electron-builder@$(ElectronBuilderVersion) --save-dev </_NpmCmd>
<_NpmCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpmCmd)'</_NpmCmd>
</PropertyGroup>
<Message Importance="High" Text="ElectronPublishApp: ElectronPublishDirFullPath - $(ElectronPublishDirFullPath)" />
<Message Importance="High" Text="ElectronPublishApp: ElectronAppDirFullPath - $(ElectronAppDirFullPath)" />
<Exec Command="$(_NpmCmd)" WorkingDirectory="$(ElectronPublishDirFullPath)" Timeout="600000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="@(CopiedFiles->Count()) > 0">
<!-- Install the app's runtime (prod) dependencies into app\node_modules so they end up
inside app.asar. devDependencies (electron, eslint, typescript) are not needed here:
TypeScript is already compiled at build time and electron-builder fetches Electron itself. -->
<PropertyGroup>
<_NpmAppDepsCmd>npm install --omit=dev</_NpmAppDepsCmd>
<_NpmAppDepsCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpmAppDepsCmd)'</_NpmAppDepsCmd>
</PropertyGroup>
<Exec Command="$(_NpmAppDepsCmd)" WorkingDirectory="$(ElectronAppDirFullPath)" Timeout="600000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="'$(ElectronSkipExecCommands)' != 'true' AND @(CopiedFiles->Count()) > 0">
<Output TaskParameter="ExitCode" PropertyName="ExecExitCode"/>
</Exec>
<Message Importance="High" Text="Electron setup failed!" Condition="'$(ExecExitCode)' != '0'" />
<Message Importance="High" Text="Electron app dependency install failed!" Condition="'$(ExecExitCode)' != '' AND '$(ExecExitCode)' != '0'" />
<!-- Install electron-builder (the dev tool) into the publish root, which is the
electron-builder projectDir (cwd). app metadata + runtime deps are read from
app\ via directories.app (standard electron-builder two-package.json layout).
Render the dev package.json first: the two-package.json layout requires a
package.json at the projectDir, and electron-builder requires the 'build'
configuration to live in this development package.json (it is rejected in the
application package.json under app\). The .NET app's metadata/version come from
app\package.json instead. -->
<ItemGroup>
<DevTemplateProperty Include="ElectronPackageId" Value="$(ElectronPackageId)" />
<DevTemplateProperty Include="ElectronExecutableName" Value="$(ElectronExecutableName)" />
<DevTemplateProperty Include="Title" Value="$(Title)" />
<DevTemplateProperty Include="Version" Value="$(Version)" />
</ItemGroup>
<ReplaceTemplateTask TemplateFile="$(MSBuildThisFileDirectory)package.dev.template.json"
OutputFile="$([System.IO.Path]::Combine('$(ElectronPublishDirFullPath)', 'package.json'))"
TemplateProperties="@(DevTemplateProperty)"
Condition="@(CopiedFiles->Count()) > 0" />
<PropertyGroup>
<_NpmCmd>npm install electron-builder@$(ElectronBuilderVersion)</_NpmCmd>
<_NpmCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpmCmd)'</_NpmCmd>
</PropertyGroup>
<Exec Command="$(_NpmCmd)" WorkingDirectory="$(ElectronPublishDirFullPath)" Timeout="600000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="'$(ElectronSkipExecCommands)' != 'true' AND @(CopiedFiles->Count()) > 0">
<Output TaskParameter="ExitCode" PropertyName="ExecExitCode"/>
</Exec>
<Message Importance="High" Text="Electron setup failed!" Condition="'$(ExecExitCode)' != '' AND '$(ExecExitCode)' != '0'" />
<!-- Transform ElectronPublishUrlFullPath to a wslpath if IsLinuxWsl is true -->
<Exec Command="wsl wslpath '$(ElectronPublishUrlFullPath)'" ConsoleToMsBuild="true" Condition="'$(IsLinuxWsl)' == 'true'">
@@ -530,18 +665,22 @@ For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migr
<ElectronPaParams Condition="'$(Version)' != ''">$(ElectronPaParams) -c.buildVersion &quot;$(Version)&quot;</ElectronPaParams>
<ElectronPaParams Condition="'$(Copyright)' != ''">$(ElectronPaParams) -c.copyright &quot;$(Copyright)&quot;</ElectronPaParams>
<ElectronPaParams>$(ElectronPaParams) -c.extraResources &quot;bin/**/*&quot;</ElectronPaParams>
<!-- Build app.asar from the 'app' subfolder only (host JS + runtime node_modules),
keeping the .NET app under 'bin' out of the asar. cwd stays the publish root so
extraResources and user icon paths under bin/ still resolve. -->
<ElectronPaParams>$(ElectronPaParams) -c.directories.app &quot;app&quot;</ElectronPaParams>
</PropertyGroup>
<PropertyGroup>
<_NpxCmd>npx electron-builder --config=./$(ElectronBuilderJson) --$(ElectronPlatform) --$(ElectronArch) -c.electronVersion=$(ElectronVersion) -c.directories.output &quot;$(ElectronPublishUrlFullPath)&quot; $(ElectronPaParams)</_NpxCmd>
<_NpxCmd>npx electron-builder -c.$(ElectronPlatform).defaultArch=$(ElectronArch) --config=./$(ElectronBuilderJson) -c.electronVersion=$(ElectronVersion) --$(ElectronPlatform) --$(ElectronArch) -c.directories.output &quot;$(ElectronPublishUrlFullPath)&quot; $(ElectronPaParams)</_NpxCmd>
<_NpxCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpxCmd)'</_NpxCmd>
</PropertyGroup>
<Exec Command="$(_NpxCmd)" WorkingDirectory="$(ElectronPublishDirFullPath)" Timeout="1800000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="@(CopiedFiles->Count()) > 0">
<Exec Command="$(_NpxCmd)" WorkingDirectory="$(ElectronPublishDirFullPath)" Timeout="1800000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="'$(ElectronSkipExecCommands)' != 'true' AND @(CopiedFiles->Count()) > 0">
<Output TaskParameter="ExitCode" PropertyName="ExecExitCode"/>
</Exec>
<Message Importance="High" Text="Electron setup failed!" Condition="'$(ExecExitCode)' != '0'" />
<Message Importance="High" Text="Electron setup failed!" Condition="'$(ExecExitCode)' != '' AND '$(ExecExitCode)' != '0'" />
</Target>

View File

@@ -437,6 +437,8 @@
<EnumValue Name="40.10.0" DisplayName="40.10.0" />
<EnumValue Name="40.10.1" DisplayName="40.10.1" />
<EnumValue Name="40.10.2" DisplayName="40.10.2" />
<EnumValue Name="40.10.3" DisplayName="40.10.3" />
<EnumValue Name="40.10.4" DisplayName="40.10.4" />
<EnumValue Name="41.0.0" DisplayName="41.0.0" />
<EnumValue Name="41.0.1" DisplayName="41.0.1" />
<EnumValue Name="41.0.2" DisplayName="41.0.2" />
@@ -456,6 +458,8 @@
<EnumValue Name="41.6.1" DisplayName="41.6.1" />
<EnumValue Name="41.7.0" DisplayName="41.7.0" />
<EnumValue Name="41.7.1" DisplayName="41.7.1" />
<EnumValue Name="41.7.2" DisplayName="41.7.2" />
<EnumValue Name="41.8.0" DisplayName="41.8.0" />
<EnumValue Name="42.0.0" DisplayName="42.0.0" />
<EnumValue Name="42.0.1" DisplayName="42.0.1" />
<EnumValue Name="42.1.0" DisplayName="42.1.0" />
@@ -464,6 +468,8 @@
<EnumValue Name="42.3.1" DisplayName="42.3.1" />
<EnumValue Name="42.3.2" DisplayName="42.3.2" />
<EnumValue Name="42.3.3" DisplayName="42.3.3" />
<EnumValue Name="42.4.0" DisplayName="42.4.0" />
<EnumValue Name="42.4.1" DisplayName="42.4.1" />
</EnumProperty>
<EnumProperty Name="ElectronBuilderVersion"
@@ -547,6 +553,30 @@
Category="General">
</StringProperty>
<StringProperty Name="ElectronExecutableName"
DisplayName="Executable Name"
Description="Name of the executable inside the package, without extension. Defaults to the title on Windows and to the package id on Linux and macOS"
Category="General">
</StringProperty>
<StringProperty Name="ElectronRootDir"
DisplayName="Electron Root Directory"
Description="Location of the Electron binary relative to the .NET application directory of a packaged app. Default: ../.. (the .NET app lives in resources/bin)"
Category="General">
</StringProperty>
<BoolProperty Name="ElectronSkipExecCommands"
DisplayName="Skip npm/npx Commands"
Description="If enabled, the npm and npx invocations of the Electron build and publish targets are skipped"
Category="General">
</BoolProperty>
<StringProperty Name="ElectronIntermediatePublishDir"
DisplayName="Intermediate Publish Directory"
Description="Overrides the intermediate publish directory used while packaging. Default: $(IntermediateOutputPath)PubTmp\"
Category="General">
</StringProperty>
<StringProperty Name="ElectronSplashScreen"
DisplayName="Splash Screen Image"
Description="Choose a PNG image to be shown as splash screen on startup"
@@ -566,7 +596,7 @@
<StringProperty Name="ElectronIcon"
DisplayName="App Icon"
Description="Choose a ICO file to be used as application icon"
Description="Choose an icon path for the app (e.g. .ico, .icns, or modern macOS .icon folder)"
Subtype="File"
Category="General">
<StringProperty.DataSource>
@@ -575,7 +605,7 @@
<StringProperty.ValueEditors>
<ValueEditor EditorType="FilePath">
<ValueEditor.Metadata>
<NameValuePair Name="FileTypeFilter" Value="Icon files (*.ico)|*.ico|All files (*.*)|*.*" />
<NameValuePair Name="FileTypeFilter" Value="Icon files (*.ico,*.icns)|*.ico;*.icns|All files (*.*)|*.*" />
</ValueEditor.Metadata>
</ValueEditor>
</StringProperty.ValueEditors>

View File

@@ -0,0 +1,25 @@
{
"name": "electron-builder-host",
"version": "$(Version)",
"private": true,
"build": {
"appId": "$(ElectronPackageId)",
"win": {
"executableName": "$(ElectronExecutableName)"
},
"mac": {
"executableName": "$(ElectronExecutableName)"
},
"linux": {
"desktop": {
"entry": { "Name": "$(Title)" }
},
"executableName": "$(ElectronExecutableName)"
},
"deb": {
"desktop": {
"entry": { "Name": "$(Title)" }
}
}
}
}

View File

@@ -1,20 +1,6 @@
{
"name": "$(ElectronPackageId)",
"productName": "$(ElectronTitle)",
"build": {
"appId": "$(ElectronPackageId)",
"linux": {
"desktop": {
"entry": { "Name": "$(Title)" }
},
"executableName": "$(ElectronPackageId)"
},
"deb": {
"desktop": {
"entry": { "Name": "$(Title)" }
}
}
},
"description": "$(Description)",
"version": "$(Version)",
"main": "main.js",

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>0.5.1</Version>
<Version>0.6.0</Version>
<PackageNamePrefix>ElectronNET.Core</PackageNamePrefix>
<Authors>Gregor Biswanger, Florian Rappl, softworkz</Authors>
<Product>Electron.NET</Product>
@@ -18,6 +18,7 @@
<FileVersion>$(Version)</FileVersion>
<Version>$(Version)$(VersionPostFix)</Version>
<InformationalVersion>$(Version)</InformationalVersion>
<ElectronNetTargetFrameworks Condition="'$(ElectronNetTargetFrameworks)' == ''">net6.0;net8.0;net10.0</ElectronNetTargetFrameworks>
</PropertyGroup>
</Project>