@push.rocks/smartproxy 23.0.0 → 23.1.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 (161) hide show
  1. package/changelog.md +10 -0
  2. package/dist_rust/{rustproxy → rustproxy_linux_amd64} +0 -0
  3. package/dist_rust/rustproxy_linux_arm64 +0 -0
  4. package/dist_ts/00_commitinfo_data.js +1 -1
  5. package/dist_ts/plugins.d.ts +2 -1
  6. package/dist_ts/plugins.js +3 -2
  7. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +9 -21
  8. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +83 -212
  9. package/dist_ts/proxies/smart-proxy/smart-proxy.js +2 -3
  10. package/npmextra.json +3 -0
  11. package/package.json +13 -11
  12. package/readme.md +41 -11
  13. package/ts/00_commitinfo_data.ts +1 -1
  14. package/ts/plugins.ts +2 -0
  15. package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +102 -233
  16. package/ts/proxies/smart-proxy/smart-proxy.ts +1 -2
  17. package/dist_ts/common/eventUtils.d.ts +0 -14
  18. package/dist_ts/common/eventUtils.js +0 -20
  19. package/dist_ts/common/types.d.ts +0 -82
  20. package/dist_ts/common/types.js +0 -15
  21. package/dist_ts/core/utils/event-system.d.ts +0 -200
  22. package/dist_ts/core/utils/event-system.js +0 -224
  23. package/dist_ts/core/utils/event-utils.d.ts +0 -15
  24. package/dist_ts/core/utils/event-utils.js +0 -11
  25. package/dist_ts/core/utils/route-manager.d.ts +0 -88
  26. package/dist_ts/core/utils/route-manager.js +0 -342
  27. package/dist_ts/core/utils/route-utils.d.ts +0 -28
  28. package/dist_ts/core/utils/route-utils.js +0 -67
  29. package/dist_ts/detection/detectors/http-detector-v2.d.ts +0 -33
  30. package/dist_ts/detection/detectors/http-detector-v2.js +0 -87
  31. package/dist_ts/detection/detectors/tls-detector-v2.d.ts +0 -33
  32. package/dist_ts/detection/detectors/tls-detector-v2.js +0 -80
  33. package/dist_ts/detection/protocol-detector-v2.d.ts +0 -46
  34. package/dist_ts/detection/protocol-detector-v2.js +0 -116
  35. package/dist_ts/forwarding/config/forwarding-types.d.ts +0 -42
  36. package/dist_ts/forwarding/config/forwarding-types.js +0 -18
  37. package/dist_ts/forwarding/config/index.d.ts +0 -9
  38. package/dist_ts/forwarding/config/index.js +0 -10
  39. package/dist_ts/forwarding/factory/forwarding-factory.d.ts +0 -25
  40. package/dist_ts/forwarding/factory/forwarding-factory.js +0 -172
  41. package/dist_ts/forwarding/factory/index.d.ts +0 -4
  42. package/dist_ts/forwarding/factory/index.js +0 -5
  43. package/dist_ts/forwarding/handlers/base-handler.d.ts +0 -62
  44. package/dist_ts/forwarding/handlers/base-handler.js +0 -121
  45. package/dist_ts/forwarding/handlers/http-handler.d.ts +0 -30
  46. package/dist_ts/forwarding/handlers/http-handler.js +0 -143
  47. package/dist_ts/forwarding/handlers/https-passthrough-handler.d.ts +0 -29
  48. package/dist_ts/forwarding/handlers/https-passthrough-handler.js +0 -156
  49. package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.d.ts +0 -36
  50. package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +0 -276
  51. package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.d.ts +0 -35
  52. package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +0 -261
  53. package/dist_ts/forwarding/handlers/index.d.ts +0 -8
  54. package/dist_ts/forwarding/handlers/index.js +0 -9
  55. package/dist_ts/forwarding/index.d.ts +0 -13
  56. package/dist_ts/forwarding/index.js +0 -16
  57. package/dist_ts/http/index.d.ts +0 -5
  58. package/dist_ts/http/index.js +0 -8
  59. package/dist_ts/http/models/http-types.d.ts +0 -6
  60. package/dist_ts/http/models/http-types.js +0 -7
  61. package/dist_ts/http/router/index.d.ts +0 -8
  62. package/dist_ts/http/router/index.js +0 -7
  63. package/dist_ts/http/router/proxy-router.d.ts +0 -115
  64. package/dist_ts/http/router/proxy-router.js +0 -325
  65. package/dist_ts/http/router/route-router.d.ts +0 -108
  66. package/dist_ts/http/router/route-router.js +0 -393
  67. package/dist_ts/protocols/tls/constants.d.ts +0 -122
  68. package/dist_ts/protocols/tls/constants.js +0 -135
  69. package/dist_ts/protocols/tls/parser.d.ts +0 -53
  70. package/dist_ts/protocols/tls/parser.js +0 -294
  71. package/dist_ts/protocols/tls/types.d.ts +0 -65
  72. package/dist_ts/protocols/tls/types.js +0 -5
  73. package/dist_ts/proxies/http-proxy/certificate-manager.d.ts +0 -95
  74. package/dist_ts/proxies/http-proxy/certificate-manager.js +0 -214
  75. package/dist_ts/proxies/http-proxy/connection-pool.d.ts +0 -47
  76. package/dist_ts/proxies/http-proxy/connection-pool.js +0 -195
  77. package/dist_ts/proxies/http-proxy/context-creator.d.ts +0 -34
  78. package/dist_ts/proxies/http-proxy/context-creator.js +0 -108
  79. package/dist_ts/proxies/http-proxy/default-certificates.d.ts +0 -54
  80. package/dist_ts/proxies/http-proxy/default-certificates.js +0 -127
  81. package/dist_ts/proxies/http-proxy/function-cache.d.ts +0 -95
  82. package/dist_ts/proxies/http-proxy/function-cache.js +0 -215
  83. package/dist_ts/proxies/http-proxy/handlers/index.d.ts +0 -4
  84. package/dist_ts/proxies/http-proxy/handlers/index.js +0 -6
  85. package/dist_ts/proxies/http-proxy/handlers/redirect-handler.d.ts +0 -18
  86. package/dist_ts/proxies/http-proxy/handlers/redirect-handler.js +0 -78
  87. package/dist_ts/proxies/http-proxy/handlers/static-handler.d.ts +0 -19
  88. package/dist_ts/proxies/http-proxy/handlers/static-handler.js +0 -211
  89. package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -117
  90. package/dist_ts/proxies/http-proxy/http-proxy.js +0 -521
  91. package/dist_ts/proxies/http-proxy/http-request-handler.d.ts +0 -40
  92. package/dist_ts/proxies/http-proxy/http-request-handler.js +0 -257
  93. package/dist_ts/proxies/http-proxy/http2-request-handler.d.ts +0 -24
  94. package/dist_ts/proxies/http-proxy/http2-request-handler.js +0 -201
  95. package/dist_ts/proxies/http-proxy/index.d.ts +0 -14
  96. package/dist_ts/proxies/http-proxy/index.js +0 -16
  97. package/dist_ts/proxies/http-proxy/models/http-types.d.ts +0 -117
  98. package/dist_ts/proxies/http-proxy/models/http-types.js +0 -92
  99. package/dist_ts/proxies/http-proxy/models/index.d.ts +0 -5
  100. package/dist_ts/proxies/http-proxy/models/index.js +0 -6
  101. package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -75
  102. package/dist_ts/proxies/http-proxy/models/types.js +0 -35
  103. package/dist_ts/proxies/http-proxy/request-handler.d.ts +0 -97
  104. package/dist_ts/proxies/http-proxy/request-handler.js +0 -737
  105. package/dist_ts/proxies/http-proxy/security-manager.d.ts +0 -98
  106. package/dist_ts/proxies/http-proxy/security-manager.js +0 -341
  107. package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +0 -50
  108. package/dist_ts/proxies/http-proxy/websocket-handler.js +0 -505
  109. package/dist_ts/proxies/smart-proxy/acme-state-manager.d.ts +0 -42
  110. package/dist_ts/proxies/smart-proxy/acme-state-manager.js +0 -101
  111. package/dist_ts/proxies/smart-proxy/cert-store.d.ts +0 -10
  112. package/dist_ts/proxies/smart-proxy/cert-store.js +0 -72
  113. package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +0 -164
  114. package/dist_ts/proxies/smart-proxy/certificate-manager.js +0 -745
  115. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +0 -128
  116. package/dist_ts/proxies/smart-proxy/connection-manager.js +0 -689
  117. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +0 -43
  118. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +0 -180
  119. package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +0 -98
  120. package/dist_ts/proxies/smart-proxy/metrics-collector.js +0 -355
  121. package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +0 -82
  122. package/dist_ts/proxies/smart-proxy/nftables-manager.js +0 -237
  123. package/dist_ts/proxies/smart-proxy/port-manager.d.ts +0 -117
  124. package/dist_ts/proxies/smart-proxy/port-manager.js +0 -318
  125. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +0 -60
  126. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +0 -1407
  127. package/dist_ts/proxies/smart-proxy/route-manager.d.ts +0 -112
  128. package/dist_ts/proxies/smart-proxy/route-manager.js +0 -453
  129. package/dist_ts/proxies/smart-proxy/route-orchestrator.d.ts +0 -56
  130. package/dist_ts/proxies/smart-proxy/route-orchestrator.js +0 -204
  131. package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +0 -23
  132. package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +0 -104
  133. package/dist_ts/proxies/smart-proxy/security-manager.d.ts +0 -74
  134. package/dist_ts/proxies/smart-proxy/security-manager.js +0 -227
  135. package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +0 -36
  136. package/dist_ts/proxies/smart-proxy/throughput-tracker.js +0 -115
  137. package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +0 -48
  138. package/dist_ts/proxies/smart-proxy/timeout-manager.js +0 -158
  139. package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +0 -50
  140. package/dist_ts/proxies/smart-proxy/tls-manager.js +0 -110
  141. package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +0 -161
  142. package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +0 -282
  143. package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +0 -73
  144. package/dist_ts/proxies/smart-proxy/utils/route-validators.js +0 -259
  145. package/dist_ts/routing/router/proxy-router.d.ts +0 -115
  146. package/dist_ts/routing/router/proxy-router.js +0 -325
  147. package/dist_ts/routing/router/route-router.d.ts +0 -108
  148. package/dist_ts/routing/router/route-router.js +0 -393
  149. package/dist_ts/tls/alerts/index.d.ts +0 -4
  150. package/dist_ts/tls/alerts/index.js +0 -5
  151. package/dist_ts/tls/alerts/tls-alert.d.ts +0 -150
  152. package/dist_ts/tls/alerts/tls-alert.js +0 -226
  153. package/dist_ts/tls/sni/client-hello-parser.d.ts +0 -100
  154. package/dist_ts/tls/sni/client-hello-parser.js +0 -464
  155. package/dist_ts/tls/sni/sni-extraction.d.ts +0 -58
  156. package/dist_ts/tls/sni/sni-extraction.js +0 -275
  157. package/dist_ts/tls/utils/index.d.ts +0 -4
  158. package/dist_ts/tls/utils/index.js +0 -5
  159. package/dist_ts/tls/utils/tls-utils.d.ts +0 -49
  160. package/dist_ts/tls/utils/tls-utils.js +0 -75
  161. package/ts/proxies/smart-proxy/rust-binary-locator.ts +0 -112
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartproxy",
3
- "version": "23.0.0",
3
+ "version": "23.1.0",
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",
@@ -10,16 +10,17 @@
10
10
  "license": "MIT",
11
11
  "scripts": {
12
12
  "test": "(tstest test/**/test*.ts --verbose --timeout 60 --logfile)",
13
- "build": "(tsbuild tsfolders --allowimplicitany)",
13
+ "build": "(tsbuild tsfolders --allowimplicitany) && (tsrust)",
14
14
  "format": "(gitzone format)",
15
15
  "buildDocs": "tsdoc"
16
16
  },
17
17
  "devDependencies": {
18
- "@git.zone/tsbuild": "^3.1.2",
19
- "@git.zone/tsrun": "^2.0.0",
20
- "@git.zone/tstest": "^3.1.3",
21
- "@push.rocks/smartserve": "^1.4.0",
22
- "@types/node": "^24.10.2",
18
+ "@git.zone/tsbuild": "^4.1.2",
19
+ "@git.zone/tsrun": "^2.0.1",
20
+ "@git.zone/tsrust": "^1.3.0",
21
+ "@git.zone/tstest": "^3.1.8",
22
+ "@push.rocks/smartserve": "^2.0.1",
23
+ "@types/node": "^25.2.2",
23
24
  "typescript": "^5.9.3",
24
25
  "why-is-node-running": "^3.2.2"
25
26
  },
@@ -28,20 +29,21 @@
28
29
  "@push.rocks/smartacme": "^8.0.0",
29
30
  "@push.rocks/smartcrypto": "^2.0.4",
30
31
  "@push.rocks/smartdelay": "^3.0.5",
31
- "@push.rocks/smartfile": "^13.1.0",
32
+ "@push.rocks/smartfile": "^13.1.2",
32
33
  "@push.rocks/smartlog": "^3.1.10",
33
34
  "@push.rocks/smartnetwork": "^4.4.0",
34
35
  "@push.rocks/smartpromise": "^4.2.3",
35
36
  "@push.rocks/smartrequest": "^5.0.1",
37
+ "@push.rocks/smartrust": "^1.1.1",
36
38
  "@push.rocks/smartrx": "^3.0.10",
37
39
  "@push.rocks/smartstring": "^4.1.0",
38
- "@push.rocks/taskbuffer": "^3.5.0",
40
+ "@push.rocks/taskbuffer": "^4.2.0",
39
41
  "@tsclass/tsclass": "^9.3.0",
40
42
  "@types/minimatch": "^6.0.0",
41
43
  "@types/ws": "^8.18.1",
42
- "minimatch": "^10.1.1",
44
+ "minimatch": "^10.1.2",
43
45
  "pretty-ms": "^9.3.0",
44
- "ws": "^8.18.3"
46
+ "ws": "^8.19.0"
45
47
  },
46
48
  "files": [
47
49
  "ts/**/*",
package/readme.md CHANGED
@@ -378,7 +378,9 @@ await proxy.updateRoutes([...newRoutes]);
378
378
  // Get real-time metrics
379
379
  const metrics = proxy.getMetrics();
380
380
  console.log(`Active connections: ${metrics.connections.active()}`);
381
- console.log(`Requests/sec: ${metrics.throughput.requestsPerSecond()}`);
381
+ console.log(`Bytes in: ${metrics.totals.bytesIn()}`);
382
+ console.log(`Requests/sec: ${metrics.requests.perSecond()}`);
383
+ console.log(`Throughput in: ${metrics.throughput.instant().in} bytes/sec`);
382
384
 
383
385
  // Get detailed statistics from the Rust engine
384
386
  const stats = await proxy.getStatistics();
@@ -486,8 +488,8 @@ SmartProxy uses a hybrid **Rust + TypeScript** architecture:
486
488
 
487
489
  - **Rust Engine** handles all networking, TLS, HTTP proxying, connection management, security, and metrics
488
490
  - **TypeScript** provides the npm API, configuration types, route helpers, validation, and socket handler callbacks
489
- - **IPC** — JSON commands/events over stdin/stdout for seamless cross-language communication
490
- - **Socket Relay** — a Unix domain socket server for routes requiring TypeScript-side handling (socket handlers, dynamic host/port functions)
491
+ - **IPC** — The TypeScript wrapper uses [`@push.rocks/smartrust`](https://code.foss.global/push.rocks/smartrust) for type-safe JSON commands/events over stdin/stdout
492
+ - **Socket Relay** — A Unix domain socket server for routes requiring TypeScript-side handling (socket handlers, dynamic host/port functions)
491
493
 
492
494
  ## 🎯 Route Configuration Reference
493
495
 
@@ -699,7 +701,7 @@ interface ISmartProxyOptions {
699
701
 
700
702
  // Timeouts
701
703
  connectionTimeout?: number; // Backend connection timeout (default: 30s)
702
- initialDataTimeout?: number; // Initial data/SNI timeout (default: 60s)
704
+ initialDataTimeout?: number; // Initial data/SNI timeout (default: 120s)
703
705
  socketTimeout?: number; // Socket inactivity timeout (default: 1h)
704
706
  maxConnectionLifetime?: number; // Max connection lifetime (default: 24h)
705
707
  inactivityTimeout?: number; // Inactivity timeout (default: 4h)
@@ -724,12 +726,40 @@ interface ISmartProxyOptions {
724
726
  // Behavior
725
727
  enableDetailedLogging?: boolean; // Verbose connection logging
726
728
  enableTlsDebugLogging?: boolean; // TLS handshake debug logging
727
-
728
- // Rust binary
729
- rustBinaryPath?: string; // Custom path to the Rust binary
730
729
  }
731
730
  ```
732
731
 
732
+ ### IMetrics Interface
733
+
734
+ The `getMetrics()` method returns a cached metrics adapter that polls the Rust engine:
735
+
736
+ ```typescript
737
+ const metrics = proxy.getMetrics();
738
+
739
+ // Connection metrics
740
+ metrics.connections.active(); // Current active connections
741
+ metrics.connections.total(); // Total connections since start
742
+ metrics.connections.byRoute(); // Map<routeName, activeCount>
743
+ metrics.connections.byIP(); // Map<ip, activeCount>
744
+ metrics.connections.topIPs(10); // Top N IPs by connection count
745
+
746
+ // Throughput (bytes/sec)
747
+ metrics.throughput.instant(); // { in: number, out: number }
748
+ metrics.throughput.recent(); // Recent average
749
+ metrics.throughput.average(); // Overall average
750
+ metrics.throughput.byRoute(); // Map<routeName, { in, out }>
751
+
752
+ // Request rates
753
+ metrics.requests.perSecond(); // Requests per second
754
+ metrics.requests.perMinute(); // Requests per minute
755
+ metrics.requests.total(); // Total requests
756
+
757
+ // Cumulative totals
758
+ metrics.totals.bytesIn(); // Total bytes received
759
+ metrics.totals.bytesOut(); // Total bytes sent
760
+ metrics.totals.connections(); // Total connections
761
+ ```
762
+
733
763
  ## 🐛 Troubleshooting
734
764
 
735
765
  ### Certificate Issues
@@ -746,13 +776,13 @@ interface ISmartProxyOptions {
746
776
  - ✅ Enable debug logging with `enableDetailedLogging: true`
747
777
 
748
778
  ### Rust Binary Not Found
779
+
749
780
  SmartProxy searches for the Rust binary in this order:
750
781
  1. `SMARTPROXY_RUST_BINARY` environment variable
751
782
  2. Platform-specific npm package (`@push.rocks/smartproxy-linux-x64`, etc.)
752
- 3. Local dev build (`./rust/target/release/rustproxy`)
753
- 4. System PATH (`rustproxy`)
754
-
755
- Set `rustBinaryPath` in options to override.
783
+ 3. `dist_rust/rustproxy` relative to the package root (built by `tsrust`)
784
+ 4. Local dev build (`./rust/target/release/rustproxy`)
785
+ 5. System PATH (`rustproxy`)
756
786
 
757
787
  ### Performance Tuning
758
788
  - ✅ Use NFTables forwarding for high-traffic routes (Linux only)
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartproxy',
6
- version: '23.0.0',
6
+ version: '23.1.0',
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
  }
package/ts/plugins.ts CHANGED
@@ -31,6 +31,7 @@ import * as smartlog from '@push.rocks/smartlog';
31
31
  import * as smartlogDestinationLocal from '@push.rocks/smartlog/destination-local';
32
32
  import * as taskbuffer from '@push.rocks/taskbuffer';
33
33
  import * as smartrx from '@push.rocks/smartrx';
34
+ import * as smartrust from '@push.rocks/smartrust';
34
35
 
35
36
  export {
36
37
  lik,
@@ -47,6 +48,7 @@ export {
47
48
  smartlogDestinationLocal,
48
49
  taskbuffer,
49
50
  smartrx,
51
+ smartrust,
50
52
  };
51
53
 
52
54
  // third party scope
@@ -1,310 +1,179 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import { logger } from '../../core/utils/logger.js';
3
- import { RustBinaryLocator } from './rust-binary-locator.js';
4
3
  import type { IRouteConfig } from './models/route-types.js';
5
- import { ChildProcess, spawn } from 'child_process';
6
- import { createInterface, Interface as ReadlineInterface } from 'readline';
7
4
 
8
5
  /**
9
- * Management request sent to the Rust binary via stdin.
6
+ * Type-safe command definitions for the Rust proxy IPC protocol.
10
7
  */
11
- interface IManagementRequest {
12
- id: string;
13
- method: string;
14
- params: Record<string, any>;
8
+ type TSmartProxyCommands = {
9
+ start: { params: { config: any }; result: void };
10
+ stop: { params: Record<string, never>; result: void };
11
+ updateRoutes: { params: { routes: IRouteConfig[] }; result: void };
12
+ getMetrics: { params: Record<string, never>; result: any };
13
+ getStatistics: { params: Record<string, never>; result: any };
14
+ provisionCertificate: { params: { routeName: string }; result: void };
15
+ renewCertificate: { params: { routeName: string }; result: void };
16
+ getCertificateStatus: { params: { routeName: string }; result: any };
17
+ getListeningPorts: { params: Record<string, never>; result: { ports: number[] } };
18
+ getNftablesStatus: { params: Record<string, never>; result: any };
19
+ setSocketHandlerRelay: { params: { socketPath: string }; result: void };
20
+ addListeningPort: { params: { port: number }; result: void };
21
+ removeListeningPort: { params: { port: number }; result: void };
22
+ loadCertificate: { params: { domain: string; cert: string; key: string; ca?: string }; result: void };
23
+ };
24
+
25
+ /**
26
+ * Get the package root directory using import.meta.url.
27
+ * This file is at ts/proxies/smart-proxy/, so package root is 3 levels up.
28
+ */
29
+ function getPackageRoot(): string {
30
+ const thisDir = plugins.path.dirname(plugins.url.fileURLToPath(import.meta.url));
31
+ return plugins.path.resolve(thisDir, '..', '..', '..');
15
32
  }
16
33
 
17
34
  /**
18
- * Management response received from the Rust binary via stdout.
35
+ * Map Node.js process.platform/process.arch to tsrust's friendly name suffix.
36
+ * tsrust names cross-compiled binaries as: rustproxy_linux_amd64, rustproxy_linux_arm64, etc.
19
37
  */
20
- interface IManagementResponse {
21
- id: string;
22
- success: boolean;
23
- result?: any;
24
- error?: string;
38
+ function getTsrustPlatformSuffix(): string | null {
39
+ const archMap: Record<string, string> = { x64: 'amd64', arm64: 'arm64' };
40
+ const osMap: Record<string, string> = { linux: 'linux', darwin: 'macos' };
41
+ const os = osMap[process.platform];
42
+ const arch = archMap[process.arch];
43
+ if (os && arch) {
44
+ return `${os}_${arch}`;
45
+ }
46
+ return null;
25
47
  }
26
48
 
27
49
  /**
28
- * Management event received from the Rust binary (unsolicited).
50
+ * Build local search paths for the Rust binary, including dist_rust/ candidates
51
+ * (built by tsrust) and local development build paths.
29
52
  */
30
- interface IManagementEvent {
31
- event: string;
32
- data: any;
53
+ function buildLocalPaths(): string[] {
54
+ const packageRoot = getPackageRoot();
55
+ const suffix = getTsrustPlatformSuffix();
56
+ const paths: string[] = [];
57
+
58
+ // dist_rust/ candidates (tsrust cross-compiled output)
59
+ if (suffix) {
60
+ paths.push(plugins.path.join(packageRoot, 'dist_rust', `rustproxy_${suffix}`));
61
+ }
62
+ paths.push(plugins.path.join(packageRoot, 'dist_rust', 'rustproxy'));
63
+
64
+ // Local dev build paths
65
+ paths.push(plugins.path.resolve(process.cwd(), 'rust', 'target', 'release', 'rustproxy'));
66
+ paths.push(plugins.path.resolve(process.cwd(), 'rust', 'target', 'debug', 'rustproxy'));
67
+
68
+ return paths;
33
69
  }
34
70
 
35
71
  /**
36
72
  * Bridge between TypeScript SmartProxy and the Rust binary.
37
- * Communicates via JSON-over-stdin/stdout IPC protocol.
73
+ * Wraps @push.rocks/smartrust's RustBridge with type-safe command definitions.
38
74
  */
39
75
  export class RustProxyBridge extends plugins.EventEmitter {
40
- private locator = new RustBinaryLocator();
41
- private process: ChildProcess | null = null;
42
- private readline: ReadlineInterface | null = null;
43
- private pendingRequests = new Map<string, {
44
- resolve: (value: any) => void;
45
- reject: (error: Error) => void;
46
- timer: NodeJS.Timeout;
47
- }>();
48
- private requestCounter = 0;
49
- private isRunning = false;
50
- private binaryPath: string | null = null;
51
- private readonly requestTimeoutMs = 30000;
76
+ private bridge: plugins.smartrust.RustBridge<TSmartProxyCommands>;
77
+
78
+ constructor() {
79
+ super();
80
+
81
+ this.bridge = new plugins.smartrust.RustBridge<TSmartProxyCommands>({
82
+ binaryName: 'rustproxy',
83
+ envVarName: 'SMARTPROXY_RUST_BINARY',
84
+ platformPackagePrefix: '@push.rocks/smartproxy',
85
+ localPaths: buildLocalPaths(),
86
+ logger: {
87
+ log: (level: string, message: string, data?: Record<string, any>) => {
88
+ logger.log(level as any, message, data);
89
+ },
90
+ },
91
+ });
92
+
93
+ // Forward events from the inner bridge
94
+ this.bridge.on('exit', (code: number | null, signal: string | null) => {
95
+ this.emit('exit', code, signal);
96
+ });
97
+ }
52
98
 
53
99
  /**
54
100
  * Spawn the Rust binary in management mode.
55
101
  * Returns true if the binary was found and spawned successfully.
56
102
  */
57
103
  public async spawn(): Promise<boolean> {
58
- this.binaryPath = await this.locator.findBinary();
59
- if (!this.binaryPath) {
60
- return false;
61
- }
62
-
63
- return new Promise<boolean>((resolve) => {
64
- try {
65
- this.process = spawn(this.binaryPath!, ['--management'], {
66
- stdio: ['pipe', 'pipe', 'pipe'],
67
- env: { ...process.env },
68
- });
69
-
70
- // Handle stderr (logging from Rust goes here)
71
- const stderrHandler = (data: Buffer) => {
72
- const lines = data.toString().split('\n').filter(l => l.trim());
73
- for (const line of lines) {
74
- logger.log('debug', `[rustproxy] ${line}`, { component: 'rust-bridge' });
75
- }
76
- };
77
- this.process.stderr?.on('data', stderrHandler);
78
-
79
- // Handle stdout (JSON IPC)
80
- this.readline = createInterface({ input: this.process.stdout! });
81
- this.readline.on('line', (line: string) => {
82
- this.handleLine(line.trim());
83
- });
84
-
85
- // Handle process exit
86
- this.process.on('exit', (code, signal) => {
87
- logger.log('info', `RustProxy process exited (code=${code}, signal=${signal})`, { component: 'rust-bridge' });
88
- this.cleanup();
89
- this.emit('exit', code, signal);
90
- });
91
-
92
- this.process.on('error', (err) => {
93
- logger.log('error', `RustProxy process error: ${err.message}`, { component: 'rust-bridge' });
94
- this.cleanup();
95
- resolve(false);
96
- });
97
-
98
- // Wait for the 'ready' event from Rust
99
- const readyTimeout = setTimeout(() => {
100
- logger.log('error', 'RustProxy did not send ready event within 10s', { component: 'rust-bridge' });
101
- this.kill();
102
- resolve(false);
103
- }, 10000);
104
-
105
- this.once('management:ready', () => {
106
- clearTimeout(readyTimeout);
107
- this.isRunning = true;
108
- logger.log('info', 'RustProxy bridge connected', { component: 'rust-bridge' });
109
- resolve(true);
110
- });
111
- } catch (err: any) {
112
- logger.log('error', `Failed to spawn RustProxy: ${err.message}`, { component: 'rust-bridge' });
113
- resolve(false);
114
- }
115
- });
104
+ return this.bridge.spawn();
116
105
  }
117
106
 
118
107
  /**
119
- * Send a management command to the Rust process and wait for the response.
108
+ * Kill the Rust process and clean up.
120
109
  */
121
- public async sendCommand(method: string, params: Record<string, any> = {}): Promise<any> {
122
- if (!this.process || !this.isRunning) {
123
- throw new Error('RustProxy bridge is not running');
124
- }
125
-
126
- const id = `req_${++this.requestCounter}`;
127
- const request: IManagementRequest = { id, method, params };
128
-
129
- return new Promise<any>((resolve, reject) => {
130
- const timer = setTimeout(() => {
131
- this.pendingRequests.delete(id);
132
- reject(new Error(`RustProxy command '${method}' timed out after ${this.requestTimeoutMs}ms`));
133
- }, this.requestTimeoutMs);
134
-
135
- this.pendingRequests.set(id, { resolve, reject, timer });
110
+ public kill(): void {
111
+ this.bridge.kill();
112
+ }
136
113
 
137
- const json = JSON.stringify(request) + '\n';
138
- this.process!.stdin!.write(json, (err) => {
139
- if (err) {
140
- clearTimeout(timer);
141
- this.pendingRequests.delete(id);
142
- reject(new Error(`Failed to write to RustProxy stdin: ${err.message}`));
143
- }
144
- });
145
- });
114
+ /**
115
+ * Whether the bridge is currently running.
116
+ */
117
+ public get running(): boolean {
118
+ return this.bridge.running;
146
119
  }
147
120
 
148
- // Convenience methods for each management command
121
+ // --- Convenience methods for each management command ---
149
122
 
150
123
  public async startProxy(config: any): Promise<void> {
151
- await this.sendCommand('start', { config });
124
+ await this.bridge.sendCommand('start', { config });
152
125
  }
153
126
 
154
127
  public async stopProxy(): Promise<void> {
155
- await this.sendCommand('stop');
128
+ await this.bridge.sendCommand('stop', {} as Record<string, never>);
156
129
  }
157
130
 
158
131
  public async updateRoutes(routes: IRouteConfig[]): Promise<void> {
159
- await this.sendCommand('updateRoutes', { routes });
132
+ await this.bridge.sendCommand('updateRoutes', { routes });
160
133
  }
161
134
 
162
135
  public async getMetrics(): Promise<any> {
163
- return this.sendCommand('getMetrics');
136
+ return this.bridge.sendCommand('getMetrics', {} as Record<string, never>);
164
137
  }
165
138
 
166
139
  public async getStatistics(): Promise<any> {
167
- return this.sendCommand('getStatistics');
140
+ return this.bridge.sendCommand('getStatistics', {} as Record<string, never>);
168
141
  }
169
142
 
170
143
  public async provisionCertificate(routeName: string): Promise<void> {
171
- await this.sendCommand('provisionCertificate', { routeName });
144
+ await this.bridge.sendCommand('provisionCertificate', { routeName });
172
145
  }
173
146
 
174
147
  public async renewCertificate(routeName: string): Promise<void> {
175
- await this.sendCommand('renewCertificate', { routeName });
148
+ await this.bridge.sendCommand('renewCertificate', { routeName });
176
149
  }
177
150
 
178
151
  public async getCertificateStatus(routeName: string): Promise<any> {
179
- return this.sendCommand('getCertificateStatus', { routeName });
152
+ return this.bridge.sendCommand('getCertificateStatus', { routeName });
180
153
  }
181
154
 
182
155
  public async getListeningPorts(): Promise<number[]> {
183
- const result = await this.sendCommand('getListeningPorts');
156
+ const result = await this.bridge.sendCommand('getListeningPorts', {} as Record<string, never>);
184
157
  return result?.ports ?? [];
185
158
  }
186
159
 
187
160
  public async getNftablesStatus(): Promise<any> {
188
- return this.sendCommand('getNftablesStatus');
161
+ return this.bridge.sendCommand('getNftablesStatus', {} as Record<string, never>);
189
162
  }
190
163
 
191
164
  public async setSocketHandlerRelay(socketPath: string): Promise<void> {
192
- await this.sendCommand('setSocketHandlerRelay', { socketPath });
165
+ await this.bridge.sendCommand('setSocketHandlerRelay', { socketPath });
193
166
  }
194
167
 
195
168
  public async addListeningPort(port: number): Promise<void> {
196
- await this.sendCommand('addListeningPort', { port });
169
+ await this.bridge.sendCommand('addListeningPort', { port });
197
170
  }
198
171
 
199
172
  public async removeListeningPort(port: number): Promise<void> {
200
- await this.sendCommand('removeListeningPort', { port });
173
+ await this.bridge.sendCommand('removeListeningPort', { port });
201
174
  }
202
175
 
203
176
  public async loadCertificate(domain: string, cert: string, key: string, ca?: string): Promise<void> {
204
- await this.sendCommand('loadCertificate', { domain, cert, key, ca });
205
- }
206
-
207
- /**
208
- * Kill the Rust process and clean up all stdio streams.
209
- */
210
- public kill(): void {
211
- if (this.process) {
212
- const proc = this.process;
213
- this.process = null;
214
- this.isRunning = false;
215
-
216
- // Close readline (reads from stdout)
217
- if (this.readline) {
218
- this.readline.close();
219
- this.readline = null;
220
- }
221
-
222
- // Reject pending requests
223
- for (const [, pending] of this.pendingRequests) {
224
- clearTimeout(pending.timer);
225
- pending.reject(new Error('RustProxy process killed'));
226
- }
227
- this.pendingRequests.clear();
228
-
229
- // Remove all listeners so nothing keeps references
230
- proc.removeAllListeners();
231
- proc.stdout?.removeAllListeners();
232
- proc.stderr?.removeAllListeners();
233
- proc.stdin?.removeAllListeners();
234
-
235
- // Kill the process
236
- try { proc.kill('SIGTERM'); } catch { /* already dead */ }
237
-
238
- // Destroy all stdio pipes to free handles
239
- try { proc.stdin?.destroy(); } catch { /* ignore */ }
240
- try { proc.stdout?.destroy(); } catch { /* ignore */ }
241
- try { proc.stderr?.destroy(); } catch { /* ignore */ }
242
-
243
- // Unref process so Node doesn't wait for it
244
- try { proc.unref(); } catch { /* ignore */ }
245
-
246
- // Force kill after 5 seconds
247
- setTimeout(() => {
248
- try { proc.kill('SIGKILL'); } catch { /* already dead */ }
249
- }, 5000).unref();
250
- }
251
- }
252
-
253
- /**
254
- * Whether the bridge is currently running.
255
- */
256
- public get running(): boolean {
257
- return this.isRunning;
258
- }
259
-
260
- private handleLine(line: string): void {
261
- if (!line) return;
262
-
263
- let parsed: any;
264
- try {
265
- parsed = JSON.parse(line);
266
- } catch {
267
- logger.log('warn', `Non-JSON output from RustProxy: ${line}`, { component: 'rust-bridge' });
268
- return;
269
- }
270
-
271
- // Check if it's an event (has 'event' field)
272
- if ('event' in parsed) {
273
- const event = parsed as IManagementEvent;
274
- this.emit(`management:${event.event}`, event.data);
275
- return;
276
- }
277
-
278
- // Otherwise it's a response (has 'id' field)
279
- if ('id' in parsed) {
280
- const response = parsed as IManagementResponse;
281
- const pending = this.pendingRequests.get(response.id);
282
- if (pending) {
283
- clearTimeout(pending.timer);
284
- this.pendingRequests.delete(response.id);
285
- if (response.success) {
286
- pending.resolve(response.result);
287
- } else {
288
- pending.reject(new Error(response.error || 'Unknown error from RustProxy'));
289
- }
290
- }
291
- }
292
- }
293
-
294
- private cleanup(): void {
295
- this.isRunning = false;
296
- this.process = null;
297
-
298
- if (this.readline) {
299
- this.readline.close();
300
- this.readline = null;
301
- }
302
-
303
- // Reject all pending requests
304
- for (const [id, pending] of this.pendingRequests) {
305
- clearTimeout(pending.timer);
306
- pending.reject(new Error('RustProxy process exited'));
307
- }
308
- this.pendingRequests.clear();
177
+ await this.bridge.sendCommand('loadCertificate', { domain, cert, key, ca });
309
178
  }
310
179
  }
@@ -3,7 +3,6 @@ import { logger } from '../../core/utils/logger.js';
3
3
 
4
4
  // Rust bridge and helpers
5
5
  import { RustProxyBridge } from './rust-proxy-bridge.js';
6
- import { RustBinaryLocator } from './rust-binary-locator.js';
7
6
  import { RoutePreprocessor } from './route-preprocessor.js';
8
7
  import { SocketHandlerServer } from './socket-handler-server.js';
9
8
  import { RustMetricsAdapter } from './rust-metrics-adapter.js';
@@ -120,7 +119,7 @@ export class SmartProxy extends plugins.EventEmitter {
120
119
  if (!spawned) {
121
120
  throw new Error(
122
121
  'RustProxy binary not found. Set SMARTPROXY_RUST_BINARY env var, install the platform package, ' +
123
- 'or build locally with: cd rust && cargo build --release'
122
+ 'or build locally with: pnpm build'
124
123
  );
125
124
  }
126
125
 
@@ -1,14 +0,0 @@
1
- import type { ICertificateData, ICertificateFailure, ICertificateExpiring } from './types.js';
2
- /**
3
- * Subscribers callback definitions for Port80Handler events
4
- */
5
- export interface Port80HandlerSubscribers {
6
- onCertificateIssued?: (data: ICertificateData) => void;
7
- onCertificateRenewed?: (data: ICertificateData) => void;
8
- onCertificateFailed?: (data: ICertificateFailure) => void;
9
- onCertificateExpiring?: (data: ICertificateExpiring) => void;
10
- }
11
- /**
12
- * Subscribes to Port80Handler events based on provided callbacks
13
- */
14
- export declare function subscribeToPort80Handler(handler: any, subscribers: Port80HandlerSubscribers): void;
@@ -1,20 +0,0 @@
1
- // Port80Handler removed - use SmartCertManager instead
2
- import { Port80HandlerEvents } from './types.js';
3
- /**
4
- * Subscribes to Port80Handler events based on provided callbacks
5
- */
6
- export function subscribeToPort80Handler(handler, subscribers) {
7
- if (subscribers.onCertificateIssued) {
8
- handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, subscribers.onCertificateIssued);
9
- }
10
- if (subscribers.onCertificateRenewed) {
11
- handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, subscribers.onCertificateRenewed);
12
- }
13
- if (subscribers.onCertificateFailed) {
14
- handler.on(Port80HandlerEvents.CERTIFICATE_FAILED, subscribers.onCertificateFailed);
15
- }
16
- if (subscribers.onCertificateExpiring) {
17
- handler.on(Port80HandlerEvents.CERTIFICATE_EXPIRING, subscribers.onCertificateExpiring);
18
- }
19
- }
20
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRVdGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2NvbW1vbi9ldmVudFV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHVEQUF1RDtBQUN2RCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFhakQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsd0JBQXdCLENBQ3RDLE9BQVksRUFDWixXQUFxQztJQUVyQyxJQUFJLFdBQVcsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQ3BDLE9BQU8sQ0FBQyxFQUFFLENBQUMsbUJBQW1CLENBQUMsa0JBQWtCLEVBQUUsV0FBVyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDdEYsQ0FBQztJQUNELElBQUksV0FBVyxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFDckMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxtQkFBbUIsRUFBRSxXQUFXLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUN4RixDQUFDO0lBQ0QsSUFBSSxXQUFXLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUNwQyxPQUFPLENBQUMsRUFBRSxDQUFDLG1CQUFtQixDQUFDLGtCQUFrQixFQUFFLFdBQVcsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBQ3RGLENBQUM7SUFDRCxJQUFJLFdBQVcsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQ3RDLE9BQU8sQ0FBQyxFQUFFLENBQUMsbUJBQW1CLENBQUMsb0JBQW9CLEVBQUUsV0FBVyxDQUFDLHFCQUFxQixDQUFDLENBQUM7SUFDMUYsQ0FBQztBQUNILENBQUMifQ==