Compare commits

...

12 Commits

Author SHA1 Message Date
7663f502fa v11.10.4
Some checks failed
Docker (tags) / security (push) Failing after 3s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2026-03-24 13:40:28 +00:00
104cd417d8 fix(monitoring): handle multiple protocol cache entries per backend in metrics output 2026-03-24 13:40:28 +00:00
93254d5d3d v11.10.3
Some checks failed
Docker (tags) / security (push) Failing after 3s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2026-03-23 21:18:20 +00:00
9a3f121a9c fix(deps): bump tstest, smartmetrics, and taskbuffer to latest patch releases 2026-03-23 21:18:20 +00:00
bef74eb1aa v11.10.2
Some checks failed
Docker (tags) / security (push) Failing after 3s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2026-03-23 14:22:24 +00:00
308d8e4851 fix(deps): bump @api.global/typedserver to ^8.4.6 and @push.rocks/smartproxy to ^26.2.1 2026-03-23 14:22:24 +00:00
dc010dc3ae v11.10.1
Some checks failed
Docker (tags) / security (push) Failing after 3s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2026-03-23 10:29:16 +00:00
61d5d3b1ad fix(deps): bump @push.rocks/smartproxy to ^26.2.0 2026-03-23 10:29:16 +00:00
dd70790d40 v11.10.0
Some checks failed
Docker (tags) / security (push) Failing after 3s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2026-03-23 07:17:33 +00:00
2f8c04edc4 feat(monitoring): add backend protocol metrics to network stats and ops dashboard 2026-03-23 07:17:33 +00:00
474cc328dd v11.9.1
Some checks failed
Docker (tags) / security (push) Failing after 2s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2026-03-21 22:30:30 +00:00
39ff159bf7 fix(lifecycle): clean up service subscriptions, proxy retries, and stale runtime state on shutdown 2026-03-21 22:30:30 +00:00
17 changed files with 552 additions and 112 deletions

View File

@@ -1,5 +1,45 @@
# 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) ## 2026-03-20 - 11.9.0 - feat(dcrouter)
add service manager lifecycle orchestration and health-based ops status reporting add service manager lifecycle orchestration and health-based ops status reporting

View File

@@ -1,7 +1,7 @@
{ {
"name": "@serve.zone/dcrouter", "name": "@serve.zone/dcrouter",
"private": false, "private": false,
"version": "11.9.0", "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,22 +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.17.10", "@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": "7.0.0", "@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.14.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"

237
pnpm-lock.yaml generated
View File

@@ -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.17.10 specifier: ^26.2.1
version: 25.17.10 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
@@ -96,8 +96,8 @@ importers:
specifier: ^3.0.9 specifier: ^3.0.9
version: 3.0.9 version: 3.0.9
'@push.rocks/taskbuffer': '@push.rocks/taskbuffer':
specifier: 7.0.0 specifier: ^8.0.2
version: 7.0.0 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)
@@ -105,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.14.0 specifier: ^4.14.1
version: 4.14.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
@@ -127,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)
@@ -147,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==}
@@ -557,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':
@@ -1067,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==}
@@ -1205,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==}
@@ -1259,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.17.10': '@push.rocks/smartproxy@26.2.1':
resolution: {integrity: sha512-7tONZ77+Jlp4j2bGzp7ZpnS7nZC2Z8qbL23TYVQIR5KXt9GJuJV4w3CBsULtxL9PzmQajcY7jbmjFnjq2hcVqQ==} 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==}
@@ -1289,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==}
@@ -1329,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==}
@@ -1344,8 +1351,8 @@ 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@7.0.0': '@push.rocks/taskbuffer@8.0.2':
resolution: {integrity: sha512-cmjGwC/K7SzAcJrQChWSLTbIYl6YORbUkA/gyUTPVj/7Z7/BL7GzLyhYRk3ZHBS0AiCeTiP2WWNl+QJrf2WP9g==} 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==}
@@ -1556,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.14.0': '@serve.zone/remoteingress@4.14.1':
resolution: {integrity: sha512-oDbKHhhvN2LxCcvmSgYhRLF+0FknEcPN+zg5kO4I0pfNpW/zgUYiaZns4TcYStZMS5/4i9j1uVR7QEO0a571/w==} 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==}
@@ -2047,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==}
@@ -2626,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:
@@ -3552,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'}
@@ -3986,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'}
@@ -4257,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==}
@@ -4280,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
@@ -4324,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
@@ -4332,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
@@ -4359,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
@@ -4378,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
@@ -4387,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
@@ -4913,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
@@ -5148,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
@@ -5199,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
@@ -5867,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
@@ -5887,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
@@ -5952,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
@@ -6048,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
@@ -6072,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)
@@ -6102,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)
@@ -6161,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':
@@ -6180,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
@@ -6205,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
@@ -6223,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
@@ -6260,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
@@ -6363,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
@@ -6545,7 +6566,7 @@ snapshots:
'@push.rocks/smartpromise@4.2.3': {} '@push.rocks/smartpromise@4.2.3': {}
'@push.rocks/smartproxy@25.17.10': '@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
@@ -6600,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
@@ -6617,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
@@ -6626,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
@@ -6634,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
@@ -6677,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
@@ -6688,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
@@ -6712,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:
@@ -6730,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
@@ -6751,7 +6794,7 @@ 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/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
@@ -6764,10 +6807,10 @@ snapshots:
- supports-color - supports-color
- vue - vue
'@push.rocks/taskbuffer@7.0.0': '@push.rocks/taskbuffer@8.0.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/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
@@ -6797,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
@@ -6978,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.14.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
@@ -7610,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
@@ -8171,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
@@ -8180,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:
@@ -9363,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: {}
@@ -9931,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
@@ -10204,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:
@@ -10221,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: {}

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/dcrouter', name: '@serve.zone/dcrouter',
version: '11.9.0', 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.'
} }

View File

@@ -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,

View File

@@ -254,6 +254,7 @@ export class DcRouter {
// Service lifecycle management // Service lifecycle management
public serviceManager: plugins.taskbuffer.ServiceManager; public serviceManager: plugins.taskbuffer.ServiceManager;
private serviceSubjectSubscription?: plugins.smartrx.rxjs.Subscription;
public smartAcmeReady = false; public smartAcmeReady = false;
// TypedRouter for API endpoints // TypedRouter for API endpoints
@@ -516,7 +517,7 @@ export class DcRouter {
} }
// Wire up aggregated events for logging // Wire up aggregated events for logging
this.serviceManager.serviceSubject.subscribe((event) => { this.serviceSubjectSubscription = this.serviceManager.serviceSubject.subscribe((event) => {
const level = event.type === 'failed' ? 'error' : event.type === 'retrying' ? 'warn' : 'info'; const level = event.type === 'failed' ? 'error' : event.type === 'retrying' ? 'warn' : 'info';
logger.log(level as any, `Service '${event.serviceName}': ${event.type}`, { logger.log(level as any, `Service '${event.serviceName}': ${event.type}`, {
state: event.state, state: event.state,
@@ -639,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;
@@ -1126,6 +1134,12 @@ export class DcRouter {
public async stop() { public async stop() {
logger.log('info', 'Stopping DcRouter services...'); logger.log('info', 'Stopping DcRouter services...');
// Unsubscribe from service events before stopping services
if (this.serviceSubjectSubscription) {
this.serviceSubjectSubscription.unsubscribe();
this.serviceSubjectSubscription = undefined;
}
// ServiceManager handles reverse-dependency-ordered shutdown // ServiceManager handles reverse-dependency-ordered shutdown
await this.serviceManager.stop(); await this.serviceManager.stop();

View File

@@ -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);
}; };

View File

@@ -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
} }

View File

@@ -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: [],
}; };
} }
) )

View File

@@ -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 || [],
}; };
})() })()
); );

View File

@@ -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
*/ */

View File

@@ -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');
} }

View File

@@ -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;
}

View File

@@ -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[];
}; };
} }

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/dcrouter', name: '@serve.zone/dcrouter',
version: '11.9.0', 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.'
} }

View File

@@ -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,

View File

@@ -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;