Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7663f502fa | |||
| 104cd417d8 | |||
| 93254d5d3d | |||
| 9a3f121a9c | |||
| bef74eb1aa | |||
| 308d8e4851 | |||
| dc010dc3ae | |||
| 61d5d3b1ad | |||
| dd70790d40 | |||
| 2f8c04edc4 | |||
| 474cc328dd | |||
| 39ff159bf7 | |||
| c7fe7aeb50 | |||
| 2cf362020f | |||
| b62bad3616 | |||
| 3d372863a4 | |||
| 1045dc04fe | |||
| 89ef7597df | |||
| 0804544564 | |||
| 671e72452a | |||
| 647c705b81 | |||
| 40c3202082 | |||
| 3b91ed3d5a | |||
| 133b17f136 | |||
| efa45dfdc9 | |||
| 79b4ea6bd9 | |||
| b483412a2e | |||
| d964515ff9 | |||
| e2c453423e | |||
| c44b7d513a | |||
| 2487f77b8a | |||
| ea80ef005c | |||
| dd45b7fbe7 | |||
| ca73da7b9b | |||
| f6e1951aa2 | |||
| 76fd563e21 | |||
| ee831ea057 | |||
| a65c2ec096 |
111
changelog.md
111
changelog.md
@@ -1,5 +1,116 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-03-24 - 11.10.4 - fix(monitoring)
|
||||||
|
handle multiple protocol cache entries per backend in metrics output
|
||||||
|
|
||||||
|
- Group detected protocol cache entries by backend host and port so multiple domain-specific records are preserved.
|
||||||
|
- Emit one backend metrics row per cached domain and avoid dropping unmatched protocol cache entries by tracking seen entries with a composite host:port:domain key.
|
||||||
|
- Use cached protocol values when available while keeping backend-only rows for metrics without protocol cache data.
|
||||||
|
|
||||||
|
## 2026-03-23 - 11.10.3 - fix(deps)
|
||||||
|
bump tstest, smartmetrics, and taskbuffer to latest patch releases
|
||||||
|
|
||||||
|
- update @git.zone/tstest from ^3.5.0 to ^3.5.1
|
||||||
|
- update @push.rocks/smartmetrics from ^3.0.2 to ^3.0.3
|
||||||
|
- update @push.rocks/taskbuffer from ^8.0.0 to ^8.0.2
|
||||||
|
|
||||||
|
## 2026-03-23 - 11.10.2 - fix(deps)
|
||||||
|
bump @api.global/typedserver to ^8.4.6 and @push.rocks/smartproxy to ^26.2.1
|
||||||
|
|
||||||
|
- Updates @api.global/typedserver from ^8.4.2 to ^8.4.6
|
||||||
|
- Updates @push.rocks/smartproxy from ^26.2.0 to ^26.2.1
|
||||||
|
|
||||||
|
## 2026-03-23 - 11.10.1 - fix(deps)
|
||||||
|
bump @push.rocks/smartproxy to ^26.2.0
|
||||||
|
|
||||||
|
- Updates the @push.rocks/smartproxy dependency from ^26.1.0 to ^26.2.0 in package.json.
|
||||||
|
|
||||||
|
## 2026-03-23 - 11.10.0 - feat(monitoring)
|
||||||
|
add backend protocol metrics to network stats and ops dashboard
|
||||||
|
|
||||||
|
- Expose backend protocol, connection, error, and suppression metrics in stats responses.
|
||||||
|
- Add typed backend info interfaces and app state support for backend metrics.
|
||||||
|
- Render a new backend protocols table in the ops network view with detail modal and suppression badges.
|
||||||
|
- Update smartproxy and lik dependencies to support backend protocol metrics collection.
|
||||||
|
|
||||||
|
## 2026-03-21 - 11.9.1 - fix(lifecycle)
|
||||||
|
clean up service subscriptions, proxy retries, and stale runtime state on shutdown
|
||||||
|
|
||||||
|
- unsubscribe from ServiceManager event streams and use one-time signal handlers to avoid duplicate shutdown execution
|
||||||
|
- reset existing SmartProxy instances before retry setup and prune expired certificate backoff cache entries
|
||||||
|
- add periodic sweeping and shutdown cleanup for stale RADIUS accounting sessions
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.9.0 - feat(dcrouter)
|
||||||
|
add service manager lifecycle orchestration and health-based ops status reporting
|
||||||
|
|
||||||
|
- register dcrouter components with a taskbuffer ServiceManager using dependencies, retries, and critical/optional service roles
|
||||||
|
- update ops stats health output to reflect aggregated service manager state and per-service error or retry details
|
||||||
|
- add @push.rocks/taskbuffer to shared plugins and project dependencies for service lifecycle management
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.11 - fix(deps)
|
||||||
|
bump @push.rocks/smartproxy to ^25.17.10
|
||||||
|
|
||||||
|
- Updates the @push.rocks/smartproxy dependency from ^25.17.9 to ^25.17.10 in package.json
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.10 - fix(deps)
|
||||||
|
bump @push.rocks/smartproxy to ^25.17.9
|
||||||
|
|
||||||
|
- Updates @push.rocks/smartproxy from ^25.17.8 to ^25.17.9 in package.json
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.9 - fix(deps)
|
||||||
|
bump @push.rocks/smartproxy to ^25.17.8
|
||||||
|
|
||||||
|
- Updates the @push.rocks/smartproxy dependency from ^25.17.7 to ^25.17.8.
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.8 - fix(deps)
|
||||||
|
bump @push.rocks/smartproxy to ^25.17.7
|
||||||
|
|
||||||
|
- Updates the @push.rocks/smartproxy dependency from ^25.17.4 to ^25.17.7 in package.json.
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.7 - fix(deps)
|
||||||
|
bump @push.rocks/smartproxy to ^25.17.4
|
||||||
|
|
||||||
|
- updates @push.rocks/smartproxy from ^25.17.3 to ^25.17.4 in package.json
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.6 - fix(deps)
|
||||||
|
bump @push.rocks/smartproxy to ^25.17.3
|
||||||
|
|
||||||
|
- updates @push.rocks/smartproxy from ^25.17.1 to ^25.17.3 in package.json
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.5 - fix(deps)
|
||||||
|
bump @push.rocks/smartproxy to ^25.17.1
|
||||||
|
|
||||||
|
- Updates the @push.rocks/smartproxy dependency from ^25.17.0 to ^25.17.1.
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.4 - fix(deps)
|
||||||
|
bump @serve.zone/remoteingress to ^4.14.0
|
||||||
|
|
||||||
|
- Updates the @serve.zone/remoteingress dependency from ^4.13.2 to ^4.14.0 in package.json.
|
||||||
|
|
||||||
|
## 2026-03-20 - 11.8.3 - fix(deps)
|
||||||
|
bump @serve.zone/remoteingress to ^4.13.2
|
||||||
|
|
||||||
|
- Updates the @serve.zone/remoteingress dependency from ^4.13.1 to ^4.13.2.
|
||||||
|
|
||||||
|
## 2026-03-19 - 11.8.2 - fix(deps)
|
||||||
|
bump smartproxy and remoteingress dependencies
|
||||||
|
|
||||||
|
- updates @push.rocks/smartproxy from ^25.16.3 to ^25.17.0
|
||||||
|
- updates @serve.zone/remoteingress from ^4.13.0 to ^4.13.1
|
||||||
|
|
||||||
|
## 2026-03-19 - 11.8.1 - fix(dcrouter)
|
||||||
|
use constructor routes for remote ingress setup and bump smartproxy dependency
|
||||||
|
|
||||||
|
- Switch remote ingress initialization to use constructorRoutes instead of smartProxyConfig routes so derived edge ports are based on the active route set.
|
||||||
|
- Update @push.rocks/smartproxy from ^25.16.2 to ^25.16.3.
|
||||||
|
|
||||||
|
## 2026-03-19 - 11.8.0 - feat(remoteingress)
|
||||||
|
add UDP listen port derivation and edge configuration support
|
||||||
|
|
||||||
|
- derive UDP ports from remote ingress routes using transport 'udp' or 'all'
|
||||||
|
- expose effective UDP listen ports in allowed edge payloads and remote ingress interfaces
|
||||||
|
- update @push.rocks/smartproxy to ^25.16.2
|
||||||
|
|
||||||
## 2026-03-19 - 11.7.1 - fix(deps)
|
## 2026-03-19 - 11.7.1 - fix(deps)
|
||||||
bump @push.rocks/smartproxy to ^25.16.0
|
bump @push.rocks/smartproxy to ^25.16.0
|
||||||
|
|
||||||
|
|||||||
15
package.json
15
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@serve.zone/dcrouter",
|
"name": "@serve.zone/dcrouter",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "11.7.1",
|
"version": "11.10.4",
|
||||||
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
@@ -25,19 +25,19 @@
|
|||||||
"@git.zone/tsbuild": "^4.3.0",
|
"@git.zone/tsbuild": "^4.3.0",
|
||||||
"@git.zone/tsbundle": "^2.9.1",
|
"@git.zone/tsbundle": "^2.9.1",
|
||||||
"@git.zone/tsrun": "^2.0.1",
|
"@git.zone/tsrun": "^2.0.1",
|
||||||
"@git.zone/tstest": "^3.5.0",
|
"@git.zone/tstest": "^3.5.1",
|
||||||
"@git.zone/tswatch": "^3.3.0",
|
"@git.zone/tswatch": "^3.3.0",
|
||||||
"@types/node": "^25.5.0"
|
"@types/node": "^25.5.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@api.global/typedrequest": "^3.3.0",
|
"@api.global/typedrequest": "^3.3.0",
|
||||||
"@api.global/typedrequest-interfaces": "^3.0.19",
|
"@api.global/typedrequest-interfaces": "^3.0.19",
|
||||||
"@api.global/typedserver": "^8.4.2",
|
"@api.global/typedserver": "^8.4.6",
|
||||||
"@api.global/typedsocket": "^4.1.2",
|
"@api.global/typedsocket": "^4.1.2",
|
||||||
"@apiclient.xyz/cloudflare": "^7.1.0",
|
"@apiclient.xyz/cloudflare": "^7.1.0",
|
||||||
"@design.estate/dees-catalog": "^3.48.5",
|
"@design.estate/dees-catalog": "^3.48.5",
|
||||||
"@design.estate/dees-element": "^2.2.3",
|
"@design.estate/dees-element": "^2.2.3",
|
||||||
"@push.rocks/lik": "^6.3.1",
|
"@push.rocks/lik": "^6.4.0",
|
||||||
"@push.rocks/projectinfo": "^5.0.2",
|
"@push.rocks/projectinfo": "^5.0.2",
|
||||||
"@push.rocks/qenv": "^6.1.3",
|
"@push.rocks/qenv": "^6.1.3",
|
||||||
"@push.rocks/smartacme": "^9.3.0",
|
"@push.rocks/smartacme": "^9.3.0",
|
||||||
@@ -47,21 +47,22 @@
|
|||||||
"@push.rocks/smartguard": "^3.1.0",
|
"@push.rocks/smartguard": "^3.1.0",
|
||||||
"@push.rocks/smartjwt": "^2.2.1",
|
"@push.rocks/smartjwt": "^2.2.1",
|
||||||
"@push.rocks/smartlog": "^3.2.1",
|
"@push.rocks/smartlog": "^3.2.1",
|
||||||
"@push.rocks/smartmetrics": "^3.0.2",
|
"@push.rocks/smartmetrics": "^3.0.3",
|
||||||
"@push.rocks/smartmongo": "^5.1.0",
|
"@push.rocks/smartmongo": "^5.1.0",
|
||||||
"@push.rocks/smartmta": "^5.3.1",
|
"@push.rocks/smartmta": "^5.3.1",
|
||||||
"@push.rocks/smartnetwork": "^4.4.0",
|
"@push.rocks/smartnetwork": "^4.4.0",
|
||||||
"@push.rocks/smartpath": "^6.0.0",
|
"@push.rocks/smartpath": "^6.0.0",
|
||||||
"@push.rocks/smartpromise": "^4.2.3",
|
"@push.rocks/smartpromise": "^4.2.3",
|
||||||
"@push.rocks/smartproxy": "^25.16.0",
|
"@push.rocks/smartproxy": "^26.2.1",
|
||||||
"@push.rocks/smartradius": "^1.1.1",
|
"@push.rocks/smartradius": "^1.1.1",
|
||||||
"@push.rocks/smartrequest": "^5.0.1",
|
"@push.rocks/smartrequest": "^5.0.1",
|
||||||
"@push.rocks/smartrx": "^3.0.10",
|
"@push.rocks/smartrx": "^3.0.10",
|
||||||
"@push.rocks/smartstate": "^2.2.0",
|
"@push.rocks/smartstate": "^2.2.0",
|
||||||
"@push.rocks/smartunique": "^3.0.9",
|
"@push.rocks/smartunique": "^3.0.9",
|
||||||
|
"@push.rocks/taskbuffer": "^8.0.2",
|
||||||
"@serve.zone/catalog": "^2.9.0",
|
"@serve.zone/catalog": "^2.9.0",
|
||||||
"@serve.zone/interfaces": "^5.3.0",
|
"@serve.zone/interfaces": "^5.3.0",
|
||||||
"@serve.zone/remoteingress": "^4.13.0",
|
"@serve.zone/remoteingress": "^4.14.1",
|
||||||
"@tsclass/tsclass": "^9.4.0",
|
"@tsclass/tsclass": "^9.4.0",
|
||||||
"lru-cache": "^11.2.7",
|
"lru-cache": "^11.2.7",
|
||||||
"uuid": "^13.0.0"
|
"uuid": "^13.0.0"
|
||||||
|
|||||||
247
pnpm-lock.yaml
generated
247
pnpm-lock.yaml
generated
@@ -15,11 +15,11 @@ importers:
|
|||||||
specifier: ^3.0.19
|
specifier: ^3.0.19
|
||||||
version: 3.0.19
|
version: 3.0.19
|
||||||
'@api.global/typedserver':
|
'@api.global/typedserver':
|
||||||
specifier: ^8.4.2
|
specifier: ^8.4.6
|
||||||
version: 8.4.2(@tiptap/pm@2.27.2)
|
version: 8.4.6(@tiptap/pm@2.27.2)
|
||||||
'@api.global/typedsocket':
|
'@api.global/typedsocket':
|
||||||
specifier: ^4.1.2
|
specifier: ^4.1.2
|
||||||
version: 4.1.2(@push.rocks/smartserve@2.0.1)
|
version: 4.1.2(@push.rocks/smartserve@2.0.3)
|
||||||
'@apiclient.xyz/cloudflare':
|
'@apiclient.xyz/cloudflare':
|
||||||
specifier: ^7.1.0
|
specifier: ^7.1.0
|
||||||
version: 7.1.0
|
version: 7.1.0
|
||||||
@@ -30,8 +30,8 @@ importers:
|
|||||||
specifier: ^2.2.3
|
specifier: ^2.2.3
|
||||||
version: 2.2.3
|
version: 2.2.3
|
||||||
'@push.rocks/lik':
|
'@push.rocks/lik':
|
||||||
specifier: ^6.3.1
|
specifier: ^6.4.0
|
||||||
version: 6.3.1
|
version: 6.4.0
|
||||||
'@push.rocks/projectinfo':
|
'@push.rocks/projectinfo':
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
@@ -60,8 +60,8 @@ importers:
|
|||||||
specifier: ^3.2.1
|
specifier: ^3.2.1
|
||||||
version: 3.2.1
|
version: 3.2.1
|
||||||
'@push.rocks/smartmetrics':
|
'@push.rocks/smartmetrics':
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.3
|
||||||
version: 3.0.2
|
version: 3.0.3
|
||||||
'@push.rocks/smartmongo':
|
'@push.rocks/smartmongo':
|
||||||
specifier: ^5.1.0
|
specifier: ^5.1.0
|
||||||
version: 5.1.0(socks@2.8.7)
|
version: 5.1.0(socks@2.8.7)
|
||||||
@@ -78,8 +78,8 @@ importers:
|
|||||||
specifier: ^4.2.3
|
specifier: ^4.2.3
|
||||||
version: 4.2.3
|
version: 4.2.3
|
||||||
'@push.rocks/smartproxy':
|
'@push.rocks/smartproxy':
|
||||||
specifier: ^25.16.0
|
specifier: ^26.2.1
|
||||||
version: 25.16.0
|
version: 26.2.1
|
||||||
'@push.rocks/smartradius':
|
'@push.rocks/smartradius':
|
||||||
specifier: ^1.1.1
|
specifier: ^1.1.1
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
@@ -95,6 +95,9 @@ importers:
|
|||||||
'@push.rocks/smartunique':
|
'@push.rocks/smartunique':
|
||||||
specifier: ^3.0.9
|
specifier: ^3.0.9
|
||||||
version: 3.0.9
|
version: 3.0.9
|
||||||
|
'@push.rocks/taskbuffer':
|
||||||
|
specifier: ^8.0.2
|
||||||
|
version: 8.0.2
|
||||||
'@serve.zone/catalog':
|
'@serve.zone/catalog':
|
||||||
specifier: ^2.9.0
|
specifier: ^2.9.0
|
||||||
version: 2.9.0(@tiptap/pm@2.27.2)
|
version: 2.9.0(@tiptap/pm@2.27.2)
|
||||||
@@ -102,8 +105,8 @@ importers:
|
|||||||
specifier: ^5.3.0
|
specifier: ^5.3.0
|
||||||
version: 5.3.0
|
version: 5.3.0
|
||||||
'@serve.zone/remoteingress':
|
'@serve.zone/remoteingress':
|
||||||
specifier: ^4.13.0
|
specifier: ^4.14.1
|
||||||
version: 4.13.0
|
version: 4.14.1
|
||||||
'@tsclass/tsclass':
|
'@tsclass/tsclass':
|
||||||
specifier: ^9.4.0
|
specifier: ^9.4.0
|
||||||
version: 9.5.0
|
version: 9.5.0
|
||||||
@@ -124,8 +127,8 @@ importers:
|
|||||||
specifier: ^2.0.1
|
specifier: ^2.0.1
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
'@git.zone/tstest':
|
'@git.zone/tstest':
|
||||||
specifier: ^3.5.0
|
specifier: ^3.5.1
|
||||||
version: 3.5.0(socks@2.8.7)(typescript@5.9.3)
|
version: 3.5.1(socks@2.8.7)(typescript@5.9.3)
|
||||||
'@git.zone/tswatch':
|
'@git.zone/tswatch':
|
||||||
specifier: ^3.3.0
|
specifier: ^3.3.0
|
||||||
version: 3.3.0(@tiptap/pm@2.27.2)
|
version: 3.3.0(@tiptap/pm@2.27.2)
|
||||||
@@ -144,8 +147,8 @@ packages:
|
|||||||
'@api.global/typedrequest@3.3.0':
|
'@api.global/typedrequest@3.3.0':
|
||||||
resolution: {integrity: sha512-Jwobqla+9k2IBG0duwrCFtc6GU6wsvHS3f0gJJsxTrpapylBW1YSF7NnGHPGs7F9hbATsO6IoUBpR2ScoKyGJA==}
|
resolution: {integrity: sha512-Jwobqla+9k2IBG0duwrCFtc6GU6wsvHS3f0gJJsxTrpapylBW1YSF7NnGHPGs7F9hbATsO6IoUBpR2ScoKyGJA==}
|
||||||
|
|
||||||
'@api.global/typedserver@8.4.2':
|
'@api.global/typedserver@8.4.6':
|
||||||
resolution: {integrity: sha512-eESOcWvrbqkshR4s4OeTX1AK74bNCeGgiRebKgjxIzJ+b0+rkPQyn2DOaMtyXjFZRNgRHyytLm5Iqj5fdazeqw==}
|
resolution: {integrity: sha512-kSzjzM0TenzRL73rmDiwsJR/SFJ3nPI7zFC9KWxO7nIhyMo5wgO7UMVCpjXrTYMK6c4HwbhBxEPIJb4prqakww==}
|
||||||
|
|
||||||
'@api.global/typedsocket@4.1.2':
|
'@api.global/typedsocket@4.1.2':
|
||||||
resolution: {integrity: sha512-fZFuJY9ucFCICjF4wi6OvK8drsv6UcwVVsfamOT1HxFj7OBOYw6QHOceQ+cAQ8IrWbX817sf8gzlesl+jlG8JA==}
|
resolution: {integrity: sha512-fZFuJY9ucFCICjF4wi6OvK8drsv6UcwVVsfamOT1HxFj7OBOYw6QHOceQ+cAQ8IrWbX817sf8gzlesl+jlG8JA==}
|
||||||
@@ -554,8 +557,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-NEcnsjvlC1o3Z6SS3VhKCf6Ev+Sh4EAinmggslrIR/ppMrvjDbXNFXoyr3PB+GLeSAR0JRZ1fGvVYjpEzjBdIg==}
|
resolution: {integrity: sha512-NEcnsjvlC1o3Z6SS3VhKCf6Ev+Sh4EAinmggslrIR/ppMrvjDbXNFXoyr3PB+GLeSAR0JRZ1fGvVYjpEzjBdIg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@git.zone/tstest@3.5.0':
|
'@git.zone/tstest@3.5.1':
|
||||||
resolution: {integrity: sha512-ugIJzdVkbgqSSw08SZajE7TB01GIYjEAmIy67O5skhvOyszGifwzJdR+8dS1VbQGlUUWQZMGQ2IowllHbAZYJQ==}
|
resolution: {integrity: sha512-R1T3Tr9zun0B5bFq8qK8/KZ2uqHZHfDPB3/mhoL5ekwxGSI4InX5sXMpbNuhw2EdNZ7rMAHNCyeSLz2PwFmNZw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@git.zone/tswatch@3.3.0':
|
'@git.zone/tswatch@3.3.0':
|
||||||
@@ -1064,8 +1067,8 @@ packages:
|
|||||||
'@push.rocks/levelcache@3.2.0':
|
'@push.rocks/levelcache@3.2.0':
|
||||||
resolution: {integrity: sha512-Ch0Oguta2I0SVi704kHghhBcgfyfS92ua1elRu9d8X1/9LMRYuqvvBAnyXyFxQzI3S8q8QC6EkRdd8CAAYSzRg==}
|
resolution: {integrity: sha512-Ch0Oguta2I0SVi704kHghhBcgfyfS92ua1elRu9d8X1/9LMRYuqvvBAnyXyFxQzI3S8q8QC6EkRdd8CAAYSzRg==}
|
||||||
|
|
||||||
'@push.rocks/lik@6.3.1':
|
'@push.rocks/lik@6.4.0':
|
||||||
resolution: {integrity: sha512-UWDwGBaVx5yPtAFXqDDBtQZCzETUOA/7myQIXb+YBsuiIw4yQuhNZ23uY2ChQH2Zn6DLqdNSgQcYC0WywMZBNQ==}
|
resolution: {integrity: sha512-GCdXyF2a6NP+i0W6Mib1PjtA6JGrl6Ae17SbaQwqTscn4JHNta6xm9r+D8/b83XGZsoU903FlJZli3YqJCxT9Q==}
|
||||||
|
|
||||||
'@push.rocks/mongodump@1.1.0':
|
'@push.rocks/mongodump@1.1.0':
|
||||||
resolution: {integrity: sha512-kW0ZUGyf1e4nwloVwBQjNId+MzgTcNS834C+RxH21i1NqyOubbpWZtJtPP+K+s35nSJRyCTy3ICfBMdDBTAm2w==}
|
resolution: {integrity: sha512-kW0ZUGyf1e4nwloVwBQjNId+MzgTcNS834C+RxH21i1NqyOubbpWZtJtPP+K+s35nSJRyCTy3ICfBMdDBTAm2w==}
|
||||||
@@ -1202,8 +1205,8 @@ packages:
|
|||||||
'@push.rocks/smartmatch@2.0.0':
|
'@push.rocks/smartmatch@2.0.0':
|
||||||
resolution: {integrity: sha512-MBzP++1yNIBeox71X6VxpIgZ8m4bXnJpZJ4nWVH6IWpmO38MXTu4X0QF8tQnyT4LFcwvc9iiWaD15cstHa7Mmw==}
|
resolution: {integrity: sha512-MBzP++1yNIBeox71X6VxpIgZ8m4bXnJpZJ4nWVH6IWpmO38MXTu4X0QF8tQnyT4LFcwvc9iiWaD15cstHa7Mmw==}
|
||||||
|
|
||||||
'@push.rocks/smartmetrics@3.0.2':
|
'@push.rocks/smartmetrics@3.0.3':
|
||||||
resolution: {integrity: sha512-bW60TrdCubsZwsYK1+lE9y+OoXN8MfB7bhSASlTKtwhExdCbjXYXnSt9W7zerD7HbsUNOsvejIjX9q4oju+P2g==}
|
resolution: {integrity: sha512-RYY4NOla3kraZYVF9TBHgIz4/hSkqVDVNP7tLwhLK5mGBPBy8I/9NWXX6txZKQw6QihP85YD8mWUuUu2xS4D6Q==}
|
||||||
|
|
||||||
'@push.rocks/smartmime@1.0.6':
|
'@push.rocks/smartmime@1.0.6':
|
||||||
resolution: {integrity: sha512-PHd+I4UcsnOATNg8wjDsSAmmJ4CwQFrQCNzd0HSJMs4ZpiK3Ya91almd6GLpDPU370U4HFh4FaPF4eEAI6vkJQ==}
|
resolution: {integrity: sha512-PHd+I4UcsnOATNg8wjDsSAmmJ4CwQFrQCNzd0HSJMs4ZpiK3Ya91almd6GLpDPU370U4HFh4FaPF4eEAI6vkJQ==}
|
||||||
@@ -1256,8 +1259,8 @@ packages:
|
|||||||
'@push.rocks/smartpromise@4.2.3':
|
'@push.rocks/smartpromise@4.2.3':
|
||||||
resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==}
|
resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==}
|
||||||
|
|
||||||
'@push.rocks/smartproxy@25.16.0':
|
'@push.rocks/smartproxy@26.2.1':
|
||||||
resolution: {integrity: sha512-X3XtOjbYUHukKeZDBWO2g69k3otYI8JsA8RQdQySTuAKPnqj4QjhFJRfkgc+jGgWaWk3j5Mq5RMGsoVOmu4VGA==}
|
resolution: {integrity: sha512-QLngysoSFFb2KkXexmqcBmzC4qepcVTQQ1M5GZYMLL9JgvDI+j7oh1KAMI1zXmJtffTNwaZA7byS5XiZgznJKA==}
|
||||||
|
|
||||||
'@push.rocks/smartpuppeteer@2.0.5':
|
'@push.rocks/smartpuppeteer@2.0.5':
|
||||||
resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==}
|
resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==}
|
||||||
@@ -1286,11 +1289,14 @@ packages:
|
|||||||
'@push.rocks/smartserve@2.0.1':
|
'@push.rocks/smartserve@2.0.1':
|
||||||
resolution: {integrity: sha512-YQb2qexfCzCqOlLWBBXKMg6xG4zahCPAxomz/KEKAwHtW6wMTtuHKSTSkRTQ0vl9jssLMAmRz2OyafiL9XGJXQ==}
|
resolution: {integrity: sha512-YQb2qexfCzCqOlLWBBXKMg6xG4zahCPAxomz/KEKAwHtW6wMTtuHKSTSkRTQ0vl9jssLMAmRz2OyafiL9XGJXQ==}
|
||||||
|
|
||||||
|
'@push.rocks/smartserve@2.0.3':
|
||||||
|
resolution: {integrity: sha512-PttdFlh61lsDNSRvRCSlKjRzuxgD3WP2XLuBNXu1hLfqLpQXDESj0ZCRPDZslLZsyFT5aHP9godb4D4L3bzHWA==}
|
||||||
|
|
||||||
'@push.rocks/smartshell@3.3.8':
|
'@push.rocks/smartshell@3.3.8':
|
||||||
resolution: {integrity: sha512-t9J/py0vnea4ZtOs7Anc9dc6lcvg6EDvYBw5eE1mB+KUWxMQf/ROIQwWMo6B9SMNY4JS2UwvfuJQJ8makP/7Tg==}
|
resolution: {integrity: sha512-t9J/py0vnea4ZtOs7Anc9dc6lcvg6EDvYBw5eE1mB+KUWxMQf/ROIQwWMo6B9SMNY4JS2UwvfuJQJ8makP/7Tg==}
|
||||||
|
|
||||||
'@push.rocks/smartsitemap@2.0.4':
|
'@push.rocks/smartsitemap@4.0.1':
|
||||||
resolution: {integrity: sha512-76dYWG/o/EjV4vYCK7ZKM35T9xgrI+oHEiiIE6E2MDaFIU6QnSfciTfbscH5nc0vxx8Ah+I0HPEJO94BM2S39w==}
|
resolution: {integrity: sha512-FcNFB4CgGX98qP+bkKmVBTQoQomLfRXTTRAn8DklEaFyhWzak6Rl5AHXkmu7ZOZUgrpgvCmCx2q21uwmPOajbQ==}
|
||||||
|
|
||||||
'@push.rocks/smartspawn@3.0.3':
|
'@push.rocks/smartspawn@3.0.3':
|
||||||
resolution: {integrity: sha512-DyrGPV69wwOiJgKkyruk5hS3UEGZ99xFAqBE9O2nM8VXCRLbbty3xt1Ug5Z092ZZmJYaaGMSnMw3ijyZJFCT0Q==}
|
resolution: {integrity: sha512-DyrGPV69wwOiJgKkyruk5hS3UEGZ99xFAqBE9O2nM8VXCRLbbty3xt1Ug5Z092ZZmJYaaGMSnMw3ijyZJFCT0Q==}
|
||||||
@@ -1326,6 +1332,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-TeZ1PGBoBMpC4/CK8StIj5InEiFfKp7xWJSm3aYMjB/uaoeRP0vXqv1ORIC/TKYGJuEDuAXUsit8tZVjn0qT1Q==}
|
resolution: {integrity: sha512-TeZ1PGBoBMpC4/CK8StIj5InEiFfKp7xWJSm3aYMjB/uaoeRP0vXqv1ORIC/TKYGJuEDuAXUsit8tZVjn0qT1Q==}
|
||||||
engines: {node: '>=20.0.0'}
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
|
'@push.rocks/smartwatch@6.4.0':
|
||||||
|
resolution: {integrity: sha512-KDswRgE/siBmZRCsRA07MtW5oF4c9uQEBkwTGPIWneHzksbCDsvs/7agKFEL7WnNifLNwo8w1K1qoiVWkX1fvw==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
'@push.rocks/smartxml@2.0.0':
|
'@push.rocks/smartxml@2.0.0':
|
||||||
resolution: {integrity: sha512-1d06zYJX4Zt8s5w5qFOUg2LAEz9ykrh9d6CQPK4WAgOBIefb1xzVEWHc7yoxicc2OkzNgC3IBCEg3s6BncZKWw==}
|
resolution: {integrity: sha512-1d06zYJX4Zt8s5w5qFOUg2LAEz9ykrh9d6CQPK4WAgOBIefb1xzVEWHc7yoxicc2OkzNgC3IBCEg3s6BncZKWw==}
|
||||||
|
|
||||||
@@ -1341,6 +1351,9 @@ packages:
|
|||||||
'@push.rocks/taskbuffer@6.1.2':
|
'@push.rocks/taskbuffer@6.1.2':
|
||||||
resolution: {integrity: sha512-sdqKd8N/GidztQ1k3r8A86rLvD8Afyir5FjYCNJXDD9837JLoqzHaOKGltUSBsCGh2gjsZn6GydsY6HhXQgvZQ==}
|
resolution: {integrity: sha512-sdqKd8N/GidztQ1k3r8A86rLvD8Afyir5FjYCNJXDD9837JLoqzHaOKGltUSBsCGh2gjsZn6GydsY6HhXQgvZQ==}
|
||||||
|
|
||||||
|
'@push.rocks/taskbuffer@8.0.2':
|
||||||
|
resolution: {integrity: sha512-SRCAzrSHysW5XEjwZ494V60ybdpOo/s96jDD3sn7SkYolzg2Pboh+SW5Q7SVNcdkP4b9wCEizOYe9CB3vj3W6w==}
|
||||||
|
|
||||||
'@push.rocks/webrequest@4.0.5':
|
'@push.rocks/webrequest@4.0.5':
|
||||||
resolution: {integrity: sha512-wVSCaXqJ9Vh+rbwVz0wDl46dYz4rnwwSrm5vbVXKbuH6oKTPF0YRoujeJPqRltIn64RVGdLeY9/6ix+ZCrzhsg==}
|
resolution: {integrity: sha512-wVSCaXqJ9Vh+rbwVz0wDl46dYz4rnwwSrm5vbVXKbuH6oKTPF0YRoujeJPqRltIn64RVGdLeY9/6ix+ZCrzhsg==}
|
||||||
|
|
||||||
@@ -1550,8 +1563,8 @@ packages:
|
|||||||
'@serve.zone/interfaces@5.3.0':
|
'@serve.zone/interfaces@5.3.0':
|
||||||
resolution: {integrity: sha512-venO7wtDR9ixzD9NhdERBGjNKbFA5LL0yHw4eqGh0UpmvtXVc3SFG0uuHDilOKMZqZ8bttV88qVsFy1aSTJrtA==}
|
resolution: {integrity: sha512-venO7wtDR9ixzD9NhdERBGjNKbFA5LL0yHw4eqGh0UpmvtXVc3SFG0uuHDilOKMZqZ8bttV88qVsFy1aSTJrtA==}
|
||||||
|
|
||||||
'@serve.zone/remoteingress@4.13.0':
|
'@serve.zone/remoteingress@4.14.1':
|
||||||
resolution: {integrity: sha512-Gw/yIgCukh3kImIco3u9B+b2cQP4l88RgCdP7NhYpwTDrI9jrsKmrzq0cRXo/Lnja35RZ1D7fBmNvaaAqEToVQ==}
|
resolution: {integrity: sha512-rYM4msFwo9SPxgNp/qXkJCQ8uXvQiMcH3cQEyciLKJ+7HwqKwQLCK4kbl45r/rzRAVOjyxXi0ae3hjgOBzTbyw==}
|
||||||
|
|
||||||
'@sindresorhus/is@5.6.0':
|
'@sindresorhus/is@5.6.0':
|
||||||
resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==}
|
resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==}
|
||||||
@@ -2041,9 +2054,6 @@ packages:
|
|||||||
'@types/semver@7.7.1':
|
'@types/semver@7.7.1':
|
||||||
resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==}
|
resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==}
|
||||||
|
|
||||||
'@types/symbol-tree@3.2.5':
|
|
||||||
resolution: {integrity: sha512-zXnnyENt1TYQcS21MkPaJCVjfcPq7p7yc5mo5JACuumXp6sly5jnlS0IokHd+xmmuCbx6V7JqkMBpswR+nZAcw==}
|
|
||||||
|
|
||||||
'@types/tar-stream@3.1.4':
|
'@types/tar-stream@3.1.4':
|
||||||
resolution: {integrity: sha512-921gW0+g29mCJX0fRvqeHzBlE/XclDaAG0Ousy1LCghsOhvaKacDeRGEVzQP9IPfKn8Vysy7FEXAIxycpc/CMg==}
|
resolution: {integrity: sha512-921gW0+g29mCJX0fRvqeHzBlE/XclDaAG0Ousy1LCghsOhvaKacDeRGEVzQP9IPfKn8Vysy7FEXAIxycpc/CMg==}
|
||||||
|
|
||||||
@@ -2620,16 +2630,16 @@ packages:
|
|||||||
fast-xml-builder@1.1.4:
|
fast-xml-builder@1.1.4:
|
||||||
resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==}
|
resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==}
|
||||||
|
|
||||||
fast-xml-parser@4.5.4:
|
fast-xml-parser@4.5.5:
|
||||||
resolution: {integrity: sha512-jE8ugADnYOBsu1uaoayVl1tVKAMNOXyjwvv2U6udEA2ORBhDooJDWoGxTkhd4Qn4yh59JVVt/pKXtjPwx9OguQ==}
|
resolution: {integrity: sha512-cK9c5I/DwIOI7/Q7AlGN3DuTdwN61gwSfL8rvuVPK+0mcCNHHGxRrpiFtaZZRfRMJL3Gl8B2AFlBG6qXf03w9A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
fast-xml-parser@5.4.1:
|
fast-xml-parser@5.4.1:
|
||||||
resolution: {integrity: sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==}
|
resolution: {integrity: sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
fast-xml-parser@5.5.6:
|
fast-xml-parser@5.5.8:
|
||||||
resolution: {integrity: sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw==}
|
resolution: {integrity: sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
fault@2.0.1:
|
fault@2.0.1:
|
||||||
@@ -3546,6 +3556,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==}
|
resolution: {integrity: sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
|
|
||||||
|
path-expression-matcher@1.2.0:
|
||||||
|
resolution: {integrity: sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
|
||||||
path-is-absolute@1.0.1:
|
path-is-absolute@1.0.1:
|
||||||
resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=}
|
resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -3980,6 +3994,9 @@ packages:
|
|||||||
strnum@2.2.0:
|
strnum@2.2.0:
|
||||||
resolution: {integrity: sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==}
|
resolution: {integrity: sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==}
|
||||||
|
|
||||||
|
strnum@2.2.2:
|
||||||
|
resolution: {integrity: sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==}
|
||||||
|
|
||||||
strtok3@10.3.4:
|
strtok3@10.3.4:
|
||||||
resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==}
|
resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4251,6 +4268,18 @@ packages:
|
|||||||
utf-8-validate:
|
utf-8-validate:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
ws@8.20.0:
|
||||||
|
resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
bufferutil: ^4.0.1
|
||||||
|
utf-8-validate: '>=5.0.2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
bufferutil:
|
||||||
|
optional: true
|
||||||
|
utf-8-validate:
|
||||||
|
optional: true
|
||||||
|
|
||||||
xml-parse-from-string@1.0.1:
|
xml-parse-from-string@1.0.1:
|
||||||
resolution: {integrity: sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==}
|
resolution: {integrity: sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==}
|
||||||
|
|
||||||
@@ -4274,8 +4303,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
yaml@2.8.2:
|
yaml@2.8.3:
|
||||||
resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
|
resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==}
|
||||||
engines: {node: '>= 14.6'}
|
engines: {node: '>= 14.6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -4318,7 +4347,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
'@api.global/typedrequest-interfaces': 3.0.19
|
||||||
'@push.rocks/isounique': 1.0.5
|
'@push.rocks/isounique': 1.0.5
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartbuffer': 3.0.5
|
'@push.rocks/smartbuffer': 3.0.5
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartguard': 3.1.0
|
'@push.rocks/smartguard': 3.1.0
|
||||||
@@ -4326,21 +4355,21 @@ snapshots:
|
|||||||
'@push.rocks/webrequest': 4.0.5
|
'@push.rocks/webrequest': 4.0.5
|
||||||
'@push.rocks/webstream': 1.0.10
|
'@push.rocks/webstream': 1.0.10
|
||||||
|
|
||||||
'@api.global/typedserver@8.4.2(@tiptap/pm@2.27.2)':
|
'@api.global/typedserver@8.4.6(@tiptap/pm@2.27.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest': 3.3.0
|
'@api.global/typedrequest': 3.3.0
|
||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
'@api.global/typedrequest-interfaces': 3.0.19
|
||||||
'@api.global/typedsocket': 4.1.2(@push.rocks/smartserve@2.0.1)
|
'@api.global/typedsocket': 4.1.2(@push.rocks/smartserve@2.0.3)
|
||||||
'@cloudflare/workers-types': 4.20260317.1
|
'@cloudflare/workers-types': 4.20260317.1
|
||||||
'@design.estate/dees-catalog': 3.49.0(@tiptap/pm@2.27.2)
|
'@design.estate/dees-catalog': 3.49.0(@tiptap/pm@2.27.2)
|
||||||
'@design.estate/dees-comms': 1.0.30
|
'@design.estate/dees-comms': 1.0.30
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartenv': 6.0.0
|
'@push.rocks/smartenv': 6.0.0
|
||||||
'@push.rocks/smartfeed': 1.4.0
|
'@push.rocks/smartfeed': 1.4.0
|
||||||
'@push.rocks/smartfile': 13.1.2
|
'@push.rocks/smartfile': 13.1.2
|
||||||
'@push.rocks/smartfs': 1.5.0
|
'@push.rocks/smartfs': 1.5.0
|
||||||
'@push.rocks/smartjson': 5.2.0
|
'@push.rocks/smartjson': 6.0.0
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
'@push.rocks/smartlog-destination-devtools': 1.0.12
|
'@push.rocks/smartlog-destination-devtools': 1.0.12
|
||||||
'@push.rocks/smartlog-interfaces': 3.0.2
|
'@push.rocks/smartlog-interfaces': 3.0.2
|
||||||
@@ -4353,12 +4382,12 @@ snapshots:
|
|||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartrequest': 5.0.1
|
'@push.rocks/smartrequest': 5.0.1
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
'@push.rocks/smartserve': 2.0.1
|
'@push.rocks/smartserve': 2.0.3
|
||||||
'@push.rocks/smartsitemap': 2.0.4
|
'@push.rocks/smartsitemap': 4.0.1
|
||||||
'@push.rocks/smartstream': 3.4.0
|
'@push.rocks/smartstream': 3.4.0
|
||||||
'@push.rocks/smarttime': 4.2.3
|
'@push.rocks/smarttime': 4.2.3
|
||||||
'@push.rocks/smartwatch': 6.3.0
|
'@push.rocks/smartwatch': 6.4.0
|
||||||
'@push.rocks/taskbuffer': 3.5.0
|
'@push.rocks/taskbuffer': 8.0.2
|
||||||
'@push.rocks/webrequest': 4.0.5
|
'@push.rocks/webrequest': 4.0.5
|
||||||
'@push.rocks/webstore': 2.0.20
|
'@push.rocks/webstore': 2.0.20
|
||||||
'@tsclass/tsclass': 9.5.0
|
'@tsclass/tsclass': 9.5.0
|
||||||
@@ -4372,7 +4401,7 @@ snapshots:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
'@api.global/typedsocket@4.1.2(@push.rocks/smartserve@2.0.1)':
|
'@api.global/typedsocket@4.1.2(@push.rocks/smartserve@2.0.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest': 3.3.0
|
'@api.global/typedrequest': 3.3.0
|
||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
'@api.global/typedrequest-interfaces': 3.0.19
|
||||||
@@ -4381,7 +4410,7 @@ snapshots:
|
|||||||
'@push.rocks/smartjson': 5.2.0
|
'@push.rocks/smartjson': 5.2.0
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
'@push.rocks/smartserve': 2.0.1
|
'@push.rocks/smartserve': 2.0.3
|
||||||
'@push.rocks/smartstring': 4.1.0
|
'@push.rocks/smartstring': 4.1.0
|
||||||
'@push.rocks/smarturl': 3.1.0
|
'@push.rocks/smarturl': 3.1.0
|
||||||
|
|
||||||
@@ -4907,7 +4936,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest': 3.3.0
|
'@api.global/typedrequest': 3.3.0
|
||||||
'@design.estate/dees-comms': 1.0.30
|
'@design.estate/dees-comms': 1.0.30
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartjson': 6.0.0
|
'@push.rocks/smartjson': 6.0.0
|
||||||
'@push.rocks/smartmarkdown': 3.0.3
|
'@push.rocks/smartmarkdown': 3.0.3
|
||||||
@@ -5142,7 +5171,7 @@ snapshots:
|
|||||||
'@push.rocks/smartshell': 3.3.8
|
'@push.rocks/smartshell': 3.3.8
|
||||||
tsx: 4.21.0
|
tsx: 4.21.0
|
||||||
|
|
||||||
'@git.zone/tstest@3.5.0(socks@2.8.7)(typescript@5.9.3)':
|
'@git.zone/tstest@3.5.1(socks@2.8.7)(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@git.zone/tsbundle': 2.9.1
|
'@git.zone/tsbundle': 2.9.1
|
||||||
'@git.zone/tsrun': 2.0.1
|
'@git.zone/tsrun': 2.0.1
|
||||||
@@ -5193,11 +5222,11 @@ snapshots:
|
|||||||
|
|
||||||
'@git.zone/tswatch@3.3.0(@tiptap/pm@2.27.2)':
|
'@git.zone/tswatch@3.3.0(@tiptap/pm@2.27.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedserver': 8.4.2(@tiptap/pm@2.27.2)
|
'@api.global/typedserver': 8.4.6(@tiptap/pm@2.27.2)
|
||||||
'@git.zone/tsbundle': 2.9.1
|
'@git.zone/tsbundle': 2.9.1
|
||||||
'@git.zone/tsrun': 2.0.1
|
'@git.zone/tsrun': 2.0.1
|
||||||
'@push.rocks/early': 4.0.4
|
'@push.rocks/early': 4.0.4
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/npmextra': 5.3.3
|
'@push.rocks/npmextra': 5.3.3
|
||||||
'@push.rocks/smartcli': 4.0.20
|
'@push.rocks/smartcli': 4.0.20
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
@@ -5861,7 +5890,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/levelcache@3.2.0':
|
'@push.rocks/levelcache@3.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartbucket': 3.3.10
|
'@push.rocks/smartbucket': 3.3.10
|
||||||
'@push.rocks/smartcache': 1.0.18
|
'@push.rocks/smartcache': 1.0.18
|
||||||
'@push.rocks/smartenv': 5.0.13
|
'@push.rocks/smartenv': 5.0.13
|
||||||
@@ -5881,20 +5910,18 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
'@push.rocks/lik@6.3.1':
|
'@push.rocks/lik@6.4.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartmatch': 2.0.0
|
'@push.rocks/smartmatch': 2.0.0
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
'@push.rocks/smarttime': 4.2.3
|
'@push.rocks/smarttime': 4.2.3
|
||||||
'@types/minimatch': 5.1.2
|
|
||||||
'@types/symbol-tree': 3.2.5
|
|
||||||
symbol-tree: 3.2.4
|
symbol-tree: 3.2.4
|
||||||
|
|
||||||
'@push.rocks/mongodump@1.1.0(socks@2.8.7)':
|
'@push.rocks/mongodump@1.1.0(socks@2.8.7)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartfile': 11.2.7
|
'@push.rocks/smartfile': 11.2.7
|
||||||
'@push.rocks/smartjson': 5.2.0
|
'@push.rocks/smartjson': 5.2.0
|
||||||
'@push.rocks/smartpath': 6.0.0
|
'@push.rocks/smartpath': 6.0.0
|
||||||
@@ -5946,7 +5973,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@apiclient.xyz/cloudflare': 7.1.0
|
'@apiclient.xyz/cloudflare': 7.1.0
|
||||||
'@peculiar/x509': 1.14.3
|
'@peculiar/x509': 1.14.3
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdata': 7.1.0(socks@2.8.7)
|
'@push.rocks/smartdata': 7.1.0(socks@2.8.7)
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartdns': 7.9.0
|
'@push.rocks/smartdns': 7.9.0
|
||||||
@@ -6042,7 +6069,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartcli@4.0.20':
|
'@push.rocks/smartcli@4.0.20':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
'@push.rocks/smartobject': 1.0.12
|
'@push.rocks/smartobject': 1.0.12
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
@@ -6066,7 +6093,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartdata@5.16.7(socks@2.8.7)':
|
'@push.rocks/smartdata@5.16.7(socks@2.8.7)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
'@push.rocks/smartmongo': 2.2.0(socks@2.8.7)
|
'@push.rocks/smartmongo': 2.2.0(socks@2.8.7)
|
||||||
@@ -6096,7 +6123,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartdata@7.1.0(socks@2.8.7)':
|
'@push.rocks/smartdata@7.1.0(socks@2.8.7)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
'@push.rocks/smartmongo': 2.2.0(socks@2.8.7)
|
'@push.rocks/smartmongo': 2.2.0(socks@2.8.7)
|
||||||
@@ -6155,14 +6182,14 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartexit@1.1.1':
|
'@push.rocks/smartexit@1.1.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
tree-kill: 1.2.2
|
tree-kill: 1.2.2
|
||||||
|
|
||||||
'@push.rocks/smartexit@2.0.3':
|
'@push.rocks/smartexit@2.0.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
|
|
||||||
'@push.rocks/smartexpect@2.5.0':
|
'@push.rocks/smartexpect@2.5.0':
|
||||||
@@ -6174,13 +6201,13 @@ snapshots:
|
|||||||
'@push.rocks/smartfeed@1.4.0':
|
'@push.rocks/smartfeed@1.4.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tsclass/tsclass': 9.5.0
|
'@tsclass/tsclass': 9.5.0
|
||||||
fast-xml-parser: 4.5.4
|
fast-xml-parser: 4.5.5
|
||||||
|
|
||||||
'@push.rocks/smartfile-interfaces@1.0.7': {}
|
'@push.rocks/smartfile-interfaces@1.0.7': {}
|
||||||
|
|
||||||
'@push.rocks/smartfile@10.0.41':
|
'@push.rocks/smartfile@10.0.41':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartfile-interfaces': 1.0.7
|
'@push.rocks/smartfile-interfaces': 1.0.7
|
||||||
'@push.rocks/smarthash': 3.2.6
|
'@push.rocks/smarthash': 3.2.6
|
||||||
@@ -6199,7 +6226,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartfile@11.2.7':
|
'@push.rocks/smartfile@11.2.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartfile-interfaces': 1.0.7
|
'@push.rocks/smartfile-interfaces': 1.0.7
|
||||||
'@push.rocks/smarthash': 3.2.6
|
'@push.rocks/smarthash': 3.2.6
|
||||||
@@ -6217,7 +6244,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartfile@13.1.2':
|
'@push.rocks/smartfile@13.1.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartfile-interfaces': 1.0.7
|
'@push.rocks/smartfile-interfaces': 1.0.7
|
||||||
'@push.rocks/smartfs': 1.5.0
|
'@push.rocks/smartfs': 1.5.0
|
||||||
@@ -6254,7 +6281,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartinteract@2.0.16':
|
'@push.rocks/smartinteract@2.0.16':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartobject': 1.0.12
|
'@push.rocks/smartobject': 1.0.12
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
inquirer: 11.1.0
|
inquirer: 11.1.0
|
||||||
@@ -6357,7 +6384,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
matcher: 5.0.0
|
matcher: 5.0.0
|
||||||
|
|
||||||
'@push.rocks/smartmetrics@3.0.2':
|
'@push.rocks/smartmetrics@3.0.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
@@ -6539,7 +6566,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartpromise@4.2.3': {}
|
'@push.rocks/smartpromise@4.2.3': {}
|
||||||
|
|
||||||
'@push.rocks/smartproxy@25.16.0':
|
'@push.rocks/smartproxy@26.2.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartcrypto': 2.0.4
|
'@push.rocks/smartcrypto': 2.0.4
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
@@ -6594,7 +6621,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartrouter@1.3.3':
|
'@push.rocks/smartrouter@1.3.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
path-to-regexp: 8.3.0
|
path-to-regexp: 8.3.0
|
||||||
|
|
||||||
@@ -6611,7 +6638,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest': 3.3.0
|
'@api.global/typedrequest': 3.3.0
|
||||||
'@cfworker/json-schema': 4.1.1
|
'@cfworker/json-schema': 4.1.1
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartenv': 6.0.0
|
'@push.rocks/smartenv': 6.0.0
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
'@push.rocks/smartpath': 6.0.0
|
'@push.rocks/smartpath': 6.0.0
|
||||||
@@ -6620,6 +6647,19 @@ snapshots:
|
|||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
|
'@push.rocks/smartserve@2.0.3':
|
||||||
|
dependencies:
|
||||||
|
'@api.global/typedrequest': 3.3.0
|
||||||
|
'@cfworker/json-schema': 4.1.1
|
||||||
|
'@push.rocks/lik': 6.4.0
|
||||||
|
'@push.rocks/smartenv': 6.0.0
|
||||||
|
'@push.rocks/smartlog': 3.2.1
|
||||||
|
'@push.rocks/smartpath': 6.0.0
|
||||||
|
ws: 8.20.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
'@push.rocks/smartshell@3.3.8':
|
'@push.rocks/smartshell@3.3.8':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
@@ -6628,9 +6668,8 @@ snapshots:
|
|||||||
'@types/which': 3.0.4
|
'@types/which': 3.0.4
|
||||||
which: 6.0.1
|
which: 6.0.1
|
||||||
|
|
||||||
'@push.rocks/smartsitemap@2.0.4':
|
'@push.rocks/smartsitemap@4.0.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartcache': 1.0.18
|
|
||||||
'@push.rocks/smartfeed': 1.4.0
|
'@push.rocks/smartfeed': 1.4.0
|
||||||
'@push.rocks/smartxml': 2.0.0
|
'@push.rocks/smartxml': 2.0.0
|
||||||
'@push.rocks/smartyaml': 3.0.4
|
'@push.rocks/smartyaml': 3.0.4
|
||||||
@@ -6671,7 +6710,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartstream@3.4.0':
|
'@push.rocks/smartstream@3.4.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartenv': 6.0.0
|
'@push.rocks/smartenv': 6.0.0
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
@@ -6682,7 +6721,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smarttime@4.2.3':
|
'@push.rocks/smarttime@4.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
croner: 10.0.1
|
croner: 10.0.1
|
||||||
@@ -6706,16 +6745,26 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartwatch@6.3.0':
|
'@push.rocks/smartwatch@6.3.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartenv': 6.0.0
|
'@push.rocks/smartenv': 6.0.0
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
chokidar: 5.0.0
|
chokidar: 5.0.0
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
|
|
||||||
|
'@push.rocks/smartwatch@6.4.0':
|
||||||
|
dependencies:
|
||||||
|
'@push.rocks/lik': 6.4.0
|
||||||
|
'@push.rocks/smartenv': 6.0.0
|
||||||
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
|
'@push.rocks/smartrust': 1.3.2
|
||||||
|
'@push.rocks/smartrx': 3.0.10
|
||||||
|
chokidar: 5.0.0
|
||||||
|
picomatch: 4.0.3
|
||||||
|
|
||||||
'@push.rocks/smartxml@2.0.0':
|
'@push.rocks/smartxml@2.0.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-xml-parser: 5.5.6
|
fast-xml-parser: 5.5.8
|
||||||
|
|
||||||
'@push.rocks/smartyaml@2.0.5':
|
'@push.rocks/smartyaml@2.0.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6724,12 +6773,12 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartyaml@3.0.4':
|
'@push.rocks/smartyaml@3.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
yaml: 2.8.2
|
yaml: 2.8.3
|
||||||
|
|
||||||
'@push.rocks/taskbuffer@3.5.0':
|
'@push.rocks/taskbuffer@3.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@design.estate/dees-element': 2.2.3
|
'@design.estate/dees-element': 2.2.3
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
@@ -6745,7 +6794,23 @@ snapshots:
|
|||||||
'@push.rocks/taskbuffer@6.1.2':
|
'@push.rocks/taskbuffer@6.1.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@design.estate/dees-element': 2.2.3
|
'@design.estate/dees-element': 2.2.3
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
|
'@push.rocks/smartlog': 3.2.1
|
||||||
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
|
'@push.rocks/smartrx': 3.0.10
|
||||||
|
'@push.rocks/smarttime': 4.2.3
|
||||||
|
'@push.rocks/smartunique': 3.0.9
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@nuxt/kit'
|
||||||
|
- react
|
||||||
|
- supports-color
|
||||||
|
- vue
|
||||||
|
|
||||||
|
'@push.rocks/taskbuffer@8.0.2':
|
||||||
|
dependencies:
|
||||||
|
'@design.estate/dees-element': 2.2.3
|
||||||
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
@@ -6775,7 +6840,7 @@ snapshots:
|
|||||||
'@push.rocks/webstore@2.0.20':
|
'@push.rocks/webstore@2.0.20':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@api.global/typedrequest-interfaces': 3.0.19
|
'@api.global/typedrequest-interfaces': 3.0.19
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.4.0
|
||||||
'@push.rocks/smartenv': 5.0.13
|
'@push.rocks/smartenv': 5.0.13
|
||||||
'@push.rocks/smartjson': 5.2.0
|
'@push.rocks/smartjson': 5.2.0
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
@@ -6956,7 +7021,7 @@ snapshots:
|
|||||||
'@push.rocks/smartlog-interfaces': 3.0.2
|
'@push.rocks/smartlog-interfaces': 3.0.2
|
||||||
'@tsclass/tsclass': 9.5.0
|
'@tsclass/tsclass': 9.5.0
|
||||||
|
|
||||||
'@serve.zone/remoteingress@4.13.0':
|
'@serve.zone/remoteingress@4.14.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/qenv': 6.1.3
|
'@push.rocks/qenv': 6.1.3
|
||||||
'@push.rocks/smartrust': 1.3.2
|
'@push.rocks/smartrust': 1.3.2
|
||||||
@@ -7588,8 +7653,6 @@ snapshots:
|
|||||||
|
|
||||||
'@types/semver@7.7.1': {}
|
'@types/semver@7.7.1': {}
|
||||||
|
|
||||||
'@types/symbol-tree@3.2.5': {}
|
|
||||||
|
|
||||||
'@types/tar-stream@3.1.4':
|
'@types/tar-stream@3.1.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.5.0
|
'@types/node': 25.5.0
|
||||||
@@ -8149,7 +8212,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
path-expression-matcher: 1.1.3
|
path-expression-matcher: 1.1.3
|
||||||
|
|
||||||
fast-xml-parser@4.5.4:
|
fast-xml-parser@4.5.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
strnum: 1.1.2
|
strnum: 1.1.2
|
||||||
|
|
||||||
@@ -8158,11 +8221,11 @@ snapshots:
|
|||||||
fast-xml-builder: 1.1.4
|
fast-xml-builder: 1.1.4
|
||||||
strnum: 2.2.0
|
strnum: 2.2.0
|
||||||
|
|
||||||
fast-xml-parser@5.5.6:
|
fast-xml-parser@5.5.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-xml-builder: 1.1.4
|
fast-xml-builder: 1.1.4
|
||||||
path-expression-matcher: 1.1.3
|
path-expression-matcher: 1.2.0
|
||||||
strnum: 2.2.0
|
strnum: 2.2.2
|
||||||
|
|
||||||
fault@2.0.1:
|
fault@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -9341,6 +9404,8 @@ snapshots:
|
|||||||
|
|
||||||
path-expression-matcher@1.1.3: {}
|
path-expression-matcher@1.1.3: {}
|
||||||
|
|
||||||
|
path-expression-matcher@1.2.0: {}
|
||||||
|
|
||||||
path-is-absolute@1.0.1: {}
|
path-is-absolute@1.0.1: {}
|
||||||
|
|
||||||
path-key@3.1.1: {}
|
path-key@3.1.1: {}
|
||||||
@@ -9909,6 +9974,8 @@ snapshots:
|
|||||||
|
|
||||||
strnum@2.2.0: {}
|
strnum@2.2.0: {}
|
||||||
|
|
||||||
|
strnum@2.2.2: {}
|
||||||
|
|
||||||
strtok3@10.3.4:
|
strtok3@10.3.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tokenizer/token': 0.3.0
|
'@tokenizer/token': 0.3.0
|
||||||
@@ -10182,6 +10249,8 @@ snapshots:
|
|||||||
|
|
||||||
ws@8.19.0: {}
|
ws@8.19.0: {}
|
||||||
|
|
||||||
|
ws@8.20.0: {}
|
||||||
|
|
||||||
xml-parse-from-string@1.0.1: {}
|
xml-parse-from-string@1.0.1: {}
|
||||||
|
|
||||||
xml2js@0.5.0:
|
xml2js@0.5.0:
|
||||||
@@ -10199,7 +10268,7 @@ snapshots:
|
|||||||
|
|
||||||
y18n@5.0.8: {}
|
y18n@5.0.8: {}
|
||||||
|
|
||||||
yaml@2.8.2: {}
|
yaml@2.8.3: {}
|
||||||
|
|
||||||
yargs-parser@21.1.1: {}
|
yargs-parser@21.1.1: {}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/dcrouter',
|
name: '@serve.zone/dcrouter',
|
||||||
version: '11.7.1',
|
version: '11.10.4',
|
||||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,14 +61,21 @@ export class CertProvisionScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a domain is currently in backoff
|
* Check if a domain is currently in backoff.
|
||||||
|
* Expired entries are pruned from the cache to prevent unbounded growth.
|
||||||
*/
|
*/
|
||||||
async isInBackoff(domain: string): Promise<boolean> {
|
async isInBackoff(domain: string): Promise<boolean> {
|
||||||
const entry = await this.loadBackoff(domain);
|
const entry = await this.loadBackoff(domain);
|
||||||
if (!entry) return false;
|
if (!entry) return false;
|
||||||
|
|
||||||
const retryAfter = new Date(entry.retryAfter);
|
const retryAfter = new Date(entry.retryAfter);
|
||||||
return retryAfter.getTime() > Date.now();
|
if (retryAfter.getTime() > Date.now()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backoff has expired — prune the stale entry
|
||||||
|
this.backoffCache.delete(domain);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,9 +131,12 @@ export class CertProvisionScheduler {
|
|||||||
const entry = await this.loadBackoff(domain);
|
const entry = await this.loadBackoff(domain);
|
||||||
if (!entry) return null;
|
if (!entry) return null;
|
||||||
|
|
||||||
// Only return if still in backoff
|
// Only return if still in backoff — prune expired entries
|
||||||
const retryAfter = new Date(entry.retryAfter);
|
const retryAfter = new Date(entry.retryAfter);
|
||||||
if (retryAfter.getTime() <= Date.now()) return null;
|
if (retryAfter.getTime() <= Date.now()) {
|
||||||
|
this.backoffCache.delete(domain);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
failures: entry.failures,
|
failures: entry.failures,
|
||||||
|
|||||||
@@ -252,6 +252,11 @@ export class DcRouter {
|
|||||||
// Certificate provisioning scheduler with per-domain backoff
|
// Certificate provisioning scheduler with per-domain backoff
|
||||||
public certProvisionScheduler?: CertProvisionScheduler;
|
public certProvisionScheduler?: CertProvisionScheduler;
|
||||||
|
|
||||||
|
// Service lifecycle management
|
||||||
|
public serviceManager: plugins.taskbuffer.ServiceManager;
|
||||||
|
private serviceSubjectSubscription?: plugins.smartrx.rxjs.Subscription;
|
||||||
|
public smartAcmeReady = false;
|
||||||
|
|
||||||
// TypedRouter for API endpoints
|
// TypedRouter for API endpoints
|
||||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||||
|
|
||||||
@@ -279,67 +284,253 @@ export class DcRouter {
|
|||||||
|
|
||||||
// Initialize storage manager
|
// Initialize storage manager
|
||||||
this.storageManager = new StorageManager(this.options.storage);
|
this.storageManager = new StorageManager(this.options.storage);
|
||||||
|
|
||||||
|
// Initialize service manager and register all services
|
||||||
|
this.serviceManager = new plugins.taskbuffer.ServiceManager({
|
||||||
|
name: 'dcrouter',
|
||||||
|
startupTimeoutMs: 120_000,
|
||||||
|
shutdownTimeoutMs: 30_000,
|
||||||
|
});
|
||||||
|
this.registerServices();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register all dcrouter services with the ServiceManager.
|
||||||
|
* Services are started in dependency order, with failure isolation for optional services.
|
||||||
|
*/
|
||||||
|
private registerServices(): void {
|
||||||
|
// OpsServer: critical, no dependencies — provides visibility
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('OpsServer')
|
||||||
|
.critical()
|
||||||
|
.withStart(async () => {
|
||||||
|
this.opsServer = new OpsServer(this);
|
||||||
|
await this.opsServer.start();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
await this.opsServer?.stop();
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 0 }),
|
||||||
|
);
|
||||||
|
|
||||||
|
// CacheDb: optional, no dependencies
|
||||||
|
if (this.options.cacheConfig?.enabled !== false) {
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('CacheDb')
|
||||||
|
.optional()
|
||||||
|
.withStart(async () => {
|
||||||
|
await this.setupCacheDb();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
if (this.cacheCleaner) {
|
||||||
|
this.cacheCleaner.stop();
|
||||||
|
this.cacheCleaner = undefined;
|
||||||
|
}
|
||||||
|
if (this.cacheDb) {
|
||||||
|
await this.cacheDb.stop();
|
||||||
|
CacheDb.resetInstance();
|
||||||
|
this.cacheDb = undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 2, baseDelayMs: 1000, maxDelayMs: 5000 }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetricsManager: optional, depends on OpsServer
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('MetricsManager')
|
||||||
|
.optional()
|
||||||
|
.dependsOn('OpsServer')
|
||||||
|
.withStart(async () => {
|
||||||
|
this.metricsManager = new MetricsManager(this);
|
||||||
|
await this.metricsManager.start();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
if (this.metricsManager) {
|
||||||
|
await this.metricsManager.stop();
|
||||||
|
this.metricsManager = undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 1, baseDelayMs: 1000 }),
|
||||||
|
);
|
||||||
|
|
||||||
|
// SmartProxy: critical, depends on CacheDb (if enabled)
|
||||||
|
const smartProxyDeps: string[] = [];
|
||||||
|
if (this.options.cacheConfig?.enabled !== false) {
|
||||||
|
smartProxyDeps.push('CacheDb');
|
||||||
|
}
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('SmartProxy')
|
||||||
|
.critical()
|
||||||
|
.dependsOn(...smartProxyDeps)
|
||||||
|
.withStart(async () => {
|
||||||
|
await this.setupSmartProxy();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
if (this.smartProxy) {
|
||||||
|
this.smartProxy.removeAllListeners();
|
||||||
|
await this.smartProxy.stop();
|
||||||
|
this.smartProxy = undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 0 }),
|
||||||
|
);
|
||||||
|
|
||||||
|
// SmartAcme: optional, depends on SmartProxy — aggressive retry for rate limits
|
||||||
|
// Only registered if DNS challenge is configured
|
||||||
|
if (this.options.dnsChallenge?.cloudflareApiKey) {
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('SmartAcme')
|
||||||
|
.optional()
|
||||||
|
.dependsOn('SmartProxy')
|
||||||
|
.withStart(async () => {
|
||||||
|
if (this.smartAcme) {
|
||||||
|
await this.smartAcme.start();
|
||||||
|
this.smartAcmeReady = true;
|
||||||
|
logger.log('info', 'SmartAcme DNS-01 provider is now ready');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
this.smartAcmeReady = false;
|
||||||
|
if (this.smartAcme) {
|
||||||
|
await this.smartAcme.stop();
|
||||||
|
this.smartAcme = undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 20, baseDelayMs: 5000, maxDelayMs: 3_600_000, backoffFactor: 2 }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigManagers: optional, depends on SmartProxy
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('ConfigManagers')
|
||||||
|
.optional()
|
||||||
|
.dependsOn('SmartProxy')
|
||||||
|
.withStart(async () => {
|
||||||
|
this.routeConfigManager = new RouteConfigManager(
|
||||||
|
this.storageManager,
|
||||||
|
() => this.getConstructorRoutes(),
|
||||||
|
() => this.smartProxy,
|
||||||
|
() => this.options.http3,
|
||||||
|
);
|
||||||
|
this.apiTokenManager = new ApiTokenManager(this.storageManager);
|
||||||
|
await this.apiTokenManager.initialize();
|
||||||
|
await this.routeConfigManager.initialize();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
this.routeConfigManager = undefined;
|
||||||
|
this.apiTokenManager = undefined;
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 2, baseDelayMs: 1000 }),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Email Server: optional, depends on SmartProxy
|
||||||
|
if (this.options.emailConfig) {
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('EmailServer')
|
||||||
|
.optional()
|
||||||
|
.dependsOn('SmartProxy')
|
||||||
|
.withStart(async () => {
|
||||||
|
await this.setupUnifiedEmailHandling();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
if (this.emailServer) {
|
||||||
|
if ((this.emailServer as any).deliverySystem) {
|
||||||
|
(this.emailServer as any).deliverySystem.removeAllListeners();
|
||||||
|
}
|
||||||
|
this.emailServer.removeAllListeners();
|
||||||
|
await this.emailServer.stop();
|
||||||
|
this.emailServer = undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNS Server: optional, depends on SmartProxy
|
||||||
|
if (this.options.dnsNsDomains?.length > 0 && this.options.dnsScopes?.length > 0) {
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('DnsServer')
|
||||||
|
.optional()
|
||||||
|
.dependsOn('SmartProxy')
|
||||||
|
.withStart(async () => {
|
||||||
|
await this.setupDnsWithSocketHandler();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
// Flush pending DNS batch log
|
||||||
|
if (this.dnsBatchTimer) {
|
||||||
|
clearTimeout(this.dnsBatchTimer);
|
||||||
|
if (this.dnsBatchCount > 0) {
|
||||||
|
logger.log('info', `DNS: ${this.dnsBatchCount} queries processed (final flush)`, { zone: 'dns' });
|
||||||
|
}
|
||||||
|
this.dnsBatchTimer = null;
|
||||||
|
this.dnsBatchCount = 0;
|
||||||
|
this.dnsLogWindowSecond = 0;
|
||||||
|
this.dnsLogWindowCount = 0;
|
||||||
|
}
|
||||||
|
if (this.dnsServer) {
|
||||||
|
this.dnsServer.removeAllListeners();
|
||||||
|
await this.dnsServer.stop();
|
||||||
|
this.dnsServer = undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RADIUS Server: optional, no dependency on SmartProxy
|
||||||
|
if (this.options.radiusConfig) {
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('RadiusServer')
|
||||||
|
.optional()
|
||||||
|
.withStart(async () => {
|
||||||
|
await this.setupRadiusServer();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
if (this.radiusServer) {
|
||||||
|
await this.radiusServer.stop();
|
||||||
|
this.radiusServer = undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remote Ingress: optional, depends on SmartProxy
|
||||||
|
if (this.options.remoteIngressConfig?.enabled) {
|
||||||
|
this.serviceManager.addService(
|
||||||
|
new plugins.taskbuffer.Service('RemoteIngress')
|
||||||
|
.optional()
|
||||||
|
.dependsOn('SmartProxy')
|
||||||
|
.withStart(async () => {
|
||||||
|
await this.setupRemoteIngress();
|
||||||
|
})
|
||||||
|
.withStop(async () => {
|
||||||
|
if (this.tunnelManager) {
|
||||||
|
await this.tunnelManager.stop();
|
||||||
|
this.tunnelManager = undefined;
|
||||||
|
}
|
||||||
|
this.remoteIngressManager = undefined;
|
||||||
|
})
|
||||||
|
.withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wire up aggregated events for logging
|
||||||
|
this.serviceSubjectSubscription = this.serviceManager.serviceSubject.subscribe((event) => {
|
||||||
|
const level = event.type === 'failed' ? 'error' : event.type === 'retrying' ? 'warn' : 'info';
|
||||||
|
logger.log(level as any, `Service '${event.serviceName}': ${event.type}`, {
|
||||||
|
state: event.state,
|
||||||
|
...(event.error ? { error: event.error } : {}),
|
||||||
|
...(event.attempt ? { attempt: event.attempt } : {}),
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
logger.log('info', 'Starting DcRouter Services');
|
logger.log('info', 'Starting DcRouter Services');
|
||||||
|
await this.serviceManager.start();
|
||||||
|
this.logStartupSummary();
|
||||||
this.opsServer = new OpsServer(this);
|
|
||||||
await this.opsServer.start();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Initialize cache database if enabled (default: enabled)
|
|
||||||
if (this.options.cacheConfig?.enabled !== false) {
|
|
||||||
await this.setupCacheDb();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize MetricsManager
|
|
||||||
this.metricsManager = new MetricsManager(this);
|
|
||||||
await this.metricsManager.start();
|
|
||||||
|
|
||||||
// Set up SmartProxy for HTTP/HTTPS and all traffic including email routes
|
|
||||||
await this.setupSmartProxy();
|
|
||||||
|
|
||||||
// Initialize programmatic config API managers
|
|
||||||
this.routeConfigManager = new RouteConfigManager(
|
|
||||||
this.storageManager,
|
|
||||||
() => this.getConstructorRoutes(),
|
|
||||||
() => this.smartProxy,
|
|
||||||
() => this.options.http3,
|
|
||||||
);
|
|
||||||
this.apiTokenManager = new ApiTokenManager(this.storageManager);
|
|
||||||
await this.apiTokenManager.initialize();
|
|
||||||
await this.routeConfigManager.initialize();
|
|
||||||
|
|
||||||
// Set up unified email handling if configured
|
|
||||||
if (this.options.emailConfig) {
|
|
||||||
await this.setupUnifiedEmailHandling();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up DNS server if configured with nameservers and scopes
|
|
||||||
if (this.options.dnsNsDomains && this.options.dnsNsDomains.length > 0 &&
|
|
||||||
this.options.dnsScopes && this.options.dnsScopes.length > 0) {
|
|
||||||
await this.setupDnsWithSocketHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up RADIUS server if configured
|
|
||||||
if (this.options.radiusConfig) {
|
|
||||||
await this.setupRadiusServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up Remote Ingress hub if configured
|
|
||||||
if (this.options.remoteIngressConfig?.enabled) {
|
|
||||||
await this.setupRemoteIngress();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logStartupSummary();
|
|
||||||
} catch (error) {
|
|
||||||
logger.log('error', 'Error starting DcRouter', { error: String(error) });
|
|
||||||
// Try to clean up any services that may have started
|
|
||||||
await this.stop();
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -399,7 +590,21 @@ export class DcRouter {
|
|||||||
logger.log('info', `Cache Database: storage=${this.cacheDb.getStoragePath()}, db=${this.cacheDb.getDbName()}, cleaner=${this.cacheCleaner?.isActive() ? 'active' : 'inactive'} (${(this.options.cacheConfig?.cleanupIntervalHours || 1)}h interval)`);
|
logger.log('info', `Cache Database: storage=${this.cacheDb.getStoragePath()}, db=${this.cacheDb.getDbName()}, cleaner=${this.cacheCleaner?.isActive() ? 'active' : 'inactive'} (${(this.options.cacheConfig?.cleanupIntervalHours || 1)}h interval)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log('info', 'All services are running');
|
// Service status summary from ServiceManager
|
||||||
|
const health = this.serviceManager.getHealth();
|
||||||
|
const statuses = health.services;
|
||||||
|
const running = statuses.filter(s => s.state === 'running').length;
|
||||||
|
const failed = statuses.filter(s => s.state === 'failed').length;
|
||||||
|
const retrying = statuses.filter(s => s.state === 'starting' || s.state === 'degraded').length;
|
||||||
|
|
||||||
|
if (failed > 0) {
|
||||||
|
const failedNames = statuses.filter(s => s.state === 'failed').map(s => `${s.name}: ${s.lastError || 'unknown'}`);
|
||||||
|
logger.log('warn', `DcRouter started in degraded mode — ${running} running, ${failed} failed: ${failedNames.join('; ')}`);
|
||||||
|
} else if (retrying > 0) {
|
||||||
|
logger.log('info', `DcRouter started — ${running} running, ${retrying} still initializing`);
|
||||||
|
} else {
|
||||||
|
logger.log('info', `All ${running} services are running`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -435,6 +640,13 @@ export class DcRouter {
|
|||||||
*/
|
*/
|
||||||
private async setupSmartProxy(): Promise<void> {
|
private async setupSmartProxy(): Promise<void> {
|
||||||
logger.log('info', 'Setting up SmartProxy...');
|
logger.log('info', 'Setting up SmartProxy...');
|
||||||
|
|
||||||
|
// Clean up any existing SmartProxy instance (e.g. from a retry)
|
||||||
|
if (this.smartProxy) {
|
||||||
|
this.smartProxy.removeAllListeners();
|
||||||
|
this.smartProxy = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
let routes: plugins.smartproxy.IRouteConfig[] = [];
|
let routes: plugins.smartproxy.IRouteConfig[] = [];
|
||||||
let acmeConfig: plugins.smartproxy.IAcmeOptions | undefined;
|
let acmeConfig: plugins.smartproxy.IAcmeOptions | undefined;
|
||||||
|
|
||||||
@@ -535,10 +747,13 @@ export class DcRouter {
|
|||||||
// Initialize cert provision scheduler
|
// Initialize cert provision scheduler
|
||||||
this.certProvisionScheduler = new CertProvisionScheduler(this.storageManager);
|
this.certProvisionScheduler = new CertProvisionScheduler(this.storageManager);
|
||||||
|
|
||||||
// If we have DNS challenge handlers, create SmartAcme and wire to certProvisionFunction
|
// If we have DNS challenge handlers, create SmartAcme instance and wire certProvisionFunction
|
||||||
|
// Note: SmartAcme.start() is NOT called here — it runs as a separate optional service
|
||||||
|
// via the ServiceManager, with aggressive retry for rate-limit resilience.
|
||||||
if (challengeHandlers.length > 0) {
|
if (challengeHandlers.length > 0) {
|
||||||
// Stop old SmartAcme if it exists (e.g., during updateSmartProxyConfig)
|
// Stop old SmartAcme if it exists (e.g., during updateSmartProxyConfig)
|
||||||
if (this.smartAcme) {
|
if (this.smartAcme) {
|
||||||
|
this.smartAcmeReady = false;
|
||||||
await this.smartAcme.stop().catch(err =>
|
await this.smartAcme.stop().catch(err =>
|
||||||
logger.log('error', 'Error stopping old SmartAcme', { error: String(err) })
|
logger.log('error', 'Error stopping old SmartAcme', { error: String(err) })
|
||||||
);
|
);
|
||||||
@@ -550,10 +765,15 @@ export class DcRouter {
|
|||||||
challengeHandlers: challengeHandlers,
|
challengeHandlers: challengeHandlers,
|
||||||
challengePriority: ['dns-01'],
|
challengePriority: ['dns-01'],
|
||||||
});
|
});
|
||||||
await this.smartAcme.start();
|
|
||||||
|
|
||||||
const scheduler = this.certProvisionScheduler;
|
const scheduler = this.certProvisionScheduler;
|
||||||
smartProxyConfig.certProvisionFunction = async (domain, eventComms) => {
|
smartProxyConfig.certProvisionFunction = async (domain, eventComms) => {
|
||||||
|
// If SmartAcme is not yet ready (still starting or retrying), fall back to HTTP-01
|
||||||
|
if (!this.smartAcmeReady) {
|
||||||
|
eventComms.warn(`SmartAcme not yet initialized, falling back to http-01 for ${domain}`);
|
||||||
|
return 'http01';
|
||||||
|
}
|
||||||
|
|
||||||
// Check backoff before attempting provision
|
// Check backoff before attempting provision
|
||||||
if (await scheduler.isInBackoff(domain)) {
|
if (await scheduler.isInBackoff(domain)) {
|
||||||
const info = await scheduler.getBackoffInfo(domain);
|
const info = await scheduler.getBackoffInfo(domain);
|
||||||
@@ -914,105 +1134,29 @@ export class DcRouter {
|
|||||||
public async stop() {
|
public async stop() {
|
||||||
logger.log('info', 'Stopping DcRouter services...');
|
logger.log('info', 'Stopping DcRouter services...');
|
||||||
|
|
||||||
// Flush pending DNS batch log
|
// Unsubscribe from service events before stopping services
|
||||||
if (this.dnsBatchTimer) {
|
if (this.serviceSubjectSubscription) {
|
||||||
clearTimeout(this.dnsBatchTimer);
|
this.serviceSubjectSubscription.unsubscribe();
|
||||||
if (this.dnsBatchCount > 0) {
|
this.serviceSubjectSubscription = undefined;
|
||||||
logger.log('info', `DNS: ${this.dnsBatchCount} queries processed (rate limited, final flush)`, { zone: 'dns' });
|
|
||||||
}
|
|
||||||
this.dnsBatchTimer = null;
|
|
||||||
this.dnsBatchCount = 0;
|
|
||||||
this.dnsLogWindowSecond = 0;
|
|
||||||
this.dnsLogWindowCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.opsServer.stop();
|
// ServiceManager handles reverse-dependency-ordered shutdown
|
||||||
|
await this.serviceManager.stop();
|
||||||
|
|
||||||
try {
|
// Clear backoff cache in cert scheduler
|
||||||
// Remove event listeners before stopping services to prevent leaks
|
if (this.certProvisionScheduler) {
|
||||||
if (this.smartProxy) {
|
this.certProvisionScheduler.clear();
|
||||||
this.smartProxy.removeAllListeners();
|
|
||||||
}
|
|
||||||
if (this.emailServer) {
|
|
||||||
if ((this.emailServer as any).deliverySystem) {
|
|
||||||
(this.emailServer as any).deliverySystem.removeAllListeners();
|
|
||||||
}
|
|
||||||
this.emailServer.removeAllListeners();
|
|
||||||
}
|
|
||||||
if (this.dnsServer) {
|
|
||||||
this.dnsServer.removeAllListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop all services in parallel for faster shutdown
|
|
||||||
await Promise.all([
|
|
||||||
// Stop cache cleaner if running
|
|
||||||
this.cacheCleaner ? Promise.resolve(this.cacheCleaner.stop()) : Promise.resolve(),
|
|
||||||
|
|
||||||
// Stop metrics manager if running
|
|
||||||
this.metricsManager ? this.metricsManager.stop().catch(err => logger.log('error', 'Error stopping MetricsManager', { error: String(err) })) : Promise.resolve(),
|
|
||||||
|
|
||||||
// Stop unified email server if running
|
|
||||||
this.emailServer ? this.emailServer.stop().catch(err => logger.log('error', 'Error stopping email server', { error: String(err) })) : Promise.resolve(),
|
|
||||||
|
|
||||||
// Stop SmartAcme if running
|
|
||||||
this.smartAcme ? this.smartAcme.stop().catch(err => logger.log('error', 'Error stopping SmartAcme', { error: String(err) })) : Promise.resolve(),
|
|
||||||
|
|
||||||
// Stop HTTP SmartProxy if running
|
|
||||||
this.smartProxy ? this.smartProxy.stop().catch(err => logger.log('error', 'Error stopping SmartProxy', { error: String(err) })) : Promise.resolve(),
|
|
||||||
|
|
||||||
// Stop DNS server if running
|
|
||||||
this.dnsServer ?
|
|
||||||
this.dnsServer.stop().catch(err => logger.log('error', 'Error stopping DNS server', { error: String(err) })) :
|
|
||||||
Promise.resolve(),
|
|
||||||
|
|
||||||
// Stop RADIUS server if running
|
|
||||||
this.radiusServer ?
|
|
||||||
this.radiusServer.stop().catch(err => logger.log('error', 'Error stopping RADIUS server', { error: String(err) })) :
|
|
||||||
Promise.resolve(),
|
|
||||||
|
|
||||||
// Stop Remote Ingress tunnel manager if running
|
|
||||||
this.tunnelManager ?
|
|
||||||
this.tunnelManager.stop().catch(err => logger.log('error', 'Error stopping TunnelManager', { error: String(err) })) :
|
|
||||||
Promise.resolve()
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Stop cache database after other services (they may need it during shutdown)
|
|
||||||
if (this.cacheDb) {
|
|
||||||
await this.cacheDb.stop().catch(err => logger.log('error', 'Error stopping CacheDb', { error: String(err) }));
|
|
||||||
CacheDb.resetInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear backoff cache in cert scheduler
|
|
||||||
if (this.certProvisionScheduler) {
|
|
||||||
this.certProvisionScheduler.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow GC of stopped services by nulling references
|
|
||||||
this.smartProxy = undefined;
|
|
||||||
this.emailServer = undefined;
|
|
||||||
this.dnsServer = undefined;
|
|
||||||
this.metricsManager = undefined;
|
|
||||||
this.cacheCleaner = undefined;
|
|
||||||
this.cacheDb = undefined;
|
|
||||||
this.tunnelManager = undefined;
|
|
||||||
this.radiusServer = undefined;
|
|
||||||
this.smartAcme = undefined;
|
|
||||||
this.certProvisionScheduler = undefined;
|
this.certProvisionScheduler = undefined;
|
||||||
this.remoteIngressManager = undefined;
|
|
||||||
this.routeConfigManager = undefined;
|
|
||||||
this.apiTokenManager = undefined;
|
|
||||||
this.certificateStatusMap.clear();
|
|
||||||
|
|
||||||
// Reset security singletons to allow GC
|
|
||||||
SecurityLogger.resetInstance();
|
|
||||||
ContentScanner.resetInstance();
|
|
||||||
IPReputationChecker.resetInstance();
|
|
||||||
|
|
||||||
logger.log('info', 'All DcRouter services stopped');
|
|
||||||
} catch (error) {
|
|
||||||
logger.log('error', 'Error during DcRouter shutdown', { error: String(error) });
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.certificateStatusMap.clear();
|
||||||
|
|
||||||
|
// Reset security singletons to allow GC
|
||||||
|
SecurityLogger.resetInstance();
|
||||||
|
ContentScanner.resetInstance();
|
||||||
|
IPReputationChecker.resetInstance();
|
||||||
|
|
||||||
|
logger.log('info', 'All DcRouter services stopped');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1753,7 +1897,7 @@ export class DcRouter {
|
|||||||
await this.remoteIngressManager.initialize();
|
await this.remoteIngressManager.initialize();
|
||||||
|
|
||||||
// Pass current routes so the manager can derive edge ports from remoteIngress-tagged routes
|
// Pass current routes so the manager can derive edge ports from remoteIngress-tagged routes
|
||||||
const currentRoutes = this.options.smartProxyConfig?.routes || [];
|
const currentRoutes = this.constructorRoutes;
|
||||||
this.remoteIngressManager.setRoutes(currentRoutes as any[]);
|
this.remoteIngressManager.setRoutes(currentRoutes as any[]);
|
||||||
|
|
||||||
// Resolve TLS certs for tunnel: explicit paths > ACME for hubDomain > self-signed (Rust default)
|
// Resolve TLS certs for tunnel: explicit paths > ACME for hubDomain > self-signed (Rust default)
|
||||||
|
|||||||
@@ -35,6 +35,6 @@ export const runCli = async () => {
|
|||||||
await dcRouter.stop();
|
await dcRouter.stop();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
};
|
};
|
||||||
process.on('SIGINT', shutdown);
|
process.once('SIGINT', shutdown);
|
||||||
process.on('SIGTERM', shutdown);
|
process.once('SIGTERM', shutdown);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -558,6 +558,7 @@ export class MetricsManager {
|
|||||||
throughputByIP: new Map<string, { in: number; out: number }>(),
|
throughputByIP: new Map<string, { in: number; out: number }>(),
|
||||||
requestsPerSecond: 0,
|
requestsPerSecond: 0,
|
||||||
requestsTotal: 0,
|
requestsTotal: 0,
|
||||||
|
backends: [] as Array<any>,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,6 +591,110 @@ export class MetricsManager {
|
|||||||
const requestsPerSecond = proxyMetrics.requests.perSecond();
|
const requestsPerSecond = proxyMetrics.requests.perSecond();
|
||||||
const requestsTotal = proxyMetrics.requests.total();
|
const requestsTotal = proxyMetrics.requests.total();
|
||||||
|
|
||||||
|
// Collect backend protocol data
|
||||||
|
const backendMetrics = proxyMetrics.backends.byBackend();
|
||||||
|
const protocolCache = proxyMetrics.backends.detectedProtocols();
|
||||||
|
|
||||||
|
// Group protocol cache entries by host:port so we can match them to backend metrics.
|
||||||
|
// The protocol cache is keyed by (host, port, domain) in Rust, so the same host:port
|
||||||
|
// can have multiple entries for different domains.
|
||||||
|
const cacheByBackend = new Map<string, (typeof protocolCache)[number][]>();
|
||||||
|
for (const entry of protocolCache) {
|
||||||
|
const backendKey = `${entry.host}:${entry.port}`;
|
||||||
|
let entries = cacheByBackend.get(backendKey);
|
||||||
|
if (!entries) {
|
||||||
|
entries = [];
|
||||||
|
cacheByBackend.set(backendKey, entries);
|
||||||
|
}
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const backends: Array<any> = [];
|
||||||
|
const seenCacheKeys = new Set<string>();
|
||||||
|
|
||||||
|
for (const [key, bm] of backendMetrics) {
|
||||||
|
const cacheEntries = cacheByBackend.get(key);
|
||||||
|
if (!cacheEntries || cacheEntries.length === 0) {
|
||||||
|
// No protocol cache entry — emit one row with backend metrics only
|
||||||
|
backends.push({
|
||||||
|
backend: key,
|
||||||
|
domain: null,
|
||||||
|
protocol: bm.protocol,
|
||||||
|
activeConnections: bm.activeConnections,
|
||||||
|
totalConnections: bm.totalConnections,
|
||||||
|
connectErrors: bm.connectErrors,
|
||||||
|
handshakeErrors: bm.handshakeErrors,
|
||||||
|
requestErrors: bm.requestErrors,
|
||||||
|
avgConnectTimeMs: Math.round(bm.avgConnectTimeMs * 10) / 10,
|
||||||
|
poolHitRate: Math.round(bm.poolHitRate * 1000) / 1000,
|
||||||
|
h2Failures: bm.h2Failures,
|
||||||
|
h2Suppressed: false,
|
||||||
|
h3Suppressed: false,
|
||||||
|
h2CooldownRemainingSecs: null,
|
||||||
|
h3CooldownRemainingSecs: null,
|
||||||
|
h2ConsecutiveFailures: null,
|
||||||
|
h3ConsecutiveFailures: null,
|
||||||
|
h3Port: null,
|
||||||
|
cacheAgeSecs: null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// One row per domain, each enriched with the shared backend metrics
|
||||||
|
for (const cache of cacheEntries) {
|
||||||
|
const compositeKey = `${cache.host}:${cache.port}:${cache.domain ?? ''}`;
|
||||||
|
seenCacheKeys.add(compositeKey);
|
||||||
|
backends.push({
|
||||||
|
backend: key,
|
||||||
|
domain: cache.domain ?? null,
|
||||||
|
protocol: cache.protocol ?? bm.protocol,
|
||||||
|
activeConnections: bm.activeConnections,
|
||||||
|
totalConnections: bm.totalConnections,
|
||||||
|
connectErrors: bm.connectErrors,
|
||||||
|
handshakeErrors: bm.handshakeErrors,
|
||||||
|
requestErrors: bm.requestErrors,
|
||||||
|
avgConnectTimeMs: Math.round(bm.avgConnectTimeMs * 10) / 10,
|
||||||
|
poolHitRate: Math.round(bm.poolHitRate * 1000) / 1000,
|
||||||
|
h2Failures: bm.h2Failures,
|
||||||
|
h2Suppressed: cache.h2Suppressed,
|
||||||
|
h3Suppressed: cache.h3Suppressed,
|
||||||
|
h2CooldownRemainingSecs: cache.h2CooldownRemainingSecs,
|
||||||
|
h3CooldownRemainingSecs: cache.h3CooldownRemainingSecs,
|
||||||
|
h2ConsecutiveFailures: cache.h2ConsecutiveFailures,
|
||||||
|
h3ConsecutiveFailures: cache.h3ConsecutiveFailures,
|
||||||
|
h3Port: cache.h3Port,
|
||||||
|
cacheAgeSecs: cache.ageSecs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include protocol cache entries with no matching backend metric
|
||||||
|
for (const entry of protocolCache) {
|
||||||
|
const compositeKey = `${entry.host}:${entry.port}:${entry.domain ?? ''}`;
|
||||||
|
if (!seenCacheKeys.has(compositeKey)) {
|
||||||
|
backends.push({
|
||||||
|
backend: `${entry.host}:${entry.port}`,
|
||||||
|
domain: entry.domain,
|
||||||
|
protocol: entry.protocol,
|
||||||
|
activeConnections: 0,
|
||||||
|
totalConnections: 0,
|
||||||
|
connectErrors: 0,
|
||||||
|
handshakeErrors: 0,
|
||||||
|
requestErrors: 0,
|
||||||
|
avgConnectTimeMs: 0,
|
||||||
|
poolHitRate: 0,
|
||||||
|
h2Failures: 0,
|
||||||
|
h2Suppressed: entry.h2Suppressed,
|
||||||
|
h3Suppressed: entry.h3Suppressed,
|
||||||
|
h2CooldownRemainingSecs: entry.h2CooldownRemainingSecs,
|
||||||
|
h3CooldownRemainingSecs: entry.h3CooldownRemainingSecs,
|
||||||
|
h2ConsecutiveFailures: entry.h2ConsecutiveFailures,
|
||||||
|
h3ConsecutiveFailures: entry.h3ConsecutiveFailures,
|
||||||
|
h3Port: entry.h3Port,
|
||||||
|
cacheAgeSecs: entry.ageSecs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connectionsByIP,
|
connectionsByIP,
|
||||||
throughputRate,
|
throughputRate,
|
||||||
@@ -599,6 +704,7 @@ export class MetricsManager {
|
|||||||
throughputByIP,
|
throughputByIP,
|
||||||
requestsPerSecond,
|
requestsPerSecond,
|
||||||
requestsTotal,
|
requestsTotal,
|
||||||
|
backends,
|
||||||
};
|
};
|
||||||
}, 1000); // 1s cache — matches typical dashboard poll interval
|
}, 1000); // 1s cache — matches typical dashboard poll interval
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export class SecurityHandler {
|
|||||||
throughputByIP,
|
throughputByIP,
|
||||||
requestsPerSecond: networkStats.requestsPerSecond || 0,
|
requestsPerSecond: networkStats.requestsPerSecond || 0,
|
||||||
requestsTotal: networkStats.requestsTotal || 0,
|
requestsTotal: networkStats.requestsTotal || 0,
|
||||||
|
backends: networkStats.backends || [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +115,7 @@ export class SecurityHandler {
|
|||||||
throughputByIP: [],
|
throughputByIP: [],
|
||||||
requestsPerSecond: 0,
|
requestsPerSecond: 0,
|
||||||
requestsTotal: 0,
|
requestsTotal: 0,
|
||||||
|
backends: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -309,6 +309,7 @@ export class StatsHandler {
|
|||||||
throughputHistory: stats.throughputHistory || [],
|
throughputHistory: stats.throughputHistory || [],
|
||||||
requestsPerSecond: stats.requestsPerSecond || 0,
|
requestsPerSecond: stats.requestsPerSecond || 0,
|
||||||
requestsTotal: stats.requestsTotal || 0,
|
requestsTotal: stats.requestsTotal || 0,
|
||||||
|
backends: stats.backends || [],
|
||||||
};
|
};
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
@@ -489,43 +490,40 @@ export class StatsHandler {
|
|||||||
message?: string;
|
message?: string;
|
||||||
}>;
|
}>;
|
||||||
}> {
|
}> {
|
||||||
const services: Array<{
|
const dcRouter = this.opsServerRef.dcRouterRef;
|
||||||
name: string;
|
const health = dcRouter.serviceManager.getHealth();
|
||||||
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
||||||
message?: string;
|
|
||||||
}> = [];
|
|
||||||
|
|
||||||
// Check HTTP Proxy
|
const services = health.services.map((svc) => {
|
||||||
if (this.opsServerRef.dcRouterRef.smartProxy) {
|
let status: 'healthy' | 'degraded' | 'unhealthy';
|
||||||
services.push({
|
switch (svc.state) {
|
||||||
name: 'HTTP/HTTPS Proxy',
|
case 'running':
|
||||||
status: 'healthy',
|
status = 'healthy';
|
||||||
});
|
break;
|
||||||
}
|
case 'starting':
|
||||||
|
case 'degraded':
|
||||||
|
status = 'degraded';
|
||||||
|
break;
|
||||||
|
case 'failed':
|
||||||
|
status = svc.criticality === 'critical' ? 'unhealthy' : 'degraded';
|
||||||
|
break;
|
||||||
|
case 'stopped':
|
||||||
|
case 'stopping':
|
||||||
|
default:
|
||||||
|
status = 'degraded';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Check Email Server
|
let message: string | undefined;
|
||||||
if (this.opsServerRef.dcRouterRef.emailServer) {
|
if (svc.state === 'failed' && svc.lastError) {
|
||||||
services.push({
|
message = svc.lastError;
|
||||||
name: 'Email Server',
|
} else if (svc.retryCount > 0 && svc.state !== 'running') {
|
||||||
status: 'healthy',
|
message = `Retry attempt ${svc.retryCount}`;
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check DNS Server
|
return { name: svc.name, status, message };
|
||||||
if (this.opsServerRef.dcRouterRef.dnsServer) {
|
|
||||||
services.push({
|
|
||||||
name: 'DNS Server',
|
|
||||||
status: 'healthy',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check OpsServer
|
|
||||||
services.push({
|
|
||||||
name: 'OpsServer',
|
|
||||||
status: 'healthy',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const healthy = services.every(s => s.status === 'healthy');
|
const healthy = health.overall === 'healthy';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
healthy,
|
healthy,
|
||||||
|
|||||||
@@ -62,8 +62,9 @@ import * as smartradius from '@push.rocks/smartradius';
|
|||||||
import * as smartrequest from '@push.rocks/smartrequest';
|
import * as smartrequest from '@push.rocks/smartrequest';
|
||||||
import * as smartrx from '@push.rocks/smartrx';
|
import * as smartrx from '@push.rocks/smartrx';
|
||||||
import * as smartunique from '@push.rocks/smartunique';
|
import * as smartunique from '@push.rocks/smartunique';
|
||||||
|
import * as taskbuffer from '@push.rocks/taskbuffer';
|
||||||
|
|
||||||
export { projectinfo, qenv, smartacme, smartdata, smartdns, smartfile, smartguard, smartjwt, smartlog, smartmetrics, smartmongo, smartmta, smartnetwork, smartpath, smartproxy, smartpromise, smartradius, smartrequest, smartrx, smartunique };
|
export { projectinfo, qenv, smartacme, smartdata, smartdns, smartfile, smartguard, smartjwt, smartlog, smartmetrics, smartmongo, smartmta, smartnetwork, smartpath, smartproxy, smartpromise, smartradius, smartrequest, smartrx, smartunique, taskbuffer };
|
||||||
|
|
||||||
// Define SmartLog types for use in error handling
|
// Define SmartLog types for use in error handling
|
||||||
export type TLogLevel = 'error' | 'warn' | 'info' | 'success' | 'debug';
|
export type TLogLevel = 'error' | 'warn' | 'info' | 'success' | 'debug';
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ export interface IAccountingManagerConfig {
|
|||||||
detailedLogging?: boolean;
|
detailedLogging?: boolean;
|
||||||
/** Maximum active sessions to track in memory */
|
/** Maximum active sessions to track in memory */
|
||||||
maxActiveSessions?: number;
|
maxActiveSessions?: number;
|
||||||
|
/** Stale session timeout in hours — sessions with no update for this long are evicted (default: 24) */
|
||||||
|
staleSessionTimeoutHours?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,6 +107,7 @@ export class AccountingManager {
|
|||||||
private activeSessions: Map<string, IAccountingSession> = new Map();
|
private activeSessions: Map<string, IAccountingSession> = new Map();
|
||||||
private config: Required<IAccountingManagerConfig>;
|
private config: Required<IAccountingManagerConfig>;
|
||||||
private storageManager?: StorageManager;
|
private storageManager?: StorageManager;
|
||||||
|
private staleSessionSweepTimer?: ReturnType<typeof setInterval>;
|
||||||
|
|
||||||
// Counters for statistics
|
// Counters for statistics
|
||||||
private stats = {
|
private stats = {
|
||||||
@@ -121,6 +124,7 @@ export class AccountingManager {
|
|||||||
retentionDays: config?.retentionDays ?? 30,
|
retentionDays: config?.retentionDays ?? 30,
|
||||||
detailedLogging: config?.detailedLogging ?? false,
|
detailedLogging: config?.detailedLogging ?? false,
|
||||||
maxActiveSessions: config?.maxActiveSessions ?? 10000,
|
maxActiveSessions: config?.maxActiveSessions ?? 10000,
|
||||||
|
staleSessionTimeoutHours: config?.staleSessionTimeoutHours ?? 24,
|
||||||
};
|
};
|
||||||
this.storageManager = storageManager;
|
this.storageManager = storageManager;
|
||||||
}
|
}
|
||||||
@@ -132,9 +136,60 @@ export class AccountingManager {
|
|||||||
if (this.storageManager) {
|
if (this.storageManager) {
|
||||||
await this.loadActiveSessions();
|
await this.loadActiveSessions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start periodic sweep to evict stale sessions (every 15 minutes)
|
||||||
|
this.staleSessionSweepTimer = setInterval(() => {
|
||||||
|
this.sweepStaleSessions();
|
||||||
|
}, 15 * 60 * 1000);
|
||||||
|
// Allow the process to exit even if the timer is pending
|
||||||
|
if (this.staleSessionSweepTimer.unref) {
|
||||||
|
this.staleSessionSweepTimer.unref();
|
||||||
|
}
|
||||||
|
|
||||||
logger.log('info', `AccountingManager initialized with ${this.activeSessions.size} active sessions`);
|
logger.log('info', `AccountingManager initialized with ${this.activeSessions.size} active sessions`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the accounting manager and clean up timers
|
||||||
|
*/
|
||||||
|
stop(): void {
|
||||||
|
if (this.staleSessionSweepTimer) {
|
||||||
|
clearInterval(this.staleSessionSweepTimer);
|
||||||
|
this.staleSessionSweepTimer = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sweep stale active sessions that have not received any update
|
||||||
|
* within the configured timeout. These are orphaned sessions where
|
||||||
|
* the Stop packet was never received.
|
||||||
|
*/
|
||||||
|
private sweepStaleSessions(): void {
|
||||||
|
const timeoutMs = this.config.staleSessionTimeoutHours * 60 * 60 * 1000;
|
||||||
|
const cutoff = Date.now() - timeoutMs;
|
||||||
|
let swept = 0;
|
||||||
|
|
||||||
|
for (const [sessionId, session] of this.activeSessions) {
|
||||||
|
if (session.lastUpdateTime < cutoff) {
|
||||||
|
session.status = 'terminated';
|
||||||
|
session.terminateCause = 'StaleSessionTimeout';
|
||||||
|
session.endTime = Date.now();
|
||||||
|
session.sessionTime = Math.floor((session.endTime - session.startTime) / 1000);
|
||||||
|
|
||||||
|
if (this.storageManager) {
|
||||||
|
this.archiveSession(session).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.activeSessions.delete(sessionId);
|
||||||
|
swept++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swept > 0) {
|
||||||
|
logger.log('info', `Swept ${swept} stale RADIUS sessions (no update for ${this.config.staleSessionTimeoutHours}h)`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle accounting start request
|
* Handle accounting start request
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -183,6 +183,8 @@ export class RadiusServer {
|
|||||||
this.radiusServer = undefined;
|
this.radiusServer = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.accountingManager.stop();
|
||||||
|
|
||||||
this.running = false;
|
this.running = false;
|
||||||
logger.log('info', 'RADIUS server stopped');
|
logger.log('info', 'RADIUS server stopped');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,38 @@ export class RemoteIngressManager {
|
|||||||
return [...ports].sort((a, b) => a - b);
|
return [...ports].sort((a, b) => a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive UDP listen ports for an edge from routes with transport 'udp' or 'all'.
|
||||||
|
* These ports need UDP listeners on the edge (e.g. for QUIC/HTTP3).
|
||||||
|
*/
|
||||||
|
public deriveUdpPortsForEdge(edgeId: string, edgeTags?: string[]): number[] {
|
||||||
|
const ports = new Set<number>();
|
||||||
|
|
||||||
|
for (const route of this.routes) {
|
||||||
|
if (!route.remoteIngress?.enabled) continue;
|
||||||
|
|
||||||
|
// Apply edge filter if present
|
||||||
|
const filter = route.remoteIngress.edgeFilter;
|
||||||
|
if (filter && filter.length > 0) {
|
||||||
|
const idMatch = filter.includes(edgeId);
|
||||||
|
const tagMatch = edgeTags?.some((tag) => filter.includes(tag)) ?? false;
|
||||||
|
if (!idMatch && !tagMatch) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only include ports from routes that listen on UDP
|
||||||
|
const transport = route.match?.transport;
|
||||||
|
if (transport === 'udp' || transport === 'all') {
|
||||||
|
if (route.match?.ports) {
|
||||||
|
for (const p of extractPorts(route.match.ports)) {
|
||||||
|
ports.add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...ports].sort((a, b) => a - b);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the effective listen ports for an edge.
|
* Get the effective listen ports for an edge.
|
||||||
* Manual ports are always included. Auto-derived ports are added (union) when autoDerivePorts is true.
|
* Manual ports are always included. Auto-derived ports are added (union) when autoDerivePorts is true.
|
||||||
@@ -106,6 +138,18 @@ export class RemoteIngressManager {
|
|||||||
return [...new Set([...manualPorts, ...derivedPorts])].sort((a, b) => a - b);
|
return [...new Set([...manualPorts, ...derivedPorts])].sort((a, b) => a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the effective UDP listen ports for an edge.
|
||||||
|
* Manual UDP ports are always included. Auto-derived UDP ports are added when autoDerivePorts is true.
|
||||||
|
*/
|
||||||
|
public getEffectiveListenPortsUdp(edge: IRemoteIngress): number[] {
|
||||||
|
const manualPorts = edge.listenPortsUdp || [];
|
||||||
|
const shouldDerive = edge.autoDerivePorts !== false;
|
||||||
|
if (!shouldDerive) return [...manualPorts].sort((a, b) => a - b);
|
||||||
|
const derivedPorts = this.deriveUdpPortsForEdge(edge.id, edge.tags);
|
||||||
|
return [...new Set([...manualPorts, ...derivedPorts])].sort((a, b) => a - b);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get manual and derived port breakdown for an edge (used in API responses).
|
* Get manual and derived port breakdown for an edge (used in API responses).
|
||||||
* Derived ports exclude any ports already present in the manual list.
|
* Derived ports exclude any ports already present in the manual list.
|
||||||
@@ -241,15 +285,18 @@ export class RemoteIngressManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of allowed edges (enabled only) for the Rust hub.
|
* Get the list of allowed edges (enabled only) for the Rust hub.
|
||||||
|
* Includes listenPortsUdp when routes with transport 'udp' or 'all' are present.
|
||||||
*/
|
*/
|
||||||
public getAllowedEdges(): Array<{ id: string; secret: string; listenPorts: number[] }> {
|
public getAllowedEdges(): Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[] }> {
|
||||||
const result: Array<{ id: string; secret: string; listenPorts: number[] }> = [];
|
const result: Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[] }> = [];
|
||||||
for (const edge of this.edges.values()) {
|
for (const edge of this.edges.values()) {
|
||||||
if (edge.enabled) {
|
if (edge.enabled) {
|
||||||
|
const listenPortsUdp = this.getEffectiveListenPortsUdp(edge);
|
||||||
result.push({
|
result.push({
|
||||||
id: edge.id,
|
id: edge.id,
|
||||||
secret: edge.secret,
|
secret: edge.secret,
|
||||||
listenPorts: this.getEffectiveListenPorts(edge),
|
listenPorts: this.getEffectiveListenPorts(edge),
|
||||||
|
...(listenPortsUdp.length > 0 ? { listenPortsUdp } : {}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export interface IRemoteIngress {
|
|||||||
name: string;
|
name: string;
|
||||||
secret: string;
|
secret: string;
|
||||||
listenPorts: number[];
|
listenPorts: number[];
|
||||||
|
/** UDP listen ports (e.g. for QUIC/HTTP3). Derived from routes with transport 'udp' or 'all'. */
|
||||||
|
listenPortsUdp?: number[];
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
/** Whether to auto-derive ports from remoteIngress-tagged routes. Defaults to true. */
|
/** Whether to auto-derive ports from remoteIngress-tagged routes. Defaults to true. */
|
||||||
autoDerivePorts: boolean;
|
autoDerivePorts: boolean;
|
||||||
@@ -20,6 +22,8 @@ export interface IRemoteIngress {
|
|||||||
manualPorts?: number[];
|
manualPorts?: number[];
|
||||||
/** Ports auto-derived from route configs — only present in API responses. */
|
/** Ports auto-derived from route configs — only present in API responses. */
|
||||||
derivedPorts?: number[];
|
derivedPorts?: number[];
|
||||||
|
/** Effective UDP ports (union of manual + derived) — only present in API responses. */
|
||||||
|
effectiveListenPortsUdp?: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ export interface INetworkMetrics {
|
|||||||
throughputHistory?: Array<{ timestamp: number; in: number; out: number }>;
|
throughputHistory?: Array<{ timestamp: number; in: number; out: number }>;
|
||||||
requestsPerSecond?: number;
|
requestsPerSecond?: number;
|
||||||
requestsTotal?: number;
|
requestsTotal?: number;
|
||||||
|
backends?: IBackendInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IConnectionDetails {
|
export interface IConnectionDetails {
|
||||||
@@ -175,3 +176,25 @@ export interface IConnectionDetails {
|
|||||||
bytesIn: number;
|
bytesIn: number;
|
||||||
bytesOut: number;
|
bytesOut: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IBackendInfo {
|
||||||
|
backend: string;
|
||||||
|
domain: string | null;
|
||||||
|
protocol: string;
|
||||||
|
activeConnections: number;
|
||||||
|
totalConnections: number;
|
||||||
|
connectErrors: number;
|
||||||
|
handshakeErrors: number;
|
||||||
|
requestErrors: number;
|
||||||
|
avgConnectTimeMs: number;
|
||||||
|
poolHitRate: number;
|
||||||
|
h2Failures: number;
|
||||||
|
h2Suppressed: boolean;
|
||||||
|
h3Suppressed: boolean;
|
||||||
|
h2CooldownRemainingSecs: number | null;
|
||||||
|
h3CooldownRemainingSecs: number | null;
|
||||||
|
h2ConsecutiveFailures: number | null;
|
||||||
|
h3ConsecutiveFailures: number | null;
|
||||||
|
h3Port: number | null;
|
||||||
|
cacheAgeSecs: number | null;
|
||||||
|
}
|
||||||
@@ -179,5 +179,6 @@ export interface IReq_GetNetworkStats extends plugins.typedrequestInterfaces.imp
|
|||||||
throughputByIP: Array<{ ip: string; in: number; out: number }>;
|
throughputByIP: Array<{ ip: string; in: number; out: number }>;
|
||||||
requestsPerSecond: number;
|
requestsPerSecond: number;
|
||||||
requestsTotal: number;
|
requestsTotal: number;
|
||||||
|
backends?: statsInterfaces.IBackendInfo[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/dcrouter',
|
name: '@serve.zone/dcrouter',
|
||||||
version: '11.7.1',
|
version: '11.10.4',
|
||||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export interface INetworkState {
|
|||||||
throughputHistory: Array<{ timestamp: number; in: number; out: number }>;
|
throughputHistory: Array<{ timestamp: number; in: number; out: number }>;
|
||||||
requestsPerSecond: number;
|
requestsPerSecond: number;
|
||||||
requestsTotal: number;
|
requestsTotal: number;
|
||||||
|
backends: interfaces.data.IBackendInfo[];
|
||||||
lastUpdated: number;
|
lastUpdated: number;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
@@ -148,6 +149,7 @@ export const networkStatePart = await appState.getStatePart<INetworkState>(
|
|||||||
throughputHistory: [],
|
throughputHistory: [],
|
||||||
requestsPerSecond: 0,
|
requestsPerSecond: 0,
|
||||||
requestsTotal: 0,
|
requestsTotal: 0,
|
||||||
|
backends: [],
|
||||||
lastUpdated: 0,
|
lastUpdated: 0,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: null,
|
error: null,
|
||||||
@@ -503,6 +505,7 @@ export const fetchNetworkStatsAction = networkStatePart.createAction(async (stat
|
|||||||
throughputHistory: networkStatsResponse.throughputHistory || [],
|
throughputHistory: networkStatsResponse.throughputHistory || [],
|
||||||
requestsPerSecond: networkStatsResponse.requestsPerSecond || 0,
|
requestsPerSecond: networkStatsResponse.requestsPerSecond || 0,
|
||||||
requestsTotal: networkStatsResponse.requestsTotal || 0,
|
requestsTotal: networkStatsResponse.requestsTotal || 0,
|
||||||
|
backends: networkStatsResponse.backends || [],
|
||||||
lastUpdated: Date.now(),
|
lastUpdated: Date.now(),
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: null,
|
error: null,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { DeesElement, property, html, customElement, type TemplateResult, css, state, cssManager } from '@design.estate/dees-element';
|
import { DeesElement, property, html, customElement, type TemplateResult, css, state, cssManager } from '@design.estate/dees-element';
|
||||||
import * as appstate from '../appstate.js';
|
import * as appstate from '../appstate.js';
|
||||||
|
import * as interfaces from '../../dist_ts_interfaces/index.js';
|
||||||
import { viewHostCss } from './shared/css.js';
|
import { viewHostCss } from './shared/css.js';
|
||||||
import { type IStatsTile } from '@design.estate/dees-catalog';
|
import { type IStatsTile } from '@design.estate/dees-catalog';
|
||||||
|
|
||||||
@@ -198,6 +199,38 @@ export class OpsViewNetwork extends DeesElement {
|
|||||||
color: ${cssManager.bdTheme('#00796b', '#4db6ac')};
|
color: ${cssManager.bdTheme('#00796b', '#4db6ac')};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.protocolBadge.h1 {
|
||||||
|
background: ${cssManager.bdTheme('#e3f2fd', '#1a2c3a')};
|
||||||
|
color: ${cssManager.bdTheme('#1976d2', '#5a9fd4')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.protocolBadge.h2 {
|
||||||
|
background: ${cssManager.bdTheme('#e8f5e9', '#1a3a1a')};
|
||||||
|
color: ${cssManager.bdTheme('#388e3c', '#66bb6a')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.protocolBadge.h3 {
|
||||||
|
background: ${cssManager.bdTheme('#f3e5f5', '#2a1a3a')};
|
||||||
|
color: ${cssManager.bdTheme('#7b1fa2', '#ba68c8')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.protocolBadge.unknown {
|
||||||
|
background: ${cssManager.bdTheme('#f5f5f5', '#2a2a2a')};
|
||||||
|
color: ${cssManager.bdTheme('#757575', '#999999')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.suppressionBadge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
background: ${cssManager.bdTheme('#fff3e0', '#3a2a1a')};
|
||||||
|
color: ${cssManager.bdTheme('#f57c00', '#ff9933')};
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.statusBadge {
|
.statusBadge {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -265,6 +298,9 @@ export class OpsViewNetwork extends DeesElement {
|
|||||||
<!-- Top IPs Section -->
|
<!-- Top IPs Section -->
|
||||||
${this.renderTopIPs()}
|
${this.renderTopIPs()}
|
||||||
|
|
||||||
|
<!-- Backend Protocols Section -->
|
||||||
|
${this.renderBackendProtocols()}
|
||||||
|
|
||||||
<!-- Requests Table -->
|
<!-- Requests Table -->
|
||||||
<dees-table
|
<dees-table
|
||||||
.data=${this.networkRequests}
|
.data=${this.networkRequests}
|
||||||
@@ -519,6 +555,106 @@ export class OpsViewNetwork extends DeesElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderBackendProtocols(): TemplateResult {
|
||||||
|
const backends = this.networkState.backends;
|
||||||
|
if (!backends || backends.length === 0) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<dees-table
|
||||||
|
.data=${backends}
|
||||||
|
.displayFunction=${(item: interfaces.data.IBackendInfo) => {
|
||||||
|
const totalErrors = item.connectErrors + item.handshakeErrors + item.requestErrors;
|
||||||
|
const protocolClass = item.protocol.toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||||
|
|
||||||
|
return {
|
||||||
|
'Backend': item.backend,
|
||||||
|
'Domain': item.domain || '-',
|
||||||
|
'Protocol': html`
|
||||||
|
<span class="protocolBadge ${protocolClass}">${item.protocol.toUpperCase()}</span>
|
||||||
|
${item.h2Suppressed ? html`<span class="suppressionBadge" title="H2 suppressed: ${item.h2ConsecutiveFailures ?? 0} failures, cooldown ${item.h2CooldownRemainingSecs ?? 0}s">H2 suppressed</span>` : ''}
|
||||||
|
${item.h3Suppressed ? html`<span class="suppressionBadge" title="H3 suppressed: ${item.h3ConsecutiveFailures ?? 0} failures, cooldown ${item.h3CooldownRemainingSecs ?? 0}s">H3 suppressed</span>` : ''}
|
||||||
|
`,
|
||||||
|
'Active': item.activeConnections,
|
||||||
|
'Total': this.formatNumber(item.totalConnections),
|
||||||
|
'Avg Connect': item.avgConnectTimeMs > 0 ? `${item.avgConnectTimeMs.toFixed(1)}ms` : '-',
|
||||||
|
'Pool Hit Rate': item.poolHitRate > 0 ? `${(item.poolHitRate * 100).toFixed(1)}%` : '-',
|
||||||
|
'Errors': totalErrors > 0
|
||||||
|
? html`<span class="statusBadge error">${totalErrors}</span>`
|
||||||
|
: html`<span class="statusBadge success">0</span>`,
|
||||||
|
'Cache Age': item.cacheAgeSecs != null ? `${Math.round(item.cacheAgeSecs)}s` : '-',
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
.dataActions=${[
|
||||||
|
{
|
||||||
|
name: 'View Details',
|
||||||
|
iconName: 'lucide:info',
|
||||||
|
type: ['inRow', 'doubleClick', 'contextmenu'] as any,
|
||||||
|
actionFunc: async (actionData: any) => {
|
||||||
|
await this.showBackendDetails(actionData.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
heading1="Backend Protocols"
|
||||||
|
heading2="Auto-detected backend protocols and connection pool health"
|
||||||
|
searchable
|
||||||
|
.pagination=${false}
|
||||||
|
dataName="backend"
|
||||||
|
></dees-table>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async showBackendDetails(backend: interfaces.data.IBackendInfo) {
|
||||||
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
||||||
|
|
||||||
|
await DeesModal.createAndShow({
|
||||||
|
heading: `Backend: ${backend.backend}`,
|
||||||
|
content: html`
|
||||||
|
<div style="padding: 20px;">
|
||||||
|
<dees-dataview-codebox
|
||||||
|
.heading=${'Backend Details'}
|
||||||
|
progLang="json"
|
||||||
|
.codeToDisplay=${JSON.stringify({
|
||||||
|
backend: backend.backend,
|
||||||
|
domain: backend.domain,
|
||||||
|
protocol: backend.protocol,
|
||||||
|
activeConnections: backend.activeConnections,
|
||||||
|
totalConnections: backend.totalConnections,
|
||||||
|
avgConnectTimeMs: backend.avgConnectTimeMs,
|
||||||
|
poolHitRate: backend.poolHitRate,
|
||||||
|
errors: {
|
||||||
|
connect: backend.connectErrors,
|
||||||
|
handshake: backend.handshakeErrors,
|
||||||
|
request: backend.requestErrors,
|
||||||
|
h2Failures: backend.h2Failures,
|
||||||
|
},
|
||||||
|
suppression: {
|
||||||
|
h2Suppressed: backend.h2Suppressed,
|
||||||
|
h3Suppressed: backend.h3Suppressed,
|
||||||
|
h2CooldownRemainingSecs: backend.h2CooldownRemainingSecs,
|
||||||
|
h3CooldownRemainingSecs: backend.h3CooldownRemainingSecs,
|
||||||
|
h2ConsecutiveFailures: backend.h2ConsecutiveFailures,
|
||||||
|
h3ConsecutiveFailures: backend.h3ConsecutiveFailures,
|
||||||
|
},
|
||||||
|
h3Port: backend.h3Port,
|
||||||
|
cacheAgeSecs: backend.cacheAgeSecs,
|
||||||
|
}, null, 2)}
|
||||||
|
></dees-dataview-codebox>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
menuOptions: [
|
||||||
|
{
|
||||||
|
name: 'Copy Backend Key',
|
||||||
|
iconName: 'lucide:Copy',
|
||||||
|
action: async () => {
|
||||||
|
await navigator.clipboard.writeText(backend.backend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async updateNetworkData() {
|
private async updateNetworkData() {
|
||||||
// Track requests/sec history for the trend sparkline (moved out of render)
|
// Track requests/sec history for the trend sparkline (moved out of render)
|
||||||
const reqPerSec = this.networkState.requestsPerSecond || 0;
|
const reqPerSec = this.networkState.requestsPerSecond || 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user