@serve.zone/dcrouter 11.0.50 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist_serve/bundle.js +1 -1
  2. package/dist_serve/index.html +121 -0
  3. package/dist_ts/00_commitinfo_data.js +2 -2
  4. package/dist_ts_apiclient/classes.apitoken.d.ts +41 -0
  5. package/dist_ts_apiclient/classes.apitoken.js +115 -0
  6. package/dist_ts_apiclient/classes.certificate.d.ts +57 -0
  7. package/dist_ts_apiclient/classes.certificate.js +69 -0
  8. package/dist_ts_apiclient/classes.config.d.ts +7 -0
  9. package/dist_ts_apiclient/classes.config.js +11 -0
  10. package/dist_ts_apiclient/classes.dcrouterapiclient.d.ts +41 -0
  11. package/dist_ts_apiclient/classes.dcrouterapiclient.js +81 -0
  12. package/dist_ts_apiclient/classes.email.d.ts +30 -0
  13. package/dist_ts_apiclient/classes.email.js +52 -0
  14. package/dist_ts_apiclient/classes.logs.d.ts +21 -0
  15. package/dist_ts_apiclient/classes.logs.js +14 -0
  16. package/dist_ts_apiclient/classes.radius.d.ts +59 -0
  17. package/dist_ts_apiclient/classes.radius.js +95 -0
  18. package/dist_ts_apiclient/classes.remoteingress.d.ts +54 -0
  19. package/dist_ts_apiclient/classes.remoteingress.js +136 -0
  20. package/dist_ts_apiclient/classes.route.d.ts +42 -0
  21. package/dist_ts_apiclient/classes.route.js +154 -0
  22. package/dist_ts_apiclient/classes.stats.d.ts +47 -0
  23. package/dist_ts_apiclient/classes.stats.js +38 -0
  24. package/dist_ts_apiclient/index.d.ts +10 -0
  25. package/dist_ts_apiclient/index.js +14 -0
  26. package/dist_ts_apiclient/plugins.d.ts +3 -0
  27. package/dist_ts_apiclient/plugins.js +5 -0
  28. package/dist_ts_web/00_commitinfo_data.js +2 -2
  29. package/npmextra.json +2 -1
  30. package/package.json +8 -5
  31. package/readme.md +103 -7
  32. package/ts/00_commitinfo_data.ts +1 -1
  33. package/ts_apiclient/classes.apitoken.ts +157 -0
  34. package/ts_apiclient/classes.certificate.ts +123 -0
  35. package/ts_apiclient/classes.config.ts +17 -0
  36. package/ts_apiclient/classes.dcrouterapiclient.ts +112 -0
  37. package/ts_apiclient/classes.email.ts +77 -0
  38. package/ts_apiclient/classes.logs.ts +37 -0
  39. package/ts_apiclient/classes.radius.ts +180 -0
  40. package/ts_apiclient/classes.remoteingress.ts +185 -0
  41. package/ts_apiclient/classes.route.ts +203 -0
  42. package/ts_apiclient/classes.stats.ts +111 -0
  43. package/ts_apiclient/index.ts +15 -0
  44. package/ts_apiclient/plugins.ts +8 -0
  45. package/ts_apiclient/readme.md +279 -0
  46. package/ts_apiclient/tspublish.json +3 -0
  47. package/ts_web/00_commitinfo_data.ts +1 -1
  48. package/ts_web/readme.md +7 -0
@@ -0,0 +1,47 @@
1
+ import * as interfaces from '../dist_ts_interfaces/index.js';
2
+ import type { DcRouterApiClient } from './classes.dcrouterapiclient.js';
3
+ type TTimeRange = '1h' | '6h' | '24h' | '7d' | '30d';
4
+ export declare class StatsManager {
5
+ private clientRef;
6
+ constructor(clientRef: DcRouterApiClient);
7
+ getServer(options?: {
8
+ timeRange?: TTimeRange;
9
+ includeHistory?: boolean;
10
+ }): Promise<interfaces.requests.IReq_GetServerStatistics['response']>;
11
+ getEmail(options?: {
12
+ timeRange?: TTimeRange;
13
+ domain?: string;
14
+ includeDetails?: boolean;
15
+ }): Promise<interfaces.requests.IReq_GetEmailStatistics['response']>;
16
+ getDns(options?: {
17
+ timeRange?: TTimeRange;
18
+ domain?: string;
19
+ includeQueryTypes?: boolean;
20
+ }): Promise<interfaces.requests.IReq_GetDnsStatistics['response']>;
21
+ getRateLimits(options?: {
22
+ domain?: string;
23
+ ip?: string;
24
+ includeBlocked?: boolean;
25
+ }): Promise<interfaces.requests.IReq_GetRateLimitStatus['response']>;
26
+ getSecurity(options?: {
27
+ timeRange?: TTimeRange;
28
+ includeDetails?: boolean;
29
+ }): Promise<interfaces.requests.IReq_GetSecurityMetrics['response']>;
30
+ getConnections(options?: {
31
+ protocol?: 'smtp' | 'smtps' | 'http' | 'https';
32
+ state?: string;
33
+ }): Promise<interfaces.requests.IReq_GetActiveConnections['response']>;
34
+ getQueues(options?: {
35
+ queueName?: string;
36
+ }): Promise<interfaces.requests.IReq_GetQueueStatus['response']>;
37
+ getHealth(detailed?: boolean): Promise<interfaces.requests.IReq_GetHealthStatus['response']>;
38
+ getNetwork(): Promise<interfaces.requests.IReq_GetNetworkStats['response']>;
39
+ getCombined(sections?: {
40
+ server?: boolean;
41
+ email?: boolean;
42
+ dns?: boolean;
43
+ security?: boolean;
44
+ network?: boolean;
45
+ }): Promise<interfaces.requests.IReq_GetCombinedMetrics['response']>;
46
+ }
47
+ export {};
@@ -0,0 +1,38 @@
1
+ import * as interfaces from '../dist_ts_interfaces/index.js';
2
+ export class StatsManager {
3
+ clientRef;
4
+ constructor(clientRef) {
5
+ this.clientRef = clientRef;
6
+ }
7
+ async getServer(options) {
8
+ return this.clientRef.request('getServerStatistics', this.clientRef.buildRequestPayload(options || {}));
9
+ }
10
+ async getEmail(options) {
11
+ return this.clientRef.request('getEmailStatistics', this.clientRef.buildRequestPayload(options || {}));
12
+ }
13
+ async getDns(options) {
14
+ return this.clientRef.request('getDnsStatistics', this.clientRef.buildRequestPayload(options || {}));
15
+ }
16
+ async getRateLimits(options) {
17
+ return this.clientRef.request('getRateLimitStatus', this.clientRef.buildRequestPayload(options || {}));
18
+ }
19
+ async getSecurity(options) {
20
+ return this.clientRef.request('getSecurityMetrics', this.clientRef.buildRequestPayload(options || {}));
21
+ }
22
+ async getConnections(options) {
23
+ return this.clientRef.request('getActiveConnections', this.clientRef.buildRequestPayload(options || {}));
24
+ }
25
+ async getQueues(options) {
26
+ return this.clientRef.request('getQueueStatus', this.clientRef.buildRequestPayload(options || {}));
27
+ }
28
+ async getHealth(detailed) {
29
+ return this.clientRef.request('getHealthStatus', this.clientRef.buildRequestPayload({ detailed }));
30
+ }
31
+ async getNetwork() {
32
+ return this.clientRef.request('getNetworkStats', this.clientRef.buildRequestPayload());
33
+ }
34
+ async getCombined(sections) {
35
+ return this.clientRef.request('getCombinedMetrics', this.clientRef.buildRequestPayload({ sections }));
36
+ }
37
+ }
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zdGF0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzX2FwaWNsaWVudC9jbGFzc2VzLnN0YXRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxVQUFVLE1BQU0sMkJBQTJCLENBQUM7QUFLeEQsTUFBTSxPQUFPLFlBQVk7SUFDZixTQUFTLENBQW9CO0lBRXJDLFlBQVksU0FBNEI7UUFDdEMsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7SUFDN0IsQ0FBQztJQUVNLEtBQUssQ0FBQyxTQUFTLENBQUMsT0FHdEI7UUFDQyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUMzQixxQkFBcUIsRUFDckIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFRLENBQ3pELENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUlyQjtRQUNDLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQzNCLG9CQUFvQixFQUNwQixJQUFJLENBQUMsU0FBUyxDQUFDLG1CQUFtQixDQUFDLE9BQU8sSUFBSSxFQUFFLENBQVEsQ0FDekQsQ0FBQztJQUNKLENBQUM7SUFFTSxLQUFLLENBQUMsTUFBTSxDQUFDLE9BSW5CO1FBQ0MsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FDM0Isa0JBQWtCLEVBQ2xCLElBQUksQ0FBQyxTQUFTLENBQUMsbUJBQW1CLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBUSxDQUN6RCxDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQyxhQUFhLENBQUMsT0FJMUI7UUFDQyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUMzQixvQkFBb0IsRUFDcEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFRLENBQ3pELENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLFdBQVcsQ0FBQyxPQUd4QjtRQUNDLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQzNCLG9CQUFvQixFQUNwQixJQUFJLENBQUMsU0FBUyxDQUFDLG1CQUFtQixDQUFDLE9BQU8sSUFBSSxFQUFFLENBQVEsQ0FDekQsQ0FBQztJQUNKLENBQUM7SUFFTSxLQUFLLENBQUMsY0FBYyxDQUFDLE9BRzNCO1FBQ0MsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FDM0Isc0JBQXNCLEVBQ3RCLElBQUksQ0FBQyxTQUFTLENBQUMsbUJBQW1CLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBUSxDQUN6RCxDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQyxTQUFTLENBQUMsT0FFdEI7UUFDQyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUMzQixnQkFBZ0IsRUFDaEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFRLENBQ3pELENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLFNBQVMsQ0FBQyxRQUFrQjtRQUN2QyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUMzQixpQkFBaUIsRUFDakIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLFFBQVEsRUFBRSxDQUFRLENBQ3hELENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLFVBQVU7UUFDckIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FDM0IsaUJBQWlCLEVBQ2pCLElBQUksQ0FBQyxTQUFTLENBQUMsbUJBQW1CLEVBQVMsQ0FDNUMsQ0FBQztJQUNKLENBQUM7SUFFTSxLQUFLLENBQUMsV0FBVyxDQUFDLFFBTXhCO1FBQ0MsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FDM0Isb0JBQW9CLEVBQ3BCLElBQUksQ0FBQyxTQUFTLENBQUMsbUJBQW1CLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBUSxDQUN4RCxDQUFDO0lBQ0osQ0FBQztDQUNGIn0=
@@ -0,0 +1,10 @@
1
+ export { DcRouterApiClient, type IDcRouterApiClientOptions } from './classes.dcrouterapiclient.js';
2
+ export { Route, RouteBuilder, RouteManager } from './classes.route.js';
3
+ export { Certificate, CertificateManager, type ICertificateSummary } from './classes.certificate.js';
4
+ export { ApiToken, ApiTokenBuilder, ApiTokenManager } from './classes.apitoken.js';
5
+ export { RemoteIngress, RemoteIngressBuilder, RemoteIngressManager } from './classes.remoteingress.js';
6
+ export { Email, EmailManager } from './classes.email.js';
7
+ export { StatsManager } from './classes.stats.js';
8
+ export { ConfigManager } from './classes.config.js';
9
+ export { LogManager } from './classes.logs.js';
10
+ export { RadiusManager, RadiusClientManager, RadiusVlanManager, RadiusSessionManager } from './classes.radius.js';
@@ -0,0 +1,14 @@
1
+ // Main client
2
+ export { DcRouterApiClient } from './classes.dcrouterapiclient.js';
3
+ // Resource classes
4
+ export { Route, RouteBuilder, RouteManager } from './classes.route.js';
5
+ export { Certificate, CertificateManager } from './classes.certificate.js';
6
+ export { ApiToken, ApiTokenBuilder, ApiTokenManager } from './classes.apitoken.js';
7
+ export { RemoteIngress, RemoteIngressBuilder, RemoteIngressManager } from './classes.remoteingress.js';
8
+ export { Email, EmailManager } from './classes.email.js';
9
+ // Read-only managers
10
+ export { StatsManager } from './classes.stats.js';
11
+ export { ConfigManager } from './classes.config.js';
12
+ export { LogManager } from './classes.logs.js';
13
+ export { RadiusManager, RadiusClientManager, RadiusVlanManager, RadiusSessionManager } from './classes.radius.js';
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90c19hcGljbGllbnQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYztBQUNkLE9BQU8sRUFBRSxpQkFBaUIsRUFBa0MsTUFBTSxnQ0FBZ0MsQ0FBQztBQUVuRyxtQkFBbUI7QUFDbkIsT0FBTyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDdkUsT0FBTyxFQUFFLFdBQVcsRUFBRSxrQkFBa0IsRUFBNEIsTUFBTSwwQkFBMEIsQ0FBQztBQUNyRyxPQUFPLEVBQUUsUUFBUSxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNuRixPQUFPLEVBQUUsYUFBYSxFQUFFLG9CQUFvQixFQUFFLG9CQUFvQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDdkcsT0FBTyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUV6RCxxQkFBcUI7QUFDckIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDL0MsT0FBTyxFQUFFLGFBQWEsRUFBRSxtQkFBbUIsRUFBRSxpQkFBaUIsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDIn0=
@@ -0,0 +1,3 @@
1
+ import * as typedrequest from '@api.global/typedrequest';
2
+ import * as typedrequestInterfaces from '@api.global/typedrequest-interfaces';
3
+ export { typedrequest, typedrequestInterfaces, };
@@ -0,0 +1,5 @@
1
+ // @api.global scope
2
+ import * as typedrequest from '@api.global/typedrequest';
3
+ import * as typedrequestInterfaces from '@api.global/typedrequest-interfaces';
4
+ export { typedrequest, typedrequestInterfaces, };
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzX2FwaWNsaWVudC9wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG9CQUFvQjtBQUNwQixPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxzQkFBc0IsTUFBTSxxQ0FBcUMsQ0FBQztBQUU5RSxPQUFPLEVBQ0wsWUFBWSxFQUNaLHNCQUFzQixHQUN2QixDQUFDIn0=
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '11.0.50',
6
+ version: '11.2.0',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  };
9
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfd2ViLzAwX2NvbW1pdGluZm9fZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRztJQUN4QixJQUFJLEVBQUUsc0JBQXNCO0lBQzVCLE9BQU8sRUFBRSxTQUFTO0lBQ2xCLFdBQVcsRUFBRSwwRUFBMEU7Q0FDeEYsQ0FBQSJ9
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfd2ViLzAwX2NvbW1pdGluZm9fZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRztJQUN4QixJQUFJLEVBQUUsc0JBQXNCO0lBQzVCLE9BQU8sRUFBRSxRQUFRO0lBQ2pCLFdBQVcsRUFBRSwwRUFBMEU7Q0FDeEYsQ0FBQSJ9
package/npmextra.json CHANGED
@@ -22,7 +22,8 @@
22
22
  "to": "./dist_serve/bundle.js",
23
23
  "outputMode": "bundle",
24
24
  "bundler": "esbuild",
25
- "production": true
25
+ "production": true,
26
+ "includeFiles": ["./html/**/*.html"]
26
27
  }
27
28
  ]
28
29
  },
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@serve.zone/dcrouter",
3
3
  "private": false,
4
- "version": "11.0.50",
4
+ "version": "11.2.0",
5
5
  "description": "A multifaceted routing service handling mail and SMS delivery functions.",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./dist_ts/index.js",
9
- "./interfaces": "./dist_ts_interfaces/index.js"
9
+ "./interfaces": "./dist_ts_interfaces/index.js",
10
+ "./apiclient": "./dist_ts_apiclient/index.js"
10
11
  },
11
12
  "author": "Task Venture Capital GmbH",
12
13
  "license": "MIT",
@@ -19,12 +20,12 @@
19
20
  "watch": "tswatch"
20
21
  },
21
22
  "devDependencies": {
22
- "@git.zone/tsbuild": "^4.2.4",
23
- "@git.zone/tsbundle": "^2.9.0",
23
+ "@git.zone/tsbuild": "^4.3.0",
24
+ "@git.zone/tsbundle": "^2.9.1",
24
25
  "@git.zone/tsrun": "^2.0.1",
25
26
  "@git.zone/tstest": "^3.2.0",
26
27
  "@git.zone/tswatch": "^3.2.5",
27
- "@types/node": "^25.3.3"
28
+ "@types/node": "^25.3.5"
28
29
  },
29
30
  "dependencies": {
30
31
  "@api.global/typedrequest": "^3.3.0",
@@ -100,10 +101,12 @@
100
101
  "files": [
101
102
  "ts/**/*",
102
103
  "ts_web/**/*",
104
+ "ts_apiclient/**/*",
103
105
  "dist/**/*",
104
106
  "dist_*/**/*",
105
107
  "dist_ts/**/*",
106
108
  "dist_ts_web/**/*",
109
+ "dist_ts_apiclient/**/*",
107
110
  "assets/**/*",
108
111
  "cli.js",
109
112
  "npmextra.json",
package/readme.md CHANGED
@@ -26,6 +26,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
26
26
  - [Storage & Caching](#storage--caching)
27
27
  - [Security Features](#security-features)
28
28
  - [OpsServer Dashboard](#opsserver-dashboard)
29
+ - [API Client](#api-client)
29
30
  - [API Reference](#api-reference)
30
31
  - [Sub-Modules](#sub-modules)
31
32
  - [Testing](#testing)
@@ -90,6 +91,13 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
90
91
  - **Remote ingress management** with connection token generation and one-click copy
91
92
  - **Read-only configuration display** — DcRouter is configured through code
92
93
 
94
+ ### 🔧 Programmatic API Client
95
+ - **Object-oriented API** — resource classes (`Route`, `Certificate`, `ApiToken`, `RemoteIngress`, `Email`) with instance methods
96
+ - **Builder pattern** — fluent `.setName().setMatch().save()` chains for creating routes, tokens, and edges
97
+ - **Auto-injected auth** — JWT identity and API tokens included automatically in every request
98
+ - **Dual auth modes** — login with credentials (JWT) or pass an API token for programmatic access
99
+ - **Full coverage** — wraps every OpsServer endpoint with typed request/response pairs
100
+
93
101
  ## Installation
94
102
 
95
103
  ```bash
@@ -1038,12 +1046,9 @@ All management is done via TypedRequest over HTTP POST to `/typedrequest`:
1038
1046
  'getCombinedMetrics' // All metrics in one call
1039
1047
 
1040
1048
  // Email Operations
1041
- 'getQueuedEmails' // Emails pending delivery
1042
- 'getSentEmails' // Successfully delivered emails
1043
- 'getFailedEmails' // Failed emails
1049
+ 'getAllEmails' // List all emails (queued/sent/failed)
1050
+ 'getEmailDetail' // Full detail for a specific email
1044
1051
  'resendEmail' // Re-queue a failed email
1045
- 'getBounceRecords' // Bounce records
1046
- 'removeFromSuppressionList' // Unsuppress an address
1047
1052
 
1048
1053
  // Certificates
1049
1054
  'getCertificateOverview' // Domain-centric certificate status
@@ -1062,11 +1067,28 @@ All management is done via TypedRequest over HTTP POST to `/typedrequest`:
1062
1067
  'getRemoteIngressStatus' // Runtime status of all edges
1063
1068
  'getRemoteIngressConnectionToken' // Generate a connection token for an edge
1064
1069
 
1070
+ // Route Management (JWT or API token auth)
1071
+ 'getMergedRoutes' // List all routes (hardcoded + programmatic)
1072
+ 'createRoute' // Create a new programmatic route
1073
+ 'updateRoute' // Update a programmatic route
1074
+ 'deleteRoute' // Delete a programmatic route
1075
+ 'toggleRoute' // Enable/disable a programmatic route
1076
+ 'setRouteOverride' // Override a hardcoded route
1077
+ 'removeRouteOverride' // Remove a hardcoded route override
1078
+
1079
+ // API Token Management (admin JWT only)
1080
+ 'createApiToken' // Create API token → returns raw value once
1081
+ 'listApiTokens' // List all tokens (without secrets)
1082
+ 'revokeApiToken' // Delete an API token
1083
+ 'rollApiToken' // Regenerate token secret
1084
+ 'toggleApiToken' // Enable/disable a token
1085
+
1065
1086
  // Configuration (read-only)
1066
1087
  'getConfiguration' // Current system config
1067
1088
 
1068
1089
  // Logs
1069
- 'getLogs' // Retrieve system logs
1090
+ 'getRecentLogs' // Retrieve system logs with filtering
1091
+ 'getLogStream' // Stream live logs
1070
1092
 
1071
1093
  // RADIUS
1072
1094
  'getRadiusSessions' // Active RADIUS sessions
@@ -1080,6 +1102,77 @@ All management is done via TypedRequest over HTTP POST to `/typedrequest`:
1080
1102
  'testVlanAssignment' // Test what VLAN a MAC gets
1081
1103
  ```
1082
1104
 
1105
+ ## API Client
1106
+
1107
+ DcRouter ships with a typed, object-oriented API client for programmatic management of a running instance. Install it separately or import from the main package:
1108
+
1109
+ ```bash
1110
+ pnpm add @serve.zone/dcrouter-apiclient
1111
+ # or import from the main package:
1112
+ # import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
1113
+ ```
1114
+
1115
+ ### Quick Example
1116
+
1117
+ ```typescript
1118
+ import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
1119
+
1120
+ const client = new DcRouterApiClient({ baseUrl: 'https://dcrouter.example.com' });
1121
+ await client.login('admin', 'password');
1122
+
1123
+ // OO resource instances with methods
1124
+ const { routes } = await client.routes.list();
1125
+ await routes[0].toggle(false);
1126
+
1127
+ // Builder pattern for creation
1128
+ const newRoute = await client.routes.build()
1129
+ .setName('api-gateway')
1130
+ .setMatch({ ports: 443, domains: ['api.example.com'] })
1131
+ .setAction({ type: 'forward', targets: [{ host: 'backend', port: 8080 }] })
1132
+ .setTls({ mode: 'terminate', certificate: 'auto' })
1133
+ .save();
1134
+
1135
+ // Manage certificates
1136
+ const { certificates, summary } = await client.certificates.list();
1137
+ await certificates[0].reprovision();
1138
+
1139
+ // Create API tokens with builder
1140
+ const token = await client.apiTokens.build()
1141
+ .setName('ci-token')
1142
+ .setScopes(['routes:read', 'routes:write'])
1143
+ .setExpiresInDays(90)
1144
+ .save();
1145
+ console.log(token.tokenValue); // only available at creation
1146
+
1147
+ // Remote ingress edges
1148
+ const edge = await client.remoteIngress.build()
1149
+ .setName('edge-nyc-01')
1150
+ .setListenPorts([80, 443])
1151
+ .save();
1152
+ const connToken = await edge.getConnectionToken();
1153
+
1154
+ // Read-only managers
1155
+ const health = await client.stats.getHealth();
1156
+ const config = await client.config.get();
1157
+ const { logs } = await client.logs.getRecent({ level: 'error', limit: 50 });
1158
+ ```
1159
+
1160
+ ### Resource Managers
1161
+
1162
+ | Manager | Operations |
1163
+ |---------|-----------|
1164
+ | `client.routes` | `list()`, `create()`, `build()` → Route: `update()`, `delete()`, `toggle()`, `setOverride()`, `removeOverride()` |
1165
+ | `client.certificates` | `list()`, `import()` → Certificate: `reprovision()`, `delete()`, `export()` |
1166
+ | `client.apiTokens` | `list()`, `create()`, `build()` → ApiToken: `revoke()`, `roll()`, `toggle()` |
1167
+ | `client.remoteIngress` | `list()`, `getStatuses()`, `create()`, `build()` → RemoteIngress: `update()`, `delete()`, `regenerateSecret()`, `getConnectionToken()` |
1168
+ | `client.stats` | `getServer()`, `getEmail()`, `getDns()`, `getSecurity()`, `getConnections()`, `getQueues()`, `getHealth()`, `getNetwork()`, `getCombined()` |
1169
+ | `client.config` | `get(section?)` |
1170
+ | `client.logs` | `getRecent()`, `getStream()` |
1171
+ | `client.emails` | `list()` → Email: `getDetail()`, `resend()` |
1172
+ | `client.radius` | `.clients`, `.vlans`, `.sessions` sub-managers + `getStatistics()`, `getAccountingSummary()` |
1173
+
1174
+ See the [full API client documentation](./ts_apiclient/readme.md) for detailed usage of every manager, builder, and resource class.
1175
+
1083
1176
  ## API Reference
1084
1177
 
1085
1178
  ### DcRouter Class
@@ -1144,12 +1237,14 @@ DcRouter is published as a monorepo with separately-installable interface and we
1144
1237
  |---------|-------------|---------|
1145
1238
  | [`@serve.zone/dcrouter`](https://www.npmjs.com/package/@serve.zone/dcrouter) | Main package — the full router | `pnpm add @serve.zone/dcrouter` |
1146
1239
  | [`@serve.zone/dcrouter-interfaces`](https://www.npmjs.com/package/@serve.zone/dcrouter-interfaces) | TypedRequest interfaces for the OpsServer API | `pnpm add @serve.zone/dcrouter-interfaces` |
1240
+ | [`@serve.zone/dcrouter-apiclient`](https://www.npmjs.com/package/@serve.zone/dcrouter-apiclient) | OO API client with builder pattern | `pnpm add @serve.zone/dcrouter-apiclient` |
1147
1241
  | [`@serve.zone/dcrouter-web`](https://www.npmjs.com/package/@serve.zone/dcrouter-web) | Web dashboard components | `pnpm add @serve.zone/dcrouter-web` |
1148
1242
 
1149
- You can also import interfaces directly from the main package:
1243
+ You can also import directly from the main package:
1150
1244
 
1151
1245
  ```typescript
1152
1246
  import { data, requests } from '@serve.zone/dcrouter/interfaces';
1247
+ import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
1153
1248
  ```
1154
1249
 
1155
1250
  ## Testing
@@ -1171,6 +1266,7 @@ tstest test/test.opsserver-api.ts --verbose --timeout 60
1171
1266
 
1172
1267
  | Test File | Area | Tests |
1173
1268
  |-----------|------|-------|
1269
+ | `test.apiclient.ts` | API client instantiation, builders, resource hydration, exports | 18 |
1174
1270
  | `test.contentscanner.ts` | Content scanning (spam, phishing, malware, attachments) | 13 |
1175
1271
  | `test.dcrouter.email.ts` | Email config, domain and route setup | 4 |
1176
1272
  | `test.dns-server-config.ts` | DNS record parsing, grouping, extraction | 5 |
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '11.0.50',
6
+ version: '11.2.0',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }
@@ -0,0 +1,157 @@
1
+ import * as interfaces from '../ts_interfaces/index.js';
2
+ import type { DcRouterApiClient } from './classes.dcrouterapiclient.js';
3
+
4
+ export class ApiToken {
5
+ private clientRef: DcRouterApiClient;
6
+
7
+ // Data from IApiTokenInfo
8
+ public id: string;
9
+ public name: string;
10
+ public scopes: interfaces.data.TApiTokenScope[];
11
+ public createdAt: number;
12
+ public expiresAt: number | null;
13
+ public lastUsedAt: number | null;
14
+ public enabled: boolean;
15
+
16
+ /** Only set on creation or roll. Not persisted on server side. */
17
+ public tokenValue?: string;
18
+
19
+ constructor(clientRef: DcRouterApiClient, data: interfaces.data.IApiTokenInfo, tokenValue?: string) {
20
+ this.clientRef = clientRef;
21
+ this.id = data.id;
22
+ this.name = data.name;
23
+ this.scopes = data.scopes;
24
+ this.createdAt = data.createdAt;
25
+ this.expiresAt = data.expiresAt;
26
+ this.lastUsedAt = data.lastUsedAt;
27
+ this.enabled = data.enabled;
28
+ this.tokenValue = tokenValue;
29
+ }
30
+
31
+ public async revoke(): Promise<void> {
32
+ const response = await this.clientRef.request<interfaces.requests.IReq_RevokeApiToken>(
33
+ 'revokeApiToken',
34
+ this.clientRef.buildRequestPayload({ id: this.id }) as any,
35
+ );
36
+ if (!response.success) {
37
+ throw new Error(response.message || 'Failed to revoke token');
38
+ }
39
+ }
40
+
41
+ public async roll(): Promise<string> {
42
+ const response = await this.clientRef.request<interfaces.requests.IReq_RollApiToken>(
43
+ 'rollApiToken',
44
+ this.clientRef.buildRequestPayload({ id: this.id }) as any,
45
+ );
46
+ if (!response.success) {
47
+ throw new Error(response.message || 'Failed to roll token');
48
+ }
49
+ this.tokenValue = response.tokenValue;
50
+ return response.tokenValue!;
51
+ }
52
+
53
+ public async toggle(enabled: boolean): Promise<void> {
54
+ const response = await this.clientRef.request<interfaces.requests.IReq_ToggleApiToken>(
55
+ 'toggleApiToken',
56
+ this.clientRef.buildRequestPayload({ id: this.id, enabled }) as any,
57
+ );
58
+ if (!response.success) {
59
+ throw new Error(response.message || 'Failed to toggle token');
60
+ }
61
+ this.enabled = enabled;
62
+ }
63
+ }
64
+
65
+ export class ApiTokenBuilder {
66
+ private clientRef: DcRouterApiClient;
67
+ private tokenName: string = '';
68
+ private tokenScopes: interfaces.data.TApiTokenScope[] = [];
69
+ private tokenExpiresInDays?: number | null;
70
+
71
+ constructor(clientRef: DcRouterApiClient) {
72
+ this.clientRef = clientRef;
73
+ }
74
+
75
+ public setName(name: string): this {
76
+ this.tokenName = name;
77
+ return this;
78
+ }
79
+
80
+ public setScopes(scopes: interfaces.data.TApiTokenScope[]): this {
81
+ this.tokenScopes = scopes;
82
+ return this;
83
+ }
84
+
85
+ public addScope(scope: interfaces.data.TApiTokenScope): this {
86
+ if (!this.tokenScopes.includes(scope)) {
87
+ this.tokenScopes.push(scope);
88
+ }
89
+ return this;
90
+ }
91
+
92
+ public setExpiresInDays(days: number | null): this {
93
+ this.tokenExpiresInDays = days;
94
+ return this;
95
+ }
96
+
97
+ public async save(): Promise<ApiToken> {
98
+ const response = await this.clientRef.request<interfaces.requests.IReq_CreateApiToken>(
99
+ 'createApiToken',
100
+ this.clientRef.buildRequestPayload({
101
+ name: this.tokenName,
102
+ scopes: this.tokenScopes,
103
+ expiresInDays: this.tokenExpiresInDays,
104
+ }) as any,
105
+ );
106
+ if (!response.success) {
107
+ throw new Error(response.message || 'Failed to create API token');
108
+ }
109
+ return new ApiToken(
110
+ this.clientRef,
111
+ {
112
+ id: response.tokenId!,
113
+ name: this.tokenName,
114
+ scopes: this.tokenScopes,
115
+ createdAt: Date.now(),
116
+ expiresAt: this.tokenExpiresInDays
117
+ ? Date.now() + this.tokenExpiresInDays * 24 * 60 * 60 * 1000
118
+ : null,
119
+ lastUsedAt: null,
120
+ enabled: true,
121
+ },
122
+ response.tokenValue,
123
+ );
124
+ }
125
+ }
126
+
127
+ export class ApiTokenManager {
128
+ private clientRef: DcRouterApiClient;
129
+
130
+ constructor(clientRef: DcRouterApiClient) {
131
+ this.clientRef = clientRef;
132
+ }
133
+
134
+ public async list(): Promise<ApiToken[]> {
135
+ const response = await this.clientRef.request<interfaces.requests.IReq_ListApiTokens>(
136
+ 'listApiTokens',
137
+ this.clientRef.buildRequestPayload() as any,
138
+ );
139
+ return response.tokens.map((t) => new ApiToken(this.clientRef, t));
140
+ }
141
+
142
+ public async create(options: {
143
+ name: string;
144
+ scopes: interfaces.data.TApiTokenScope[];
145
+ expiresInDays?: number | null;
146
+ }): Promise<ApiToken> {
147
+ return this.build()
148
+ .setName(options.name)
149
+ .setScopes(options.scopes)
150
+ .setExpiresInDays(options.expiresInDays ?? null)
151
+ .save();
152
+ }
153
+
154
+ public build(): ApiTokenBuilder {
155
+ return new ApiTokenBuilder(this.clientRef);
156
+ }
157
+ }
@@ -0,0 +1,123 @@
1
+ import * as interfaces from '../ts_interfaces/index.js';
2
+ import type { DcRouterApiClient } from './classes.dcrouterapiclient.js';
3
+
4
+ export class Certificate {
5
+ private clientRef: DcRouterApiClient;
6
+
7
+ // Data from ICertificateInfo
8
+ public domain: string;
9
+ public routeNames: string[];
10
+ public status: interfaces.requests.TCertificateStatus;
11
+ public source: interfaces.requests.TCertificateSource;
12
+ public tlsMode: 'terminate' | 'terminate-and-reencrypt' | 'passthrough';
13
+ public expiryDate?: string;
14
+ public issuer?: string;
15
+ public issuedAt?: string;
16
+ public error?: string;
17
+ public canReprovision: boolean;
18
+ public backoffInfo?: {
19
+ failures: number;
20
+ retryAfter?: string;
21
+ lastError?: string;
22
+ };
23
+
24
+ constructor(clientRef: DcRouterApiClient, data: interfaces.requests.ICertificateInfo) {
25
+ this.clientRef = clientRef;
26
+ this.domain = data.domain;
27
+ this.routeNames = data.routeNames;
28
+ this.status = data.status;
29
+ this.source = data.source;
30
+ this.tlsMode = data.tlsMode;
31
+ this.expiryDate = data.expiryDate;
32
+ this.issuer = data.issuer;
33
+ this.issuedAt = data.issuedAt;
34
+ this.error = data.error;
35
+ this.canReprovision = data.canReprovision;
36
+ this.backoffInfo = data.backoffInfo;
37
+ }
38
+
39
+ public async reprovision(): Promise<void> {
40
+ const response = await this.clientRef.request<interfaces.requests.IReq_ReprovisionCertificateDomain>(
41
+ 'reprovisionCertificateDomain',
42
+ this.clientRef.buildRequestPayload({ domain: this.domain }) as any,
43
+ );
44
+ if (!response.success) {
45
+ throw new Error(response.message || 'Failed to reprovision certificate');
46
+ }
47
+ }
48
+
49
+ public async delete(): Promise<void> {
50
+ const response = await this.clientRef.request<interfaces.requests.IReq_DeleteCertificate>(
51
+ 'deleteCertificate',
52
+ this.clientRef.buildRequestPayload({ domain: this.domain }) as any,
53
+ );
54
+ if (!response.success) {
55
+ throw new Error(response.message || 'Failed to delete certificate');
56
+ }
57
+ }
58
+
59
+ public async export(): Promise<{
60
+ id: string;
61
+ domainName: string;
62
+ created: number;
63
+ validUntil: number;
64
+ privateKey: string;
65
+ publicKey: string;
66
+ csr: string;
67
+ } | undefined> {
68
+ const response = await this.clientRef.request<interfaces.requests.IReq_ExportCertificate>(
69
+ 'exportCertificate',
70
+ this.clientRef.buildRequestPayload({ domain: this.domain }) as any,
71
+ );
72
+ if (!response.success) {
73
+ throw new Error(response.message || 'Failed to export certificate');
74
+ }
75
+ return response.cert;
76
+ }
77
+ }
78
+
79
+ export interface ICertificateSummary {
80
+ total: number;
81
+ valid: number;
82
+ expiring: number;
83
+ expired: number;
84
+ failed: number;
85
+ unknown: number;
86
+ }
87
+
88
+ export class CertificateManager {
89
+ private clientRef: DcRouterApiClient;
90
+
91
+ constructor(clientRef: DcRouterApiClient) {
92
+ this.clientRef = clientRef;
93
+ }
94
+
95
+ public async list(): Promise<{ certificates: Certificate[]; summary: ICertificateSummary }> {
96
+ const response = await this.clientRef.request<interfaces.requests.IReq_GetCertificateOverview>(
97
+ 'getCertificateOverview',
98
+ this.clientRef.buildRequestPayload() as any,
99
+ );
100
+ return {
101
+ certificates: response.certificates.map((c) => new Certificate(this.clientRef, c)),
102
+ summary: response.summary,
103
+ };
104
+ }
105
+
106
+ public async import(cert: {
107
+ id: string;
108
+ domainName: string;
109
+ created: number;
110
+ validUntil: number;
111
+ privateKey: string;
112
+ publicKey: string;
113
+ csr: string;
114
+ }): Promise<void> {
115
+ const response = await this.clientRef.request<interfaces.requests.IReq_ImportCertificate>(
116
+ 'importCertificate',
117
+ this.clientRef.buildRequestPayload({ cert }) as any,
118
+ );
119
+ if (!response.success) {
120
+ throw new Error(response.message || 'Failed to import certificate');
121
+ }
122
+ }
123
+ }