@serve.zone/dcrouter 11.13.0 → 11.14.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 (201) hide show
  1. package/dist_serve/bundle.js +2 -2
  2. package/package.json +1 -1
  3. package/readme.md +107 -3
  4. package/ts/00_commitinfo_data.ts +1 -1
  5. package/ts_web/00_commitinfo_data.ts +1 -1
  6. package/ts_web/readme.md +17 -0
  7. package/ts_web/router.ts +1 -1
  8. package/dist_ts/00_commitinfo_data.d.ts +0 -8
  9. package/dist_ts/00_commitinfo_data.js +0 -9
  10. package/dist_ts/cache/classes.cache.cleaner.d.ts +0 -47
  11. package/dist_ts/cache/classes.cache.cleaner.js +0 -130
  12. package/dist_ts/cache/classes.cached.document.d.ts +0 -76
  13. package/dist_ts/cache/classes.cached.document.js +0 -100
  14. package/dist_ts/cache/classes.cachedb.d.ts +0 -60
  15. package/dist_ts/cache/classes.cachedb.js +0 -126
  16. package/dist_ts/cache/documents/classes.cached.email.d.ts +0 -125
  17. package/dist_ts/cache/documents/classes.cached.email.js +0 -337
  18. package/dist_ts/cache/documents/classes.cached.ip.reputation.d.ts +0 -119
  19. package/dist_ts/cache/documents/classes.cached.ip.reputation.js +0 -323
  20. package/dist_ts/cache/documents/index.d.ts +0 -2
  21. package/dist_ts/cache/documents/index.js +0 -3
  22. package/dist_ts/cache/index.d.ts +0 -4
  23. package/dist_ts/cache/index.js +0 -7
  24. package/dist_ts/classes.cert-provision-scheduler.d.ts +0 -54
  25. package/dist_ts/classes.cert-provision-scheduler.js +0 -118
  26. package/dist_ts/classes.dcrouter.d.ts +0 -386
  27. package/dist_ts/classes.dcrouter.js +0 -1682
  28. package/dist_ts/classes.storage-cert-manager.d.ts +0 -18
  29. package/dist_ts/classes.storage-cert-manager.js +0 -43
  30. package/dist_ts/config/classes.api-token-manager.d.ts +0 -46
  31. package/dist_ts/config/classes.api-token-manager.js +0 -150
  32. package/dist_ts/config/classes.route-config-manager.d.ts +0 -38
  33. package/dist_ts/config/classes.route-config-manager.js +0 -256
  34. package/dist_ts/config/index.d.ts +0 -3
  35. package/dist_ts/config/index.js +0 -5
  36. package/dist_ts/config/validator.d.ts +0 -104
  37. package/dist_ts/config/validator.js +0 -152
  38. package/dist_ts/errors/base.errors.d.ts +0 -224
  39. package/dist_ts/errors/base.errors.js +0 -320
  40. package/dist_ts/errors/error-handler.d.ts +0 -98
  41. package/dist_ts/errors/error-handler.js +0 -282
  42. package/dist_ts/errors/error.codes.d.ts +0 -115
  43. package/dist_ts/errors/error.codes.js +0 -136
  44. package/dist_ts/errors/index.d.ts +0 -54
  45. package/dist_ts/errors/index.js +0 -136
  46. package/dist_ts/errors/reputation.errors.d.ts +0 -183
  47. package/dist_ts/errors/reputation.errors.js +0 -292
  48. package/dist_ts/http3/http3-route-augmentation.d.ts +0 -50
  49. package/dist_ts/http3/http3-route-augmentation.js +0 -98
  50. package/dist_ts/http3/index.d.ts +0 -1
  51. package/dist_ts/http3/index.js +0 -2
  52. package/dist_ts/index.d.ts +0 -8
  53. package/dist_ts/index.js +0 -29
  54. package/dist_ts/logger.d.ts +0 -21
  55. package/dist_ts/logger.js +0 -81
  56. package/dist_ts/monitoring/classes.metricscache.d.ts +0 -32
  57. package/dist_ts/monitoring/classes.metricscache.js +0 -63
  58. package/dist_ts/monitoring/classes.metricsmanager.d.ts +0 -184
  59. package/dist_ts/monitoring/classes.metricsmanager.js +0 -744
  60. package/dist_ts/monitoring/index.d.ts +0 -1
  61. package/dist_ts/monitoring/index.js +0 -2
  62. package/dist_ts/opsserver/classes.opsserver.d.ts +0 -38
  63. package/dist_ts/opsserver/classes.opsserver.js +0 -87
  64. package/dist_ts/opsserver/handlers/admin.handler.d.ts +0 -31
  65. package/dist_ts/opsserver/handlers/admin.handler.js +0 -180
  66. package/dist_ts/opsserver/handlers/api-token.handler.d.ts +0 -6
  67. package/dist_ts/opsserver/handlers/api-token.handler.js +0 -62
  68. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +0 -32
  69. package/dist_ts/opsserver/handlers/certificate.handler.js +0 -421
  70. package/dist_ts/opsserver/handlers/config.handler.d.ts +0 -7
  71. package/dist_ts/opsserver/handlers/config.handler.js +0 -192
  72. package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +0 -30
  73. package/dist_ts/opsserver/handlers/email-ops.handler.js +0 -227
  74. package/dist_ts/opsserver/handlers/index.d.ts +0 -12
  75. package/dist_ts/opsserver/handlers/index.js +0 -13
  76. package/dist_ts/opsserver/handlers/logs.handler.d.ts +0 -25
  77. package/dist_ts/opsserver/handlers/logs.handler.js +0 -256
  78. package/dist_ts/opsserver/handlers/radius.handler.d.ts +0 -6
  79. package/dist_ts/opsserver/handlers/radius.handler.js +0 -295
  80. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +0 -6
  81. package/dist_ts/opsserver/handlers/remoteingress.handler.js +0 -156
  82. package/dist_ts/opsserver/handlers/route-management.handler.d.ts +0 -14
  83. package/dist_ts/opsserver/handlers/route-management.handler.js +0 -117
  84. package/dist_ts/opsserver/handlers/security.handler.d.ts +0 -9
  85. package/dist_ts/opsserver/handlers/security.handler.js +0 -233
  86. package/dist_ts/opsserver/handlers/stats.handler.d.ts +0 -11
  87. package/dist_ts/opsserver/handlers/stats.handler.js +0 -403
  88. package/dist_ts/opsserver/handlers/vpn.handler.d.ts +0 -6
  89. package/dist_ts/opsserver/handlers/vpn.handler.js +0 -199
  90. package/dist_ts/opsserver/helpers/guards.d.ts +0 -27
  91. package/dist_ts/opsserver/helpers/guards.js +0 -43
  92. package/dist_ts/opsserver/index.d.ts +0 -1
  93. package/dist_ts/opsserver/index.js +0 -2
  94. package/dist_ts/paths.d.ts +0 -26
  95. package/dist_ts/paths.js +0 -45
  96. package/dist_ts/plugins.d.ts +0 -81
  97. package/dist_ts/plugins.js +0 -115
  98. package/dist_ts/radius/classes.accounting.manager.d.ts +0 -231
  99. package/dist_ts/radius/classes.accounting.manager.js +0 -462
  100. package/dist_ts/radius/classes.radius.server.d.ts +0 -171
  101. package/dist_ts/radius/classes.radius.server.js +0 -386
  102. package/dist_ts/radius/classes.vlan.manager.d.ts +0 -128
  103. package/dist_ts/radius/classes.vlan.manager.js +0 -279
  104. package/dist_ts/radius/index.d.ts +0 -13
  105. package/dist_ts/radius/index.js +0 -14
  106. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +0 -94
  107. package/dist_ts/remoteingress/classes.remoteingress-manager.js +0 -271
  108. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +0 -59
  109. package/dist_ts/remoteingress/classes.tunnel-manager.js +0 -165
  110. package/dist_ts/remoteingress/index.d.ts +0 -2
  111. package/dist_ts/remoteingress/index.js +0 -3
  112. package/dist_ts/security/classes.contentscanner.d.ts +0 -164
  113. package/dist_ts/security/classes.contentscanner.js +0 -642
  114. package/dist_ts/security/classes.ipreputationchecker.d.ts +0 -160
  115. package/dist_ts/security/classes.ipreputationchecker.js +0 -537
  116. package/dist_ts/security/classes.securitylogger.d.ts +0 -144
  117. package/dist_ts/security/classes.securitylogger.js +0 -235
  118. package/dist_ts/security/index.d.ts +0 -3
  119. package/dist_ts/security/index.js +0 -4
  120. package/dist_ts/sms/classes.smsservice.d.ts +0 -15
  121. package/dist_ts/sms/classes.smsservice.js +0 -72
  122. package/dist_ts/sms/config/sms.config.d.ts +0 -93
  123. package/dist_ts/sms/config/sms.config.js +0 -2
  124. package/dist_ts/sms/config/sms.schema.d.ts +0 -5
  125. package/dist_ts/sms/config/sms.schema.js +0 -121
  126. package/dist_ts/sms/index.d.ts +0 -1
  127. package/dist_ts/sms/index.js +0 -2
  128. package/dist_ts/storage/classes.storagemanager.d.ts +0 -83
  129. package/dist_ts/storage/classes.storagemanager.js +0 -348
  130. package/dist_ts/storage/index.d.ts +0 -1
  131. package/dist_ts/storage/index.js +0 -3
  132. package/dist_ts/vpn/classes.vpn-manager.d.ts +0 -113
  133. package/dist_ts/vpn/classes.vpn-manager.js +0 -297
  134. package/dist_ts/vpn/index.d.ts +0 -1
  135. package/dist_ts/vpn/index.js +0 -2
  136. package/dist_ts_apiclient/classes.apitoken.d.ts +0 -41
  137. package/dist_ts_apiclient/classes.apitoken.js +0 -115
  138. package/dist_ts_apiclient/classes.certificate.d.ts +0 -57
  139. package/dist_ts_apiclient/classes.certificate.js +0 -69
  140. package/dist_ts_apiclient/classes.config.d.ts +0 -7
  141. package/dist_ts_apiclient/classes.config.js +0 -11
  142. package/dist_ts_apiclient/classes.dcrouterapiclient.d.ts +0 -41
  143. package/dist_ts_apiclient/classes.dcrouterapiclient.js +0 -81
  144. package/dist_ts_apiclient/classes.email.d.ts +0 -30
  145. package/dist_ts_apiclient/classes.email.js +0 -52
  146. package/dist_ts_apiclient/classes.logs.d.ts +0 -21
  147. package/dist_ts_apiclient/classes.logs.js +0 -14
  148. package/dist_ts_apiclient/classes.radius.d.ts +0 -59
  149. package/dist_ts_apiclient/classes.radius.js +0 -95
  150. package/dist_ts_apiclient/classes.remoteingress.d.ts +0 -54
  151. package/dist_ts_apiclient/classes.remoteingress.js +0 -136
  152. package/dist_ts_apiclient/classes.route.d.ts +0 -42
  153. package/dist_ts_apiclient/classes.route.js +0 -154
  154. package/dist_ts_apiclient/classes.stats.d.ts +0 -47
  155. package/dist_ts_apiclient/classes.stats.js +0 -38
  156. package/dist_ts_apiclient/index.d.ts +0 -10
  157. package/dist_ts_apiclient/index.js +0 -14
  158. package/dist_ts_apiclient/plugins.d.ts +0 -3
  159. package/dist_ts_apiclient/plugins.js +0 -5
  160. package/dist_ts_web/00_commitinfo_data.d.ts +0 -8
  161. package/dist_ts_web/00_commitinfo_data.js +0 -9
  162. package/dist_ts_web/appstate.d.ts +0 -238
  163. package/dist_ts_web/appstate.js +0 -1174
  164. package/dist_ts_web/elements/index.d.ts +0 -13
  165. package/dist_ts_web/elements/index.js +0 -14
  166. package/dist_ts_web/elements/ops-dashboard.d.ts +0 -23
  167. package/dist_ts_web/elements/ops-dashboard.js +0 -323
  168. package/dist_ts_web/elements/ops-view-apitokens.d.ts +0 -13
  169. package/dist_ts_web/elements/ops-view-apitokens.js +0 -371
  170. package/dist_ts_web/elements/ops-view-certificates.d.ts +0 -22
  171. package/dist_ts_web/elements/ops-view-certificates.js +0 -528
  172. package/dist_ts_web/elements/ops-view-config.d.ts +0 -19
  173. package/dist_ts_web/elements/ops-view-config.js +0 -339
  174. package/dist_ts_web/elements/ops-view-emails.d.ts +0 -21
  175. package/dist_ts_web/elements/ops-view-emails.js +0 -165
  176. package/dist_ts_web/elements/ops-view-logs.d.ts +0 -13
  177. package/dist_ts_web/elements/ops-view-logs.js +0 -159
  178. package/dist_ts_web/elements/ops-view-network.d.ts +0 -71
  179. package/dist_ts_web/elements/ops-view-network.js +0 -764
  180. package/dist_ts_web/elements/ops-view-overview.d.ts +0 -22
  181. package/dist_ts_web/elements/ops-view-overview.js +0 -456
  182. package/dist_ts_web/elements/ops-view-remoteingress.d.ts +0 -20
  183. package/dist_ts_web/elements/ops-view-remoteingress.js +0 -494
  184. package/dist_ts_web/elements/ops-view-routes.d.ts +0 -12
  185. package/dist_ts_web/elements/ops-view-routes.js +0 -404
  186. package/dist_ts_web/elements/ops-view-security.d.ts +0 -21
  187. package/dist_ts_web/elements/ops-view-security.js +0 -574
  188. package/dist_ts_web/elements/ops-view-vpn.d.ts +0 -14
  189. package/dist_ts_web/elements/ops-view-vpn.js +0 -369
  190. package/dist_ts_web/elements/shared/css.d.ts +0 -1
  191. package/dist_ts_web/elements/shared/css.js +0 -10
  192. package/dist_ts_web/elements/shared/index.d.ts +0 -2
  193. package/dist_ts_web/elements/shared/index.js +0 -3
  194. package/dist_ts_web/elements/shared/ops-sectionheading.d.ts +0 -5
  195. package/dist_ts_web/elements/shared/ops-sectionheading.js +0 -82
  196. package/dist_ts_web/index.d.ts +0 -1
  197. package/dist_ts_web/index.js +0 -10
  198. package/dist_ts_web/plugins.d.ts +0 -6
  199. package/dist_ts_web/plugins.js +0 -11
  200. package/dist_ts_web/router.d.ts +0 -19
  201. package/dist_ts_web/router.js +0 -91
@@ -1,1174 +0,0 @@
1
- import * as plugins from './plugins.js';
2
- import * as interfaces from '../dist_ts_interfaces/index.js';
3
- // Create main app state instance
4
- export const appState = new plugins.domtools.plugins.smartstate.Smartstate();
5
- // Create state parts with appropriate persistence
6
- export const loginStatePart = await appState.getStatePart('login', {
7
- identity: null,
8
- isLoggedIn: false,
9
- }, 'persistent' // Login state persists across browser sessions
10
- );
11
- export const statsStatePart = await appState.getStatePart('stats', {
12
- serverStats: null,
13
- emailStats: null,
14
- dnsStats: null,
15
- securityMetrics: null,
16
- lastUpdated: 0,
17
- isLoading: false,
18
- error: null,
19
- }, 'soft' // Stats are cached but not persisted
20
- );
21
- export const configStatePart = await appState.getStatePart('config', {
22
- config: null,
23
- isLoading: false,
24
- error: null,
25
- });
26
- // Determine initial view from URL path
27
- const getInitialView = () => {
28
- const path = typeof window !== 'undefined' ? window.location.pathname : '/';
29
- const validViews = ['overview', 'network', 'emails', 'logs', 'routes', 'apitokens', 'configuration', 'security', 'certificates', 'remoteingress'];
30
- const segments = path.split('/').filter(Boolean);
31
- const view = segments[0];
32
- return validViews.includes(view) ? view : 'overview';
33
- };
34
- export const uiStatePart = await appState.getStatePart('ui', {
35
- activeView: getInitialView(),
36
- sidebarCollapsed: false,
37
- autoRefresh: true,
38
- refreshInterval: 1000, // 1 second
39
- theme: 'light',
40
- });
41
- export const logStatePart = await appState.getStatePart('logs', {
42
- recentLogs: [],
43
- isStreaming: false,
44
- filters: {},
45
- }, 'soft');
46
- export const networkStatePart = await appState.getStatePart('network', {
47
- connections: [],
48
- connectionsByIP: {},
49
- throughputRate: { bytesInPerSecond: 0, bytesOutPerSecond: 0 },
50
- totalBytes: { in: 0, out: 0 },
51
- topIPs: [],
52
- throughputByIP: [],
53
- throughputHistory: [],
54
- requestsPerSecond: 0,
55
- requestsTotal: 0,
56
- backends: [],
57
- lastUpdated: 0,
58
- isLoading: false,
59
- error: null,
60
- }, 'soft');
61
- export const emailOpsStatePart = await appState.getStatePart('emailOps', {
62
- emails: [],
63
- isLoading: false,
64
- error: null,
65
- lastUpdated: 0,
66
- }, 'soft');
67
- export const certificateStatePart = await appState.getStatePart('certificates', {
68
- certificates: [],
69
- summary: { total: 0, valid: 0, expiring: 0, expired: 0, failed: 0, unknown: 0 },
70
- isLoading: false,
71
- error: null,
72
- lastUpdated: 0,
73
- }, 'soft');
74
- export const remoteIngressStatePart = await appState.getStatePart('remoteIngress', {
75
- edges: [],
76
- statuses: [],
77
- selectedEdgeId: null,
78
- newEdgeId: null,
79
- isLoading: false,
80
- error: null,
81
- lastUpdated: 0,
82
- }, 'soft');
83
- export const routeManagementStatePart = await appState.getStatePart('routeManagement', {
84
- mergedRoutes: [],
85
- warnings: [],
86
- apiTokens: [],
87
- isLoading: false,
88
- error: null,
89
- lastUpdated: 0,
90
- }, 'soft');
91
- const getActionContext = () => {
92
- const identity = loginStatePart.getState().identity;
93
- // Treat expired JWTs as no identity — prevents stale persisted sessions from firing requests
94
- if (identity && identity.expiresAt && identity.expiresAt < Date.now()) {
95
- return { identity: null };
96
- }
97
- return { identity };
98
- };
99
- // Login Action
100
- export const loginAction = loginStatePart.createAction(async (statePartArg, dataArg) => {
101
- const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'adminLoginWithUsernameAndPassword');
102
- try {
103
- const response = await typedRequest.fire({
104
- username: dataArg.username,
105
- password: dataArg.password,
106
- });
107
- if (response.identity) {
108
- return {
109
- identity: response.identity,
110
- isLoggedIn: true,
111
- };
112
- }
113
- return statePartArg.getState();
114
- }
115
- catch (error) {
116
- console.error('Login failed:', error);
117
- return statePartArg.getState();
118
- }
119
- });
120
- // Logout Action — always clears state, even if identity is expired/missing
121
- export const logoutAction = loginStatePart.createAction(async (statePartArg) => {
122
- const context = getActionContext();
123
- // Try to notify server, but don't block logout if identity is missing/expired
124
- if (context.identity) {
125
- const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'adminLogout');
126
- try {
127
- await typedRequest.fire({ identity: context.identity });
128
- }
129
- catch (error) {
130
- console.error('Logout error:', error);
131
- }
132
- }
133
- // Always clear login state
134
- return {
135
- identity: null,
136
- isLoggedIn: false,
137
- };
138
- });
139
- // Fetch All Stats Action - Using combined endpoint for efficiency
140
- export const fetchAllStatsAction = statsStatePart.createAction(async (statePartArg) => {
141
- const context = getActionContext();
142
- const currentState = statePartArg.getState();
143
- if (!context.identity)
144
- return currentState;
145
- try {
146
- // Use combined metrics endpoint - single request instead of 4
147
- const combinedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getCombinedMetrics');
148
- const combinedResponse = await combinedRequest.fire({
149
- identity: context.identity,
150
- sections: {
151
- server: true,
152
- email: true,
153
- dns: true,
154
- security: true,
155
- network: false, // Network is fetched separately for the network view
156
- },
157
- });
158
- // Update state with all stats from combined response
159
- return {
160
- serverStats: combinedResponse.metrics.server || currentState.serverStats,
161
- emailStats: combinedResponse.metrics.email || currentState.emailStats,
162
- dnsStats: combinedResponse.metrics.dns || currentState.dnsStats,
163
- securityMetrics: combinedResponse.metrics.security || currentState.securityMetrics,
164
- lastUpdated: Date.now(),
165
- isLoading: false,
166
- error: null,
167
- };
168
- }
169
- catch (error) {
170
- return {
171
- ...currentState,
172
- isLoading: false,
173
- error: error.message || 'Failed to fetch statistics',
174
- };
175
- }
176
- });
177
- // Fetch Configuration Action (read-only)
178
- export const fetchConfigurationAction = configStatePart.createAction(async (statePartArg) => {
179
- const context = getActionContext();
180
- const currentState = statePartArg.getState();
181
- if (!context.identity)
182
- return currentState;
183
- try {
184
- const configRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getConfiguration');
185
- const response = await configRequest.fire({
186
- identity: context.identity,
187
- });
188
- return {
189
- config: response.config,
190
- isLoading: false,
191
- error: null,
192
- };
193
- }
194
- catch (error) {
195
- return {
196
- ...currentState,
197
- isLoading: false,
198
- error: error.message || 'Failed to fetch configuration',
199
- };
200
- }
201
- });
202
- // Fetch Recent Logs Action
203
- export const fetchRecentLogsAction = logStatePart.createAction(async (statePartArg, dataArg) => {
204
- const context = getActionContext();
205
- if (!context.identity)
206
- return statePartArg.getState();
207
- const logsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getRecentLogs');
208
- const response = await logsRequest.fire({
209
- identity: context.identity,
210
- limit: dataArg.limit || 100,
211
- level: dataArg.level,
212
- category: dataArg.category,
213
- });
214
- return {
215
- ...statePartArg.getState(),
216
- recentLogs: response.logs,
217
- };
218
- });
219
- // Toggle Auto Refresh Action
220
- export const toggleAutoRefreshAction = uiStatePart.createAction(async (statePartArg) => {
221
- const currentState = statePartArg.getState();
222
- return {
223
- ...currentState,
224
- autoRefresh: !currentState.autoRefresh,
225
- };
226
- });
227
- // Set Active View Action
228
- export const setActiveViewAction = uiStatePart.createAction(async (statePartArg, viewName) => {
229
- const currentState = statePartArg.getState();
230
- // If switching to network view, ensure we fetch network data
231
- if (viewName === 'network' && currentState.activeView !== 'network') {
232
- setTimeout(() => {
233
- networkStatePart.dispatchAction(fetchNetworkStatsAction, null);
234
- }, 100);
235
- }
236
- // If switching to certificates view, ensure we fetch certificate data
237
- if (viewName === 'certificates' && currentState.activeView !== 'certificates') {
238
- setTimeout(() => {
239
- certificateStatePart.dispatchAction(fetchCertificateOverviewAction, null);
240
- }, 100);
241
- }
242
- // If switching to routes view, ensure we fetch route data
243
- if (viewName === 'routes' && currentState.activeView !== 'routes') {
244
- setTimeout(() => {
245
- routeManagementStatePart.dispatchAction(fetchMergedRoutesAction, null);
246
- }, 100);
247
- }
248
- // If switching to apitokens view, ensure we fetch token data
249
- if (viewName === 'apitokens' && currentState.activeView !== 'apitokens') {
250
- setTimeout(() => {
251
- routeManagementStatePart.dispatchAction(fetchApiTokensAction, null);
252
- }, 100);
253
- }
254
- // If switching to remoteingress view, ensure we fetch edge data
255
- if (viewName === 'remoteingress' && currentState.activeView !== 'remoteingress') {
256
- setTimeout(() => {
257
- remoteIngressStatePart.dispatchAction(fetchRemoteIngressAction, null);
258
- }, 100);
259
- }
260
- return {
261
- ...currentState,
262
- activeView: viewName,
263
- };
264
- });
265
- // Fetch Network Stats Action
266
- export const fetchNetworkStatsAction = networkStatePart.createAction(async (statePartArg) => {
267
- const context = getActionContext();
268
- const currentState = statePartArg.getState();
269
- if (!context.identity)
270
- return currentState;
271
- try {
272
- // Fetch active connections using the existing endpoint
273
- const connectionsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getActiveConnections');
274
- const connectionsResponse = await connectionsRequest.fire({
275
- identity: context.identity,
276
- });
277
- // Get network stats for throughput and IP data
278
- const networkStatsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getNetworkStats');
279
- const networkStatsResponse = await networkStatsRequest.fire({
280
- identity: context.identity,
281
- });
282
- // Use the connections data for the connection list
283
- // and network stats for throughput and IP analytics
284
- const connectionsByIP = {};
285
- // Build connectionsByIP from network stats if available
286
- if (networkStatsResponse.connectionsByIP && Array.isArray(networkStatsResponse.connectionsByIP)) {
287
- networkStatsResponse.connectionsByIP.forEach((item) => {
288
- connectionsByIP[item.ip] = item.count;
289
- });
290
- }
291
- else {
292
- // Fallback: calculate from connections
293
- connectionsResponse.connections.forEach(conn => {
294
- const ip = conn.remoteAddress;
295
- connectionsByIP[ip] = (connectionsByIP[ip] || 0) + 1;
296
- });
297
- }
298
- return {
299
- connections: connectionsResponse.connections,
300
- connectionsByIP,
301
- throughputRate: networkStatsResponse.throughputRate || { bytesInPerSecond: 0, bytesOutPerSecond: 0 },
302
- totalBytes: networkStatsResponse.totalDataTransferred
303
- ? { in: networkStatsResponse.totalDataTransferred.bytesIn, out: networkStatsResponse.totalDataTransferred.bytesOut }
304
- : { in: 0, out: 0 },
305
- topIPs: networkStatsResponse.topIPs || [],
306
- throughputByIP: networkStatsResponse.throughputByIP || [],
307
- throughputHistory: networkStatsResponse.throughputHistory || [],
308
- requestsPerSecond: networkStatsResponse.requestsPerSecond || 0,
309
- requestsTotal: networkStatsResponse.requestsTotal || 0,
310
- backends: networkStatsResponse.backends || [],
311
- lastUpdated: Date.now(),
312
- isLoading: false,
313
- error: null,
314
- };
315
- }
316
- catch (error) {
317
- console.error('Failed to fetch network stats:', error);
318
- return {
319
- ...currentState,
320
- isLoading: false,
321
- error: error instanceof Error ? error.message : 'Failed to fetch network stats',
322
- };
323
- }
324
- });
325
- // ============================================================================
326
- // Email Operations Actions
327
- // ============================================================================
328
- // Fetch All Emails Action
329
- export const fetchAllEmailsAction = emailOpsStatePart.createAction(async (statePartArg) => {
330
- const context = getActionContext();
331
- const currentState = statePartArg.getState();
332
- if (!context.identity)
333
- return currentState;
334
- try {
335
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getAllEmails');
336
- const response = await request.fire({
337
- identity: context.identity,
338
- });
339
- return {
340
- emails: response.emails,
341
- isLoading: false,
342
- error: null,
343
- lastUpdated: Date.now(),
344
- };
345
- }
346
- catch (error) {
347
- return {
348
- ...currentState,
349
- isLoading: false,
350
- error: error instanceof Error ? error.message : 'Failed to fetch emails',
351
- };
352
- }
353
- });
354
- // ============================================================================
355
- // Certificate Actions
356
- // ============================================================================
357
- export const fetchCertificateOverviewAction = certificateStatePart.createAction(async (statePartArg) => {
358
- const context = getActionContext();
359
- const currentState = statePartArg.getState();
360
- if (!context.identity)
361
- return currentState;
362
- try {
363
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getCertificateOverview');
364
- const response = await request.fire({
365
- identity: context.identity,
366
- });
367
- return {
368
- certificates: response.certificates,
369
- summary: response.summary,
370
- isLoading: false,
371
- error: null,
372
- lastUpdated: Date.now(),
373
- };
374
- }
375
- catch (error) {
376
- return {
377
- ...currentState,
378
- isLoading: false,
379
- error: error instanceof Error ? error.message : 'Failed to fetch certificate overview',
380
- };
381
- }
382
- });
383
- export const reprovisionCertificateAction = certificateStatePart.createAction(async (statePartArg, domain, actionContext) => {
384
- const context = getActionContext();
385
- const currentState = statePartArg.getState();
386
- try {
387
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'reprovisionCertificateDomain');
388
- await request.fire({
389
- identity: context.identity,
390
- domain,
391
- });
392
- // Re-fetch overview after reprovisioning
393
- return await actionContext.dispatch(fetchCertificateOverviewAction, null);
394
- }
395
- catch (error) {
396
- return {
397
- ...currentState,
398
- error: error instanceof Error ? error.message : 'Failed to reprovision certificate',
399
- };
400
- }
401
- });
402
- export const deleteCertificateAction = certificateStatePart.createAction(async (statePartArg, domain, actionContext) => {
403
- const context = getActionContext();
404
- const currentState = statePartArg.getState();
405
- try {
406
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'deleteCertificate');
407
- await request.fire({
408
- identity: context.identity,
409
- domain,
410
- });
411
- // Re-fetch overview after deletion
412
- return await actionContext.dispatch(fetchCertificateOverviewAction, null);
413
- }
414
- catch (error) {
415
- return {
416
- ...currentState,
417
- error: error instanceof Error ? error.message : 'Failed to delete certificate',
418
- };
419
- }
420
- });
421
- export const importCertificateAction = certificateStatePart.createAction(async (statePartArg, cert, actionContext) => {
422
- const context = getActionContext();
423
- const currentState = statePartArg.getState();
424
- try {
425
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'importCertificate');
426
- await request.fire({
427
- identity: context.identity,
428
- cert,
429
- });
430
- // Re-fetch overview after import
431
- return await actionContext.dispatch(fetchCertificateOverviewAction, null);
432
- }
433
- catch (error) {
434
- return {
435
- ...currentState,
436
- error: error instanceof Error ? error.message : 'Failed to import certificate',
437
- };
438
- }
439
- });
440
- export async function fetchCertificateExport(domain) {
441
- const context = getActionContext();
442
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'exportCertificate');
443
- return request.fire({
444
- identity: context.identity,
445
- domain,
446
- });
447
- }
448
- // ============================================================================
449
- // Remote Ingress Standalone Functions
450
- // ============================================================================
451
- export async function fetchConnectionToken(edgeId) {
452
- const context = getActionContext();
453
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getRemoteIngressConnectionToken');
454
- return request.fire({ identity: context.identity, edgeId });
455
- }
456
- // ============================================================================
457
- // Remote Ingress Actions
458
- // ============================================================================
459
- export const fetchRemoteIngressAction = remoteIngressStatePart.createAction(async (statePartArg) => {
460
- const context = getActionContext();
461
- const currentState = statePartArg.getState();
462
- if (!context.identity)
463
- return currentState;
464
- try {
465
- const edgesRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getRemoteIngresses');
466
- const statusRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getRemoteIngressStatus');
467
- const [edgesResponse, statusResponse] = await Promise.all([
468
- edgesRequest.fire({ identity: context.identity }),
469
- statusRequest.fire({ identity: context.identity }),
470
- ]);
471
- return {
472
- ...currentState,
473
- edges: edgesResponse.edges,
474
- statuses: statusResponse.statuses,
475
- isLoading: false,
476
- error: null,
477
- lastUpdated: Date.now(),
478
- };
479
- }
480
- catch (error) {
481
- return {
482
- ...currentState,
483
- isLoading: false,
484
- error: error instanceof Error ? error.message : 'Failed to fetch remote ingress data',
485
- };
486
- }
487
- });
488
- export const createRemoteIngressAction = remoteIngressStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
489
- const context = getActionContext();
490
- const currentState = statePartArg.getState();
491
- try {
492
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'createRemoteIngress');
493
- const response = await request.fire({
494
- identity: context.identity,
495
- name: dataArg.name,
496
- listenPorts: dataArg.listenPorts,
497
- autoDerivePorts: dataArg.autoDerivePorts,
498
- tags: dataArg.tags,
499
- });
500
- if (response.success) {
501
- // Refresh the list
502
- await actionContext.dispatch(fetchRemoteIngressAction, null);
503
- return {
504
- ...statePartArg.getState(),
505
- newEdgeId: response.edge.id,
506
- };
507
- }
508
- return currentState;
509
- }
510
- catch (error) {
511
- return {
512
- ...currentState,
513
- error: error instanceof Error ? error.message : 'Failed to create edge',
514
- };
515
- }
516
- });
517
- export const deleteRemoteIngressAction = remoteIngressStatePart.createAction(async (statePartArg, edgeId, actionContext) => {
518
- const context = getActionContext();
519
- const currentState = statePartArg.getState();
520
- try {
521
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'deleteRemoteIngress');
522
- await request.fire({
523
- identity: context.identity,
524
- id: edgeId,
525
- });
526
- return await actionContext.dispatch(fetchRemoteIngressAction, null);
527
- }
528
- catch (error) {
529
- return {
530
- ...currentState,
531
- error: error instanceof Error ? error.message : 'Failed to delete edge',
532
- };
533
- }
534
- });
535
- export const updateRemoteIngressAction = remoteIngressStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
536
- const context = getActionContext();
537
- const currentState = statePartArg.getState();
538
- try {
539
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'updateRemoteIngress');
540
- await request.fire({
541
- identity: context.identity,
542
- id: dataArg.id,
543
- name: dataArg.name,
544
- listenPorts: dataArg.listenPorts,
545
- autoDerivePorts: dataArg.autoDerivePorts,
546
- tags: dataArg.tags,
547
- });
548
- return await actionContext.dispatch(fetchRemoteIngressAction, null);
549
- }
550
- catch (error) {
551
- return {
552
- ...currentState,
553
- error: error instanceof Error ? error.message : 'Failed to update edge',
554
- };
555
- }
556
- });
557
- export const regenerateRemoteIngressSecretAction = remoteIngressStatePart.createAction(async (statePartArg, edgeId) => {
558
- const context = getActionContext();
559
- const currentState = statePartArg.getState();
560
- try {
561
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'regenerateRemoteIngressSecret');
562
- const response = await request.fire({
563
- identity: context.identity,
564
- id: edgeId,
565
- });
566
- if (response.success) {
567
- return {
568
- ...currentState,
569
- newEdgeId: edgeId,
570
- };
571
- }
572
- return currentState;
573
- }
574
- catch (error) {
575
- return {
576
- ...currentState,
577
- error: error instanceof Error ? error.message : 'Failed to regenerate secret',
578
- };
579
- }
580
- });
581
- export const clearNewEdgeIdAction = remoteIngressStatePart.createAction(async (statePartArg) => {
582
- return {
583
- ...statePartArg.getState(),
584
- newEdgeId: null,
585
- };
586
- });
587
- export const toggleRemoteIngressAction = remoteIngressStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
588
- const context = getActionContext();
589
- const currentState = statePartArg.getState();
590
- try {
591
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'updateRemoteIngress');
592
- await request.fire({
593
- identity: context.identity,
594
- id: dataArg.id,
595
- enabled: dataArg.enabled,
596
- });
597
- return await actionContext.dispatch(fetchRemoteIngressAction, null);
598
- }
599
- catch (error) {
600
- return {
601
- ...currentState,
602
- error: error instanceof Error ? error.message : 'Failed to toggle edge',
603
- };
604
- }
605
- });
606
- export const vpnStatePart = await appState.getStatePart('vpn', {
607
- clients: [],
608
- status: null,
609
- isLoading: false,
610
- error: null,
611
- lastUpdated: 0,
612
- newClientConfig: null,
613
- }, 'soft');
614
- // ============================================================================
615
- // VPN Actions
616
- // ============================================================================
617
- export const fetchVpnAction = vpnStatePart.createAction(async (statePartArg) => {
618
- const context = getActionContext();
619
- const currentState = statePartArg.getState();
620
- if (!context.identity)
621
- return currentState;
622
- try {
623
- const clientsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getVpnClients');
624
- const statusRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getVpnStatus');
625
- const [clientsResponse, statusResponse] = await Promise.all([
626
- clientsRequest.fire({ identity: context.identity }),
627
- statusRequest.fire({ identity: context.identity }),
628
- ]);
629
- return {
630
- ...currentState,
631
- clients: clientsResponse.clients,
632
- status: statusResponse.status,
633
- isLoading: false,
634
- error: null,
635
- lastUpdated: Date.now(),
636
- };
637
- }
638
- catch (error) {
639
- return {
640
- ...currentState,
641
- isLoading: false,
642
- error: error instanceof Error ? error.message : 'Failed to fetch VPN data',
643
- };
644
- }
645
- });
646
- export const createVpnClientAction = vpnStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
647
- const context = getActionContext();
648
- const currentState = statePartArg.getState();
649
- try {
650
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'createVpnClient');
651
- const response = await request.fire({
652
- identity: context.identity,
653
- clientId: dataArg.clientId,
654
- tags: dataArg.tags,
655
- description: dataArg.description,
656
- });
657
- if (!response.success) {
658
- return { ...currentState, error: response.message || 'Failed to create client' };
659
- }
660
- const refreshed = await actionContext.dispatch(fetchVpnAction, null);
661
- return {
662
- ...refreshed,
663
- newClientConfig: response.wireguardConfig || null,
664
- };
665
- }
666
- catch (error) {
667
- return {
668
- ...currentState,
669
- error: error instanceof Error ? error.message : 'Failed to create VPN client',
670
- };
671
- }
672
- });
673
- export const deleteVpnClientAction = vpnStatePart.createAction(async (statePartArg, clientId, actionContext) => {
674
- const context = getActionContext();
675
- const currentState = statePartArg.getState();
676
- try {
677
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'deleteVpnClient');
678
- await request.fire({ identity: context.identity, clientId });
679
- return await actionContext.dispatch(fetchVpnAction, null);
680
- }
681
- catch (error) {
682
- return {
683
- ...currentState,
684
- error: error instanceof Error ? error.message : 'Failed to delete VPN client',
685
- };
686
- }
687
- });
688
- export const toggleVpnClientAction = vpnStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
689
- const context = getActionContext();
690
- const currentState = statePartArg.getState();
691
- try {
692
- const method = dataArg.enabled ? 'enableVpnClient' : 'disableVpnClient';
693
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', method);
694
- await request.fire({ identity: context.identity, clientId: dataArg.clientId });
695
- return await actionContext.dispatch(fetchVpnAction, null);
696
- }
697
- catch (error) {
698
- return {
699
- ...currentState,
700
- error: error instanceof Error ? error.message : 'Failed to toggle VPN client',
701
- };
702
- }
703
- });
704
- export const clearNewClientConfigAction = vpnStatePart.createAction(async (statePartArg) => {
705
- return { ...statePartArg.getState(), newClientConfig: null };
706
- });
707
- // ============================================================================
708
- // Route Management Actions
709
- // ============================================================================
710
- export const fetchMergedRoutesAction = routeManagementStatePart.createAction(async (statePartArg) => {
711
- const context = getActionContext();
712
- const currentState = statePartArg.getState();
713
- if (!context.identity)
714
- return currentState;
715
- try {
716
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getMergedRoutes');
717
- const response = await request.fire({
718
- identity: context.identity,
719
- });
720
- return {
721
- ...currentState,
722
- mergedRoutes: response.routes,
723
- warnings: response.warnings,
724
- isLoading: false,
725
- error: null,
726
- lastUpdated: Date.now(),
727
- };
728
- }
729
- catch (error) {
730
- return {
731
- ...currentState,
732
- isLoading: false,
733
- error: error instanceof Error ? error.message : 'Failed to fetch routes',
734
- };
735
- }
736
- });
737
- export const createRouteAction = routeManagementStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
738
- const context = getActionContext();
739
- const currentState = statePartArg.getState();
740
- try {
741
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'createRoute');
742
- await request.fire({
743
- identity: context.identity,
744
- route: dataArg.route,
745
- enabled: dataArg.enabled,
746
- });
747
- return await actionContext.dispatch(fetchMergedRoutesAction, null);
748
- }
749
- catch (error) {
750
- return {
751
- ...currentState,
752
- error: error instanceof Error ? error.message : 'Failed to create route',
753
- };
754
- }
755
- });
756
- export const deleteRouteAction = routeManagementStatePart.createAction(async (statePartArg, routeId, actionContext) => {
757
- const context = getActionContext();
758
- const currentState = statePartArg.getState();
759
- try {
760
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'deleteRoute');
761
- await request.fire({
762
- identity: context.identity,
763
- id: routeId,
764
- });
765
- return await actionContext.dispatch(fetchMergedRoutesAction, null);
766
- }
767
- catch (error) {
768
- return {
769
- ...currentState,
770
- error: error instanceof Error ? error.message : 'Failed to delete route',
771
- };
772
- }
773
- });
774
- export const toggleRouteAction = routeManagementStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
775
- const context = getActionContext();
776
- const currentState = statePartArg.getState();
777
- try {
778
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'toggleRoute');
779
- await request.fire({
780
- identity: context.identity,
781
- id: dataArg.id,
782
- enabled: dataArg.enabled,
783
- });
784
- return await actionContext.dispatch(fetchMergedRoutesAction, null);
785
- }
786
- catch (error) {
787
- return {
788
- ...currentState,
789
- error: error instanceof Error ? error.message : 'Failed to toggle route',
790
- };
791
- }
792
- });
793
- export const setRouteOverrideAction = routeManagementStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
794
- const context = getActionContext();
795
- const currentState = statePartArg.getState();
796
- try {
797
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'setRouteOverride');
798
- await request.fire({
799
- identity: context.identity,
800
- routeName: dataArg.routeName,
801
- enabled: dataArg.enabled,
802
- });
803
- return await actionContext.dispatch(fetchMergedRoutesAction, null);
804
- }
805
- catch (error) {
806
- return {
807
- ...currentState,
808
- error: error instanceof Error ? error.message : 'Failed to set override',
809
- };
810
- }
811
- });
812
- export const removeRouteOverrideAction = routeManagementStatePart.createAction(async (statePartArg, routeName, actionContext) => {
813
- const context = getActionContext();
814
- const currentState = statePartArg.getState();
815
- try {
816
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'removeRouteOverride');
817
- await request.fire({
818
- identity: context.identity,
819
- routeName,
820
- });
821
- return await actionContext.dispatch(fetchMergedRoutesAction, null);
822
- }
823
- catch (error) {
824
- return {
825
- ...currentState,
826
- error: error instanceof Error ? error.message : 'Failed to remove override',
827
- };
828
- }
829
- });
830
- // ============================================================================
831
- // API Token Actions
832
- // ============================================================================
833
- export const fetchApiTokensAction = routeManagementStatePart.createAction(async (statePartArg) => {
834
- const context = getActionContext();
835
- const currentState = statePartArg.getState();
836
- if (!context.identity)
837
- return currentState;
838
- try {
839
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'listApiTokens');
840
- const response = await request.fire({
841
- identity: context.identity,
842
- });
843
- return {
844
- ...currentState,
845
- apiTokens: response.tokens,
846
- };
847
- }
848
- catch (error) {
849
- return {
850
- ...currentState,
851
- error: error instanceof Error ? error.message : 'Failed to fetch tokens',
852
- };
853
- }
854
- });
855
- export async function createApiToken(name, scopes, expiresInDays) {
856
- const context = getActionContext();
857
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'createApiToken');
858
- return request.fire({
859
- identity: context.identity,
860
- name,
861
- scopes,
862
- expiresInDays,
863
- });
864
- }
865
- export async function rollApiToken(id) {
866
- const context = getActionContext();
867
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'rollApiToken');
868
- return request.fire({
869
- identity: context.identity,
870
- id,
871
- });
872
- }
873
- export const revokeApiTokenAction = routeManagementStatePart.createAction(async (statePartArg, tokenId, actionContext) => {
874
- const context = getActionContext();
875
- const currentState = statePartArg.getState();
876
- try {
877
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'revokeApiToken');
878
- await request.fire({
879
- identity: context.identity,
880
- id: tokenId,
881
- });
882
- return await actionContext.dispatch(fetchApiTokensAction, null);
883
- }
884
- catch (error) {
885
- return {
886
- ...currentState,
887
- error: error instanceof Error ? error.message : 'Failed to revoke token',
888
- };
889
- }
890
- });
891
- export const toggleApiTokenAction = routeManagementStatePart.createAction(async (statePartArg, dataArg, actionContext) => {
892
- const context = getActionContext();
893
- const currentState = statePartArg.getState();
894
- try {
895
- const request = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'toggleApiToken');
896
- await request.fire({
897
- identity: context.identity,
898
- id: dataArg.id,
899
- enabled: dataArg.enabled,
900
- });
901
- return await actionContext.dispatch(fetchApiTokensAction, null);
902
- }
903
- catch (error) {
904
- return {
905
- ...currentState,
906
- error: error instanceof Error ? error.message : 'Failed to toggle token',
907
- };
908
- }
909
- });
910
- // ============================================================================
911
- // TypedSocket Client for Real-time Log Streaming
912
- // ============================================================================
913
- let socketClient = null;
914
- const socketRouter = new plugins.domtools.plugins.typedrequest.TypedRouter();
915
- // Batched log entry handler — buffers incoming entries and flushes once per animation frame
916
- let logEntryBuffer = [];
917
- let logFlushScheduled = false;
918
- function flushLogEntries() {
919
- logFlushScheduled = false;
920
- if (logEntryBuffer.length === 0)
921
- return;
922
- const current = logStatePart.getState();
923
- const updated = [...current.recentLogs, ...logEntryBuffer];
924
- logEntryBuffer = [];
925
- // Cap at 2000 entries
926
- if (updated.length > 2000) {
927
- updated.splice(0, updated.length - 2000);
928
- }
929
- logStatePart.setState({ ...current, recentLogs: updated });
930
- }
931
- // Register handler for pushed log entries from the server
932
- socketRouter.addTypedHandler(new plugins.domtools.plugins.typedrequest.TypedHandler('pushLogEntry', async (dataArg) => {
933
- logEntryBuffer.push(dataArg.entry);
934
- if (!logFlushScheduled) {
935
- logFlushScheduled = true;
936
- requestAnimationFrame(flushLogEntries);
937
- }
938
- return {};
939
- }));
940
- async function connectSocket() {
941
- if (socketClient)
942
- return;
943
- try {
944
- socketClient = await plugins.typedsocket.TypedSocket.createClient(socketRouter, plugins.typedsocket.TypedSocket.useWindowLocationOriginUrl());
945
- await socketClient.setTag('role', 'ops_dashboard');
946
- }
947
- catch (err) {
948
- console.error('TypedSocket connection failed:', err);
949
- socketClient = null;
950
- }
951
- }
952
- async function disconnectSocket() {
953
- if (socketClient) {
954
- try {
955
- await socketClient.stop();
956
- }
957
- catch {
958
- // ignore disconnect errors
959
- }
960
- socketClient = null;
961
- }
962
- }
963
- // In-flight guard to prevent concurrent refresh requests
964
- let isRefreshing = false;
965
- // Combined refresh action for efficient polling
966
- async function dispatchCombinedRefreshAction() {
967
- if (isRefreshing)
968
- return;
969
- isRefreshing = true;
970
- try {
971
- await dispatchCombinedRefreshActionInner();
972
- }
973
- finally {
974
- isRefreshing = false;
975
- }
976
- }
977
- async function dispatchCombinedRefreshActionInner() {
978
- const context = getActionContext();
979
- if (!context.identity)
980
- return;
981
- const currentView = uiStatePart.getState().activeView;
982
- try {
983
- // Always fetch basic stats for dashboard widgets
984
- const combinedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getCombinedMetrics');
985
- const combinedResponse = await combinedRequest.fire({
986
- identity: context.identity,
987
- sections: {
988
- server: true,
989
- email: true,
990
- dns: true,
991
- security: true,
992
- network: currentView === 'network', // Only fetch network if on network view
993
- },
994
- });
995
- // Update all stats from combined response
996
- const currentStatsState = statsStatePart.getState();
997
- statsStatePart.setState({
998
- ...currentStatsState,
999
- serverStats: combinedResponse.metrics.server || currentStatsState.serverStats,
1000
- emailStats: combinedResponse.metrics.email || currentStatsState.emailStats,
1001
- dnsStats: combinedResponse.metrics.dns || currentStatsState.dnsStats,
1002
- securityMetrics: combinedResponse.metrics.security || currentStatsState.securityMetrics,
1003
- lastUpdated: Date.now(),
1004
- isLoading: false,
1005
- error: null,
1006
- });
1007
- // Update network stats if included
1008
- if (combinedResponse.metrics.network && currentView === 'network') {
1009
- const network = combinedResponse.metrics.network;
1010
- const connectionsByIP = {};
1011
- // Convert connection details to IP counts
1012
- network.connectionDetails.forEach(conn => {
1013
- connectionsByIP[conn.remoteAddress] = (connectionsByIP[conn.remoteAddress] || 0) + 1;
1014
- });
1015
- // Fetch detailed connections for the network view
1016
- try {
1017
- const connectionsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'getActiveConnections');
1018
- const connectionsResponse = await connectionsRequest.fire({
1019
- identity: context.identity,
1020
- });
1021
- networkStatePart.setState({
1022
- ...networkStatePart.getState(),
1023
- connections: connectionsResponse.connections,
1024
- connectionsByIP,
1025
- throughputRate: {
1026
- bytesInPerSecond: network.totalBandwidth.in,
1027
- bytesOutPerSecond: network.totalBandwidth.out
1028
- },
1029
- totalBytes: network.totalBytes || { in: 0, out: 0 },
1030
- topIPs: network.topEndpoints.map(e => ({ ip: e.endpoint, count: e.requests })),
1031
- throughputByIP: network.topEndpoints.map(e => ({ ip: e.endpoint, in: e.bandwidth?.in || 0, out: e.bandwidth?.out || 0 })),
1032
- throughputHistory: network.throughputHistory || [],
1033
- requestsPerSecond: network.requestsPerSecond || 0,
1034
- requestsTotal: network.requestsTotal || 0,
1035
- backends: network.backends || [],
1036
- lastUpdated: Date.now(),
1037
- isLoading: false,
1038
- error: null,
1039
- });
1040
- }
1041
- catch (error) {
1042
- console.error('Failed to fetch connections:', error);
1043
- networkStatePart.setState({
1044
- ...networkStatePart.getState(),
1045
- connections: [],
1046
- connectionsByIP,
1047
- throughputRate: {
1048
- bytesInPerSecond: network.totalBandwidth.in,
1049
- bytesOutPerSecond: network.totalBandwidth.out
1050
- },
1051
- totalBytes: network.totalBytes || { in: 0, out: 0 },
1052
- topIPs: network.topEndpoints.map(e => ({ ip: e.endpoint, count: e.requests })),
1053
- throughputByIP: network.topEndpoints.map(e => ({ ip: e.endpoint, in: e.bandwidth?.in || 0, out: e.bandwidth?.out || 0 })),
1054
- throughputHistory: network.throughputHistory || [],
1055
- requestsPerSecond: network.requestsPerSecond || 0,
1056
- requestsTotal: network.requestsTotal || 0,
1057
- backends: network.backends || [],
1058
- lastUpdated: Date.now(),
1059
- isLoading: false,
1060
- error: null,
1061
- });
1062
- }
1063
- }
1064
- // Refresh certificate data if on certificates view
1065
- if (currentView === 'certificates') {
1066
- try {
1067
- await certificateStatePart.dispatchAction(fetchCertificateOverviewAction, null);
1068
- }
1069
- catch (error) {
1070
- console.error('Certificate refresh failed:', error);
1071
- }
1072
- }
1073
- // Refresh remote ingress data if on remoteingress view
1074
- if (currentView === 'remoteingress') {
1075
- try {
1076
- await remoteIngressStatePart.dispatchAction(fetchRemoteIngressAction, null);
1077
- }
1078
- catch (error) {
1079
- console.error('Remote ingress refresh failed:', error);
1080
- }
1081
- }
1082
- // Refresh VPN data if on vpn view
1083
- if (currentView === 'vpn') {
1084
- try {
1085
- await vpnStatePart.dispatchAction(fetchVpnAction, null);
1086
- }
1087
- catch (error) {
1088
- console.error('VPN refresh failed:', error);
1089
- }
1090
- }
1091
- }
1092
- catch (error) {
1093
- console.error('Combined refresh failed:', error);
1094
- // If the error looks like an auth failure (invalid JWT), force re-login
1095
- const errMsg = String(error);
1096
- if (errMsg.includes('invalid') || errMsg.includes('unauthorized') || errMsg.includes('401')) {
1097
- await loginStatePart.dispatchAction(logoutAction, null);
1098
- window.location.reload();
1099
- }
1100
- }
1101
- }
1102
- // Create a proper action for the combined refresh so we can use createScheduledAction
1103
- const combinedRefreshAction = statsStatePart.createAction(async (statePartArg) => {
1104
- await dispatchCombinedRefreshAction();
1105
- // Return current state — dispatchCombinedRefreshAction already updates all state parts directly
1106
- return statePartArg.getState();
1107
- });
1108
- // Scheduled refresh process with autoPause: 'visibility' — automatically pauses when tab is hidden
1109
- let refreshProcess = null;
1110
- const startAutoRefresh = () => {
1111
- const uiState = uiStatePart.getState();
1112
- const loginState = loginStatePart.getState();
1113
- if (uiState.autoRefresh && loginState.isLoggedIn) {
1114
- // Dispose old process if interval changed or not running
1115
- if (refreshProcess) {
1116
- refreshProcess.dispose();
1117
- refreshProcess = null;
1118
- }
1119
- refreshProcess = statsStatePart.createScheduledAction({
1120
- action: combinedRefreshAction,
1121
- payload: undefined,
1122
- intervalMs: uiState.refreshInterval,
1123
- autoPause: 'visibility',
1124
- });
1125
- }
1126
- else {
1127
- if (refreshProcess) {
1128
- refreshProcess.dispose();
1129
- refreshProcess = null;
1130
- }
1131
- }
1132
- };
1133
- // Watch for relevant changes
1134
- let previousAutoRefresh = uiStatePart.getState().autoRefresh;
1135
- let previousRefreshInterval = uiStatePart.getState().refreshInterval;
1136
- let previousIsLoggedIn = loginStatePart.getState().isLoggedIn;
1137
- uiStatePart.select((s) => ({ autoRefresh: s.autoRefresh, refreshInterval: s.refreshInterval }))
1138
- .subscribe((state) => {
1139
- if (state.autoRefresh !== previousAutoRefresh ||
1140
- state.refreshInterval !== previousRefreshInterval) {
1141
- previousAutoRefresh = state.autoRefresh;
1142
- previousRefreshInterval = state.refreshInterval;
1143
- startAutoRefresh();
1144
- }
1145
- });
1146
- loginStatePart.select((s) => s.isLoggedIn).subscribe((isLoggedIn) => {
1147
- if (isLoggedIn !== previousIsLoggedIn) {
1148
- previousIsLoggedIn = isLoggedIn;
1149
- startAutoRefresh();
1150
- // Connect/disconnect TypedSocket based on login state
1151
- if (isLoggedIn) {
1152
- connectSocket();
1153
- }
1154
- else {
1155
- disconnectSocket();
1156
- }
1157
- }
1158
- });
1159
- // Pause/resume WebSocket when tab visibility changes
1160
- document.addEventListener('visibilitychange', () => {
1161
- if (document.hidden) {
1162
- disconnectSocket();
1163
- }
1164
- else if (loginStatePart.getState().isLoggedIn) {
1165
- connectSocket();
1166
- }
1167
- });
1168
- // Initial start
1169
- startAutoRefresh();
1170
- // Connect TypedSocket if already logged in (e.g., persistent session)
1171
- if (loginStatePart.getState().isLoggedIn) {
1172
- connectSocket();
1173
- }
1174
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwc3RhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c193ZWIvYXBwc3RhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxLQUFLLFVBQVUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUU3RCxpQ0FBaUM7QUFDakMsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUFHLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLFVBQVUsRUFBRSxDQUFDO0FBd0U3RSxrREFBa0Q7QUFDbEQsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLE1BQU0sUUFBUSxDQUFDLFlBQVksQ0FDdkQsT0FBTyxFQUNQO0lBQ0UsUUFBUSxFQUFFLElBQUk7SUFDZCxVQUFVLEVBQUUsS0FBSztDQUNsQixFQUNELFlBQVksQ0FBQywrQ0FBK0M7Q0FDN0QsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxNQUFNLFFBQVEsQ0FBQyxZQUFZLENBQ3ZELE9BQU8sRUFDUDtJQUNFLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLFVBQVUsRUFBRSxJQUFJO0lBQ2hCLFFBQVEsRUFBRSxJQUFJO0lBQ2QsZUFBZSxFQUFFLElBQUk7SUFDckIsV0FBVyxFQUFFLENBQUM7SUFDZCxTQUFTLEVBQUUsS0FBSztJQUNoQixLQUFLLEVBQUUsSUFBSTtDQUNaLEVBQ0QsTUFBTSxDQUFDLHFDQUFxQztDQUM3QyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHLE1BQU0sUUFBUSxDQUFDLFlBQVksQ0FDeEQsUUFBUSxFQUNSO0lBQ0UsTUFBTSxFQUFFLElBQUk7SUFDWixTQUFTLEVBQUUsS0FBSztJQUNoQixLQUFLLEVBQUUsSUFBSTtDQUNaLENBQ0YsQ0FBQztBQUVGLHVDQUF1QztBQUN2QyxNQUFNLGNBQWMsR0FBRyxHQUFXLEVBQUU7SUFDbEMsTUFBTSxJQUFJLEdBQUcs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