@serve.zone/dcrouter 7.3.0 → 7.4.1

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 (32) hide show
  1. package/dist_serve/bundle.js +592 -592
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/classes.dcrouter.js +50 -104
  4. package/dist_ts/logger.d.ts +2 -0
  5. package/dist_ts/logger.js +3 -3
  6. package/dist_ts/monitoring/classes.metricsmanager.d.ts +9 -2
  7. package/dist_ts/monitoring/classes.metricsmanager.js +23 -8
  8. package/dist_ts/opsserver/handlers/logs.handler.d.ts +5 -0
  9. package/dist_ts/opsserver/handlers/logs.handler.js +43 -2
  10. package/dist_ts/opsserver/handlers/stats.handler.js +3 -1
  11. package/dist_ts_interfaces/data/stats.d.ts +7 -0
  12. package/dist_ts_interfaces/requests/logs.d.ts +7 -0
  13. package/dist_ts_web/00_commitinfo_data.js +1 -1
  14. package/dist_ts_web/appstate.js +51 -1
  15. package/dist_ts_web/elements/ops-view-logs.d.ts +1 -0
  16. package/dist_ts_web/elements/ops-view-logs.js +31 -7
  17. package/dist_ts_web/elements/ops-view-overview.d.ts +1 -0
  18. package/dist_ts_web/elements/ops-view-overview.js +12 -3
  19. package/dist_ts_web/plugins.d.ts +2 -1
  20. package/dist_ts_web/plugins.js +4 -2
  21. package/package.json +3 -3
  22. package/ts/00_commitinfo_data.ts +1 -1
  23. package/ts/classes.dcrouter.ts +54 -107
  24. package/ts/logger.ts +2 -2
  25. package/ts/monitoring/classes.metricsmanager.ts +25 -9
  26. package/ts/opsserver/handlers/logs.handler.ts +47 -2
  27. package/ts/opsserver/handlers/stats.handler.ts +4 -1
  28. package/ts_web/00_commitinfo_data.ts +1 -1
  29. package/ts_web/appstate.ts +61 -0
  30. package/ts_web/elements/ops-view-logs.ts +28 -5
  31. package/ts_web/elements/ops-view-overview.ts +12 -2
  32. package/ts_web/plugins.ts +5 -1
@@ -1075,6 +1075,55 @@ export const toggleRemoteIngressAction = remoteIngressStatePart.createAction<{
1075
1075
  }
1076
1076
  });
1077
1077
 
1078
+ // ============================================================================
1079
+ // TypedSocket Client for Real-time Log Streaming
1080
+ // ============================================================================
1081
+
1082
+ let socketClient: plugins.typedsocket.TypedSocket | null = null;
1083
+ const socketRouter = new plugins.domtools.plugins.typedrequest.TypedRouter();
1084
+
1085
+ // Register handler for pushed log entries from the server
1086
+ socketRouter.addTypedHandler(
1087
+ new plugins.domtools.plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PushLogEntry>(
1088
+ 'pushLogEntry',
1089
+ async (dataArg) => {
1090
+ const current = logStatePart.getState();
1091
+ const updated = [...current.recentLogs, dataArg.entry];
1092
+ // Cap at 2000 entries
1093
+ if (updated.length > 2000) {
1094
+ updated.splice(0, updated.length - 2000);
1095
+ }
1096
+ logStatePart.setState({ ...current, recentLogs: updated });
1097
+ return {};
1098
+ }
1099
+ )
1100
+ );
1101
+
1102
+ async function connectSocket() {
1103
+ if (socketClient) return;
1104
+ try {
1105
+ socketClient = await plugins.typedsocket.TypedSocket.createClient(
1106
+ socketRouter,
1107
+ plugins.typedsocket.TypedSocket.useWindowLocationOriginUrl(),
1108
+ );
1109
+ await socketClient.setTag('role', 'ops_dashboard');
1110
+ } catch (err) {
1111
+ console.error('TypedSocket connection failed:', err);
1112
+ socketClient = null;
1113
+ }
1114
+ }
1115
+
1116
+ async function disconnectSocket() {
1117
+ if (socketClient) {
1118
+ try {
1119
+ await socketClient.stop();
1120
+ } catch {
1121
+ // ignore disconnect errors
1122
+ }
1123
+ socketClient = null;
1124
+ }
1125
+ }
1126
+
1078
1127
  // Combined refresh action for efficient polling
1079
1128
  async function dispatchCombinedRefreshAction() {
1080
1129
  const context = getActionContext();
@@ -1237,9 +1286,21 @@ let currentRefreshRate = 1000; // Track current refresh rate to avoid unnecessar
1237
1286
  if (state.isLoggedIn !== previousIsLoggedIn) {
1238
1287
  previousIsLoggedIn = state.isLoggedIn;
1239
1288
  startAutoRefresh();
1289
+
1290
+ // Connect/disconnect TypedSocket based on login state
1291
+ if (state.isLoggedIn) {
1292
+ connectSocket();
1293
+ } else {
1294
+ disconnectSocket();
1295
+ }
1240
1296
  }
1241
1297
  });
1242
1298
 
1243
1299
  // Initial start
1244
1300
  startAutoRefresh();
1301
+
1302
+ // Connect TypedSocket if already logged in (e.g., persistent session)
1303
+ if (loginStatePart.getState().isLoggedIn) {
1304
+ connectSocket();
1305
+ }
1245
1306
  })();
@@ -29,6 +29,8 @@ export class OpsViewLogs extends DeesElement {
29
29
  @state()
30
30
  accessor filterLimit: number = 100;
31
31
 
32
+ private lastPushedCount = 0;
33
+
32
34
  constructor() {
33
35
  super();
34
36
  const subscription = appstate.logStatePart
@@ -110,7 +112,11 @@ export class OpsViewLogs extends DeesElement {
110
112
 
111
113
  async connectedCallback() {
112
114
  super.connectedCallback();
113
- this.fetchLogs();
115
+ this.lastPushedCount = 0;
116
+ // Only fetch if state is empty (streaming will handle new entries)
117
+ if (this.logState.recentLogs.length === 0) {
118
+ this.fetchLogs();
119
+ }
114
120
  }
115
121
 
116
122
  async updated(changedProperties: Map<string, any>) {
@@ -127,10 +133,27 @@ export class OpsViewLogs extends DeesElement {
127
133
  // Ensure the chart element has finished its own initialization
128
134
  await chartLog.updateComplete;
129
135
 
130
- chartLog.clearLogs();
131
- const entries = this.getMappedLogEntries();
132
- if (entries.length > 0) {
133
- chartLog.updateLog(entries);
136
+ // Wait for xterm terminal to finish initializing (CDN load)
137
+ if (!chartLog.terminalReady) {
138
+ await new Promise<void>((resolve) => {
139
+ const check = () => {
140
+ if (chartLog.terminalReady) { resolve(); return; }
141
+ setTimeout(check, 50);
142
+ };
143
+ check();
144
+ });
145
+ }
146
+
147
+ const allEntries = this.getMappedLogEntries();
148
+ if (this.lastPushedCount === 0 && allEntries.length > 0) {
149
+ // Initial load: push all entries
150
+ chartLog.updateLog(allEntries);
151
+ this.lastPushedCount = allEntries.length;
152
+ } else if (allEntries.length > this.lastPushedCount) {
153
+ // Incremental: only push new entries
154
+ const newEntries = allEntries.slice(this.lastPushedCount);
155
+ chartLog.updateLog(newEntries);
156
+ this.lastPushedCount = allEntries.length;
134
157
  }
135
158
  }
136
159
 
@@ -133,8 +133,8 @@ export class OpsViewOverview extends DeesElement {
133
133
  .logEntries=${this.getRecentEventEntries()}
134
134
  ></dees-chart-log>
135
135
  <dees-chart-log
136
- .label=${'Security Alerts'}
137
- .logEntries=${this.getSecurityAlertEntries()}
136
+ .label=${'DNS Queries'}
137
+ .logEntries=${this.getDnsQueryEntries()}
138
138
  ></dees-chart-log>
139
139
  </div>
140
140
  `}
@@ -395,6 +395,16 @@ export class OpsViewOverview extends DeesElement {
395
395
  }));
396
396
  }
397
397
 
398
+ private getDnsQueryEntries(): Array<{ timestamp: string; level: 'debug' | 'info' | 'warn' | 'error' | 'success'; message: string; source?: string }> {
399
+ const queries: any[] = (this.statsState.dnsStats as any)?.recentQueries || [];
400
+ return queries.map((q: any) => ({
401
+ timestamp: new Date(q.timestamp).toISOString(),
402
+ level: q.answered ? 'info' as const : 'warn' as const,
403
+ message: `${q.type} ${q.domain} (${q.responseTimeMs}ms)`,
404
+ source: 'dns',
405
+ }));
406
+ }
407
+
398
408
  private getEmailTrafficSeries(): Array<{ name: string; color: string; data: Array<{ x: number; y: number }> }> {
399
409
  const ts = this.statsState.emailStats?.timeSeries;
400
410
  if (!ts) return [];
package/ts_web/plugins.ts CHANGED
@@ -2,9 +2,13 @@
2
2
  import * as deesElement from '@design.estate/dees-element';
3
3
  import * as deesCatalog from '@design.estate/dees-catalog';
4
4
 
5
+ // TypedSocket for real-time push communication
6
+ import * as typedsocket from '@api.global/typedsocket';
7
+
5
8
  export {
6
9
  deesElement,
7
- deesCatalog
10
+ deesCatalog,
11
+ typedsocket,
8
12
  }
9
13
 
10
14
  // domtools gives us TypedRequest and other utilities