@serve.zone/dcrouter 13.13.0 → 13.15.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.
@@ -10,22 +10,6 @@ declare global {
10
10
  }
11
11
  }
12
12
 
13
- interface INetworkRequest {
14
- id: string;
15
- timestamp: number;
16
- method: string;
17
- url: string;
18
- hostname: string;
19
- port: number;
20
- protocol: 'http' | 'https' | 'tcp' | 'udp';
21
- statusCode?: number;
22
- duration: number;
23
- bytesIn: number;
24
- bytesOut: number;
25
- remoteIp: string;
26
- route?: string;
27
- }
28
-
29
13
  @customElement('ops-view-network-activity')
30
14
  export class OpsViewNetworkActivity extends DeesElement {
31
15
  /** How far back the traffic chart shows */
@@ -42,9 +26,6 @@ export class OpsViewNetworkActivity extends DeesElement {
42
26
  accessor networkState = appstate.networkStatePart.getState()!;
43
27
 
44
28
 
45
- @state()
46
- accessor networkRequests: INetworkRequest[] = [];
47
-
48
29
  @state()
49
30
  accessor trafficDataIn: Array<{ x: string | number; y: number }> = [];
50
31
 
@@ -314,108 +295,21 @@ export class OpsViewNetworkActivity extends DeesElement {
314
295
  <!-- Protocol Distribution Charts -->
315
296
  ${this.renderProtocolCharts()}
316
297
 
317
- <!-- Top IPs Section -->
298
+ <!-- Top IPs by Connection Count -->
318
299
  ${this.renderTopIPs()}
319
300
 
301
+ <!-- Top IPs by Bandwidth -->
302
+ ${this.renderTopIPsByBandwidth()}
303
+
304
+ <!-- Domain Activity -->
305
+ ${this.renderDomainActivity()}
306
+
320
307
  <!-- Backend Protocols Section -->
321
308
  ${this.renderBackendProtocols()}
322
-
323
- <!-- Requests Table -->
324
- <dees-table
325
- .data=${this.networkRequests}
326
- .rowKey=${'id'}
327
- .highlightUpdates=${'flash'}
328
- .displayFunction=${(req: INetworkRequest) => ({
329
- Time: new Date(req.timestamp).toLocaleTimeString(),
330
- Protocol: html`<span class="protocolBadge ${req.protocol}">${req.protocol.toUpperCase()}</span>`,
331
- Method: req.method,
332
- 'Host:Port': `${req.hostname}:${req.port}`,
333
- Path: this.truncateUrl(req.url),
334
- Status: this.renderStatus(req.statusCode),
335
- Duration: `${req.duration}ms`,
336
- 'In/Out': `${this.formatBytes(req.bytesIn)} / ${this.formatBytes(req.bytesOut)}`,
337
- 'Remote IP': req.remoteIp,
338
- })}
339
- .dataActions=${[
340
- {
341
- name: 'View Details',
342
- iconName: 'fa:magnifyingGlass',
343
- type: ['inRow', 'doubleClick', 'contextmenu'],
344
- actionFunc: async (actionData) => {
345
- await this.showRequestDetails(actionData.item);
346
- }
347
- }
348
- ]}
349
- heading1="Recent Network Activity"
350
- heading2="Recent network requests"
351
- searchable
352
- .showColumnFilters=${true}
353
- .pagination=${true}
354
- .paginationSize=${50}
355
- dataName="request"
356
- ></dees-table>
357
309
  </div>
358
310
  `;
359
311
  }
360
312
 
361
- private async showRequestDetails(request: INetworkRequest) {
362
- const { DeesModal } = await import('@design.estate/dees-catalog');
363
-
364
- await DeesModal.createAndShow({
365
- heading: 'Request Details',
366
- content: html`
367
- <div style="padding: 20px;">
368
- <dees-dataview-codebox
369
- .heading=${'Request Information'}
370
- progLang="json"
371
- .codeToDisplay=${JSON.stringify({
372
- id: request.id,
373
- timestamp: new Date(request.timestamp).toISOString(),
374
- protocol: request.protocol,
375
- method: request.method,
376
- url: request.url,
377
- hostname: request.hostname,
378
- port: request.port,
379
- statusCode: request.statusCode,
380
- duration: `${request.duration}ms`,
381
- bytesIn: request.bytesIn,
382
- bytesOut: request.bytesOut,
383
- remoteIp: request.remoteIp,
384
- route: request.route,
385
- }, null, 2)}
386
- ></dees-dataview-codebox>
387
- </div>
388
- `,
389
- menuOptions: [
390
- {
391
- name: 'Copy Request ID',
392
- iconName: 'lucide:Copy',
393
- action: async () => {
394
- await navigator.clipboard.writeText(request.id);
395
- }
396
- }
397
- ]
398
- });
399
- }
400
-
401
-
402
- private renderStatus(statusCode?: number): TemplateResult {
403
- if (!statusCode) {
404
- return html`<span class="statusBadge warning">N/A</span>`;
405
- }
406
-
407
- const statusClass = statusCode >= 200 && statusCode < 300 ? 'success' :
408
- statusCode >= 400 ? 'error' : 'warning';
409
-
410
- return html`<span class="statusBadge ${statusClass}">${statusCode}</span>`;
411
- }
412
-
413
- private truncateUrl(url: string, maxLength = 50): string {
414
- if (url.length <= maxLength) return url;
415
- return url.substring(0, maxLength - 3) + '...';
416
- }
417
-
418
-
419
313
  private formatNumber(num: number): string {
420
314
  if (num >= 1000000) {
421
315
  return (num / 1000000).toFixed(1) + 'M';
@@ -619,6 +513,66 @@ export class OpsViewNetworkActivity extends DeesElement {
619
513
  `;
620
514
  }
621
515
 
516
+ private renderTopIPsByBandwidth(): TemplateResult {
517
+ if (!this.networkState.topIPsByBandwidth || this.networkState.topIPsByBandwidth.length === 0) {
518
+ return html``;
519
+ }
520
+
521
+ return html`
522
+ <dees-table
523
+ .data=${this.networkState.topIPsByBandwidth}
524
+ .rowKey=${'ip'}
525
+ .highlightUpdates=${'flash'}
526
+ .displayFunction=${(ipData: { ip: string; count: number; bwIn: number; bwOut: number }) => {
527
+ return {
528
+ 'IP Address': ipData.ip,
529
+ 'Bandwidth In': this.formatBitsPerSecond(ipData.bwIn),
530
+ 'Bandwidth Out': this.formatBitsPerSecond(ipData.bwOut),
531
+ 'Total Bandwidth': this.formatBitsPerSecond(ipData.bwIn + ipData.bwOut),
532
+ 'Connections': ipData.count,
533
+ };
534
+ }}
535
+ heading1="Top IPs by Bandwidth"
536
+ heading2="IPs with highest throughput"
537
+ searchable
538
+ .showColumnFilters=${true}
539
+ .pagination=${false}
540
+ dataName="ip"
541
+ ></dees-table>
542
+ `;
543
+ }
544
+
545
+ private renderDomainActivity(): TemplateResult {
546
+ if (!this.networkState.domainActivity || this.networkState.domainActivity.length === 0) {
547
+ return html``;
548
+ }
549
+
550
+ return html`
551
+ <dees-table
552
+ .data=${this.networkState.domainActivity}
553
+ .rowKey=${'domain'}
554
+ .highlightUpdates=${'flash'}
555
+ .displayFunction=${(item: interfaces.data.IDomainActivity) => {
556
+ const totalBytesPerMin = (item.bytesInPerSecond + item.bytesOutPerSecond) * 60;
557
+ return {
558
+ 'Domain': item.domain,
559
+ 'Throughput In': this.formatBitsPerSecond(item.bytesInPerSecond),
560
+ 'Throughput Out': this.formatBitsPerSecond(item.bytesOutPerSecond),
561
+ 'Transferred / min': this.formatBytes(totalBytesPerMin),
562
+ 'Connections': item.activeConnections,
563
+ 'Routes': item.routeCount,
564
+ };
565
+ }}
566
+ heading1="Domain Activity"
567
+ heading2="Per-domain network activity aggregated from route metrics"
568
+ searchable
569
+ .showColumnFilters=${true}
570
+ .pagination=${false}
571
+ dataName="domain"
572
+ ></dees-table>
573
+ `;
574
+ }
575
+
622
576
  private renderBackendProtocols(): TemplateResult {
623
577
  const backends = this.networkState.backends;
624
578
  if (!backends || backends.length === 0) {
@@ -730,25 +684,6 @@ export class OpsViewNetworkActivity extends DeesElement {
730
684
  this.requestsPerSecHistory.shift();
731
685
  }
732
686
 
733
- // Reassign unconditionally so dees-table's flash diff can compare per-cell
734
- // values against the previous snapshot. Row identity is preserved via
735
- // rowKey='id', so DOM nodes are reused across ticks.
736
- this.networkRequests = this.networkState.connections.map((conn) => ({
737
- id: conn.id,
738
- timestamp: conn.startTime,
739
- method: 'GET', // Default method for proxy connections
740
- url: '/',
741
- hostname: conn.remoteAddress,
742
- port: conn.protocol === 'https' ? 443 : 80,
743
- protocol: conn.protocol === 'https' || conn.protocol === 'http' ? conn.protocol : 'tcp',
744
- statusCode: conn.state === 'connected' ? 200 : undefined,
745
- duration: Date.now() - conn.startTime,
746
- bytesIn: conn.bytesReceived,
747
- bytesOut: conn.bytesSent,
748
- remoteIp: conn.remoteAddress,
749
- route: 'proxy',
750
- }));
751
-
752
687
  // Load server-side throughput history into chart (once)
753
688
  if (!this.historyLoaded && this.networkState.throughputHistory && this.networkState.throughputHistory.length > 0) {
754
689
  this.loadThroughputHistory();