mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-09-13 05:34:34 +00:00
Compare commits
15
Commits
8eb1a47b5a
...
ce2b28651d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce2b28651d | ||
|
|
518ac0b4b4 | ||
|
|
c5e2ba024c | ||
|
|
c765b5c9b6 | ||
|
|
84d67c0946 | ||
|
|
04f99688eb | ||
|
|
0991ed467e | ||
|
|
4d8d3f0d46 | ||
|
|
db5ccb018f | ||
|
|
4d4d716e5f | ||
|
|
94926b0ca7 | ||
|
|
98a6199a69 | ||
|
|
416fecfaed | ||
|
|
319dfe6944 | ||
|
|
3d0399b3a8 |
@@ -16,6 +16,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
|
||||
## Fixed
|
||||
|
||||
- shunting yard show json
|
||||
- `system/sendmail` called from a Command or the Scheduler computed its value twice, which stripped the quotes from literal text and then failed on characters like `!`. Also shunting yard treated a `?` inside a quoted string as a ternary, so text like `"too hot?"` returned nothing
|
||||
- memory leak when using different timezones for ems-esp and thermostat[#3184](https://github.com/emsesp/EMS-ESP32/issues/3184)
|
||||
- LED stayed off on a healthy system when "Disable LED" was unchecked
|
||||
- Ethernet MAC address changed with the new SDK, breaking DHCP reservations (currently disabled)
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
"@alova/adapter-xhr": "2.3.3",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@mui/icons-material": "^9.3.1",
|
||||
"@mui/material": "^9.3.1",
|
||||
"@mui/icons-material": "^9.4.0",
|
||||
"@mui/material": "^9.4.0",
|
||||
"@table-library/react-table-library": "4.1.15",
|
||||
"alova": "^3.5.5",
|
||||
"jwt-decode": "^4.0.0",
|
||||
@@ -35,14 +35,14 @@
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-icons": "^5.7.0",
|
||||
"react-router": "^8.3.0",
|
||||
"react-router": "^8.3.1",
|
||||
"typesafe-i18n": "^5.27.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@preact/preset-vite": "^2.10.6",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"@types/node": "^26.2.0",
|
||||
"@types/node": "^26.4.0",
|
||||
"@types/react": "^19.2.18",
|
||||
"@types/react-dom": "^19.2.5",
|
||||
"concurrently": "^10.0.5",
|
||||
@@ -52,7 +52,7 @@
|
||||
"mime-types": "^3.0.2",
|
||||
"prettier": "^3.9.6",
|
||||
"rollup-plugin-visualizer": "^7.1.1",
|
||||
"terser": "^5.50.0",
|
||||
"terser": "^5.51.2",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.68.0",
|
||||
"vite": "^8.2.2",
|
||||
|
||||
Generated
+171
-171
@@ -18,11 +18,11 @@ importers:
|
||||
specifier: ^11.14.1
|
||||
version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2)
|
||||
'@mui/icons-material':
|
||||
specifier: ^9.3.1
|
||||
version: 9.3.1(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)
|
||||
specifier: ^9.4.0
|
||||
version: 9.4.0(@mui/material@9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)
|
||||
'@mui/material':
|
||||
specifier: ^9.3.1
|
||||
version: 9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
specifier: ^9.4.0
|
||||
version: 9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
'@table-library/react-table-library':
|
||||
specifier: 4.1.15
|
||||
version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
@@ -45,8 +45,8 @@ importers:
|
||||
specifier: ^5.7.0
|
||||
version: 5.7.0(react@19.2.8)
|
||||
react-router:
|
||||
specifier: ^8.3.0
|
||||
version: 8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
specifier: ^8.3.1
|
||||
version: 8.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
typesafe-i18n:
|
||||
specifier: ^5.27.1
|
||||
version: 5.27.1(typescript@6.0.3)
|
||||
@@ -56,13 +56,13 @@ importers:
|
||||
version: 10.0.1(eslint@10.9.1(supports-color@10.2.2))
|
||||
'@preact/preset-vite':
|
||||
specifier: ^2.10.6
|
||||
version: 2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.2.0)(terser@5.50.0))
|
||||
version: 2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2))
|
||||
'@trivago/prettier-plugin-sort-imports':
|
||||
specifier: ^6.0.2
|
||||
version: 6.0.2(prettier@3.9.6)(supports-color@10.2.2)
|
||||
'@types/node':
|
||||
specifier: ^26.2.0
|
||||
version: 26.2.0
|
||||
specifier: ^26.4.0
|
||||
version: 26.4.0
|
||||
'@types/react':
|
||||
specifier: ^19.2.18
|
||||
version: 19.2.18
|
||||
@@ -89,10 +89,10 @@ importers:
|
||||
version: 3.9.6
|
||||
rollup-plugin-visualizer:
|
||||
specifier: ^7.1.1
|
||||
version: 7.1.1(rolldown@1.2.5)
|
||||
version: 7.1.1(rolldown@1.2.6)
|
||||
terser:
|
||||
specifier: ^5.50.0
|
||||
version: 5.50.0
|
||||
specifier: ^5.51.2
|
||||
version: 5.51.2
|
||||
typescript:
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3
|
||||
@@ -101,10 +101,10 @@ importers:
|
||||
version: 8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)
|
||||
vite:
|
||||
specifier: ^8.2.2
|
||||
version: 8.2.2(@types/node@26.2.0)(terser@5.50.0)
|
||||
version: 8.2.2(@types/node@26.4.0)(terser@5.51.2)
|
||||
vite-plugin-imagemin:
|
||||
specifier: ^0.6.1
|
||||
version: 0.6.1(supports-color@10.2.2)(vite@8.2.2(@types/node@26.2.0)(terser@5.50.0))
|
||||
version: 0.6.1(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2))
|
||||
|
||||
packages:
|
||||
|
||||
@@ -345,33 +345,33 @@ packages:
|
||||
'@jridgewell/source-map@0.3.11':
|
||||
resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5':
|
||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||
'@jridgewell/sourcemap-codec@1.6.0':
|
||||
resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||
|
||||
'@mui/core-downloads-tracker@9.3.1':
|
||||
resolution: {integrity: sha512-IAyAFNQbT7hysJ9HXphiOmWJF7G1OglzHanqCgvQgH9LA2ydxtmaTBDbcBqw6euZesyShiwvpvbnYO1GY1AyXQ==}
|
||||
'@mui/core-downloads-tracker@9.4.0':
|
||||
resolution: {integrity: sha512-d+gIYM1raJP87yrVQcVg+Q3vycVMArMkgu/TjJLi2vTvO9FHKWNRR1xs9nnN4eLpM9nGxxm02UMvc9BrmcUKvQ==}
|
||||
|
||||
'@mui/icons-material@9.3.1':
|
||||
resolution: {integrity: sha512-rZj5ccG7vkpV38o/l4ys+chfE9GFypmvZr9dSNBoYVCNBD9yC6KfKq1TYpEMshWbjic7GKQ8MA1LQlcpGgcq9Q==}
|
||||
'@mui/icons-material@9.4.0':
|
||||
resolution: {integrity: sha512-5PVgBYtLOXTk6u0YUAjoV9GoTUQDbeZ8g+pus2h0GphLT/rpmftRnB5D/Kw6QCAovB7EyBX7UxKdZqPBBAHUKw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@mui/material': ^9.3.1
|
||||
'@mui/material': ^9.4.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/material@9.3.1':
|
||||
resolution: {integrity: sha512-NahAEGIXqS1K0bA4th1jeFxBguS59NOcLbMA0vU+fSaPWKjtwGBGGHeTwlc9PSmzMjOZKceeFWESB8fVHr31hA==}
|
||||
'@mui/material@9.4.0':
|
||||
resolution: {integrity: sha512-6KKUIvkQ2r/s48s9VZV9JEZ1W2dRa7RndVsF+Ipx4CYxDOQeozeRsS5r9NiheFf8A5hpbqJJIGoX7hjg5X4XUw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.5.0
|
||||
'@emotion/styled': ^11.3.0
|
||||
'@mui/material-pigment-css': ^9.3.0
|
||||
'@mui/material-pigment-css': ^9.4.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
@@ -385,8 +385,8 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/private-theming@9.3.0':
|
||||
resolution: {integrity: sha512-ERvqk5pejf9aRnQcDILSWGtFmsEMiVxlQ4+xsVCjsEvmK0fV9BiVP/cQwAF5dwyDFbve4lTrlcgeFEecVzTNiA==}
|
||||
'@mui/private-theming@9.4.0':
|
||||
resolution: {integrity: sha512-qQpX/2XPGDz5F2OIWzo4kkorURlDeXGKytRQudXCdLS5TuwKsMKaZyx77LZEVSB73c7o3UrLWwQ/goRuHBdtjw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
@@ -395,8 +395,8 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/styled-engine@9.3.0':
|
||||
resolution: {integrity: sha512-x9+KYxhjoHYZ4nioxdKnvQWdw0RScbhoZfQ4tv3Db742683U3wlYSp6zV6Us78dMFnKnyTrPTkQKyutp14gnKA==}
|
||||
'@mui/styled-engine@9.4.0':
|
||||
resolution: {integrity: sha512-SlqVEYqnyEgXMFW4JuIDMelyhKzoWBJ85v2mNCQd0XtU0uk7U9E1zaJZ06XqodhA8oJrb+4Q+3E/JlwBe4jWkw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.4.1
|
||||
@@ -408,8 +408,8 @@ packages:
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
|
||||
'@mui/system@9.3.0':
|
||||
resolution: {integrity: sha512-0l4LqHJxZj65xSrioniGsxm7VNoGXonPo203oZjhBUvIDPeBqRTb7Mqc45Qxs6sO6WGR7WE/9cJ6lb4lkvHkjg==}
|
||||
'@mui/system@9.4.0':
|
||||
resolution: {integrity: sha512-AZz9z13oGS1J0BYeAFHTbV7PegCtPiE/uMEIi7TJ1kTx3Vkt+jUpLyXF/2uV8B6Y79iTh98kVeOH9fX3x3zXXg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.5.0
|
||||
@@ -424,16 +424,16 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/types@9.3.0':
|
||||
resolution: {integrity: sha512-2JSxyfpEFWNUB2vKs/T1BvkfyNisMHWph8bLMj8T0uHwmLl/0qfAwQkfwMT6kxLXN9uIum9AEbECXU8er3amIg==}
|
||||
'@mui/types@9.4.0':
|
||||
resolution: {integrity: sha512-13DH0Oniua4WmGqeYbQAZqmiN7r4nfd0zwIoGJ5QeJwyIHgEmf+LkRw/jV1HZb6AiUoHX8Oxf4xgalq3vYHcIw==}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/utils@9.3.0':
|
||||
resolution: {integrity: sha512-2HZdHwWJ6eB+7lVGSOHsByGw8jeRulT4g0NZ608Wb8Q57DE2jbNqrWPFuJsvkQQiBiTmlpvQL3i+/62zsiPrkw==}
|
||||
'@mui/utils@9.4.0':
|
||||
resolution: {integrity: sha512-WkzY8uYtqUDyGKPShrRQRBomfMQHddlsyKu/gRRESYO24tDPD2z0xRE8CBoUsWqpBa+YrFs9KixiS7kQRjsPAQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
@@ -454,8 +454,8 @@ packages:
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@oxc-project/types@0.146.0':
|
||||
resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==}
|
||||
'@oxc-project/types@0.147.0':
|
||||
resolution: {integrity: sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==}
|
||||
|
||||
'@popperjs/core@2.11.8':
|
||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||
@@ -469,8 +469,8 @@ packages:
|
||||
'@prefresh/babel-plugin@0.5.3':
|
||||
resolution: {integrity: sha512-57LX2SHs4BX2s1IwCjNzTE2OJeEepRCNf1VTEpbNcUyHfMO68eeOWGDIt4ob9aYlW6PEWZ1SuwNikuoIXANDtQ==}
|
||||
|
||||
'@prefresh/core@1.5.10':
|
||||
resolution: {integrity: sha512-7yPTFbG56sutaFu8krp3B4a200KOFUvrtlllKWRuLjsYXo9UUucHOZRcer+gtgMkFTpv6ob8TGcTwA32bSwa1w==}
|
||||
'@prefresh/core@1.5.11':
|
||||
resolution: {integrity: sha512-Ml00PP8jeHaADxfQqxUs4+M5JS+T5J26UnvPVfsrmlpGw2I3e9XtM0DMeuzkmvg+Tn7VdHSMpLBrDPG0iHoDqQ==}
|
||||
peerDependencies:
|
||||
preact: ^10.0.0 || ^11.0.0-0
|
||||
|
||||
@@ -483,98 +483,98 @@ packages:
|
||||
preact: ^10.4.0 || ^11.0.0-0
|
||||
vite: '>=2.0.0'
|
||||
|
||||
'@rolldown/binding-android-arm-eabi@1.2.5':
|
||||
resolution: {integrity: sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==}
|
||||
'@rolldown/binding-android-arm-eabi@1.2.6':
|
||||
resolution: {integrity: sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-android-arm64@1.2.5':
|
||||
resolution: {integrity: sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==}
|
||||
'@rolldown/binding-android-arm64@1.2.6':
|
||||
resolution: {integrity: sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.2.5':
|
||||
resolution: {integrity: sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==}
|
||||
'@rolldown/binding-darwin-arm64@1.2.6':
|
||||
resolution: {integrity: sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.2.5':
|
||||
resolution: {integrity: sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==}
|
||||
'@rolldown/binding-darwin-x64@1.2.6':
|
||||
resolution: {integrity: sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.2.5':
|
||||
resolution: {integrity: sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==}
|
||||
'@rolldown/binding-freebsd-x64@1.2.6':
|
||||
resolution: {integrity: sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.5':
|
||||
resolution: {integrity: sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==}
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.6':
|
||||
resolution: {integrity: sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.5':
|
||||
resolution: {integrity: sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==}
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.6':
|
||||
resolution: {integrity: sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.5':
|
||||
resolution: {integrity: sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==}
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.6':
|
||||
resolution: {integrity: sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.5':
|
||||
resolution: {integrity: sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==}
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.6':
|
||||
resolution: {integrity: sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.5':
|
||||
resolution: {integrity: sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==}
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.6':
|
||||
resolution: {integrity: sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.5':
|
||||
resolution: {integrity: sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==}
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.6':
|
||||
resolution: {integrity: sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.2.5':
|
||||
resolution: {integrity: sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==}
|
||||
'@rolldown/binding-linux-x64-musl@1.2.6':
|
||||
resolution: {integrity: sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.2.5':
|
||||
resolution: {integrity: sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==}
|
||||
'@rolldown/binding-openharmony-arm64@1.2.6':
|
||||
resolution: {integrity: sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.5':
|
||||
resolution: {integrity: sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==}
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.6':
|
||||
resolution: {integrity: sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.5':
|
||||
resolution: {integrity: sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==}
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.6':
|
||||
resolution: {integrity: sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -668,8 +668,8 @@ packages:
|
||||
resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==}
|
||||
deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed.
|
||||
|
||||
'@types/node@26.2.0':
|
||||
resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==}
|
||||
'@types/node@26.4.0':
|
||||
resolution: {integrity: sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==}
|
||||
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
@@ -1433,8 +1433,8 @@ packages:
|
||||
resolution: {integrity: sha512-a6Qh1RMCNbSrU1+sAyAAZH3rTe+OaWJbNZIq0S+ifZciUUOQtlVxBJwoTUE2bYhysmG/RYyI5WJFIKdBahJdrQ==}
|
||||
hasBin: true
|
||||
|
||||
fastq@1.20.1:
|
||||
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
|
||||
fastq@1.20.3:
|
||||
resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==}
|
||||
|
||||
fd-slicer@1.1.0:
|
||||
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
|
||||
@@ -2178,8 +2178,8 @@ packages:
|
||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
open@11.0.1:
|
||||
resolution: {integrity: sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw==}
|
||||
open@11.0.2:
|
||||
resolution: {integrity: sha512-RWqF+pBSkqecEvCKOn8QYhaNdRMJDZRIrlS/7rTDdLHaPcfXGCZ/h8zb413NfvdeAV0MR7T1yJcA34/q+CSm1Q==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
optionator@0.9.4:
|
||||
@@ -2354,8 +2354,8 @@ packages:
|
||||
resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
powershell-utils@0.2.0:
|
||||
resolution: {integrity: sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==}
|
||||
powershell-utils@0.2.1:
|
||||
resolution: {integrity: sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
preact@10.29.8:
|
||||
@@ -2428,8 +2428,8 @@ packages:
|
||||
react-is@19.2.8:
|
||||
resolution: {integrity: sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==}
|
||||
|
||||
react-router@8.3.0:
|
||||
resolution: {integrity: sha512-qyPMvW83jGIct3yiieisxdk9M745anqhpIMKN5m1t6yBMfgVPpt77aHOqs5fUlEJRMCGffg9BaQLH9oPVOL7xQ==}
|
||||
react-router@8.3.1:
|
||||
resolution: {integrity: sha512-TEOpiO2g0TJHEOJeRVv4amUFun9v1npCKszvcquNvzETUtJ8udV86ah5eFoHT7g26bsBvT6EiIhqulR8eDF++A==}
|
||||
engines: {node: '>=22.22.0'}
|
||||
peerDependencies:
|
||||
react: '>=19.2.7'
|
||||
@@ -2505,8 +2505,8 @@ packages:
|
||||
deprecated: Rimraf versions prior to v4 are no longer supported
|
||||
hasBin: true
|
||||
|
||||
rolldown@1.2.5:
|
||||
resolution: {integrity: sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==}
|
||||
rolldown@1.2.6:
|
||||
resolution: {integrity: sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
@@ -2750,8 +2750,8 @@ packages:
|
||||
resolution: {integrity: sha512-ZOn6nJUgvgC09+doCEF3oB+r3ag7kUvlsXEGX069QRD60p+P3uP7XG9N2/at+EyIRGSN//ZY3LyEotA1YpmjuA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
terser@5.50.0:
|
||||
resolution: {integrity: sha512-CN9BVxWhgS/hRxtUMjtC2uRWSTcSfQFHMDWma6sKKfIivCD91sM+FOPfvwoaRMqCSrUpe1nv3jDamd9eEQ4y+w==}
|
||||
terser@5.51.2:
|
||||
resolution: {integrity: sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
@@ -3269,7 +3269,7 @@ snapshots:
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.13':
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
'@jridgewell/sourcemap-codec': 1.6.0
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
|
||||
'@jridgewell/remapping@2.3.5':
|
||||
@@ -3284,30 +3284,30 @@ snapshots:
|
||||
'@jridgewell/gen-mapping': 0.3.13
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
'@jridgewell/sourcemap-codec@1.6.0': {}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
'@jridgewell/sourcemap-codec': 1.6.0
|
||||
|
||||
'@mui/core-downloads-tracker@9.3.1': {}
|
||||
'@mui/core-downloads-tracker@9.4.0': {}
|
||||
|
||||
'@mui/icons-material@9.3.1(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)':
|
||||
'@mui/icons-material@9.4.0(@mui/material@9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
'@mui/material': 9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
'@mui/material': 9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
react: 19.2.8
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.18
|
||||
|
||||
'@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)':
|
||||
'@mui/material@9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
'@mui/core-downloads-tracker': 9.3.1
|
||||
'@mui/system': 9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)
|
||||
'@mui/types': 9.3.0(@types/react@19.2.18)
|
||||
'@mui/utils': 9.3.0(@types/react@19.2.18)(react@19.2.8)
|
||||
'@mui/core-downloads-tracker': 9.4.0
|
||||
'@mui/system': 9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)
|
||||
'@mui/types': 9.4.0(@types/react@19.2.18)
|
||||
'@mui/utils': 9.4.0(@types/react@19.2.18)(react@19.2.8)
|
||||
'@popperjs/core': 2.11.8
|
||||
'@types/react-transition-group': 4.4.12(@types/react@19.2.18)
|
||||
clsx: 2.1.1
|
||||
@@ -3322,16 +3322,16 @@ snapshots:
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2)
|
||||
'@types/react': 19.2.18
|
||||
|
||||
'@mui/private-theming@9.3.0(@types/react@19.2.18)(react@19.2.8)':
|
||||
'@mui/private-theming@9.4.0(@types/react@19.2.18)(react@19.2.8)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
'@mui/utils': 9.3.0(@types/react@19.2.18)(react@19.2.8)
|
||||
'@mui/utils': 9.4.0(@types/react@19.2.18)(react@19.2.8)
|
||||
prop-types: 15.8.1
|
||||
react: 19.2.8
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.18
|
||||
|
||||
'@mui/styled-engine@9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(react@19.2.8)':
|
||||
'@mui/styled-engine@9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(react@19.2.8)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
'@emotion/cache': 11.14.0
|
||||
@@ -3344,13 +3344,13 @@ snapshots:
|
||||
'@emotion/react': 11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2)
|
||||
|
||||
'@mui/system@9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)':
|
||||
'@mui/system@9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
'@mui/private-theming': 9.3.0(@types/react@19.2.18)(react@19.2.8)
|
||||
'@mui/styled-engine': 9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(react@19.2.8)
|
||||
'@mui/types': 9.3.0(@types/react@19.2.18)
|
||||
'@mui/utils': 9.3.0(@types/react@19.2.18)(react@19.2.8)
|
||||
'@mui/private-theming': 9.4.0(@types/react@19.2.18)(react@19.2.8)
|
||||
'@mui/styled-engine': 9.4.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(react@19.2.8)
|
||||
'@mui/types': 9.4.0(@types/react@19.2.18)
|
||||
'@mui/utils': 9.4.0(@types/react@19.2.18)(react@19.2.8)
|
||||
clsx: 2.1.1
|
||||
csstype: 3.2.3
|
||||
prop-types: 15.8.1
|
||||
@@ -3360,16 +3360,16 @@ snapshots:
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.8)(supports-color@10.2.2)
|
||||
'@types/react': 19.2.18
|
||||
|
||||
'@mui/types@9.3.0(@types/react@19.2.18)':
|
||||
'@mui/types@9.4.0(@types/react@19.2.18)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.18
|
||||
|
||||
'@mui/utils@9.3.0(@types/react@19.2.18)(react@19.2.8)':
|
||||
'@mui/utils@9.4.0(@types/react@19.2.18)(react@19.2.8)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
'@mui/types': 9.3.0(@types/react@19.2.18)
|
||||
'@mui/types': 9.4.0(@types/react@19.2.18)
|
||||
'@types/prop-types': 15.7.15
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
@@ -3388,25 +3388,25 @@ snapshots:
|
||||
'@nodelib/fs.walk@1.2.8':
|
||||
dependencies:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.20.1
|
||||
fastq: 1.20.3
|
||||
|
||||
'@oxc-project/types@0.146.0': {}
|
||||
'@oxc-project/types@0.147.0': {}
|
||||
|
||||
'@popperjs/core@2.11.8': {}
|
||||
|
||||
'@preact/preset-vite@2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.2.0)(terser@5.50.0))':
|
||||
'@preact/preset-vite@2.10.6(@babel/core@7.29.7(supports-color@10.2.2))(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2))':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.7(supports-color@10.2.2)
|
||||
'@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)
|
||||
'@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)
|
||||
'@prefresh/vite': 2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.2.0)(terser@5.50.0))
|
||||
'@prefresh/vite': 2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2))
|
||||
'@rollup/pluginutils': 5.4.0
|
||||
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.7(supports-color@10.2.2))
|
||||
debug: 4.4.3(supports-color@10.2.2)
|
||||
magic-string: 0.30.21
|
||||
picocolors: 1.1.1
|
||||
vite: 8.2.2(@types/node@26.2.0)(terser@5.50.0)
|
||||
vite-prerender-plugin: 0.5.13(vite@8.2.2(@types/node@26.2.0)(terser@5.50.0))
|
||||
vite: 8.2.2(@types/node@26.4.0)(terser@5.51.2)
|
||||
vite-prerender-plugin: 0.5.13(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2))
|
||||
zimmerframe: 1.1.4
|
||||
transitivePeerDependencies:
|
||||
- preact
|
||||
@@ -3415,67 +3415,67 @@ snapshots:
|
||||
|
||||
'@prefresh/babel-plugin@0.5.3': {}
|
||||
|
||||
'@prefresh/core@1.5.10(preact@10.29.8)':
|
||||
'@prefresh/core@1.5.11(preact@10.29.8)':
|
||||
dependencies:
|
||||
preact: 10.29.8
|
||||
|
||||
'@prefresh/utils@1.2.1': {}
|
||||
|
||||
'@prefresh/vite@2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.2.0)(terser@5.50.0))':
|
||||
'@prefresh/vite@2.4.12(preact@10.29.8)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2))':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.7(supports-color@10.2.2)
|
||||
'@prefresh/babel-plugin': 0.5.3
|
||||
'@prefresh/core': 1.5.10(preact@10.29.8)
|
||||
'@prefresh/core': 1.5.11(preact@10.29.8)
|
||||
'@prefresh/utils': 1.2.1
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
preact: 10.29.8
|
||||
vite: 8.2.2(@types/node@26.2.0)(terser@5.50.0)
|
||||
vite: 8.2.2(@types/node@26.4.0)(terser@5.51.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@rolldown/binding-android-arm-eabi@1.2.5':
|
||||
'@rolldown/binding-android-arm-eabi@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.2.5':
|
||||
'@rolldown/binding-android-arm64@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.2.5':
|
||||
'@rolldown/binding-darwin-arm64@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.2.5':
|
||||
'@rolldown/binding-darwin-x64@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.2.5':
|
||||
'@rolldown/binding-freebsd-x64@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.5':
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.5':
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.5':
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.5':
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.5':
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.5':
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.2.5':
|
||||
'@rolldown/binding-linux-x64-musl@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.2.5':
|
||||
'@rolldown/binding-openharmony-arm64@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.5':
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.5':
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.6':
|
||||
optional: true
|
||||
|
||||
'@rolldown/pluginutils@1.0.1': {}
|
||||
@@ -3523,7 +3523,7 @@ snapshots:
|
||||
'@types/glob@7.2.0':
|
||||
dependencies:
|
||||
'@types/minimatch': 6.0.0
|
||||
'@types/node': 26.2.0
|
||||
'@types/node': 26.4.0
|
||||
|
||||
'@types/imagemin-gifsicle@7.0.4':
|
||||
dependencies:
|
||||
@@ -3552,23 +3552,23 @@ snapshots:
|
||||
|
||||
'@types/imagemin@7.0.1':
|
||||
dependencies:
|
||||
'@types/node': 26.2.0
|
||||
'@types/node': 26.4.0
|
||||
|
||||
'@types/imagemin@9.0.1':
|
||||
dependencies:
|
||||
'@types/node': 26.2.0
|
||||
'@types/node': 26.4.0
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/keyv@3.1.4':
|
||||
dependencies:
|
||||
'@types/node': 26.2.0
|
||||
'@types/node': 26.4.0
|
||||
|
||||
'@types/minimatch@6.0.0':
|
||||
dependencies:
|
||||
minimatch: 10.2.6
|
||||
|
||||
'@types/node@26.2.0':
|
||||
'@types/node@26.4.0':
|
||||
dependencies:
|
||||
undici-types: 8.3.0
|
||||
|
||||
@@ -3590,11 +3590,11 @@ snapshots:
|
||||
|
||||
'@types/responselike@1.0.3':
|
||||
dependencies:
|
||||
'@types/node': 26.2.0
|
||||
'@types/node': 26.4.0
|
||||
|
||||
'@types/svgo@2.6.4':
|
||||
dependencies:
|
||||
'@types/node': 26.2.0
|
||||
'@types/node': 26.4.0
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.68.0(@typescript-eslint/parser@8.68.0(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.9.1(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)':
|
||||
dependencies:
|
||||
@@ -4436,7 +4436,7 @@ snapshots:
|
||||
dependencies:
|
||||
strnum: 1.1.2
|
||||
|
||||
fastq@1.20.1:
|
||||
fastq@1.20.3:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
|
||||
@@ -5021,7 +5021,7 @@ snapshots:
|
||||
|
||||
magic-string@0.30.21:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
'@jridgewell/sourcemap-codec': 1.6.0
|
||||
|
||||
make-dir@1.3.0:
|
||||
dependencies:
|
||||
@@ -5145,13 +5145,13 @@ snapshots:
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
|
||||
open@11.0.1:
|
||||
open@11.0.2:
|
||||
dependencies:
|
||||
default-browser: 5.5.1
|
||||
define-lazy-prop: 3.0.0
|
||||
is-in-ssh: 1.0.0
|
||||
is-inside-container: 1.0.0
|
||||
powershell-utils: 0.2.0
|
||||
powershell-utils: 0.2.1
|
||||
wsl-utils: 1.0.0
|
||||
|
||||
optionator@0.9.4:
|
||||
@@ -5297,7 +5297,7 @@ snapshots:
|
||||
|
||||
powershell-utils@0.1.0: {}
|
||||
|
||||
powershell-utils@0.2.0: {}
|
||||
powershell-utils@0.2.1: {}
|
||||
|
||||
preact@10.29.8: {}
|
||||
|
||||
@@ -5351,7 +5351,7 @@ snapshots:
|
||||
|
||||
react-is@19.2.8: {}
|
||||
|
||||
react-router@8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
|
||||
react-router@8.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
|
||||
dependencies:
|
||||
cookie-es: 3.1.1
|
||||
react: 19.2.8
|
||||
@@ -5432,35 +5432,35 @@ snapshots:
|
||||
dependencies:
|
||||
glob: 7.2.3
|
||||
|
||||
rolldown@1.2.5:
|
||||
rolldown@1.2.6:
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.146.0
|
||||
'@oxc-project/types': 0.147.0
|
||||
'@rolldown/pluginutils': 1.0.1
|
||||
optionalDependencies:
|
||||
'@rolldown/binding-android-arm-eabi': 1.2.5
|
||||
'@rolldown/binding-android-arm64': 1.2.5
|
||||
'@rolldown/binding-darwin-arm64': 1.2.5
|
||||
'@rolldown/binding-darwin-x64': 1.2.5
|
||||
'@rolldown/binding-freebsd-x64': 1.2.5
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.2.5
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.2.5
|
||||
'@rolldown/binding-linux-arm64-musl': 1.2.5
|
||||
'@rolldown/binding-linux-ppc64-gnu': 1.2.5
|
||||
'@rolldown/binding-linux-s390x-gnu': 1.2.5
|
||||
'@rolldown/binding-linux-x64-gnu': 1.2.5
|
||||
'@rolldown/binding-linux-x64-musl': 1.2.5
|
||||
'@rolldown/binding-openharmony-arm64': 1.2.5
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.2.5
|
||||
'@rolldown/binding-win32-x64-msvc': 1.2.5
|
||||
'@rolldown/binding-android-arm-eabi': 1.2.6
|
||||
'@rolldown/binding-android-arm64': 1.2.6
|
||||
'@rolldown/binding-darwin-arm64': 1.2.6
|
||||
'@rolldown/binding-darwin-x64': 1.2.6
|
||||
'@rolldown/binding-freebsd-x64': 1.2.6
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.2.6
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.2.6
|
||||
'@rolldown/binding-linux-arm64-musl': 1.2.6
|
||||
'@rolldown/binding-linux-ppc64-gnu': 1.2.6
|
||||
'@rolldown/binding-linux-s390x-gnu': 1.2.6
|
||||
'@rolldown/binding-linux-x64-gnu': 1.2.6
|
||||
'@rolldown/binding-linux-x64-musl': 1.2.6
|
||||
'@rolldown/binding-openharmony-arm64': 1.2.6
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.2.6
|
||||
'@rolldown/binding-win32-x64-msvc': 1.2.6
|
||||
|
||||
rollup-plugin-visualizer@7.1.1(rolldown@1.2.5):
|
||||
rollup-plugin-visualizer@7.1.1(rolldown@1.2.6):
|
||||
dependencies:
|
||||
open: 11.0.1
|
||||
open: 11.0.2
|
||||
picomatch: 4.0.7
|
||||
source-map: 0.8.0
|
||||
yargs: 18.1.0
|
||||
optionalDependencies:
|
||||
rolldown: 1.2.5
|
||||
rolldown: 1.2.6
|
||||
|
||||
run-applescript@7.1.0: {}
|
||||
|
||||
@@ -5664,7 +5664,7 @@ snapshots:
|
||||
temp-dir: 1.0.0
|
||||
uuid: 3.4.0
|
||||
|
||||
terser@5.50.0:
|
||||
terser@5.51.2:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.11
|
||||
acorn: 8.18.0
|
||||
@@ -5775,7 +5775,7 @@ snapshots:
|
||||
spdx-correct: 3.2.0
|
||||
spdx-expression-parse: 3.0.1
|
||||
|
||||
vite-plugin-imagemin@0.6.1(supports-color@10.2.2)(vite@8.2.2(@types/node@26.2.0)(terser@5.50.0)):
|
||||
vite-plugin-imagemin@0.6.1(supports-color@10.2.2)(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2)):
|
||||
dependencies:
|
||||
'@types/imagemin': 7.0.1
|
||||
'@types/imagemin-gifsicle': 7.0.4
|
||||
@@ -5800,11 +5800,11 @@ snapshots:
|
||||
imagemin-webp: 6.1.0
|
||||
jpegtran-bin: 6.0.1
|
||||
pathe: 0.2.0
|
||||
vite: 8.2.2(@types/node@26.2.0)(terser@5.50.0)
|
||||
vite: 8.2.2(@types/node@26.4.0)(terser@5.51.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vite-prerender-plugin@0.5.13(vite@8.2.2(@types/node@26.2.0)(terser@5.50.0)):
|
||||
vite-prerender-plugin@0.5.13(vite@8.2.2(@types/node@26.4.0)(terser@5.51.2)):
|
||||
dependencies:
|
||||
kolorist: 1.8.0
|
||||
magic-string: 0.30.21
|
||||
@@ -5812,19 +5812,19 @@ snapshots:
|
||||
simple-code-frame: 1.3.0
|
||||
source-map: 0.7.6
|
||||
stack-trace: 1.0.0
|
||||
vite: 8.2.2(@types/node@26.2.0)(terser@5.50.0)
|
||||
vite: 8.2.2(@types/node@26.4.0)(terser@5.51.2)
|
||||
|
||||
vite@8.2.2(@types/node@26.2.0)(terser@5.50.0):
|
||||
vite@8.2.2(@types/node@26.4.0)(terser@5.51.2):
|
||||
dependencies:
|
||||
lightningcss: 1.33.0
|
||||
picomatch: 4.0.7
|
||||
postcss: 8.5.26
|
||||
rolldown: 1.2.5
|
||||
rolldown: 1.2.6
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 26.2.0
|
||||
'@types/node': 26.4.0
|
||||
fsevents: 2.3.3
|
||||
terser: 5.50.0
|
||||
terser: 5.51.2
|
||||
|
||||
which-typed-array@1.1.22:
|
||||
dependencies:
|
||||
|
||||
@@ -95,7 +95,7 @@ const CommandsDialog = ({
|
||||
{ immediate: false }
|
||||
)
|
||||
.onSuccess(() => {
|
||||
toast.success(LL.COMMAND_SENT());
|
||||
toast.success(LL.COMMAND_EXECUTED());
|
||||
})
|
||||
.onError((error) => {
|
||||
toast.error(String(error.error?.message || 'An error occurred'));
|
||||
|
||||
@@ -70,7 +70,7 @@ const DevicesDialog = ({
|
||||
{ immediate: false }
|
||||
)
|
||||
.onSuccess(() => {
|
||||
toast.success(LL.COMMAND_SENT());
|
||||
toast.success(LL.COMMAND_EXECUTED());
|
||||
})
|
||||
.onError((error) => {
|
||||
toast.error(String(error.error?.message || 'An error occurred'));
|
||||
|
||||
@@ -177,7 +177,7 @@ const ApplicationSettings = () => {
|
||||
await sendAPI({
|
||||
device: 'system',
|
||||
cmd: 'sendmail',
|
||||
data: 'Email notification test successful!',
|
||||
data: '"Email notification test successful!"',
|
||||
id: 0
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
@@ -347,7 +347,7 @@ const cs: Translation = {
|
||||
SYSTEM_NAME: 'Název systému',
|
||||
COMMANDS: 'Příkazy',
|
||||
COMMANDS_HELP_1: 'Definujte vlastní příkazy pro magistrali EMS',
|
||||
COMMAND_SENT: 'Příkaz odeslán',
|
||||
COMMAND_EXECUTED: 'Příkaz úspěšně spuštěn',
|
||||
RUN: 'Spustit příkaz',
|
||||
INTERNET_CONNECTION_CHECK: 'Kontrola online pro dostupné verze'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const de: Translation = {
|
||||
SYSTEM_NAME: 'Systemname',
|
||||
COMMANDS: 'Befehle',
|
||||
COMMANDS_HELP_1: 'Definieren Sie eigene Befehle für die EMS-Magistral',
|
||||
COMMAND_SENT: 'Befehl gesendet',
|
||||
COMMAND_EXECUTED: 'Befehl erfolgreich ausgeführt',
|
||||
RUN: 'Befehl ausführen',
|
||||
INTERNET_CONNECTION_CHECK: 'Online-Prüfung auf verfügbare Versionen'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const en: Translation = {
|
||||
SYSTEM_NAME: 'System Name',
|
||||
COMMANDS: 'Commands',
|
||||
COMMANDS_HELP_1: 'Define reusable named commands below. These can be executed from the console, API/MQTT, or referenced by the Scheduler',
|
||||
COMMAND_SENT: 'Command sent',
|
||||
COMMAND_EXECUTED: 'Command executed successfully',
|
||||
RUN: 'Run',
|
||||
INTERNET_CONNECTION_CHECK: 'Checking online for available versions'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const fr: Translation = {
|
||||
SYSTEM_NAME: 'Nom du système',
|
||||
COMMANDS: 'Commandes',
|
||||
COMMANDS_HELP_1: 'Définir des commandes personnalisées pour la magistral EMS',
|
||||
COMMAND_SENT: 'Commande envoyée',
|
||||
COMMAND_EXECUTED: 'Commande exécutée avec succès',
|
||||
RUN: 'Exécuter une commande',
|
||||
INTERNET_CONNECTION_CHECK: 'Vérification en ligne pour les versions disponibles'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const it: Translation = {
|
||||
SYSTEM_NAME: 'Nome del sistema',
|
||||
COMMANDS: 'Comandi',
|
||||
COMMANDS_HELP_1: 'Definisci comandi personalizzati per la magistrali EMS',
|
||||
COMMAND_SENT: 'Comando inviato',
|
||||
COMMAND_EXECUTED: 'Comando eseguito con successo',
|
||||
RUN: 'Esegui comando',
|
||||
INTERNET_CONNECTION_CHECK: 'Controllo online per le versioni disponibili'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const nl: Translation = {
|
||||
SYSTEM_NAME: 'Systeemnaam',
|
||||
COMMANDS: 'Commando\'s',
|
||||
COMMANDS_HELP_1: 'Definieer hergebruikbare benoemde commando\'s hieronder. Deze kunnen worden uitgevoerd vanuit de console, API/MQTT, of worden aangeroepen door de Scheduler',
|
||||
COMMAND_SENT: 'Commando verzonden',
|
||||
COMMAND_EXECUTED: 'Commando uitgevoerd succesvol',
|
||||
RUN: 'Commando uitvoeren',
|
||||
INTERNET_CONNECTION_CHECK: 'Controleren op online beschikbare versies'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const no: Translation = {
|
||||
SYSTEM_NAME: 'Systemnavn',
|
||||
COMMANDS: 'Kommandoer',
|
||||
COMMANDS_HELP_1: 'Definer egne kommandoer for EMS-Magistral',
|
||||
COMMAND_SENT: 'Kommando sendt',
|
||||
COMMAND_EXECUTED: 'Kommando kjørt lykkes',
|
||||
RUN: 'Kjør',
|
||||
INTERNET_CONNECTION_CHECK: 'Kontrollerer online for tilgjengelige versjoner'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const pl: BaseTranslation = {
|
||||
SYSTEM_NAME: 'Nazwa systemu',
|
||||
COMMANDS: 'Komendy',
|
||||
COMMANDS_HELP_1: 'Zdefiniuj niestandardowe komendy dla magistrali EMS',
|
||||
COMMAND_SENT: 'Komenda wysłana',
|
||||
COMMAND_EXECUTED: 'Komenda wykonana pomyślnie',
|
||||
RUN: 'Wykonaj',
|
||||
INTERNET_CONNECTION_CHECK: 'Sprawdzanie online dla dostępnych wersji'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const sk: Translation = {
|
||||
SYSTEM_NAME: 'Názov systému',
|
||||
COMMANDS: 'Príkazy',
|
||||
COMMANDS_HELP_1: 'Definujte vlastné príkazy pre magistrali EMS',
|
||||
COMMAND_SENT: 'Príkaz odoslaný',
|
||||
COMMAND_EXECUTED: 'Príkaz vykonaný úspešne',
|
||||
RUN: 'Volať príkaz',
|
||||
INTERNET_CONNECTION_CHECK: 'Kontrola online pre dostupné verzie'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const sv: Translation = {
|
||||
SYSTEM_NAME: 'Systemnamn',
|
||||
COMMANDS: 'Kommandon',
|
||||
COMMANDS_HELP_1: 'Definiera egna kommandon för EMS-Magistral',
|
||||
COMMAND_SENT: 'Kommando skickat',
|
||||
COMMAND_EXECUTED: 'Kommando kört lyckades',
|
||||
RUN: 'Kör kommando',
|
||||
INTERNET_CONNECTION_CHECK: 'Kontrollerar online för tillgängliga versioner'
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ const tr: Translation = {
|
||||
SYSTEM_NAME: 'Sistem Adı',
|
||||
COMMANDS: 'Komutlar',
|
||||
COMMANDS_HELP_1: 'Özel komutları EMS hattına tanımlayın',
|
||||
COMMAND_SENT: 'Komut gönderildi',
|
||||
COMMAND_EXECUTED: 'Komut başarıyla çalıştırıldı',
|
||||
RUN: 'Komutu çalıştır',
|
||||
INTERNET_CONNECTION_CHECK: 'Online bağlantısı kontrol ediliyor'
|
||||
};
|
||||
|
||||
@@ -41,6 +41,8 @@ class WiFiClient {
|
||||
}
|
||||
void setTimeout(uint32_t){
|
||||
|
||||
}
|
||||
void setConnectionTimeout(uint32_t) {
|
||||
}
|
||||
// ESP32 socket option passthrough (e.g. TCP_NODELAY)
|
||||
int setSocketOption(int, int, const void *, size_t) {
|
||||
|
||||
Generated
+5
-5
@@ -71,8 +71,8 @@ packages:
|
||||
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5':
|
||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||
'@jridgewell/sourcemap-codec@1.6.0':
|
||||
resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||
@@ -227,17 +227,17 @@ snapshots:
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.13':
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
'@jridgewell/sourcemap-codec': 1.6.0
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
|
||||
'@jridgewell/resolve-uri@3.1.2': {}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
'@jridgewell/sourcemap-codec@1.6.0': {}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
'@jridgewell/sourcemap-codec': 1.6.0
|
||||
|
||||
'@msgpack/msgpack@3.1.3': {}
|
||||
|
||||
|
||||
+10
-1
@@ -65,7 +65,16 @@ let settings = {
|
||||
modbus_max_clients: 10,
|
||||
modbus_timeout: 10000,
|
||||
developer_mode: true,
|
||||
disable_reset: false
|
||||
disable_reset: false,
|
||||
email_enabled: false,
|
||||
email_security: 2,
|
||||
email_server: 'smtp.gmail.com',
|
||||
email_port: 587,
|
||||
email_login: 'test@emsesp.org',
|
||||
email_pass: 'password',
|
||||
email_sender: 'test@emsesp.org',
|
||||
email_recp: 'test@emsesp.org',
|
||||
email_subject: 'ems-esp notification'
|
||||
};
|
||||
|
||||
// EMS-ESP System Settings
|
||||
|
||||
+2
-1
@@ -1344,4 +1344,5 @@ IILE
|
||||
Sumr
|
||||
eraseap
|
||||
roomtempoffset
|
||||
dhcpc
|
||||
dhcpc
|
||||
wifioff
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020-2026 emsesp.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "emsesp.h"
|
||||
|
||||
#include "httpClient.h"
|
||||
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP_SSLClient.h>
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
int HttpClient::request(std::string url, const std::string & method, const std::string & value, JsonObjectConst headers, std::string & result) {
|
||||
int httpResult = 0;
|
||||
const bool is_post = value.length() || Helpers::toLower(method) == "post";
|
||||
const auto lower_url = Helpers::toLower(url.c_str());
|
||||
|
||||
const bool is_https = lower_url.starts_with("https://");
|
||||
if (!is_https && !lower_url.starts_with("http://")) {
|
||||
return 0; // unsupported scheme
|
||||
}
|
||||
|
||||
WiFiClient * basic_client = new WiFiClient;
|
||||
ESP_SSLClient * ssl_client = new ESP_SSLClient;
|
||||
if (is_https) {
|
||||
ssl_client->setInsecure();
|
||||
// Notes: with root CA we should set here: ssl_client->setCACert(rootCACert);
|
||||
// 1 KB RX buffer is fine for small JSON-style endpoints used by the scheduler/shunting-yard but it is NOT enough for servers that send full-size TLS records (>1 KB)
|
||||
ssl_client->setBufferSizes(16384, 1024);
|
||||
ssl_client->setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
|
||||
}
|
||||
// WiFiClient is NetworkClient, which declares no setTimeout() of its own - calling it binds to
|
||||
// Stream::setTimeout() and only affects readBytes(), leaving the socket on the core's 3s default
|
||||
basic_client->setConnectionTimeout(CONNECT_TIMEOUT_MS);
|
||||
ssl_client->setTimeout(5); // seconds, drives BearSSL only - unused on the plain HTTP path
|
||||
ssl_client->setClient(basic_client, is_https); // enableSSL = false for plain HTTP
|
||||
|
||||
url.replace(0, is_https ? 8 : 7, "");
|
||||
std::string host = url;
|
||||
auto index = url.find_first_of('/');
|
||||
if (index != std::string::npos) {
|
||||
host = url.substr(0, index);
|
||||
url.replace(0, index, "");
|
||||
} else {
|
||||
url = "/";
|
||||
}
|
||||
|
||||
const uint16_t port = is_https ? 443 : 80;
|
||||
if (ssl_client->connect(host.c_str(), port)) {
|
||||
bool content_set = false;
|
||||
bool agent_set = false;
|
||||
|
||||
// assemble the request in one buffer. Sent as a dozen small writes it is left to Nagle to
|
||||
// dribble them out an ACK at a time, which on a slow link can cost more than the read budget
|
||||
std::string req = (is_post ? "POST " : "GET ") + url + " HTTP/1.1\r\nHost: " + host + "\r\n";
|
||||
for (JsonPairConst p : headers) {
|
||||
const auto key = Helpers::toLower(p.key().c_str());
|
||||
content_set |= (key == "content-type");
|
||||
agent_set |= (key == "user-agent");
|
||||
req += std::string(p.key().c_str()) + ": " + p.value().as<std::string>() + "\r\n";
|
||||
}
|
||||
if (!agent_set) {
|
||||
req += "User-Agent: EMS-ESP\r\n"; // CDNs are more likely to stall on a request without one
|
||||
}
|
||||
if (is_post) {
|
||||
if (!content_set) {
|
||||
req += "Content-Type: ";
|
||||
req += value.starts_with('{') ? asyncsrv::T_application_json : asyncsrv::T_text_plain;
|
||||
req += "\r\n";
|
||||
}
|
||||
req += "Content-Length: " + std::to_string(value.length()) + "\r\n";
|
||||
}
|
||||
req += "Connection: close\r\n\r\n"; // the blank line terminates the headers - without it the server never responds
|
||||
|
||||
ssl_client->print(req.c_str());
|
||||
if (is_post && value.length()) {
|
||||
ssl_client->print(value.c_str()); // sent separately so the body isn't copied into req
|
||||
}
|
||||
|
||||
// available() drops to zero between TCP segments, so stopping at the first gap truncates
|
||||
// any response that doesn't arrive in a single packet. Keep reading until the peer closes,
|
||||
// the stream goes idle, or the overall budget runs out
|
||||
const uint32_t started = millis();
|
||||
uint32_t last_data = started;
|
||||
while (millis() - started < TOTAL_TIMEOUT_MS) {
|
||||
const int avail = ssl_client->available();
|
||||
if (avail > 0) {
|
||||
uint8_t buf[128];
|
||||
const size_t want = (avail < (int)sizeof(buf)) ? (size_t)avail : sizeof(buf);
|
||||
const int len = ssl_client->read(buf, want);
|
||||
if (len > 0) {
|
||||
result.append(reinterpret_cast<const char *>(buf), len);
|
||||
last_data = millis();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!ssl_client->connected()) {
|
||||
break; // closed, with nothing left buffered
|
||||
}
|
||||
// the server may take a while to start replying
|
||||
if (millis() - last_data > (result.empty() ? FIRST_BYTE_TIMEOUT_MS : IDLE_TIMEOUT_MS)) {
|
||||
break;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
ssl_client->stop();
|
||||
|
||||
const auto received = result.length();
|
||||
|
||||
// parse the status line "HTTP/1.x <code> <reason>". stoi() would abort rather than throw on
|
||||
// a malformed response, since the firmware is built with -fno-exceptions
|
||||
if (result.starts_with("HTTP/")) {
|
||||
index = result.find_first_of(' ');
|
||||
if (index != std::string::npos) {
|
||||
httpResult = Helpers::atoint(result.c_str() + index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
index = result.find("\r\n\r\n");
|
||||
if (index != std::string::npos) {
|
||||
result.replace(0, index + 4, "");
|
||||
}
|
||||
|
||||
if (httpResult == 0) {
|
||||
// the TCP connect worked but nothing usable came back
|
||||
EMSESP::logger().warning("%s no valid response from %s (%u bytes)", is_https ? "HTTPS" : "HTTP", host.c_str(), (unsigned)received);
|
||||
}
|
||||
} else {
|
||||
EMSESP::logger().warning("%s connection to %s failed", is_https ? "HTTPS" : "HTTP", host.c_str());
|
||||
}
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
|
||||
return httpResult;
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020-2026 emsesp.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_HTTPCLIENT_H
|
||||
#define EMSESP_HTTPCLIENT_H
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class HttpClient {
|
||||
public:
|
||||
static int request(std::string url, const std::string & method, const std::string & value, JsonObjectConst headers, std::string & result);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t CONNECT_TIMEOUT_MS = 5000; // TCP connect, the core defaults to 3s
|
||||
static constexpr uint32_t FIRST_BYTE_TIMEOUT_MS = 8000; // how long the server may take to start replying
|
||||
static constexpr uint32_t IDLE_TIMEOUT_MS = 500; // gap in the stream that marks the end of a response
|
||||
static constexpr uint32_t TOTAL_TIMEOUT_MS = 10000; // ceiling for the whole read
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
@@ -78,20 +78,20 @@ void Network::begin() {
|
||||
|
||||
phase_ = initialPhase();
|
||||
|
||||
// Initialise WiFi once when the Network service starts
|
||||
// Initialise WiFi once when the Network service starts.
|
||||
// persistent(false) keeps credentials in RAM so we don't auto-join leftover NVS config.
|
||||
WiFi.persistent(false);
|
||||
WiFi.setAutoReconnect(false);
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
// Keep the radio up. disconnect(wifioff=true) maps to STA.end() -> esp_wifi_stop()
|
||||
if (WiFi.STA.started()) {
|
||||
WiFi.disconnect(true, true); // wipe old settings; only when STA is up
|
||||
} else {
|
||||
WiFi.disconnect(true, false); // disconnect/off without erase, so no warning is shown
|
||||
WiFi.disconnect(false, true); // drop leftover association, wipe RAM config
|
||||
}
|
||||
|
||||
WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
|
||||
WiFi.setHostname(hostname_.c_str()); // updates shared default_hostname buffer
|
||||
WiFi.enableSTA(true); // creates the STA netif
|
||||
WiFi.enableSTA(true); // no-op if already STA; recreates netif after a full off
|
||||
WiFi.STA.setHostname(hostname_.c_str()); // pushes to esp_netif_set_hostname
|
||||
WiFi.enableIPv6(true);
|
||||
if (staticIPConfig_) {
|
||||
@@ -220,10 +220,10 @@ void Network::reconnect() {
|
||||
LOG_DEBUG("Reconnecting all networks");
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// disconnect WiFi
|
||||
// Drop STA association but leave the driver running. begin() re-applies hostname
|
||||
// and IPv6; tearing the radio down here races with WIFI_EVENT_STA_START (12289/259).
|
||||
if (wifi_connected()) {
|
||||
WiFi.disconnect(true, true);
|
||||
WiFi.mode(WIFI_STA); // reset mode
|
||||
WiFi.disconnect(false, true);
|
||||
}
|
||||
|
||||
// disconnect AP
|
||||
|
||||
+28
-106
@@ -22,8 +22,7 @@
|
||||
|
||||
#include "shuntingYard.h"
|
||||
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP_SSLClient.h>
|
||||
#include "httpClient.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
@@ -336,7 +335,6 @@ bool isnum(const std::string & s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// replace commands like "<device>/<hc>/<cmd>" with its value"
|
||||
std::string commands(std::string & expr, bool quotes) {
|
||||
auto expr_new = Helpers::toLower(expr);
|
||||
@@ -481,14 +479,14 @@ std::string calculate(const std::string & expr) {
|
||||
const auto rhs = stack.back();
|
||||
stack.pop_back();
|
||||
if (token.str[0] == '!') {
|
||||
if (to_logic(rhs) < 0) {
|
||||
}
|
||||
if (to_logic(rhs) >= 0) {
|
||||
stack.push_back(to_logic(rhs) == 0 ? "1" : "0");
|
||||
const auto logic = to_logic(rhs);
|
||||
if (logic >= 0) {
|
||||
stack.push_back(logic == 0 ? "1" : "0");
|
||||
} else if (isnum(rhs)) {
|
||||
stack.push_back(std::stod(rhs) == 0 ? "1" : "0");
|
||||
} else {
|
||||
EMSESP::logger().warning("missing operator");
|
||||
// usually literal text that was left unquoted, so its '!' got read as a logical NOT
|
||||
EMSESP::logger().warning("'!' needs a boolean or numeric operand, got '%s'. Literal text must be quoted", rhs.c_str());
|
||||
return "";
|
||||
}
|
||||
break;
|
||||
@@ -691,98 +689,22 @@ std::string calculate(const std::string & expr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// perform an HTTP/HTTPS request; returns the HTTP status code (0 on failure or unsupported scheme)
|
||||
// the response headers are always stripped, so `result` contains only the body
|
||||
int http_request(std::string url, const std::string & method, const std::string & value, JsonObjectConst headers, std::string & result) {
|
||||
int httpResult = 0;
|
||||
const bool is_post = value.length() || Helpers::toLower(method) == "post";
|
||||
const auto lower_url = Helpers::toLower(url.c_str());
|
||||
|
||||
const bool is_https = lower_url.starts_with("https://");
|
||||
if (!is_https && !lower_url.starts_with("http://")) {
|
||||
return 0; // unsupported scheme
|
||||
// find the next occurrence of c at or after `from` that is not inside a quoted string, so that
|
||||
// literal text like "too hot?" is not mistaken for a ternary. Always scans from the start of the
|
||||
// string because the quote state at `from` depends on everything before it.
|
||||
static size_t find_unquoted(const std::string & s, char c, size_t from = 0) {
|
||||
bool in_single = false;
|
||||
bool in_double = false;
|
||||
for (size_t i = 0; i < s.length(); i++) {
|
||||
if (!in_single && s[i] == '"') {
|
||||
in_double = !in_double;
|
||||
} else if (!in_double && s[i] == '\'') {
|
||||
in_single = !in_single;
|
||||
} else if (!in_single && !in_double && s[i] == c && i >= from) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
WiFiClient * basic_client = new WiFiClient;
|
||||
ESP_SSLClient * ssl_client = new ESP_SSLClient;
|
||||
if (is_https) {
|
||||
ssl_client->setInsecure(); // with root CA we should set here: ssl_client->setCACert(rootCACert);
|
||||
// NOTE: 1 KB RX buffer is fine for small JSON-style endpoints used by the scheduler/shunting-yard,
|
||||
// but it is NOT enough for servers that send full-size TLS records (>1 KB), e.g. GitHub release
|
||||
// assets / large CDN responses. Such servers do not negotiate max_fragment_length, so the body
|
||||
// can't be decoded and reads return 0. If this path is ever used to fetch large or CDN-hosted
|
||||
// payloads, bump the RX buffer to 16384 (see uploadFirmwareURL in core/system.cpp for reference).
|
||||
ssl_client->setBufferSizes(16384, 1024);
|
||||
ssl_client->setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
|
||||
}
|
||||
basic_client->setTimeout(5000); // socket-level read timeout
|
||||
ssl_client->setTimeout(5); // Stream::readBytes timeout used by Update
|
||||
ssl_client->setClient(basic_client, is_https); // enableSSL = false for plain HTTP
|
||||
|
||||
url.replace(0, is_https ? 8 : 7, "");
|
||||
std::string host = url;
|
||||
auto index = url.find_first_of('/');
|
||||
if (index != std::string::npos) {
|
||||
host = url.substr(0, index);
|
||||
url.replace(0, index, "");
|
||||
} else {
|
||||
url = "/";
|
||||
}
|
||||
|
||||
const uint16_t port = is_https ? 443 : 80;
|
||||
if (ssl_client->connect(host.c_str(), port)) {
|
||||
bool content_set = false;
|
||||
ssl_client->print(is_post ? "POST " : "GET ");
|
||||
ssl_client->print(url.c_str());
|
||||
ssl_client->println(" HTTP/1.1");
|
||||
ssl_client->print("Host: ");
|
||||
ssl_client->println(host.c_str());
|
||||
for (JsonPairConst p : headers) {
|
||||
content_set |= (Helpers::toLower(p.key().c_str()) == "content-type");
|
||||
ssl_client->print(p.key().c_str());
|
||||
ssl_client->print(": ");
|
||||
ssl_client->println(p.value().as<std::string>().c_str());
|
||||
}
|
||||
if (is_post) {
|
||||
if (!content_set) {
|
||||
ssl_client->print("Content-Type: ");
|
||||
ssl_client->println(value.starts_with('{') ? asyncsrv::T_application_json : asyncsrv::T_text_plain);
|
||||
}
|
||||
ssl_client->print("Content-Length: ");
|
||||
ssl_client->println(value.length());
|
||||
ssl_client->println("Connection: close");
|
||||
ssl_client->print("\r\n");
|
||||
ssl_client->print(value.c_str());
|
||||
} else {
|
||||
ssl_client->println("Connection: close");
|
||||
ssl_client->print("\r\n"); // terminate headers - without this the server never responds
|
||||
}
|
||||
|
||||
auto ms = millis();
|
||||
while (ssl_client->connected() && !ssl_client->available() && millis() - ms < 3000) {
|
||||
delay(1);
|
||||
}
|
||||
|
||||
while (ssl_client->available()) {
|
||||
result += (char)ssl_client->read();
|
||||
}
|
||||
ssl_client->stop();
|
||||
|
||||
index = result.find_first_of(' ');
|
||||
if (index != std::string::npos) {
|
||||
httpResult = stoi(result.substr(index + 1, 3));
|
||||
}
|
||||
index = result.find("\r\n\r\n");
|
||||
if (index != std::string::npos) {
|
||||
result.replace(0, index + 4, "");
|
||||
}
|
||||
} else {
|
||||
EMSESP::logger().warning("%s connection failed", is_https ? "HTTPS" : "HTTP");
|
||||
}
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
|
||||
return httpResult;
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
// check for multiple instances of <cond> ? <expr1> : <expr2>
|
||||
@@ -829,7 +751,7 @@ std::string compute(const std::string & expr) {
|
||||
std::string method = doc[method_s] | "GET";
|
||||
std::string result;
|
||||
|
||||
int httpResult = http_request(url, method, value, doc[header_s].as<JsonObjectConst>(), result);
|
||||
int httpResult = HttpClient::request(url, method, value, doc[header_s].as<JsonObjectConst>(), result);
|
||||
if (httpResult == 200) {
|
||||
std::string key = doc[key_s] | "";
|
||||
JsonDocument keys_doc; // JsonDocument to hold "keys" after doc is parsed with HTTP body
|
||||
@@ -868,14 +790,14 @@ std::string compute(const std::string & expr) {
|
||||
}
|
||||
|
||||
// positions: q-questionmark, c-colon
|
||||
auto q = expr_new.find_first_of('?');
|
||||
auto q = find_unquoted(expr_new, '?');
|
||||
while (q != std::string::npos) {
|
||||
// find corresponding colon
|
||||
auto c1 = expr_new.find_first_of(':', q + 1);
|
||||
auto q1 = expr_new.find_first_of('?', q + 1);
|
||||
auto c1 = find_unquoted(expr_new, ':', q + 1);
|
||||
auto q1 = find_unquoted(expr_new, '?', q + 1);
|
||||
while (q1 < c1 && q1 != std::string::npos && c1 != std::string::npos) {
|
||||
q1 = expr_new.find_first_of('?', q1 + 1);
|
||||
c1 = expr_new.find_first_of(':', c1 + 1);
|
||||
q1 = find_unquoted(expr_new, '?', q1 + 1);
|
||||
c1 = find_unquoted(expr_new, ':', c1 + 1);
|
||||
}
|
||||
if (c1 == std::string::npos) {
|
||||
return ""; // error: missing colon
|
||||
@@ -906,7 +828,7 @@ std::string compute(const std::string & expr) {
|
||||
} else {
|
||||
return ""; // error
|
||||
}
|
||||
q = expr_new.find_first_of('?'); // search next instance
|
||||
q = find_unquoted(expr_new, '?'); // search next instance
|
||||
}
|
||||
|
||||
return calculate(expr_new);
|
||||
|
||||
@@ -84,8 +84,6 @@ std::string calculate(const std::string & expr);
|
||||
// check for multiple instances of <cond> ? <expr1> : <expr2>
|
||||
std::string compute(const std::string & expr);
|
||||
|
||||
int http_request(std::string url, const std::string & method, const std::string & value, JsonObjectConst headers, std::string & result);
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace emsesp
|
||||
#endif
|
||||
+80
-55
@@ -40,9 +40,6 @@
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#define ENABLE_SMTP
|
||||
#define USE_ESP_SSLCLIENT
|
||||
#define READYCLIENT_SSL_CLIENT ESP_SSLClient
|
||||
#define READYCLIENT_TYPE_1 // TYPE 1 when using ESP_SSLClient
|
||||
#include <ESP_SSLClient.h>
|
||||
#include <ReadyMail.h>
|
||||
#endif
|
||||
@@ -94,6 +91,13 @@ std::vector<uint8_t, AllocatorPSRAM<uint8_t>> System::valid_
|
||||
std::vector<System::GpioUsage, AllocatorPSRAM<System::GpioUsage>> System::used_gpios_;
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// TLSHandshakeCallback is a C function pointer, so STARTTLS needs a process-wide client slot.
|
||||
static ESP_SSLClient * sendmail_ssl_client = nullptr;
|
||||
|
||||
static void sendmail_tls_handshake(bool & success) {
|
||||
success = sendmail_ssl_client != nullptr && sendmail_ssl_client->connectSSL();
|
||||
}
|
||||
|
||||
// The DNS slots are shared between IPv4 and IPv6, so with IPv6 enabled the first slot can hold an
|
||||
// IPv6 server. Pick the first IPv4 one so it matches the label we print it under.
|
||||
static IPAddress dns_ipv4(const NetworkInterface & netif) {
|
||||
@@ -147,61 +151,88 @@ bool System::command_sendmail(const char * value, const int8_t) {
|
||||
port,
|
||||
security == EMAIL_SECURITY::SSL ? " (SSL)"
|
||||
: security == EMAIL_SECURITY::STARTTLS ? " (STARTTLS)"
|
||||
: "",
|
||||
: " (plain)",
|
||||
value);
|
||||
|
||||
bool success = false;
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
auto * basic_client = new WiFiClient;
|
||||
auto * ssl_client = new ESP_SSLClient;
|
||||
auto * r_client = new ReadyClient(*ssl_client);
|
||||
auto * smtp = new SMTPClient(*r_client);
|
||||
|
||||
ssl_client->setClient(basic_client);
|
||||
ssl_client->setInsecure();
|
||||
ssl_client->setBufferSizes(16384, 1024);
|
||||
basic_client->setTimeout(5000); // socket-level read timeout
|
||||
ssl_client->setTimeout(5); // Stream::readBytes timeout used by Update
|
||||
r_client->addPort(port,
|
||||
security == EMAIL_SECURITY::NONE ? readymail_protocol_plain_text
|
||||
: security == EMAIL_SECURITY::SSL ? readymail_protocol_ssl
|
||||
: readymail_protocol_tls);
|
||||
|
||||
|
||||
// smtp->connect(server, port, sendmailCallback);
|
||||
smtp->connect(server, port);
|
||||
if (!smtp->isConnected()) {
|
||||
LOG_ERROR("send email connection error");
|
||||
delete smtp;
|
||||
delete r_client;
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
return false;
|
||||
}
|
||||
|
||||
// LOG_INFO("authenticate %s:%s", login.c_str(), pass.c_str());
|
||||
smtp->authenticate(login, pass, readymail_auth_password);
|
||||
if (!smtp->isAuthenticated()) {
|
||||
LOG_ERROR("send email authentication error");
|
||||
delete smtp;
|
||||
delete r_client;
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
return false;
|
||||
}
|
||||
// Resolve the message before opening the SMTP session: compute() can do entity lookups and a
|
||||
// blocking {url} fetch, which would otherwise leave the connection idle long enough to time out.
|
||||
// The value is either a plain body or a JSON envelope overriding the configured subject/to/from.
|
||||
JsonDocument doc(PSRAM_DOC);
|
||||
String body = value;
|
||||
if (body.length()) {
|
||||
auto error = deserializeJson(doc, (const char *)value);
|
||||
if (!error && doc.as<JsonObject>().size() >= 0) {
|
||||
if (!error && doc.is<JsonObject>()) {
|
||||
subject = doc["subject"] | subject;
|
||||
recp = doc["to"] | recp;
|
||||
sender = doc["from"] | sender;
|
||||
body = doc["body"] | body;
|
||||
}
|
||||
}
|
||||
// keep the original body if the calculator returns nothing, so unquoted literal text still gets sent
|
||||
std::string computed_body = compute(body.c_str());
|
||||
if (!computed_body.empty()) {
|
||||
body = computed_body.c_str();
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// Do not use ReadyClient: after the 220 greeting it calls connectSSL() whenever
|
||||
// STARTTLS is off, so Security=Off still sends a TLS Client Hello on port 25.
|
||||
auto * basic_client = new WiFiClient;
|
||||
ESP_SSLClient * ssl_client = nullptr;
|
||||
SMTPClient * smtp = nullptr;
|
||||
|
||||
basic_client->setTimeout(5000);
|
||||
|
||||
const bool implicit_ssl = (security == EMAIL_SECURITY::SSL);
|
||||
const bool start_tls = (security == EMAIL_SECURITY::STARTTLS);
|
||||
const bool tls_enabled = (security != EMAIL_SECURITY::NONE);
|
||||
|
||||
if (security == EMAIL_SECURITY::NONE) {
|
||||
smtp = new SMTPClient(*basic_client);
|
||||
} else {
|
||||
ssl_client = new ESP_SSLClient;
|
||||
ssl_client->setInsecure();
|
||||
ssl_client->setBufferSizes(16384, 1024);
|
||||
ssl_client->setTimeout(5);
|
||||
// enableSSL is baked in at setClient() — true only for implicit SSL (port 465)
|
||||
ssl_client->setClient(basic_client, implicit_ssl);
|
||||
if (start_tls) {
|
||||
sendmail_ssl_client = ssl_client;
|
||||
smtp = new SMTPClient(*ssl_client, sendmail_tls_handshake, true);
|
||||
} else {
|
||||
smtp = new SMTPClient(*ssl_client);
|
||||
}
|
||||
}
|
||||
|
||||
auto cleanup = [&]() {
|
||||
delete smtp;
|
||||
sendmail_ssl_client = nullptr;
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
};
|
||||
|
||||
if (!smtp->connect(server, port, String(""), static_cast<SMTPResponseCallback>(nullptr), tls_enabled)) {
|
||||
LOG_ERROR("send email connection error: %s", smtp->status().text.c_str());
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
if (!smtp->isConnected()) {
|
||||
LOG_ERROR("send email connection error: %s", smtp->status().text.c_str());
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
// internal/open relays often have no AUTH; empty login means skip it
|
||||
if (!login.isEmpty()) {
|
||||
smtp->authenticate(login, pass, readymail_auth_password);
|
||||
if (!smtp->isAuthenticated()) {
|
||||
LOG_ERROR("send email authentication error: %s", smtp->status().text.c_str());
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SMTPMessage & msg = smtp->getMessage();
|
||||
msg.headers.add(rfc822_subject, subject);
|
||||
msg.headers.add(rfc822_from, sender);
|
||||
@@ -211,12 +242,6 @@ bool System::command_sendmail(const char * value, const int8_t) {
|
||||
// msg.headers.addCustom("Importance", PRIORITY);
|
||||
// msg.headers.addCustom("X-MSMail-Priority", PRIORITY);
|
||||
// msg.headers.addCustom("X-Priority", PRIORITY_NUM);
|
||||
// run the body through the Shunting Yard calculator (entity substitution, expressions, optional {url} fetch)
|
||||
// keep the original body if the calculator returns nothing
|
||||
std::string computed_body = compute(body.c_str());
|
||||
if (!computed_body.empty()) {
|
||||
body = computed_body.c_str();
|
||||
}
|
||||
msg.text.body(body);
|
||||
|
||||
// bodyText.replace("\r\n", "<br>\r\n");
|
||||
@@ -230,11 +255,11 @@ bool System::command_sendmail(const char * value, const int8_t) {
|
||||
msg.timestamp = time(nullptr);
|
||||
|
||||
success = smtp->send(msg);
|
||||
if (!success) {
|
||||
LOG_ERROR("send email failed: %s", smtp->status().text.c_str());
|
||||
}
|
||||
|
||||
delete smtp;
|
||||
delete r_client;
|
||||
delete ssl_client;
|
||||
delete basic_client;
|
||||
cleanup();
|
||||
#endif
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.9.0-dev.5"
|
||||
#define EMSESP_APP_VERSION "3.9.0-dev.6"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "WebCommandService.h"
|
||||
|
||||
#include "shuntingYard.h"
|
||||
#include "httpClient.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
@@ -99,6 +100,13 @@ bool WebCommandService::isUrlCommand(const std::string & command) {
|
||||
return lower_url.starts_with("http://") || lower_url.starts_with("https://");
|
||||
}
|
||||
|
||||
// true if the command runs the shunting-yard on its own argument. Those values must be passed
|
||||
// through raw: a first pass strips the quotes from literal text, so the command's own pass then
|
||||
// re-parses that text as an expression and chokes on characters like '!' or drops the spaces.
|
||||
bool WebCommandService::computesOwnValue(const std::string & cmd) {
|
||||
return cmd == "system/message" || cmd == "system/sendmail";
|
||||
}
|
||||
|
||||
// true if a value expression contains an embedded {"url":...} JSON snippet, which compute()
|
||||
// will resolve with a blocking HTTP request. Mirrors the scan compute() does in shuntingYard.cpp
|
||||
bool WebCommandService::valueContainsUrl(const std::string & value) {
|
||||
@@ -238,13 +246,13 @@ bool WebCommandService::executeCommand(const char * name, const std::string & co
|
||||
// run the value through the shunting-yard calculator so expressions like "custom/heatcnt + 1"
|
||||
// are resolved (entity references replaced by their values, then computed). Plain values pass
|
||||
// through unchanged. Applies to both URL and internal commands, like the old scheduler code
|
||||
// which computed the value before executing. system/message runs the shunting-yard on its own
|
||||
// argument, so pre-computing it here would run it twice - pass it through raw.
|
||||
// which computed the value before executing. Commands that compute their own argument are
|
||||
// skipped here so the value is only ever evaluated once.
|
||||
std::string computed_data = data;
|
||||
if (!data.empty() && cmd != "system/message") {
|
||||
if (!data.empty() && !computesOwnValue(cmd)) {
|
||||
computed_data = compute(data);
|
||||
if (computed_data.empty()) {
|
||||
EMSESP::logger().warning("Command '%s': cannot compute value '%s'", name, data.c_str());
|
||||
EMSESP::logger().warning("Command '%s': cannot compute value '%s'. Literal text must be quoted", name, data.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -267,7 +275,7 @@ bool WebCommandService::executeCommand(const char * name, const std::string & co
|
||||
auto lower_url = Helpers::toLower(url.c_str());
|
||||
if (lower_url.starts_with("http://") || lower_url.starts_with("https://")) {
|
||||
std::string result;
|
||||
int httpResult = http_request(url, method, value, doc["header"].as<JsonObjectConst>(), result);
|
||||
int httpResult = HttpClient::request(url, method, value, doc["header"].as<JsonObjectConst>(), result);
|
||||
if (httpResult != 200) {
|
||||
EMSESP::logger().warning("Command '%s': URL command failed with http code %d", name, httpResult);
|
||||
return false;
|
||||
|
||||
@@ -85,6 +85,7 @@ class WebCommandService : public StatefulService<WebCommands> {
|
||||
|
||||
static bool isUrlCommand(const std::string & command); // true if the command definition is a HTTP/URL command
|
||||
static bool valueContainsUrl(const std::string & value); // true if a value embeds a {"url":...} compute() will fetch
|
||||
static bool computesOwnValue(const std::string & cmd); // true if the command runs the shunting-yard itself
|
||||
|
||||
const CommandItem * find(const char * name);
|
||||
|
||||
|
||||
@@ -316,8 +316,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
settings.weblog_level = root["weblog_level"] | EMSESP_DEFAULT_WEBLOG_LEVEL;
|
||||
settings.weblog_compact = root["weblog_compact"] | EMSESP_DEFAULT_WEBLOG_COMPACT;
|
||||
|
||||
settings.email_enabled = root["email_enabled"] | FACTORY_EMAIL_ENABLE;
|
||||
settings.email_security = root["email_security"] | FACTORY_EMAIL_SECURITY;
|
||||
settings.email_enabled = root["email_enabled"] | FACTORY_EMAIL_ENABLE;
|
||||
// Off is 0, so `| FACTORY_EMAIL_SECURITY` would replace it with STARTTLS (2)
|
||||
settings.email_security = root["email_security"].isNull() ? FACTORY_EMAIL_SECURITY : root["email_security"].as<uint8_t>();
|
||||
settings.email_server = root["email_server"] | FACTORY_EMAIL_SERVER;
|
||||
settings.email_port = root["email_port"] | FACTORY_EMAIL_PORT;
|
||||
settings.email_login = root["email_login"] | FACTORY_EMAIL_LOGIN;
|
||||
|
||||
@@ -20,10 +20,8 @@
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#include <esp_ota_ops.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP_SSLClient.h>
|
||||
#endif
|
||||
#include "shuntingYard.h"
|
||||
#include "httpClient.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
@@ -427,9 +425,9 @@ bool WebStatusService::refresh_versions_cache() {
|
||||
#else
|
||||
std::string result;
|
||||
JsonDocument doc;
|
||||
auto http_code = http_request(VERSIONS_URL, "GET", "", doc.as<JsonObjectConst>(), result);
|
||||
auto http_code = HttpClient::request(VERSIONS_URL, "GET", "", doc.as<JsonObjectConst>(), result);
|
||||
if (http_code != 200) {
|
||||
EMSESP::logger().warning("refresh_versions_cache() HTTP error code %d", http_code);
|
||||
EMSESP::logger().warning("Unable to retrieve online version information (HTTP error code %d)", http_code);
|
||||
return false;
|
||||
}
|
||||
DeserializationError err = deserializeJson(doc, result);
|
||||
|
||||
@@ -120,6 +120,31 @@ void shuntingYard_test28() {
|
||||
run_shuntingYard_test("", "-x");
|
||||
}
|
||||
|
||||
// quoted text keeps its spaces and punctuation, unquoted text does not
|
||||
void shuntingYard_test29() {
|
||||
run_shuntingYard_test("email test!", "\"email test!\"");
|
||||
}
|
||||
|
||||
// a trailing '!' on unquoted text is read as a logical NOT and has no valid operand
|
||||
void shuntingYard_test30() {
|
||||
run_shuntingYard_test("", "email test!");
|
||||
}
|
||||
|
||||
// computing an already computed value is lossy - callers must run compute() only once
|
||||
void shuntingYard_test31() {
|
||||
run_shuntingYard_test("", emsesp::compute("\"email test!\""));
|
||||
}
|
||||
|
||||
// a '?' inside quotes is literal text, not a ternary
|
||||
void shuntingYard_test32() {
|
||||
run_shuntingYard_test("Is it hot?", "\"Is it hot?\"");
|
||||
}
|
||||
|
||||
// mixing quoted text with entity values keeps the punctuation of both parts
|
||||
void shuntingYard_test33() {
|
||||
run_shuntingYard_test("temp is 40 C!", "\"temp is \" + boiler/flowtempoffset + \" C!\"");
|
||||
}
|
||||
|
||||
void run_shuntingYard_tests() {
|
||||
RUN_TEST(shuntingYard_test1);
|
||||
RUN_TEST(shuntingYard_test2);
|
||||
@@ -149,4 +174,9 @@ void run_shuntingYard_tests() {
|
||||
RUN_TEST(shuntingYard_test26);
|
||||
RUN_TEST(shuntingYard_test27);
|
||||
RUN_TEST(shuntingYard_test28);
|
||||
RUN_TEST(shuntingYard_test29);
|
||||
RUN_TEST(shuntingYard_test30);
|
||||
RUN_TEST(shuntingYard_test31);
|
||||
RUN_TEST(shuntingYard_test32);
|
||||
RUN_TEST(shuntingYard_test33);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user