@serve.zone/dcrouter 13.27.1 → 13.28.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 +913 -799
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/classes.dcrouter.d.ts +2 -1
  4. package/dist_ts/classes.dcrouter.js +11 -6
  5. package/dist_ts/config/classes.gateway-client-manager.d.ts +22 -0
  6. package/dist_ts/config/classes.gateway-client-manager.js +101 -0
  7. package/dist_ts/config/index.d.ts +1 -0
  8. package/dist_ts/config/index.js +2 -1
  9. package/dist_ts/db/documents/classes.gateway-client.doc.d.ts +18 -0
  10. package/dist_ts/db/documents/classes.gateway-client.doc.js +133 -0
  11. package/dist_ts/db/documents/index.d.ts +1 -0
  12. package/dist_ts/db/documents/index.js +2 -1
  13. package/dist_ts/opsserver/handlers/certificate.handler.js +5 -1
  14. package/dist_ts/opsserver/handlers/workhoster.handler.d.ts +4 -0
  15. package/dist_ts/opsserver/handlers/workhoster.handler.js +146 -16
  16. package/dist_ts_apiclient/classes.workhoster.d.ts +1 -0
  17. package/dist_ts_apiclient/classes.workhoster.js +5 -1
  18. package/dist_ts_interfaces/data/workhoster.d.ts +28 -3
  19. package/dist_ts_interfaces/requests/workhoster.d.ts +83 -1
  20. package/dist_ts_web/00_commitinfo_data.js +1 -1
  21. package/dist_ts_web/appstate.d.ts +29 -0
  22. package/dist_ts_web/appstate.js +79 -1
  23. package/dist_ts_web/elements/access/ops-view-apitokens.js +2 -1
  24. package/dist_ts_web/elements/access/ops-view-gatewayclients.d.ts +15 -0
  25. package/dist_ts_web/elements/access/ops-view-gatewayclients.js +293 -0
  26. package/dist_ts_web/elements/domains/ops-view-certificates.d.ts +6 -0
  27. package/dist_ts_web/elements/domains/ops-view-certificates.js +155 -13
  28. package/dist_ts_web/elements/network/ops-view-routes.js +2 -1
  29. package/dist_ts_web/elements/ops-dashboard.js +3 -1
  30. package/dist_ts_web/router.js +3 -3
  31. package/package.json +1 -1
  32. package/ts/00_commitinfo_data.ts +1 -1
  33. package/ts/classes.dcrouter.ts +10 -5
  34. package/ts/config/classes.gateway-client-manager.ts +117 -0
  35. package/ts/config/index.ts +2 -1
  36. package/ts/db/documents/classes.gateway-client.doc.ts +54 -0
  37. package/ts/db/documents/index.ts +1 -0
  38. package/ts/opsserver/handlers/certificate.handler.ts +5 -0
  39. package/ts/opsserver/handlers/workhoster.handler.ts +191 -17
  40. package/ts_apiclient/classes.workhoster.ts +8 -0
  41. package/ts_web/00_commitinfo_data.ts +1 -1
  42. package/ts_web/appstate.ts +111 -0
  43. package/ts_web/elements/access/ops-view-apitokens.ts +1 -0
  44. package/ts_web/elements/access/ops-view-gatewayclients.ts +250 -0
  45. package/ts_web/elements/domains/ops-view-certificates.ts +166 -11
  46. package/ts_web/elements/network/ops-view-routes.ts +1 -0
  47. package/ts_web/elements/ops-dashboard.ts +2 -0
  48. package/ts_web/router.ts +2 -2
@@ -8,7 +8,7 @@ const subviewMap = {
8
8
  overview: ['stats', 'configuration'],
9
9
  network: ['activity', 'routes', 'sourceprofiles', 'networktargets', 'targetprofiles', 'remoteingress', 'vpn'],
10
10
  email: ['log', 'security', 'domains'],
11
- access: ['apitokens', 'users'],
11
+ access: ['gatewayclients', 'apitokens', 'users'],
12
12
  security: ['overview', 'blocked', 'authentication'],
13
13
  domains: ['providers', 'domains', 'dns', 'certificates'],
14
14
  };
@@ -17,7 +17,7 @@ const defaultSubview = {
17
17
  overview: 'stats',
18
18
  network: 'activity',
19
19
  email: 'log',
20
- access: 'apitokens',
20
+ access: 'gatewayclients',
21
21
  security: 'overview',
22
22
  domains: 'domains',
23
23
  };
@@ -148,4 +148,4 @@ class AppRouter {
148
148
  }
149
149
  }
150
150
  export const appRouter = new AppRouter();
151
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHNfd2ViL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEtBQUssUUFBUSxNQUFNLGVBQWUsQ0FBQztBQUUxQyxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDO0FBRXJFLHFDQUFxQztBQUNyQyxNQUFNLFNBQVMsR0FBRyxDQUFDLE1BQU0sQ0FBVSxDQUFDO0FBRXBDLHdDQUF3QztBQUN4QyxNQUFNLFVBQVUsR0FBc0M7SUFDcEQsUUFBUSxFQUFFLENBQUMsT0FBTyxFQUFFLGVBQWUsQ0FBVTtJQUM3QyxPQUFPLEVBQUUsQ0FBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxLQUFLLENBQVU7SUFDdEgsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxTQUFTLENBQVU7SUFDOUMsTUFBTSxFQUFFLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBVTtJQUN2QyxRQUFRLEVBQUUsQ0FBQyxVQUFVLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixDQUFVO0lBQzVELE9BQU8sRUFBRSxDQUFDLFdBQVcsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLGNBQWMsQ0FBVTtDQUNsRSxDQUFDO0FBRUYsdURBQXVEO0FBQ3ZELE1BQU0sY0FBYyxHQUEyQjtJQUM3QyxRQUFRLEVBQUUsT0FBTztJQUNqQixPQUFPLEVBQUUsVUFBVTtJQUNuQixLQUFLLEVBQUUsS0FBSztJQUNaLE1BQU0sRUFBRSxXQUFXO0lBQ25CLFFBQVEsRUFBRSxVQUFVO0lBQ3BCLE9BQU8sRUFBRSxTQUFTO0NBQ25CLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxDQUFD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
151
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHNfd2ViL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEtBQUssUUFBUSxNQUFNLGVBQWUsQ0FBQztBQUUxQyxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDO0FBRXJFLHFDQUFxQztBQUNyQyxNQUFNLFNBQVMsR0FBRyxDQUFDLE1BQU0sQ0FBVSxDQUFDO0FBRXBDLHdDQUF3QztBQUN4QyxNQUFNLFVBQVUsR0FBc0M7SUFDcEQsUUFBUSxFQUFFLENBQUMsT0FBTyxFQUFFLGVBQWUsQ0FBVTtJQUM3QyxPQUFPLEVBQUUsQ0FBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxLQUFLLENBQVU7SUFDdEgsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxTQUFTLENBQVU7SUFDOUMsTUFBTSxFQUFFLENBQUMsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLE9BQU8sQ0FBVTtJQUN6RCxRQUFRLEVBQUUsQ0FBQyxVQUFVLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixDQUFVO0lBQzVELE9BQU8sRUFBRSxDQUFDLFdBQVcsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLGNBQWMsQ0FBVTtDQUNsRSxDQUFDO0FBRUYsdURBQXVEO0FBQ3ZELE1BQU0sY0FBYyxHQUEyQjtJQUM3QyxRQUFRLEVBQUUsT0FBTztJQUNqQixPQUFPLEVBQUUsVUFBVTtJQUNuQixLQUFLLEVBQUUsS0FBSztJQUNaLE1BQU0sRUFBRSxnQkFBZ0I7SUFDeEIsUUFBUSxFQUFFLFVBQVU7SUFDcEIsT0FBTyxFQUFFLFNBQVM7Q0FDbkIsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLENBQUMsR0FBRyxTQUFTLEVBQUUsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFVLENBQUM7QUFHdEYsTUFBTSxVQUFVLFdBQVcsQ0FBQyxJQUFZO0lBQ3RDLE9BQVEsa0JBQXdDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2xFLENBQUM7QUFFRCxNQUFNLFVBQVUsY0FBYyxDQUFDLElBQVksRUFBRSxPQUFlO0lBQzFELE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxLQUFLLENBQUM7QUFDdEQsQ0FBQztBQUVELE1BQU0sU0FBUztJQUNMLE1BQU0sQ0FBbUM7SUFDekMsV0FBVyxHQUFHLEtBQUssQ0FBQztJQUNwQixtQkFBbUIsR0FBRyxLQUFLLENBQUM7SUFFcEM7UUFDRSxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksV0FBVyxDQUFDLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVNLElBQUk7UUFDVCxJQUFJLElBQUksQ0FBQyxXQUFXO1lBQUUsT0FBTztRQUM3QixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDbkIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3RCLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO0lBQzFCLENBQUM7SUFFTyxXQUFXO1FBQ2pCLGFBQWE7UUFDYixLQUFLLE1BQU0sSUFBSSxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQzdCLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxFQUFFLEVBQUUsS0FBSyxJQUFJLEVBQUU7Z0JBQ3BDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ25DLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELGVBQWU7UUFDZixLQUFLLE1BQU0sSUFBSSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztZQUMzQyw0Q0FBNEM7WUFDNUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLEVBQUUsRUFBRSxLQUFLLElBQUksRUFBRTtnQkFDcEMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLElBQUksSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3RELENBQUMsQ0FBQyxDQUFDO1lBQ0gscUJBQXFCO1lBQ3JCLEtBQUssTUFBTSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxJQUFJLEdBQUcsRUFBRSxFQUFFLEtBQUssSUFBSSxFQUFFO29CQUMzQyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFDbEMsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztRQUVELGdCQUFnQjtRQUNoQixJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDN0IsSUFBSSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMvQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyxjQUFjO1FBQ3BCLFFBQVEsQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDbEQsSUFBSSxJQUFJLENBQUMsbUJBQW1CO2dCQUFFLE9BQU87WUFFckMsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7WUFDN0MsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLGFBQWE7Z0JBQ3hDLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxVQUFVLElBQUksT0FBTyxDQUFDLGFBQWEsRUFBRTtnQkFDbkQsQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBRTdCLElBQUksV0FBVyxLQUFLLFlBQVksRUFBRSxDQUFDO2dCQUNqQyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDO2dCQUNoQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDbEMsSUFBSSxDQUFDLG1CQUFtQixHQUFHLEtBQUssQ0FBQztZQUNuQyxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sa0JBQWtCO1FBQ3hCLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDO1FBRXRDLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQzFCLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ2pDLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDakQsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3pCLE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUV4QixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDdkIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDakMsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3JCLElBQUksR0FBRyxJQUFJLGNBQWMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDckMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDbEMsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLCtDQUErQztnQkFDL0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxJQUFJLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUMxRCxDQUFDO1FBQ0gsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNuQyxDQUFDO0lBQ0gsQ0FBQztJQUVPLGVBQWUsQ0FBQyxJQUFZLEVBQUUsT0FBc0I7UUFDMUQsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksQ0FBQztRQUNoQyxNQUFNLFlBQVksR0FBRyxRQUFRLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRyxDQUFDO1FBQ3RELElBQUksWUFBWSxDQUFDLFVBQVUsS0FBSyxJQUFJLElBQUksWUFBWSxDQUFDLGFBQWEsS0FBSyxPQUFPLEVBQUUsQ0FBQztZQUMvRSxRQUFRLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQztnQkFDNUIsR0FBRyxZQUFZO2dCQUNmLFVBQVUsRUFBRSxJQUFJO2dCQUNoQixhQUFhLEVBQUUsT0FBTzthQUNGLENBQUMsQ0FBQztRQUMxQixDQUFDO1FBQ0QsSUFBSSxDQUFDLG1CQUFtQixHQUFHLEtBQUssQ0FBQztJQUNuQyxDQUFDO0lBRU0sVUFBVSxDQUFDLElBQVk7UUFDNUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVNLGNBQWMsQ0FBQyxJQUFZLEVBQUUsT0FBZ0I7UUFDbEQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDN0IsT0FBTztRQUNULENBQUM7UUFDRCxJQUFJLE9BQU8sSUFBSSxjQUFjLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDN0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLElBQUksSUFBSSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ3pDLENBQUM7YUFBTSxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQzVCLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxJQUFJLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN0RCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzlCLENBQUM7SUFDSCxDQUFDO0lBRU0sY0FBYztRQUNuQixPQUFPLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxFQUFHLENBQUMsVUFBVSxDQUFDO0lBQ3JELENBQUM7SUFFTSxPQUFPO1FBQ1osSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUN0QixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQztJQUMzQixDQUFDO0NBQ0Y7QUFFRCxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQyJ9
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@serve.zone/dcrouter",
3
3
  "private": false,
4
- "version": "13.27.1",
4
+ "version": "13.28.0",
5
5
  "description": "A multifaceted routing service handling mail and SMS delivery functions.",
6
6
  "type": "module",
7
7
  "exports": {
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '13.27.1',
6
+ version: '13.28.0',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }
@@ -25,7 +25,7 @@ import { MetricsManager } from './monitoring/index.js';
25
25
  import { RadiusServer, type IRadiusServerConfig } from './radius/index.js';
26
26
  import { RemoteIngressManager, TunnelManager } from './remoteingress/index.js';
27
27
  import { VpnManager, type IVpnManagerConfig } from './vpn/index.js';
28
- import { RouteConfigManager, ApiTokenManager, ReferenceResolver, DbSeeder, TargetProfileManager } from './config/index.js';
28
+ import { RouteConfigManager, ApiTokenManager, GatewayClientManager, ReferenceResolver, DbSeeder, TargetProfileManager } from './config/index.js';
29
29
  import type { TIpAllowEntry } from './config/classes.route-config-manager.js';
30
30
  import { SecurityLogger, ContentScanner, IPReputationChecker, SecurityPolicyManager } from './security/index.js';
31
31
  import { type IHttp3Config, augmentRoutesWithHttp3 } from './http3/index.js';
@@ -276,6 +276,7 @@ export class DcRouter {
276
276
  // Programmatic config API
277
277
  public routeConfigManager?: RouteConfigManager;
278
278
  public apiTokenManager?: ApiTokenManager;
279
+ public gatewayClientManager?: GatewayClientManager;
279
280
  public referenceResolver?: ReferenceResolver;
280
281
  public targetProfileManager?: TargetProfileManager;
281
282
 
@@ -617,6 +618,8 @@ export class DcRouter {
617
618
  );
618
619
  this.apiTokenManager = new ApiTokenManager();
619
620
  await this.apiTokenManager.initialize();
621
+ this.gatewayClientManager = new GatewayClientManager();
622
+ await this.gatewayClientManager.initialize();
620
623
  await this.routeConfigManager.initialize(
621
624
  this.seedConfigRoutes as import('../ts_interfaces/data/remoteingress.js').IDcRouterRouteConfig[],
622
625
  this.seedEmailRoutes as import('../ts_interfaces/data/remoteingress.js').IDcRouterRouteConfig[],
@@ -634,6 +637,7 @@ export class DcRouter {
634
637
  .withStop(async () => {
635
638
  this.routeConfigManager = undefined;
636
639
  this.apiTokenManager = undefined;
640
+ this.gatewayClientManager = undefined;
637
641
  this.referenceResolver = undefined;
638
642
  this.targetProfileManager = undefined;
639
643
  })
@@ -1101,6 +1105,7 @@ export class DcRouter {
1101
1105
  });
1102
1106
 
1103
1107
  const scheduler = this.certProvisionScheduler;
1108
+ smartProxyConfig.certProvisionFallbackToAcme = false;
1104
1109
  smartProxyConfig.certProvisionFunction = async (domain, eventComms) => {
1105
1110
  // If SmartAcme is not yet ready (still starting or retrying), fall back to HTTP-01
1106
1111
  if (!this.smartAcmeReady) {
@@ -1149,10 +1154,10 @@ export class DcRouter {
1149
1154
  await scheduler.clearBackoff(domain);
1150
1155
  return result;
1151
1156
  } catch (err: unknown) {
1152
- // Record failure for backoff tracking
1153
- await scheduler.recordFailure(domain, (err as Error).message);
1154
- eventComms.warn(`SmartAcme DNS-01 failed for ${domain}: ${(err as Error).message}, falling back to http-01`);
1155
- return 'http01';
1157
+ const message = `DNS-01 failed for ${domain}: ${(err as Error).message}`;
1158
+ await scheduler.recordFailure(domain, message);
1159
+ eventComms.warn(message);
1160
+ throw new Error(message);
1156
1161
  }
1157
1162
  };
1158
1163
  }
@@ -0,0 +1,117 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { GatewayClientDoc } from '../db/index.js';
3
+ import type { IGatewayClient } from '../../ts_interfaces/data/workhoster.js';
4
+
5
+ const defaultCapabilities: IGatewayClient['capabilities'] = {
6
+ readDomains: true,
7
+ readDnsRecords: true,
8
+ syncRoutes: true,
9
+ syncDnsRecords: false,
10
+ requestCertificates: false,
11
+ };
12
+
13
+ export class GatewayClientManager {
14
+ public async initialize(): Promise<void> {}
15
+
16
+ public async listClients(): Promise<IGatewayClient[]> {
17
+ const docs = await GatewayClientDoc.findAll();
18
+ return docs.map((doc) => this.toPublicClient(doc));
19
+ }
20
+
21
+ public async getClient(id: string): Promise<IGatewayClient | null> {
22
+ const doc = await GatewayClientDoc.findById(id);
23
+ return doc ? this.toPublicClient(doc) : null;
24
+ }
25
+
26
+ public async createClient(options: {
27
+ id?: string;
28
+ type: IGatewayClient['type'];
29
+ name: string;
30
+ description?: string;
31
+ hostnamePatterns?: string[];
32
+ allowedRouteTargets?: IGatewayClient['allowedRouteTargets'];
33
+ capabilities?: IGatewayClient['capabilities'];
34
+ createdBy: string;
35
+ }): Promise<IGatewayClient> {
36
+ const id = this.normalizeId(options.id || `${options.type}-${plugins.uuid.v4()}`);
37
+ if (!id) {
38
+ throw new Error('gateway client id is required');
39
+ }
40
+ if (await GatewayClientDoc.findById(id)) {
41
+ throw new Error('gateway client already exists');
42
+ }
43
+
44
+ const now = Date.now();
45
+ const doc = new GatewayClientDoc();
46
+ doc.id = id;
47
+ doc.type = options.type;
48
+ doc.name = options.name.trim();
49
+ doc.description = options.description?.trim() || undefined;
50
+ doc.hostnamePatterns = this.normalizeStringList(options.hostnamePatterns || []);
51
+ doc.allowedRouteTargets = this.normalizeAllowedRouteTargets(options.allowedRouteTargets || []);
52
+ doc.capabilities = { ...defaultCapabilities, ...(options.capabilities || {}) };
53
+ doc.enabled = true;
54
+ doc.createdAt = now;
55
+ doc.updatedAt = now;
56
+ doc.createdBy = options.createdBy;
57
+ await doc.save();
58
+ return this.toPublicClient(doc);
59
+ }
60
+
61
+ public async updateClient(
62
+ id: string,
63
+ patch: Partial<Pick<IGatewayClient, 'name' | 'description' | 'hostnamePatterns' | 'allowedRouteTargets' | 'capabilities' | 'enabled'>>,
64
+ ): Promise<IGatewayClient | null> {
65
+ const doc = await GatewayClientDoc.findById(id);
66
+ if (!doc) return null;
67
+ if (patch.name !== undefined) doc.name = patch.name.trim();
68
+ if (patch.description !== undefined) doc.description = patch.description.trim() || undefined;
69
+ if (patch.hostnamePatterns !== undefined) doc.hostnamePatterns = this.normalizeStringList(patch.hostnamePatterns);
70
+ if (patch.allowedRouteTargets !== undefined) doc.allowedRouteTargets = this.normalizeAllowedRouteTargets(patch.allowedRouteTargets);
71
+ if (patch.capabilities !== undefined) doc.capabilities = { ...defaultCapabilities, ...patch.capabilities };
72
+ if (patch.enabled !== undefined) doc.enabled = patch.enabled;
73
+ doc.updatedAt = Date.now();
74
+ await doc.save();
75
+ return this.toPublicClient(doc);
76
+ }
77
+
78
+ public async deleteClient(id: string): Promise<boolean> {
79
+ const doc = await GatewayClientDoc.findById(id);
80
+ if (!doc) return false;
81
+ await doc.delete();
82
+ return true;
83
+ }
84
+
85
+ private normalizeId(id: string): string {
86
+ return id.trim().toLowerCase().replace(/[^a-z0-9._-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
87
+ }
88
+
89
+ private normalizeStringList(values: string[]): string[] {
90
+ return values.map((value) => value.trim().toLowerCase()).filter(Boolean);
91
+ }
92
+
93
+ private normalizeAllowedRouteTargets(targets: IGatewayClient['allowedRouteTargets']): IGatewayClient['allowedRouteTargets'] {
94
+ return targets
95
+ .map((target) => ({
96
+ host: target.host.trim().toLowerCase(),
97
+ ports: target.ports.filter((port) => Number.isInteger(port) && port > 0 && port <= 65535),
98
+ }))
99
+ .filter((target) => target.host && target.ports.length > 0);
100
+ }
101
+
102
+ private toPublicClient(doc: GatewayClientDoc): IGatewayClient {
103
+ return {
104
+ id: doc.id,
105
+ type: doc.type,
106
+ name: doc.name,
107
+ description: doc.description,
108
+ hostnamePatterns: doc.hostnamePatterns || [],
109
+ allowedRouteTargets: doc.allowedRouteTargets || [],
110
+ capabilities: doc.capabilities || {},
111
+ enabled: doc.enabled,
112
+ createdAt: doc.createdAt,
113
+ updatedAt: doc.updatedAt,
114
+ createdBy: doc.createdBy,
115
+ };
116
+ }
117
+ }
@@ -2,6 +2,7 @@
2
2
  export * from './validator.js';
3
3
  export { RouteConfigManager } from './classes.route-config-manager.js';
4
4
  export { ApiTokenManager } from './classes.api-token-manager.js';
5
+ export { GatewayClientManager } from './classes.gateway-client-manager.js';
5
6
  export { ReferenceResolver } from './classes.reference-resolver.js';
6
7
  export { DbSeeder } from './classes.db-seeder.js';
7
- export { TargetProfileManager } from './classes.target-profile-manager.js';
8
+ export { TargetProfileManager } from './classes.target-profile-manager.js';
@@ -0,0 +1,54 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { DcRouterDb } from '../classes.dcrouter-db.js';
3
+ import type { IApiTokenPolicy, TGatewayClientType } from '../../../ts_interfaces/data/route-management.js';
4
+
5
+ const getDb = () => DcRouterDb.getInstance().getDb();
6
+
7
+ @plugins.smartdata.Collection(() => getDb())
8
+ export class GatewayClientDoc extends plugins.smartdata.SmartDataDbDoc<GatewayClientDoc, GatewayClientDoc> {
9
+ @plugins.smartdata.unI()
10
+ @plugins.smartdata.svDb()
11
+ public id!: string;
12
+
13
+ @plugins.smartdata.svDb()
14
+ public type!: TGatewayClientType;
15
+
16
+ @plugins.smartdata.svDb()
17
+ public name: string = '';
18
+
19
+ @plugins.smartdata.svDb()
20
+ public description?: string;
21
+
22
+ @plugins.smartdata.svDb()
23
+ public hostnamePatterns: string[] = [];
24
+
25
+ @plugins.smartdata.svDb()
26
+ public allowedRouteTargets: NonNullable<IApiTokenPolicy['allowedRouteTargets']> = [];
27
+
28
+ @plugins.smartdata.svDb()
29
+ public capabilities: NonNullable<IApiTokenPolicy['capabilities']> = {};
30
+
31
+ @plugins.smartdata.svDb()
32
+ public enabled: boolean = true;
33
+
34
+ @plugins.smartdata.svDb()
35
+ public createdAt!: number;
36
+
37
+ @plugins.smartdata.svDb()
38
+ public updatedAt!: number;
39
+
40
+ @plugins.smartdata.svDb()
41
+ public createdBy!: string;
42
+
43
+ constructor() {
44
+ super();
45
+ }
46
+
47
+ public static async findById(id: string): Promise<GatewayClientDoc | null> {
48
+ return await GatewayClientDoc.getInstance({ id });
49
+ }
50
+
51
+ public static async findAll(): Promise<GatewayClientDoc[]> {
52
+ return await GatewayClientDoc.getInstances({});
53
+ }
54
+ }
@@ -8,6 +8,7 @@ export * from './classes.security-policy-audit.doc.js';
8
8
  // Config document classes
9
9
  export * from './classes.route.doc.js';
10
10
  export * from './classes.api-token.doc.js';
11
+ export * from './classes.gateway-client.doc.js';
11
12
  export * from './classes.source-profile.doc.js';
12
13
  export * from './classes.target-profile.doc.js';
13
14
  export * from './classes.network-target.doc.js';
@@ -307,6 +307,11 @@ export class CertificateHandler {
307
307
  }
308
308
  }
309
309
 
310
+ if (backoffInfo && status !== 'valid' && status !== 'expiring') {
311
+ status = 'failed';
312
+ error = error || backoffInfo.lastError;
313
+ }
314
+
310
315
  certificates.push({
311
316
  domain,
312
317
  routeNames: info.routeNames,
@@ -45,6 +45,16 @@ export class WorkHosterHandler {
45
45
  throw new plugins.typedrequest.TypedResponseError('unauthorized');
46
46
  }
47
47
 
48
+ private async requireAdmin(request: { identity?: interfaces.data.IIdentity }): Promise<string> {
49
+ if (request.identity?.jwt) {
50
+ const isAdmin = await this.opsServerRef.adminHandler.adminIdentityGuard.exec({
51
+ identity: request.identity,
52
+ });
53
+ if (isAdmin) return request.identity.userId;
54
+ }
55
+ throw new plugins.typedrequest.TypedResponseError('admin identity required');
56
+ }
57
+
48
58
  private registerHandlers(): void {
49
59
  this.typedrouter.addTypedHandler(
50
60
  new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetGatewayCapabilities>(
@@ -56,6 +66,122 @@ export class WorkHosterHandler {
56
66
  ),
57
67
  );
58
68
 
69
+ this.typedrouter.addTypedHandler(
70
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetGatewayClientContext>(
71
+ 'getGatewayClientContext',
72
+ async (dataArg) => {
73
+ const auth = await this.requireAuth(dataArg, 'gateway-clients:read');
74
+ return {
75
+ context: this.getGatewayClientContext(auth),
76
+ capabilities: this.getGatewayCapabilities(),
77
+ };
78
+ },
79
+ ),
80
+ );
81
+
82
+ this.typedrouter.addTypedHandler(
83
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ListGatewayClients>(
84
+ 'listGatewayClients',
85
+ async (dataArg) => {
86
+ await this.requireAdmin(dataArg);
87
+ return { gatewayClients: await this.listManagedGatewayClients() };
88
+ },
89
+ ),
90
+ );
91
+
92
+ this.typedrouter.addTypedHandler(
93
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateGatewayClient>(
94
+ 'createGatewayClient',
95
+ async (dataArg) => {
96
+ const userId = await this.requireAdmin(dataArg);
97
+ const manager = this.opsServerRef.dcRouterRef.gatewayClientManager;
98
+ if (!manager) return { success: false, message: 'Gateway client management not initialized' };
99
+ try {
100
+ const gatewayClient = await manager.createClient({
101
+ id: dataArg.id,
102
+ type: dataArg.type,
103
+ name: dataArg.name,
104
+ description: dataArg.description,
105
+ hostnamePatterns: dataArg.hostnamePatterns,
106
+ allowedRouteTargets: dataArg.allowedRouteTargets,
107
+ capabilities: dataArg.capabilities,
108
+ createdBy: userId,
109
+ });
110
+ return { success: true, gatewayClient };
111
+ } catch (error) {
112
+ return { success: false, message: (error as Error).message };
113
+ }
114
+ },
115
+ ),
116
+ );
117
+
118
+ this.typedrouter.addTypedHandler(
119
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateGatewayClient>(
120
+ 'updateGatewayClient',
121
+ async (dataArg) => {
122
+ await this.requireAdmin(dataArg);
123
+ const manager = this.opsServerRef.dcRouterRef.gatewayClientManager;
124
+ if (!manager) return { success: false, message: 'Gateway client management not initialized' };
125
+ const gatewayClient = await manager.updateClient(dataArg.id, {
126
+ name: dataArg.name,
127
+ description: dataArg.description,
128
+ hostnamePatterns: dataArg.hostnamePatterns,
129
+ allowedRouteTargets: dataArg.allowedRouteTargets,
130
+ capabilities: dataArg.capabilities,
131
+ enabled: dataArg.enabled,
132
+ });
133
+ return gatewayClient
134
+ ? { success: true, gatewayClient }
135
+ : { success: false, message: 'Gateway client not found' };
136
+ },
137
+ ),
138
+ );
139
+
140
+ this.typedrouter.addTypedHandler(
141
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteGatewayClient>(
142
+ 'deleteGatewayClient',
143
+ async (dataArg) => {
144
+ await this.requireAdmin(dataArg);
145
+ const manager = this.opsServerRef.dcRouterRef.gatewayClientManager;
146
+ if (!manager) return { success: false, message: 'Gateway client management not initialized' };
147
+ const success = await manager.deleteClient(dataArg.id);
148
+ return { success, message: success ? undefined : 'Gateway client not found' };
149
+ },
150
+ ),
151
+ );
152
+
153
+ this.typedrouter.addTypedHandler(
154
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateGatewayClientToken>(
155
+ 'createGatewayClientToken',
156
+ async (dataArg) => {
157
+ const userId = await this.requireAdmin(dataArg);
158
+ const gatewayClient = await this.opsServerRef.dcRouterRef.gatewayClientManager?.getClient(dataArg.gatewayClientId);
159
+ const tokenManager = this.opsServerRef.dcRouterRef.apiTokenManager;
160
+ if (!gatewayClient || !gatewayClient.enabled) {
161
+ return { success: false, message: 'Gateway client not found or disabled' };
162
+ }
163
+ if (!tokenManager) {
164
+ return { success: false, message: 'Token management not initialized' };
165
+ }
166
+ const result = await tokenManager.createToken(
167
+ dataArg.name?.trim() || `${gatewayClient.name} Token`,
168
+ ['gateway-clients:read', 'gateway-clients:write'],
169
+ dataArg.expiresInDays ?? null,
170
+ userId,
171
+ {
172
+ role: 'gatewayClient',
173
+ scopes: ['gateway-clients:read', 'gateway-clients:write'],
174
+ gatewayClient: { type: gatewayClient.type, id: gatewayClient.id },
175
+ hostnamePatterns: gatewayClient.hostnamePatterns,
176
+ allowedRouteTargets: gatewayClient.allowedRouteTargets,
177
+ capabilities: gatewayClient.capabilities,
178
+ },
179
+ );
180
+ return { success: true, tokenId: result.id, tokenValue: result.rawToken };
181
+ },
182
+ ),
183
+ );
184
+
59
185
  this.typedrouter.addTypedHandler(
60
186
  new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetGatewayClientDomains>(
61
187
  'getGatewayClientDomains',
@@ -183,6 +309,30 @@ export class WorkHosterHandler {
183
309
  };
184
310
  }
185
311
 
312
+ private getGatewayClientContext(auth: TAuthContext): interfaces.data.IGatewayClientContext {
313
+ const policy = auth.token?.policy;
314
+ const role = auth.isAdmin ? 'admin' : policy?.role || 'operator';
315
+ return {
316
+ role,
317
+ scopes: auth.token?.scopes || ['*'],
318
+ gatewayClient: policy?.gatewayClient,
319
+ hostnamePatterns: policy?.hostnamePatterns || [],
320
+ allowedRouteTargets: policy?.allowedRouteTargets || [],
321
+ capabilities: policy?.capabilities || {},
322
+ };
323
+ }
324
+
325
+ private async listManagedGatewayClients(): Promise<interfaces.data.IGatewayClient[]> {
326
+ const manager = this.opsServerRef.dcRouterRef.gatewayClientManager;
327
+ if (!manager) return [];
328
+ const clients = await manager.listClients();
329
+ const tokens = this.opsServerRef.dcRouterRef.apiTokenManager?.listTokens() || [];
330
+ return clients.map((client) => ({
331
+ ...client,
332
+ tokenCount: tokens.filter((token) => token.policy?.gatewayClient?.id === client.id).length,
333
+ }));
334
+ }
335
+
186
336
  private buildExternalKey(ownership: interfaces.data.IWorkAppRouteOwnership): string {
187
337
  return [
188
338
  ownership.workHosterType,
@@ -212,15 +362,38 @@ export class WorkHosterHandler {
212
362
  return policyClient.id;
213
363
  }
214
364
 
215
- private assertGatewayClientOwnership(auth: TAuthContext, ownership: interfaces.data.IGatewayClientOwnership): void {
365
+ private resolveGatewayClientOwnership(
366
+ auth: TAuthContext,
367
+ ownership: interfaces.data.IGatewayClientOwnership,
368
+ ): Required<interfaces.data.IGatewayClientOwnership> {
216
369
  const policy = auth.token?.policy;
217
- if (!policy || policy.role !== 'gatewayClient') return;
218
- if (!policy.gatewayClient) {
219
- throw new plugins.typedrequest.TypedResponseError('gateway client token is missing gatewayClient binding');
370
+ if (policy?.role === 'gatewayClient') {
371
+ if (!policy.gatewayClient) {
372
+ throw new plugins.typedrequest.TypedResponseError('gateway client token is missing gatewayClient binding');
373
+ }
374
+ if (ownership.gatewayClientType && ownership.gatewayClientType !== policy.gatewayClient.type) {
375
+ throw new plugins.typedrequest.TypedResponseError('gateway client token cannot act for this ownership');
376
+ }
377
+ if (ownership.gatewayClientId && ownership.gatewayClientId !== policy.gatewayClient.id) {
378
+ throw new plugins.typedrequest.TypedResponseError('gateway client token cannot act for this ownership');
379
+ }
380
+ return {
381
+ gatewayClientType: policy.gatewayClient.type,
382
+ gatewayClientId: policy.gatewayClient.id,
383
+ appId: ownership.appId,
384
+ hostname: ownership.hostname,
385
+ };
220
386
  }
221
- if (ownership.gatewayClientType !== policy.gatewayClient.type || ownership.gatewayClientId !== policy.gatewayClient.id) {
222
- throw new plugins.typedrequest.TypedResponseError('gateway client token cannot act for this ownership');
387
+
388
+ if (!ownership.gatewayClientType || !ownership.gatewayClientId) {
389
+ throw new plugins.typedrequest.TypedResponseError('gateway client ownership is missing type or id');
223
390
  }
391
+ return ownership as Required<interfaces.data.IGatewayClientOwnership>;
392
+ }
393
+
394
+ private assertGatewayClientOwnership(auth: TAuthContext, ownership: Required<interfaces.data.IGatewayClientOwnership>): void {
395
+ const policy = auth.token?.policy;
396
+ if (!policy || policy.role !== 'gatewayClient') return;
224
397
  if (!this.matchesHostnamePatterns(ownership.hostname, policy.hostnamePatterns || [])) {
225
398
  throw new plugins.typedrequest.TypedResponseError('hostname is outside token policy');
226
399
  }
@@ -403,7 +576,8 @@ export class WorkHosterHandler {
403
576
  enabled?: boolean,
404
577
  deleteRoute?: boolean,
405
578
  ): Promise<interfaces.data.IGatewayClientRouteSyncResult> {
406
- this.assertGatewayClientOwnership(auth, ownership);
579
+ const resolvedOwnership = this.resolveGatewayClientOwnership(auth, ownership);
580
+ this.assertGatewayClientOwnership(auth, resolvedOwnership);
407
581
  this.assertRouteTargetsAllowed(auth, route);
408
582
 
409
583
  const manager = this.opsServerRef.dcRouterRef.routeConfigManager;
@@ -411,7 +585,7 @@ export class WorkHosterHandler {
411
585
  return { success: false, message: 'Route management not initialized' };
412
586
  }
413
587
 
414
- const externalKey = this.buildGatewayClientExternalKey(ownership);
588
+ const externalKey = this.buildGatewayClientExternalKey(resolvedOwnership);
415
589
  const existingRoute = manager.findApiRouteByExternalKey(externalKey);
416
590
 
417
591
  if (deleteRoute) {
@@ -430,15 +604,15 @@ export class WorkHosterHandler {
430
604
 
431
605
  const metadata: interfaces.data.IRouteMetadata = {
432
606
  ownerType: 'gatewayClient',
433
- gatewayClientType: ownership.gatewayClientType,
434
- gatewayClientId: ownership.gatewayClientId,
435
- gatewayClientAppId: ownership.appId,
436
- workHosterType: ownership.gatewayClientType,
437
- workHosterId: ownership.gatewayClientId,
438
- workAppId: ownership.appId,
607
+ gatewayClientType: resolvedOwnership.gatewayClientType,
608
+ gatewayClientId: resolvedOwnership.gatewayClientId,
609
+ gatewayClientAppId: resolvedOwnership.appId,
610
+ workHosterType: resolvedOwnership.gatewayClientType,
611
+ workHosterId: resolvedOwnership.gatewayClientId,
612
+ workAppId: resolvedOwnership.appId,
439
613
  externalKey,
440
614
  };
441
- const normalizedRoute = this.normalizeGatewayClientRoute(route, ownership, externalKey);
615
+ const normalizedRoute = this.normalizeGatewayClientRoute(route, resolvedOwnership, externalKey);
442
616
 
443
617
  if (existingRoute) {
444
618
  const result = await manager.updateRoute(existingRoute.id, {
@@ -455,7 +629,7 @@ export class WorkHosterHandler {
455
629
  return { success: true, action: 'created', routeId };
456
630
  }
457
631
 
458
- private buildGatewayClientExternalKey(ownership: interfaces.data.IGatewayClientOwnership): string {
632
+ private buildGatewayClientExternalKey(ownership: Required<interfaces.data.IGatewayClientOwnership>): string {
459
633
  return [
460
634
  ownership.gatewayClientType,
461
635
  ownership.gatewayClientId,
@@ -478,7 +652,7 @@ export class WorkHosterHandler {
478
652
 
479
653
  private normalizeGatewayClientRoute(
480
654
  route: interfaces.data.IDcRouterRouteConfig,
481
- ownership: interfaces.data.IGatewayClientOwnership,
655
+ ownership: Required<interfaces.data.IGatewayClientOwnership>,
482
656
  externalKey: string,
483
657
  ): interfaces.data.IDcRouterRouteConfig {
484
658
  const normalizedRoute = { ...route };
@@ -12,6 +12,14 @@ export class WorkHosterManager {
12
12
  return response.capabilities;
13
13
  }
14
14
 
15
+ public async getGatewayClientContext(): Promise<interfaces.data.IGatewayClientContext> {
16
+ const response = await this.clientRef.request<interfaces.requests.IReq_GetGatewayClientContext>(
17
+ 'getGatewayClientContext',
18
+ this.clientRef.buildRequestPayload() as any,
19
+ );
20
+ return response.context;
21
+ }
22
+
15
23
  public async getDomains(): Promise<interfaces.data.IWorkHosterDomain[]> {
16
24
  const response = await this.clientRef.request<interfaces.requests.IReq_GetWorkHosterDomains>(
17
25
  'getWorkHosterDomains',
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '13.27.1',
6
+ version: '13.28.0',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }