From 1d0f47f2566a4d8d5a62015342fba8b36be0df39 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Thu, 19 Mar 2026 16:41:16 +0000 Subject: [PATCH] feat(opsserver): add configurable OpsServer port and update related tests and documentation --- changelog.md | 9 ++++ package.json | 10 ++-- pnpm-lock.yaml | 50 +++++++++---------- readme.md | 8 ++- test/test.dcrouter.email.ts | 1 + test/test.dns-socket-handler.ts | 1 + test/test.jwt-auth.ts | 13 ++--- test/test.opsserver-api.ts | 13 ++--- test/test.protected-endpoint.ts | 13 ++--- ts/00_commitinfo_data.ts | 2 +- ts/classes.dcrouter.ts | 3 ++ ts/opsserver/classes.opsserver.ts | 2 +- ts/readme.md | 7 ++- .../classes.remoteingress-manager.ts | 2 +- ts_web/00_commitinfo_data.ts | 2 +- 15 files changed, 80 insertions(+), 56 deletions(-) diff --git a/changelog.md b/changelog.md index ea1d560..da6796a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,14 @@ # Changelog +## 2026-03-19 - 11.5.0 - feat(opsserver) +add configurable OpsServer port and update related tests and documentation + +- introduces an optional `opsServerPort` configuration that overrides the default OpsServer port 3000 +- updates OpsServer startup logic to use the configured port +- adjusts integration tests to run against dedicated OpsServer ports to avoid conflicts +- documents the new OpsServer port option in the README and TypeScript docs +- includes dependency updates and a remote ingress port range type refinement + ## 2026-03-19 - 11.4.0 - feat(docs) document OCI container deployment and enable verbose docker build scripts diff --git a/package.json b/package.json index 9eefb20..f0da855 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@git.zone/tsbuild": "^4.3.0", "@git.zone/tsbundle": "^2.9.1", "@git.zone/tsrun": "^2.0.1", - "@git.zone/tstest": "^3.3.2", + "@git.zone/tstest": "^3.5.0", "@git.zone/tswatch": "^3.3.0", "@types/node": "^25.5.0" }, @@ -40,7 +40,7 @@ "@push.rocks/lik": "^6.3.1", "@push.rocks/projectinfo": "^5.0.2", "@push.rocks/qenv": "^6.1.3", - "@push.rocks/smartacme": "^9.1.3", + "@push.rocks/smartacme": "^9.3.0", "@push.rocks/smartdata": "^7.1.0", "@push.rocks/smartdns": "^7.9.0", "@push.rocks/smartfile": "^13.1.2", @@ -53,15 +53,15 @@ "@push.rocks/smartnetwork": "^4.4.0", "@push.rocks/smartpath": "^6.0.0", "@push.rocks/smartpromise": "^4.2.3", - "@push.rocks/smartproxy": "^25.11.24", + "@push.rocks/smartproxy": "^25.14.1", "@push.rocks/smartradius": "^1.1.1", "@push.rocks/smartrequest": "^5.0.1", "@push.rocks/smartrx": "^3.0.10", "@push.rocks/smartstate": "^2.2.0", "@push.rocks/smartunique": "^3.0.9", - "@serve.zone/catalog": "^2.7.0", + "@serve.zone/catalog": "^2.9.0", "@serve.zone/interfaces": "^5.3.0", - "@serve.zone/remoteingress": "^4.9.0", + "@serve.zone/remoteingress": "^4.13.0", "@tsclass/tsclass": "^9.4.0", "lru-cache": "^11.2.7", "uuid": "^13.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 459028e..b58837e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,8 +39,8 @@ importers: specifier: ^6.1.3 version: 6.1.3 '@push.rocks/smartacme': - specifier: ^9.1.3 - version: 9.1.3(socks@2.8.7) + specifier: ^9.3.0 + version: 9.3.0(socks@2.8.7) '@push.rocks/smartdata': specifier: ^7.1.0 version: 7.1.0(socks@2.8.7) @@ -78,8 +78,8 @@ importers: specifier: ^4.2.3 version: 4.2.3 '@push.rocks/smartproxy': - specifier: ^25.11.24 - version: 25.11.24 + specifier: ^25.14.1 + version: 25.14.1 '@push.rocks/smartradius': specifier: ^1.1.1 version: 1.1.1 @@ -96,14 +96,14 @@ importers: specifier: ^3.0.9 version: 3.0.9 '@serve.zone/catalog': - specifier: ^2.7.0 - version: 2.8.0(@tiptap/pm@2.27.2) + specifier: ^2.9.0 + version: 2.9.0(@tiptap/pm@2.27.2) '@serve.zone/interfaces': specifier: ^5.3.0 version: 5.3.0 '@serve.zone/remoteingress': - specifier: ^4.9.0 - version: 4.9.1 + specifier: ^4.13.0 + version: 4.13.0 '@tsclass/tsclass': specifier: ^9.4.0 version: 9.5.0 @@ -124,8 +124,8 @@ importers: specifier: ^2.0.1 version: 2.0.1 '@git.zone/tstest': - specifier: ^3.3.2 - version: 3.4.0(socks@2.8.7)(typescript@5.9.3) + specifier: ^3.5.0 + version: 3.5.0(socks@2.8.7)(typescript@5.9.3) '@git.zone/tswatch': specifier: ^3.3.0 version: 3.3.0(@tiptap/pm@2.27.2) @@ -554,8 +554,8 @@ packages: resolution: {integrity: sha512-NEcnsjvlC1o3Z6SS3VhKCf6Ev+Sh4EAinmggslrIR/ppMrvjDbXNFXoyr3PB+GLeSAR0JRZ1fGvVYjpEzjBdIg==} hasBin: true - '@git.zone/tstest@3.4.0': - resolution: {integrity: sha512-EpIrwlfU8BfhO3na6bb/2RcBB2Zi8rbQfoO+QLY+rc1nj/iHW+mgSeDnXuKQTATI0OQ0xsq3xB4qIZ0tKSYvYw==} + '@git.zone/tstest@3.5.0': + resolution: {integrity: sha512-ugIJzdVkbgqSSw08SZajE7TB01GIYjEAmIy67O5skhvOyszGifwzJdR+8dS1VbQGlUUWQZMGQ2IowllHbAZYJQ==} hasBin: true '@git.zone/tswatch@3.3.0': @@ -1079,8 +1079,8 @@ packages: '@push.rocks/qenv@6.1.3': resolution: {integrity: sha512-+z2hsAU/7CIgpYLFqvda8cn9rUBMHqLdQLjsFfRn5jPoD7dJ5rFlpkbhfM4Ws8mHMniwWaxGKo+q/YBhtzRBLg==} - '@push.rocks/smartacme@9.1.3': - resolution: {integrity: sha512-rxb4zGZQvcR7l8cb8SvLy+zkCgXKg8rO7b12zaE9ZBe5Q+khoInxscC0eKjmNZ7BOUFFDOxDKoQhgeqwHGOqZQ==} + '@push.rocks/smartacme@9.3.0': + resolution: {integrity: sha512-R6+fBNqlIy3fP2ECmOjBB65tl35w2+2vmSierO6oC9/5DW+khwjvFsT0+5WnfyjejEtWzdAprEseYWmBbyTGtA==} '@push.rocks/smartarchive@4.2.4': resolution: {integrity: sha512-uiqVAXPxmr8G5rv3uZvZFMOCt8l7cZC3nzvsy4YQqKf/VkPhKIEX+b7LkAeNlxPSYUiBQUkNRoawg9+5BaMcHg==} @@ -1256,8 +1256,8 @@ packages: '@push.rocks/smartpromise@4.2.3': resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==} - '@push.rocks/smartproxy@25.11.24': - resolution: {integrity: sha512-dkeQJM2W5wKwTBZXxy3hGhIyQv2XeAQqwWliDbi/2oy6LU6BFdgpzEdhE5emG+wOcfQTagALpOIt7lBAzetjSA==} + '@push.rocks/smartproxy@25.14.1': + resolution: {integrity: sha512-QXJ1M7Or81lmCusAKkmIB8M9jJwl1/AKItnmTkn8IQ9zsPd6r+0uhP1j5tCO/LwRQRpzOADnpSrpVcrtMKK9kQ==} '@push.rocks/smartpuppeteer@2.0.5': resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==} @@ -1544,14 +1544,14 @@ packages: '@selderee/plugin-htmlparser2@0.11.0': resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} - '@serve.zone/catalog@2.8.0': - resolution: {integrity: sha512-p0ES14JwUoJE88DBtLSHcCfFPVa0vKhvHnQLaAY3OC15kfheNKidi1SwTFyMh43jj0ZNi4Lecc3W02wG6sasHw==} + '@serve.zone/catalog@2.9.0': + resolution: {integrity: sha512-7FgwS44pD/DFVj29jS0Kwwyn1i5h8cf4/yWMBEY8+8GO70ab3QctbcKMu+BVa1G3gIrpLqhpmxLFDoeL/zDnQA==} '@serve.zone/interfaces@5.3.0': resolution: {integrity: sha512-venO7wtDR9ixzD9NhdERBGjNKbFA5LL0yHw4eqGh0UpmvtXVc3SFG0uuHDilOKMZqZ8bttV88qVsFy1aSTJrtA==} - '@serve.zone/remoteingress@4.9.1': - resolution: {integrity: sha512-z3UwPIlcrQp1fm1BpSY5JxUorDiBawd2h7St5FNWbL6X4qCWu+/fLB+EdAyZQy+JD02lRglZiaxk4wpnp8rQkA==} + '@serve.zone/remoteingress@4.13.0': + resolution: {integrity: sha512-Gw/yIgCukh3kImIco3u9B+b2cQP4l88RgCdP7NhYpwTDrI9jrsKmrzq0cRXo/Lnja35RZ1D7fBmNvaaAqEToVQ==} '@sindresorhus/is@5.6.0': resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} @@ -5142,7 +5142,7 @@ snapshots: '@push.rocks/smartshell': 3.3.8 tsx: 4.21.0 - '@git.zone/tstest@3.4.0(socks@2.8.7)(typescript@5.9.3)': + '@git.zone/tstest@3.5.0(socks@2.8.7)(typescript@5.9.3)': dependencies: '@git.zone/tsbundle': 2.9.1 '@git.zone/tsrun': 2.0.1 @@ -5942,7 +5942,7 @@ snapshots: '@push.rocks/smartlog': 3.2.1 '@push.rocks/smartpath': 6.0.0 - '@push.rocks/smartacme@9.1.3(socks@2.8.7)': + '@push.rocks/smartacme@9.3.0(socks@2.8.7)': dependencies: '@apiclient.xyz/cloudflare': 7.1.0 '@peculiar/x509': 1.14.3 @@ -6539,7 +6539,7 @@ snapshots: '@push.rocks/smartpromise@4.2.3': {} - '@push.rocks/smartproxy@25.11.24': + '@push.rocks/smartproxy@25.14.1': dependencies: '@push.rocks/smartcrypto': 2.0.4 '@push.rocks/smartlog': 3.2.1 @@ -6937,7 +6937,7 @@ snapshots: domhandler: 5.0.3 selderee: 0.11.0 - '@serve.zone/catalog@2.8.0(@tiptap/pm@2.27.2)': + '@serve.zone/catalog@2.9.0(@tiptap/pm@2.27.2)': dependencies: '@design.estate/dees-catalog': 3.49.0(@tiptap/pm@2.27.2) '@design.estate/dees-domtools': 2.5.1 @@ -6956,7 +6956,7 @@ snapshots: '@push.rocks/smartlog-interfaces': 3.0.2 '@tsclass/tsclass': 9.5.0 - '@serve.zone/remoteingress@4.9.1': + '@serve.zone/remoteingress@4.13.0': dependencies: '@push.rocks/qenv': 6.1.3 '@push.rocks/smartrust': 1.3.2 diff --git a/readme.md b/readme.md index 8e662b6..a3c18d3 100644 --- a/readme.md +++ b/readme.md @@ -344,7 +344,7 @@ graph TB DcRouter acts purely as an **orchestrator** — it doesn't implement protocols itself. Instead, it wires together best-in-class packages for each protocol: -1. **On `start()`**: DcRouter initializes OpsServer (port 3000), then spins up SmartProxy, smartmta, SmartDNS, SmartRadius, and RemoteIngress based on which configs are provided. +1. **On `start()`**: DcRouter initializes OpsServer (default port 3000, configurable via `opsServerPort`), then spins up SmartProxy, smartmta, SmartDNS, SmartRadius, and RemoteIngress based on which configs are provided. 2. **During operation**: Each service handles its own protocol independently. SmartProxy uses a Rust-powered engine for maximum throughput. smartmta uses a hybrid TypeScript + Rust architecture for reliable email delivery. RemoteIngress runs a Rust data plane for edge tunnel networking. SmartAcme v9 handles all certificate operations with built-in concurrency control and rate limiting. 3. **On `stop()`**: All services are gracefully shut down in parallel, including cleanup of HTTP agents and DNS clients. @@ -425,6 +425,10 @@ interface IDcRouterOptions { }; }; + // ── OpsServer ──────────────────────────────────────────────── + /** Port for the OpsServer web dashboard (default: 3000) */ + opsServerPort?: number; + // ── TLS & Certificates ──────────────────────────────────────── tls?: { contactEmail: string; @@ -1016,7 +1020,7 @@ action: { ## OpsServer Dashboard -The OpsServer provides a web-based management interface served on port 3000. It's built with modern web components using [@design.estate/dees-catalog](https://code.foss.global/design.estate/dees-catalog). +The OpsServer provides a web-based management interface served on port 3000 by default (configurable via `opsServerPort`). It's built with modern web components using [@design.estate/dees-catalog](https://code.foss.global/design.estate/dees-catalog). ### Dashboard Views diff --git a/test/test.dcrouter.email.ts b/test/test.dcrouter.email.ts index 8bb057a..6e84d7a 100644 --- a/test/test.dcrouter.email.ts +++ b/test/test.dcrouter.email.ts @@ -129,6 +129,7 @@ tap.test('DcRouter class - Email config with domains and routes', async () => { tls: { contactEmail: 'test@example.com' }, + opsServerPort: 3104, cacheConfig: { enabled: false, } diff --git a/test/test.dns-socket-handler.ts b/test/test.dns-socket-handler.ts index bf49e88..4ec01ac 100644 --- a/test/test.dns-socket-handler.ts +++ b/test/test.dns-socket-handler.ts @@ -9,6 +9,7 @@ tap.test('should NOT instantiate DNS server when dnsNsDomains is not set', async smartProxyConfig: { routes: [] }, + opsServerPort: 3100, cacheConfig: { enabled: false } }); diff --git a/test/test.jwt-auth.ts b/test/test.jwt-auth.ts index 3fa4b6a..be336ef 100644 --- a/test/test.jwt-auth.ts +++ b/test/test.jwt-auth.ts @@ -9,6 +9,7 @@ let identity: interfaces.data.IIdentity; tap.test('should start DCRouter with OpsServer', async () => { testDcRouter = new DcRouter({ // Minimal config for testing + opsServerPort: 3102, cacheConfig: { enabled: false }, }); @@ -18,7 +19,7 @@ tap.test('should start DCRouter with OpsServer', async () => { tap.test('should login with admin credentials and receive JWT', async () => { const loginRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3102/typedrequest', 'adminLoginWithUsernameAndPassword' ); @@ -41,7 +42,7 @@ tap.test('should login with admin credentials and receive JWT', async () => { tap.test('should verify valid JWT identity', async () => { const verifyRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3102/typedrequest', 'verifyIdentity' ); @@ -57,7 +58,7 @@ tap.test('should verify valid JWT identity', async () => { tap.test('should reject invalid JWT', async () => { const verifyRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3102/typedrequest', 'verifyIdentity' ); @@ -74,7 +75,7 @@ tap.test('should reject invalid JWT', async () => { tap.test('should verify JWT matches identity data', async () => { const verifyRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3102/typedrequest', 'verifyIdentity' ); @@ -91,7 +92,7 @@ tap.test('should verify JWT matches identity data', async () => { tap.test('should handle logout', async () => { const logoutRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3102/typedrequest', 'adminLogout' ); @@ -105,7 +106,7 @@ tap.test('should handle logout', async () => { tap.test('should reject wrong credentials', async () => { const loginRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3102/typedrequest', 'adminLoginWithUsernameAndPassword' ); diff --git a/test/test.opsserver-api.ts b/test/test.opsserver-api.ts index b2fd0a3..0f856ad 100644 --- a/test/test.opsserver-api.ts +++ b/test/test.opsserver-api.ts @@ -9,6 +9,7 @@ let adminIdentity: interfaces.data.IIdentity; tap.test('should start DCRouter with OpsServer', async () => { testDcRouter = new DcRouter({ // Minimal config for testing + opsServerPort: 3101, cacheConfig: { enabled: false }, }); @@ -18,7 +19,7 @@ tap.test('should start DCRouter with OpsServer', async () => { tap.test('should login as admin', async () => { const loginRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3101/typedrequest', 'adminLoginWithUsernameAndPassword' ); @@ -33,7 +34,7 @@ tap.test('should login as admin', async () => { tap.test('should respond to health status request', async () => { const healthRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3101/typedrequest', 'getHealthStatus' ); @@ -49,7 +50,7 @@ tap.test('should respond to health status request', async () => { tap.test('should respond to server statistics request', async () => { const statsRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3101/typedrequest', 'getServerStatistics' ); @@ -66,7 +67,7 @@ tap.test('should respond to server statistics request', async () => { tap.test('should respond to configuration request', async () => { const configRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3101/typedrequest', 'getConfiguration' ); @@ -87,7 +88,7 @@ tap.test('should respond to configuration request', async () => { tap.test('should handle log retrieval request', async () => { const logsRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3101/typedrequest', 'getRecentLogs' ); @@ -104,7 +105,7 @@ tap.test('should handle log retrieval request', async () => { tap.test('should reject unauthenticated requests', async () => { const healthRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3101/typedrequest', 'getHealthStatus' ); diff --git a/test/test.protected-endpoint.ts b/test/test.protected-endpoint.ts index ffe9ab1..6b2756d 100644 --- a/test/test.protected-endpoint.ts +++ b/test/test.protected-endpoint.ts @@ -9,6 +9,7 @@ let adminIdentity: interfaces.data.IIdentity; tap.test('should start DCRouter with OpsServer', async () => { testDcRouter = new DcRouter({ // Minimal config for testing + opsServerPort: 3103, cacheConfig: { enabled: false }, }); @@ -18,7 +19,7 @@ tap.test('should start DCRouter with OpsServer', async () => { tap.test('should login as admin', async () => { const loginRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3103/typedrequest', 'adminLoginWithUsernameAndPassword' ); @@ -34,7 +35,7 @@ tap.test('should login as admin', async () => { tap.test('should allow admin to verify identity', async () => { const verifyRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3103/typedrequest', 'verifyIdentity' ); @@ -49,7 +50,7 @@ tap.test('should allow admin to verify identity', async () => { tap.test('should reject verify identity without identity', async () => { const verifyRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3103/typedrequest', 'verifyIdentity' ); @@ -64,7 +65,7 @@ tap.test('should reject verify identity without identity', async () => { tap.test('should reject verify identity with invalid JWT', async () => { const verifyRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3103/typedrequest', 'verifyIdentity' ); @@ -84,7 +85,7 @@ tap.test('should reject verify identity with invalid JWT', async () => { tap.test('should reject protected endpoints without auth', async () => { const healthRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3103/typedrequest', 'getHealthStatus' ); @@ -100,7 +101,7 @@ tap.test('should reject protected endpoints without auth', async () => { tap.test('should allow authenticated access to protected endpoints', async () => { const configRequest = new TypedRequest( - 'http://localhost:3000/typedrequest', + 'http://localhost:3103/typedrequest', 'getConfiguration' ); diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 23a3c83..3fb6a33 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/dcrouter', - version: '11.4.0', + version: '11.5.0', description: 'A multifaceted routing service handling mail and SMS delivery functions.' } diff --git a/ts/classes.dcrouter.ts b/ts/classes.dcrouter.ts index f3a403d..693c694 100644 --- a/ts/classes.dcrouter.ts +++ b/ts/classes.dcrouter.ts @@ -163,6 +163,9 @@ export interface IDcRouterOptions { * Remote Ingress configuration for edge tunnel nodes * Enables edge nodes to accept incoming connections and tunnel them to this DcRouter */ + /** Port for the OpsServer web UI (default: 3000) */ + opsServerPort?: number; + remoteIngressConfig?: { /** Enable remote ingress hub (default: false) */ enabled?: boolean; diff --git a/ts/opsserver/classes.opsserver.ts b/ts/opsserver/classes.opsserver.ts index 5cba64b..4b0d684 100644 --- a/ts/opsserver/classes.opsserver.ts +++ b/ts/opsserver/classes.opsserver.ts @@ -50,7 +50,7 @@ export class OpsServer { // Set up handlers await this.setupHandlers(); - await this.server.start(3000); + await this.server.start(this.dcRouterRef.options.opsServerPort ?? 3000); } /** diff --git a/ts/readme.md b/ts/readme.md index 9f62c4b..92fd2ac 100644 --- a/ts/readme.md +++ b/ts/readme.md @@ -37,7 +37,7 @@ const router = new DcRouter({ }); await router.start(); -// OpsServer dashboard at http://localhost:3000 +// OpsServer dashboard at http://localhost:3000 (configurable via opsServerPort) // Graceful shutdown await router.stop(); @@ -71,7 +71,10 @@ ts/ │ ├── email.handler.ts # Email operations │ ├── certificate.handler.ts # Certificate management │ ├── radius.handler.ts # RADIUS management -│ └── remoteingress.handler.ts # Remote ingress edge + token management +│ ├── remoteingress.handler.ts # Remote ingress edge + token management +│ ├── route-management.handler.ts # Programmatic route CRUD +│ ├── api-token.handler.ts # API token management +│ └── security.handler.ts # Security metrics + connections ├── radius/ # RADIUS server integration ├── remoteingress/ # Remote ingress hub integration │ ├── classes.remoteingress-manager.ts # Edge CRUD + port derivation diff --git a/ts/remoteingress/classes.remoteingress-manager.ts b/ts/remoteingress/classes.remoteingress-manager.ts index 1f9af64..ccc335a 100644 --- a/ts/remoteingress/classes.remoteingress-manager.ts +++ b/ts/remoteingress/classes.remoteingress-manager.ts @@ -7,7 +7,7 @@ const STORAGE_PREFIX = '/remote-ingress/'; /** * Flatten a port range (number | number[] | Array<{from, to}>) to a sorted unique number array. */ -function extractPorts(portRange: number | number[] | Array<{ from: number; to: number }>): number[] { +function extractPorts(portRange: number | Array): number[] { const ports = new Set(); if (typeof portRange === 'number') { ports.add(portRange); diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index 23a3c83..3fb6a33 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/dcrouter', - version: '11.4.0', + version: '11.5.0', description: 'A multifaceted routing service handling mail and SMS delivery functions.' }