@push.rocks/smartproxy 25.9.3 → 25.10.2

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.
package/changelog.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-03-12 - 25.10.2 - fix(repo)
4
+ no code changes to release
5
+
6
+
7
+ ## 2026-03-12 - 25.10.1 - fix(repo)
8
+ no changes to commit
9
+
10
+
11
+ ## 2026-03-12 - 25.10.0 - feat(metrics)
12
+ add per-backend connection, error, protocol, and pool metrics with stale backend pruning
13
+
14
+ - tracks backend connection lifecycle, connect timing, protocol detection, pool hit/miss rates, handshake/request errors, and h2 fallback failures in Rust metrics
15
+ - exposes backend metrics through the TypeScript metrics adapter with backend listings, protocol lookup, and top error summaries
16
+ - prunes backend metrics for backends no longer referenced by active routes, including preserved-port targets expanded across listening ports
17
+
3
18
  ## 2026-03-11 - 25.9.3 - fix(rustproxy-http)
4
19
  Evict stale HTTP/2 pooled senders and retry bodyless requests with fresh backend connections to avoid 502s
5
20
 
Binary file
Binary file
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartproxy',
6
- version: '25.9.3',
6
+ version: '25.10.2',
7
7
  description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
8
8
  };
9
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLHFQQUFxUDtDQUNuUSxDQUFBIn0=
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsV0FBVyxFQUFFLHFQQUFxUDtDQUNuUSxDQUFBIn0=
@@ -59,6 +59,14 @@ export interface IMetrics {
59
59
  bytesOut(): number;
60
60
  connections(): number;
61
61
  };
62
+ backends: {
63
+ byBackend(): Map<string, IBackendMetrics>;
64
+ protocols(): Map<string, string>;
65
+ topByErrors(limit?: number): Array<{
66
+ backend: string;
67
+ errors: number;
68
+ }>;
69
+ };
62
70
  percentiles: {
63
71
  connectionDuration(): {
64
72
  p50: number;
@@ -93,6 +101,20 @@ export interface IMetricsConfig {
93
101
  prometheusPath: string;
94
102
  prometheusPrefix: string;
95
103
  }
104
+ /**
105
+ * Per-backend metrics
106
+ */
107
+ export interface IBackendMetrics {
108
+ protocol: string;
109
+ activeConnections: number;
110
+ totalConnections: number;
111
+ connectErrors: number;
112
+ handshakeErrors: number;
113
+ requestErrors: number;
114
+ avgConnectTimeMs: number;
115
+ poolHitRate: number;
116
+ h2Failures: number;
117
+ }
96
118
  /**
97
119
  * Internal interface for connection byte tracking
98
120
  */
@@ -1,4 +1,4 @@
1
- import type { IMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
1
+ import type { IMetrics, IBackendMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
2
2
  import type { RustProxyBridge } from './rust-proxy-bridge.js';
3
3
  /**
4
4
  * Adapts Rust JSON metrics to the IMetrics interface.
@@ -52,6 +52,14 @@ export declare class RustMetricsAdapter implements IMetrics {
52
52
  bytesOut: () => number;
53
53
  connections: () => number;
54
54
  };
55
+ backends: {
56
+ byBackend: () => Map<string, IBackendMetrics>;
57
+ protocols: () => Map<string, string>;
58
+ topByErrors: (limit?: number) => Array<{
59
+ backend: string;
60
+ errors: number;
61
+ }>;
62
+ };
55
63
  percentiles: {
56
64
  connectionDuration: () => {
57
65
  p50: number;
@@ -125,6 +125,55 @@ export class RustMetricsAdapter {
125
125
  return this.cache?.totalConnections ?? 0;
126
126
  },
127
127
  };
128
+ this.backends = {
129
+ byBackend: () => {
130
+ const result = new Map();
131
+ if (this.cache?.backends) {
132
+ for (const [key, bm] of Object.entries(this.cache.backends)) {
133
+ const m = bm;
134
+ const totalTimeUs = m.totalConnectTimeUs ?? 0;
135
+ const count = m.connectCount ?? 0;
136
+ const poolHits = m.poolHits ?? 0;
137
+ const poolMisses = m.poolMisses ?? 0;
138
+ const poolTotal = poolHits + poolMisses;
139
+ result.set(key, {
140
+ protocol: m.protocol ?? 'unknown',
141
+ activeConnections: m.activeConnections ?? 0,
142
+ totalConnections: m.totalConnections ?? 0,
143
+ connectErrors: m.connectErrors ?? 0,
144
+ handshakeErrors: m.handshakeErrors ?? 0,
145
+ requestErrors: m.requestErrors ?? 0,
146
+ avgConnectTimeMs: count > 0 ? (totalTimeUs / count) / 1000 : 0,
147
+ poolHitRate: poolTotal > 0 ? poolHits / poolTotal : 0,
148
+ h2Failures: m.h2Failures ?? 0,
149
+ });
150
+ }
151
+ }
152
+ return result;
153
+ },
154
+ protocols: () => {
155
+ const result = new Map();
156
+ if (this.cache?.backends) {
157
+ for (const [key, bm] of Object.entries(this.cache.backends)) {
158
+ result.set(key, bm.protocol ?? 'unknown');
159
+ }
160
+ }
161
+ return result;
162
+ },
163
+ topByErrors: (limit = 10) => {
164
+ const result = [];
165
+ if (this.cache?.backends) {
166
+ for (const [key, bm] of Object.entries(this.cache.backends)) {
167
+ const m = bm;
168
+ const errors = (m.connectErrors ?? 0) + (m.handshakeErrors ?? 0) + (m.requestErrors ?? 0);
169
+ if (errors > 0)
170
+ result.push({ backend: key, errors });
171
+ }
172
+ }
173
+ result.sort((a, b) => b.errors - a.errors);
174
+ return result.slice(0, limit);
175
+ },
176
+ };
128
177
  this.percentiles = {
129
178
  connectionDuration: () => {
130
179
  return { p50: 0, p95: 0, p99: 0 };
@@ -169,4 +218,4 @@ export class RustMetricsAdapter {
169
218
  }
170
219
  }
171
220
  }
172
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVzdC1tZXRyaWNzLWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3J1c3QtbWV0cmljcy1hZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBTTdCLFlBQVksTUFBdUIsRUFBRSxjQUFjLEdBQUcsSUFBSTtRQUpsRCxVQUFLLEdBQVEsSUFBSSxDQUFDO1FBQ2xCLGNBQVMsR0FBMEMsSUFBSSxDQUFDO1FBc0NoRSxrQ0FBa0M7UUFFM0IsZ0JBQVcsR0FBRztZQUNuQixNQUFNLEVBQUUsR0FBVyxFQUFFO2dCQUNuQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLElBQUksQ0FBQyxDQUFDO1lBQzVDLENBQUM7WUFDRCxLQUFLLEVBQUUsR0FBVyxFQUFFO2dCQUNsQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxDQUFDO1lBQzNDLENBQUM7WUFDRCxPQUFPLEVBQUUsR0FBd0IsRUFBRTtnQkFDakMsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7Z0JBQ3pDLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQztvQkFDdkIsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO3dCQUMzRCxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRyxFQUFVLENBQUMsaUJBQWlCLElBQUksQ0FBQyxDQUFDLENBQUM7b0JBQ3ZELENBQUM7Z0JBQ0gsQ0FBQztnQkFDRCxPQUFPLE1BQU0sQ0FBQztZQUNoQixDQUFDO1lBQ0QsSUFBSSxFQUFFLEdBQXdCLEVBQUU7Z0JBQzlCLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO2dCQUN6QyxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUM7b0JBQ3BCLEtBQUssTUFBTSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQzt3QkFDdEQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUcsRUFBVSxDQUFDLGlCQUFpQixJQUFJLENBQUMsQ0FBQyxDQUFDO29CQUNyRCxDQUFDO2dCQUNILENBQUM7Z0JBQ0QsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztZQUNELE1BQU0sRUFBRSxDQUFDLFFBQWdCLEVBQUUsRUFBd0MsRUFBRTtnQkFDbkUsTUFBTSxNQUFNLEdBQXlDLEVBQUUsQ0FBQztnQkFDeEQsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDO29CQUNwQixLQUFLLE1BQU0sQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7d0JBQ3RELE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFHLEVBQVUsQ0FBQyxpQkFBaUIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUNqRSxDQUFDO2dCQUNILENBQUM7Z0JBQ0QsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN6QyxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2hDLENBQUM7U0FDRixDQUFDO1FBRUssZUFBVSxHQUFHO1lBQ2xCLE9BQU8sRUFBRSxHQUFvQixFQUFFO2dCQUM3QixPQUFPO29CQUNMLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLHVCQUF1QixJQUFJLENBQUM7b0JBQzVDLEdBQUcsRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLHdCQUF3QixJQUFJLENBQUM7aUJBQy9DLENBQUM7WUFDSixDQUFDO1lBQ0QsTUFBTSxFQUFFLEdBQW9CLEVBQUU7Z0JBQzVCLE9BQU87b0JBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsNkJBQTZCLElBQUksQ0FBQztvQkFDbEQsR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsOEJBQThCLElBQUksQ0FBQztpQkFDckQsQ0FBQztZQUNKLENBQUM7WUFDRCxPQUFPLEVBQUUsR0FBb0IsRUFBRTtnQkFDN0IsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ25DLENBQUM7WUFDRCxNQUFNLEVBQUUsQ0FBQyxRQUFnQixFQUFtQixFQUFFO2dCQUM1QyxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbkMsQ0FBQztZQUNELE9BQU8sRUFBRSxDQUFDLE9BQWUsRUFBa0MsRUFBRTtnQkFDM0QsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsaUJBQWlCO29CQUFFLE9BQU8sRUFBRSxDQUFDO2dCQUM5QyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO29CQUNuRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLFdBQVc7b0JBQ3hCLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTztvQkFDYixHQUFHLEVBQUUsQ0FBQyxDQUFDLFFBQVE7aUJBQ2hCLENBQUMsQ0FBQyxDQUFDO1lBQ04sQ0FBQztZQUNELE9BQU8sRUFBRSxDQUFDLGNBQXVCLEVBQWdDLEVBQUU7Z0JBQ2pFLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxFQUEyQixDQUFDO2dCQUNsRCxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUM7b0JBQ3ZCLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQzt3QkFDM0QsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUU7NEJBQ2YsRUFBRSxFQUFHLEVBQVUsQ0FBQyx1QkFBdUIsSUFBSSxDQUFDOzRCQUM1QyxHQUFHLEVBQUcsRUFBVSxDQUFDLHdCQUF3QixJQUFJLENBQUM7eUJBQy9DLENBQUMsQ0FBQztvQkFDTCxDQUFDO2dCQUNILENBQUM7Z0JBQ0QsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztZQUNELElBQUksRUFBRSxDQUFDLGNBQXVCLEVBQWdDLEVBQUU7Z0JBQzlELE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxFQUEyQixDQUFDO2dCQUNsRCxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUM7b0JBQ3BCLEtBQUssTUFBTSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQzt3QkFDdEQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUU7NEJBQ2IsRUFBRSxFQUFHLEVBQVUsQ0FBQyx1QkFBdUIsSUFBSSxDQUFDOzRCQUM1QyxHQUFHLEVBQUcsRUFBVSxDQUFDLHdCQUF3QixJQUFJLENBQUM7eUJBQy9DLENBQUMsQ0FBQztvQkFDTCxDQUFDO2dCQUNILENBQUM7Z0JBQ0QsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztTQUNGLENBQUM7UUFFSyxhQUFRLEdBQUc7WUFDaEIsU0FBUyxFQUFFLEdBQVcsRUFBRTtnQkFDdEIsT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLGtCQUFrQixJQUFJLENBQUMsQ0FBQztZQUM3QyxDQUFDO1lBQ0QsU0FBUyxFQUFFLEdBQVcsRUFBRTtnQkFDdEIsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsd0JBQXdCLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzFELENBQUM7WUFDRCxLQUFLLEVBQUUsR0FBVyxFQUFFO2dCQUNsQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsSUFBSSxDQUFDLENBQUM7WUFDNUUsQ0FBQztTQUNGLENBQUM7UUFFSyxXQUFNLEdBQUc7WUFDZCxPQUFPLEVBQUUsR0FBVyxFQUFFO2dCQUNwQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsT0FBTyxJQUFJLENBQUMsQ0FBQztZQUNsQyxDQUFDO1lBQ0QsUUFBUSxFQUFFLEdBQVcsRUFBRTtnQkFDckIsT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsSUFBSSxDQUFDLENBQUM7WUFDbkMsQ0FBQztZQUNELFdBQVcsRUFBRSxHQUFXLEVBQUU7Z0JBQ3hCLE9BQU8sSUFBSSxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsSUFBSSxDQUFDLENBQUM7WUFDM0MsQ0FBQztTQUNGLENBQUM7UUFFSyxnQkFBVyxHQUFHO1lBQ25CLGtCQUFrQixFQUFFLEdBQThDLEVBQUU7Z0JBQ2xFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQ3BDLENBQUM7WUFDRCxnQkFBZ0IsRUFBRSxHQUdoQixFQUFFO2dCQUNGLE9BQU87b0JBQ0wsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUU7b0JBQzlCLEdBQUcsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFO2lCQUNoQyxDQUFDO1lBQ0osQ0FBQztTQUNGLENBQUM7UUFuS0EsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLGNBQWMsR0FBRyxjQUFjLENBQUM7SUFDdkMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLElBQUk7UUFDZixJQUFJLENBQUM7WUFDSCxJQUFJLENBQUMsS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUM5QyxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsbURBQW1EO1FBQ3JELENBQUM7SUFDSCxDQUFDO0lBRU0sWUFBWTtRQUNqQixJQUFJLElBQUksQ0FBQyxTQUFTO1lBQUUsT0FBTztRQUMzQixrREFBa0Q7UUFDbEQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1osSUFBSSxDQUFDLFNBQVMsR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFO1lBQ2hDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNkLENBQUMsRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDeEIsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3pCLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDekIsQ0FBQztJQUNILENBQUM7SUFFTSxXQUFXO1FBQ2hCLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25CLGFBQWEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDOUIsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUM7UUFDeEIsQ0FBQztJQUNILENBQUM7Q0FvSUYifQ==
221
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVzdC1tZXRyaWNzLWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3J1c3QtbWV0cmljcy1hZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBTTdCLFlBQVksTUFBdUIsRUFBRSxjQUFjLEdBQUcsSUFBSTtRQUpsRCxVQUFLLEdBQVEsSUFBSSxDQUFDO1FBQ2xCLGNBQVMsR0FBMEMsSUFBSSxDQUFDO1FBc0NoRSxrQ0FBa0M7UUFFM0IsZ0JBQVcsR0FBRztZQUNuQixNQUFNLEVBQUUsR0FBVyxFQUFFO2dCQUNuQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLElBQUksQ0FBQyxDQUFDO1lBQzVDLENBQUM7WUFDRCxLQUFLLEVBQUUsR0FBVyxFQUFFO2dCQUNsQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxDQUFDO1lBQzNDLENBQUM7WUFDRCxPQUFPLEVBQUUsR0FBd0IsRUFBRTtnQkFDakMsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7Z0JBQ3pDLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQztvQkFDdkIsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO3dCQUMzRCxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRyxFQUFVLENBQUMsaUJBQWlCLElBQUksQ0FBQyxDQUFDLENBQUM7b0JBQ3ZELENBQUM7Z0JBQ0gsQ0FBQztnQkFDRCxPQUFPLE1BQU0sQ0FBQztZQUNoQixDQUFDO1lBQ0QsSUFBSSxFQUFFLEdBQXdCLEVBQUU7Z0JBQzlCLE1BQU0sTUFBTSxHQUFHLElB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartproxy",
3
- "version": "25.9.3",
3
+ "version": "25.10.2",
4
4
  "private": false,
5
5
  "description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.",
6
6
  "main": "dist_ts/index.js",
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartproxy',
6
- version: '25.9.3',
6
+ version: '25.10.2',
7
7
  description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
8
8
  }
@@ -67,6 +67,13 @@ export interface IMetrics {
67
67
  connections(): number;
68
68
  };
69
69
 
70
+ // Backend metrics
71
+ backends: {
72
+ byBackend(): Map<string, IBackendMetrics>;
73
+ protocols(): Map<string, string>;
74
+ topByErrors(limit?: number): Array<{ backend: string; errors: number }>;
75
+ };
76
+
70
77
  // Performance metrics
71
78
  percentiles: {
72
79
  connectionDuration(): { p50: number; p95: number; p99: number };
@@ -98,6 +105,21 @@ export interface IMetricsConfig {
98
105
  prometheusPrefix: string; // Default: smartproxy_
99
106
  }
100
107
 
108
+ /**
109
+ * Per-backend metrics
110
+ */
111
+ export interface IBackendMetrics {
112
+ protocol: string;
113
+ activeConnections: number;
114
+ totalConnections: number;
115
+ connectErrors: number;
116
+ handshakeErrors: number;
117
+ requestErrors: number;
118
+ avgConnectTimeMs: number;
119
+ poolHitRate: number;
120
+ h2Failures: number;
121
+ }
122
+
101
123
  /**
102
124
  * Internal interface for connection byte tracking
103
125
  */
@@ -1,4 +1,4 @@
1
- import type { IMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
1
+ import type { IMetrics, IBackendMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
2
2
  import type { RustProxyBridge } from './rust-proxy-bridge.js';
3
3
 
4
4
  /**
@@ -169,6 +169,55 @@ export class RustMetricsAdapter implements IMetrics {
169
169
  },
170
170
  };
171
171
 
172
+ public backends = {
173
+ byBackend: (): Map<string, IBackendMetrics> => {
174
+ const result = new Map<string, IBackendMetrics>();
175
+ if (this.cache?.backends) {
176
+ for (const [key, bm] of Object.entries(this.cache.backends)) {
177
+ const m = bm as any;
178
+ const totalTimeUs = m.totalConnectTimeUs ?? 0;
179
+ const count = m.connectCount ?? 0;
180
+ const poolHits = m.poolHits ?? 0;
181
+ const poolMisses = m.poolMisses ?? 0;
182
+ const poolTotal = poolHits + poolMisses;
183
+ result.set(key, {
184
+ protocol: m.protocol ?? 'unknown',
185
+ activeConnections: m.activeConnections ?? 0,
186
+ totalConnections: m.totalConnections ?? 0,
187
+ connectErrors: m.connectErrors ?? 0,
188
+ handshakeErrors: m.handshakeErrors ?? 0,
189
+ requestErrors: m.requestErrors ?? 0,
190
+ avgConnectTimeMs: count > 0 ? (totalTimeUs / count) / 1000 : 0,
191
+ poolHitRate: poolTotal > 0 ? poolHits / poolTotal : 0,
192
+ h2Failures: m.h2Failures ?? 0,
193
+ });
194
+ }
195
+ }
196
+ return result;
197
+ },
198
+ protocols: (): Map<string, string> => {
199
+ const result = new Map<string, string>();
200
+ if (this.cache?.backends) {
201
+ for (const [key, bm] of Object.entries(this.cache.backends)) {
202
+ result.set(key, (bm as any).protocol ?? 'unknown');
203
+ }
204
+ }
205
+ return result;
206
+ },
207
+ topByErrors: (limit: number = 10): Array<{ backend: string; errors: number }> => {
208
+ const result: Array<{ backend: string; errors: number }> = [];
209
+ if (this.cache?.backends) {
210
+ for (const [key, bm] of Object.entries(this.cache.backends)) {
211
+ const m = bm as any;
212
+ const errors = (m.connectErrors ?? 0) + (m.handshakeErrors ?? 0) + (m.requestErrors ?? 0);
213
+ if (errors > 0) result.push({ backend: key, errors });
214
+ }
215
+ }
216
+ result.sort((a, b) => b.errors - a.errors);
217
+ return result.slice(0, limit);
218
+ },
219
+ };
220
+
172
221
  public percentiles = {
173
222
  connectionDuration: (): { p50: number; p95: number; p99: number } => {
174
223
  return { p50: 0, p95: 0, p99: 0 };