@push.rocks/smartproxy 30.1.0 → 31.0.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 (33) hide show
  1. package/.smartconfig.json +5 -3
  2. package/changelog.md +73 -0
  3. package/dist_rust/rustproxy_linux_amd64_musl +0 -0
  4. package/dist_rust/rustproxy_linux_amd64_musl.tsrust-build.json +5 -5
  5. package/dist_rust/rustproxy_linux_arm64_musl +0 -0
  6. package/dist_rust/rustproxy_linux_arm64_musl.tsrust-build.json +5 -5
  7. package/dist_ts/00_commitinfo_data.js +1 -1
  8. package/dist_ts/index.d.ts +1 -1
  9. package/dist_ts/proxies/index.d.ts +1 -1
  10. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +6 -1
  11. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +27 -0
  12. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  13. package/dist_ts/proxies/smart-proxy/models/rust-types.d.ts +14 -0
  14. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +7 -2
  15. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +8 -3
  16. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +18 -1
  17. package/dist_ts/proxies/smart-proxy/smart-proxy.js +100 -36
  18. package/dist_ts/proxies/smart-proxy/utils/route-validator.d.ts +44 -2
  19. package/dist_ts/proxies/smart-proxy/utils/route-validator.js +281 -2
  20. package/dist_ts/proxies/smart-proxy/utils/rust-config.d.ts +2 -2
  21. package/dist_ts/proxies/smart-proxy/utils/rust-config.js +8 -5
  22. package/package.json +9 -11
  23. package/readme.md +67 -10
  24. package/ts/00_commitinfo_data.ts +1 -1
  25. package/ts/index.ts +1 -1
  26. package/ts/proxies/index.ts +1 -1
  27. package/ts/proxies/smart-proxy/models/interfaces.ts +7 -1
  28. package/ts/proxies/smart-proxy/models/route-types.ts +28 -1
  29. package/ts/proxies/smart-proxy/models/rust-types.ts +17 -1
  30. package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +13 -3
  31. package/ts/proxies/smart-proxy/smart-proxy.ts +109 -38
  32. package/ts/proxies/smart-proxy/utils/route-validator.ts +315 -3
  33. package/ts/proxies/smart-proxy/utils/rust-config.ts +9 -5
package/.smartconfig.json CHANGED
@@ -51,13 +51,15 @@
51
51
  },
52
52
  "schemaVersion": 2
53
53
  },
54
- "@git.zone/tsdoc": {
55
- "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
54
+ "@git.zone/tsrepo": {
55
+ "docs": {
56
+ "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
57
+ }
56
58
  },
57
59
  "@ship.zone/szci": {
58
60
  "npmGlobalTools": []
59
61
  },
60
- "@git.zone/tsrust": {
62
+ "@git.zone/rsrepo": {
61
63
  "targets": [
62
64
  "linux_amd64_musl",
63
65
  "linux_arm64_musl"
package/changelog.md CHANGED
@@ -1,5 +1,78 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-10-20 - 31.0.0
4
+
5
+ ### Breaking Changes
6
+
7
+ - Refuse routes that set `security.authentication` (smart-proxy, rust)
8
+ - Nothing in the proxy read `security.authentication`: validation accepted a route that set it, and the route was served without any authentication. `RouteValidator` and the engine now refuse such a route with "security.authentication is not supported; use security.basicAuth or security.jwtAuth", and the field is marked deprecated in `IRouteSecurity`. A configuration that set it fails at `start()` or `updateRoutes()` until it moves to `basicAuth` or `jwtAuth`, which are enforced.
9
+ - Never forward a route with HTTP controls as a raw TCP stream (rust)
10
+ - A port-only forward or socket-handler route without TLS was forwarded raw when the client sent nothing within 10 ms of connecting, a shortcut meant for server-speaks-first protocols. A client that waited before sending its request bypassed the route's basic auth, JWT auth, rate limit, challenge, WebSocket origin allow list, header and URL rewriting, and `match.protocol: 'http'`; a client that sent non-HTTP bytes reached the backend of such a forward route at once, and so did non-HTTP data after TLS termination.
11
+ - A route that uses any HTTP feature (those controls, `headers`, `advanced.headers`/`urlRewrite`/`staticFiles`, `websocket.customHeaders`/`rewritePath`, target headers or `match.path`/`headers`/`method` on a target, or `protocol: 'http'`) no longer takes the shortcut. Such a forward route, unless it is TLS passthrough, always waits for the request and goes through the HTTP proxy, and a connection that sends it anything other than HTTP, before or after TLS termination, is closed. A socket-handler route with `protocol: 'http'` now receives only HTTP connections. Routes without HTTP features keep the shortcut, so server-speaks-first protocols are unchanged.
12
+ - Enforce route `maxConnections` on raw connections, and refuse HTTP-only access controls on routes that forward raw (smart-proxy, rust)
13
+ - `security.maxConnections` was counted only by the HTTP layer. A raw TCP forward, a TLS passthrough or socket-handler route, non-HTTP traffic on a TLS-terminating route, a QUIC route without HTTP/3 and a UDP route accepted any number of connections. One limiter now serves every listener: HTTP traffic still holds a slot per in-flight request or upgraded tunnel, while a raw TCP connection, a raw QUIC connection and a UDP session hold one for their lifetime. A connection above the limit is closed without being forwarded, and a datagram that would open a UDP session above it is dropped. Datagrams to a UDP `datagramHandler` route open no session and are not counted.
14
+ - Counters are keyed by the route's id, else its name, else its content. Before, all routes without a name or id shared one counter, and routes with different ids but the same name shared theirs.
15
+ - Basic auth, JWT auth, rate limits, challenges and the WebSocket origin allow list run only in the HTTP layer, so a route whose traffic never reaches it served them unprotected. `RouteValidator` and the engine now refuse a route that enables one of them when the route is a socket-handler route, uses TLS passthrough, matches `protocol: 'tcp'`, or listens on UDP (`transport: 'udp'` or `'all'`) without `action.udp.quic.enableHttp3`. The error names the control, the reason and what to configure instead, for example "security.basicAuth is enforced only on HTTP traffic, but TLS passthrough forwards the encrypted stream unread; use tls.mode "terminate" or "terminate-and-reencrypt"". A configuration that set one of these fails at `start()` and `updateRoutes()`; move the control to an HTTP route or terminate TLS.
16
+ - Refuse dynamic-target routes that lose forwarding settings, and pass the Host of a plaintext connection to the relay (smart-proxy, rust)
17
+ - A target whose `host` or `port` is a function is served by the TypeScript relay, which resolves one target per connection, connects to it over plain TCP and forwards the whole connection. Validation accepted such a route together with more than one target or a target `match`, `sendProxyProtocol`, TLS `terminate-and-reencrypt`, `backendTransport: 'udp'`, `match.path`, `match.headers` or a UDP transport, and the relay ignored the setting: it picked a random target, sent no PROXY header and connected without TLS. Basic auth, JWT auth, rate limits, challenges and the WebSocket origin allow list on such a route were never enforced. `RouteValidator` now refuses these combinations, for example "action.sendProxyProtocol is not supported with a dynamic target (a function host or port): the relay sends no PROXY protocol header; use static targets" and "security.basicAuth is enforced only on HTTP traffic, but a dynamic target (a function host or port) is served by a relay that forwards the raw connection; use static targets". A configuration that used one of them fails in `new SmartProxy()` and `updateRoutes()`; such a route needs static targets.
18
+ - The engine routed a plaintext connection by its `Host` header but relayed it with no domain, so a dynamic target function or socket handler saw no `context.domain`. It now passes the `Host` header when there is no SNI. The readme's dynamic routing example chose the backend by `context.path`, which the relay never provides; it now chooses by `context.domain`, and the readme lists what dynamic targets support.
19
+ - Install nftables rules only for enabled routes, remove them when applying fails, and refuse nftables routes the kernel rules cannot honour (smart-proxy)
20
+ - A route with `forwardingEngine: 'nftables'` got its kernel DNAT rules even with `enabled: false`. It no longer does.
21
+ - When one rule failed to apply, the rules applied before it stayed in the kernel with no handle to remove them, so not even `stop()` removed them. A failed apply now removes its table and rethrows, so `start()` fails clean. `updateRoutes()` now replaces the kernel rules before it hands the routes to the engine: when a rule or the engine refuses the update, the previous rules are applied again and the running routes stay as they were. Before, a failed rule had already given the engine the new routes and left the proxy without the previous rules.
22
+ - The kernel rules forward every packet on the listed ports to one IPv4 address before the proxy sees it, yet validation accepted nftables routes with access controls, domain, path or client matching, TLS termination, header rewrites and several targets: they were served unprotected, unmatched, or to the first target. Port ranges and function hosts got no rule, and a host list forwarded to its first host. `RouteValidator` now refuses these, for example "match.domains is not supported with forwardingEngine "nftables": the kernel rules match packets by port only; use the default forwarding engine". A configuration that used one fails in `new SmartProxy()` and `updateRoutes()`. The readme's nftables example, which terminated TLS for a domain, now forwards a port to an IPv4 address.
23
+ - Verify the certificates of TLS backends (smart-proxy, rust)
24
+ - Every connection the engine opened to a backend over TLS accepted any certificate: `terminate-and-reencrypt` over HTTP and the raw TLS tunnel, targets with `tls`, WebSocket upgrades, and HTTP/3 backends reached over QUIC, including those found through `Alt-Svc`. Anyone on the path to a backend could read and change the traffic. The engine now verifies the backend certificate and the name it sends as SNI, by default against the system root store.
25
+ - New `tls.backend` settings on a route (`action.tls.backend`) or a target (`targets[].tls.backend`), and a proxy-wide `backendTls` default: `ca` replaces the system roots with the given PEM certificates, as Node's `ca` does; `rejectUnauthorized: false` accepts any certificate; `serverName` sets the SNI and the name checked. A target's settings replace the route's, which replace the default; the whole object applies. Pooled backend connections are kept apart per trust policy.
26
+ - The name sent and checked is `serverName`, else the requested domain on routes that match named domains, else the target host. Two names change: the raw TLS tunnel of a route with named domains sends the client's SNI instead of the target host, and HTTP requests on a route without domains or with `*` send the target host instead of the requested `Host`, which such a route does not restrict.
27
+ - Behaviour change: a backend with a self-signed or private-CA certificate is now refused (`502`, or a closed tunnel) until its route sets `ca` or `rejectUnauthorized: false`. A self-signed CA certificate (`CA:TRUE`) serving as the backend's own certificate cannot be trusted through `ca`; give the backend an end-entity certificate or set `rejectUnauthorized: false`. On a system without root certificates, `start()` and `updateRoutes()` refuse the routes that rely on them.
28
+ - `RouteValidator` and the engine refuse `ca` together with `rejectUnauthorized: false`, an empty `ca` or `serverName`, `tls.backend` on TLS passthrough routes, and `backendTls.serverName`; the engine also refuses a `ca` without certificates, and `RouteValidator` refuses `tls.backend` on dynamic-target routes, whose relay connects without TLS.
29
+ - Re-encrypt the backend leg of raw QUIC routes in `terminate-and-reencrypt` mode (rust)
30
+ - A QUIC route without HTTP/3 forwards each QUIC stream to its target over a TCP connection of its own. In `terminate-and-reencrypt` mode that connection was plain TCP: traffic the client sent encrypted crossed the path to the backend in clear text, and a backend that speaks TLS refused it. Each stream's backend connection now uses TLS, verified like the raw TLS tunnel on TCP: by the target's or route's `tls.backend`, else the proxy-wide `backendTls`, else the system roots, and named by the client's SNI on routes that name their domains.
31
+ - The backend connect and TLS handshake of a raw QUIC stream now count against the stream's 60-second inactivity timeout, and a route update or proxy stop ends them; before, the connect ran until the operating system gave up.
32
+ - Behaviour change: a raw QUIC `terminate-and-reencrypt` route whose backend speaks plain TCP no longer reaches it; such a route needs `tls.mode: 'terminate'`.
33
+
34
+ ### Fixes
35
+
36
+ - Route a TLS connection by its SNI, and an HTTP connection by its Host header, when the first bytes arrive in more than one read (rust)
37
+ - The TCP listener routed on the bytes of its first read. When a ClientHello arrived in several TCP segments, as a post-quantum ClientHello larger than one segment does, the listener peeked again, got the same queued bytes back at once, and the SNI parser reported "no SNI" for a hello that had simply not fully arrived. The connection then matched no domain route and was answered with TLS alert 112 `unrecognized_name`, or closed. Browsers whose randomized extension order put the SNI in a later segment failed intermittently with `ERR_SSL_UNRECOGNIZED_NAME_ALERT`. A plain HTTP request whose Host header arrived after the first read failed the same way with `502 No route matched`, and a Host header cut mid-value was read as a shorter host name.
38
+ - The listener now keeps peeking until routing can decide, within the existing pre-routing deadline (the initial-data timeout, at most 30 s; arriving bytes do not extend it): a TLS connection until every record carrying the ClientHello is in, also when the hello spans several TLS records; an HTTP request until its Host header line or its head is complete, or 16 KiB of it have arrived. The PROXY header wait uses the same read. The bytes stay unread on the socket, so passthrough, TLS termination and the HTTP proxy receive them unchanged. A connection whose first bytes are not yet enough to tell TLS or HTTP apart (a lone `0x16` byte, or `G`, `PO` and the like) also waits for more; any other first bytes are routed as they are.
39
+ - A connection that does not complete its ClientHello or request head by the deadline is closed without an answer, as one that sends nothing already was. A handshake record longer than TLS allows (2^14 bytes), a ClientHello that cannot fit one record of that size with its header, and a complete ClientHello whose structure overruns its own lengths close the connection at once.
40
+ - Keep metrics sampling, certificate renewal and routes shared with TCP alive when UDP listeners stop (rust)
41
+ - `updateRoutes()` that removed the last UDP route stopped the UDP listener manager, which cancelled the proxy-wide token it had been handed: metrics sampling and certificate renewal ended for the rest of the proxy's life, and UDP routes added later started under a token that was already cancelled. The UDP listener manager now runs on a child of that token.
42
+ - The per-route cancellation token that a route's TCP and QUIC connections share was created as a child of the QUIC listener when a QUIC connection came first. Closing that listener, as removing its port or rebinding it does, then also cut the route's TCP connections. Route tokens now descend from one proxy-wide parent.
43
+ - Apply the configured route defaults to routes replaced by `updateRoutes()` (rust)
44
+ - The engine applied `defaults.security` and `defaults.target` only to the routes it was started with. Routes installed by `updateRoutes()` went without them: a route that relied on the default IP allow or block list accepted every client after the first update, and its default connection limit no longer applied. A route without targets, which only a direct caller of the engine can send (the TypeScript route validation requires targets), was refused with "forward action has no targets". The engine now applies the defaults to updated routes before validation, as at start.
45
+ - Refuse HTTP/3 request header sections larger than 16 KiB with `431` (rust)
46
+ - The HTTP/3 listener accepted header sections and trailers of any size and decoded them in full, so a client could make the proxy hold arbitrarily large header lists. It now advertises and enforces a `SETTINGS_MAX_FIELD_SECTION_SIZE` of 16 KiB, the limit the HTTP/2 listener already applies: a larger request is answered with `431 Request Header Fields Too Large` and never reaches the backend. A client that sent larger header sections over HTTP/3, such as very large cookies, now gets `431` there as it already did over HTTP/2.
47
+ - Send the replies of a UDP `datagramHandler` route from the port the client sent to (rust)
48
+ - The engine sent each reply from a fresh socket on a random port. A client whose UDP socket was connected to the proxy, as DNS resolvers and most UDP clients do, dropped the reply, and so did NAT and stateful firewalls on the way. Replies now leave through the listener socket the datagram arrived on; a reply for a port that no longer listens is dropped.
49
+ - Answer native ACME HTTP-01 challenges on a port the proxy already listens on (rust)
50
+ - The engine's certificate renewal, and `provisionCertificate()` after start, bound their own challenge server on `acme.port` (default 80). When a route listened on that port, as an HTTP-to-HTTPS redirect does, the bind failed with `EADDRINUSE` and the renewal was skipped every interval, so certificates the engine issued through ACME ran out. Only the provisioning at `start()` worked, because it runs before the listeners bind.
51
+ - The pending challenge tokens now live in one store per proxy. The proxy's listener on `acme.port` answers `GET /.well-known/acme-challenge/<token>` for a pending token before route matching, on the first request of a connection and on later requests of a keep-alive HTTP connection; any other request is routed as before. An order binds its own challenge server only when no listener is bound on that port, and on stop it withdraws only its own tokens. While tokens are pending, connections to that port skip the 10 ms raw-forwarding shortcut, so a validation request sent after it is still answered.
52
+ - Serve the certificates the engine renews through ACME (rust)
53
+ - The engine's renewal task stored a renewed certificate only in its certificate manager. The TCP and QUIC listeners kept serving the old certificate until a later `updateRoutes()` or `loadCertificate()` rebuilt their certificates, or until it expired. The task also held the certificate manager's lock for the whole ACME order, so `updateRoutes()`, `loadCertificate()` and `getCertificateStatus()` waited for the order to finish.
54
+ - The renewal task now orders without that lock, stores the certificate and hands its domain to the management loop, which hot-swaps it into the TCP and QUIC listeners as `loadCertificate()` does. A certificate loaded for the domain while the order runs still wins over the renewed one. A certificate issued through `provisionCertificate()` now replaces one loaded for the same domain earlier; before, the loaded one came back at the next `loadCertificate()`.
55
+ - Order `'http01'` and ACME-fallback certificates through the engine's ACME client when a `certProvisionFunction` is set (smart-proxy, rust)
56
+ - With a `certProvisionFunction`, SmartProxy started the engine with ACME disabled, so a callback that returned `'http01'` and the ACME fallback after a failed callback (on by default) always failed with "No certificate manager configured": the domain kept the self-signed fallback certificate. A failed `'http01'` order raised no `certificate-failed` event and started no failure cooldown, so every sweep tried again, and the fallback ordered for the route's first domain, not the failed one.
57
+ - The engine now keeps its ACME client but orders only on request (`autoProvision: false`): no order at start and no renewal timer, because the provisioning sweeps own renewal. `'http01'` and the fallback order the failed domain, over HTTP-01 on `acme.port`, wait up to `certProvisionTimeout`, and SmartProxy records the issued certificate's validity, so sweeps skip the domain until its renewal window. Both need `acme` with an `email`; without `acme` the domain fails with "Rust ACME cannot order a certificate for <domain>: acme is not configured".
58
+ - A failed `'http01'` order now emits `certificate-failed` and starts the cooldown; it takes no ACME fallback, which would only order again. A successful fallback emits `certificate-issued` with source `acme`. With the fallback on (the default) and `acme` configured, a failing callback now leads to a real Let's Encrypt order; set `certProvisionFallbackToAcme: false` to keep the callback the only source. The engine's `provisionCertificate` command takes an optional `domain` and answers the issued certificate chain. Certificates the engine issues are not passed to `certStore.save()`.
59
+ - Match HTTP/3 requests as HTTP/3 over UDP (rust)
60
+ - The HTTP service matched every request as plain TCP HTTP (no transport, protocol `http`), HTTP/3 requests included. The readme's own HTTP/3 route (`transport: 'udp'`, `protocol: 'quic'`, `enableHttp3`) accepted the QUIC connection and then answered every request with `502 No route matched`, as did a `transport: 'udp'` route without `protocol`, and a `protocol: 'quic'` route with `transport: 'all'`. A TCP-only route on the same port served HTTP/3 requests whose Host named it, on a connection opened for another hostname. A `protocol: 'http3'` route, and a `transport: 'udp'` route with `protocol: 'http'` and `enableHttp3`, refused every QUIC connection.
61
+ - An HTTP/3 request now matches as transport UDP and protocol `http3`, which a route for `http3`, `quic` or `http` accepts; a TCP-only route no longer serves it. Such a request is answered `421 Misdirected Request`, so a client that reused an HTTP/3 connection for another hostname its certificate covers retries on a new connection; a request no route serves is still answered `502 No route matched`. A QUIC connection, matched before its ALPN is known, is accepted under a `quic` or `http3` route or one without `protocol`, and under an `http` route with `enableHttp3` that listens on UDP (`transport: 'udp'` or `'all'`).
62
+ - Serve TLS routes that match by `path` or `headers`, and plain HTTP routes that match by `headers` (rust)
63
+ - The TCP listener chose a connection's route from its first bytes, before TLS termination and before the request headers were read, and held it to every route criterion. A route's `path` or `headers` could not match there. A TLS-terminating route that set either, such as the readme's API gateway route (`domains: 'api.example.com'`, `path: '/api/*'`), refused every connection with TLS alert 112 `unrecognized_name` unless a route without them also matched the domain. A plain HTTP route that matched by `headers` was answered `502 No route matched`, and a TLS-terminating route whose targets all matched by `path` or `headers` closed every connection.
64
+ - When no route matches outright, the listener now admits the connection under a route whose requests the HTTP proxy matches again, that is a route that terminates the connection's TLS or, for plain HTTP, has no TLS, if only the path (of a TLS connection) or the headers are left to match; port, domain, client address and `tlsVersion` stay strict. The HTTP proxy matches each request with its path and headers as before, sends it to the route that matches and applies that route's security; a request no route serves is answered `502 No route matched`. A route that matches outright, such as a passthrough route for the same domain, still takes the connection.
65
+ - A route admitted this way does not apply its IP allow and block lists, VPN and ingress rules to the connection, since its requests may belong to another route: each request gets the security of its own route, and a refused client completes the TLS handshake and is answered `403` instead of having the connection closed. A request to the reserved challenge path now also meets its challenge route's IP allow and block lists and VPN rules in the HTTP proxy, which before checked only its ingress rules there. A route with `match.path` or `match.headers` now counts as an HTTP route, so non-HTTP data on its connections is closed instead of forwarded raw.
66
+ - Bound the QUIC relay in front of listeners that accept PROXY protocol (rust)
67
+ - A UDP listener whose route accepts inbound PROXY protocol (`inboundProxyProtocol` with `mode: 'optional'` or `'required'`) puts a relay in front of its QUIC endpoint. The relay gave every new source address its own socket and task on its first datagram of any kind, kept them until two minutes after its last datagram and set no limit, so a sender could make the proxy open sockets and tasks until it ran out of file descriptors or memory. In `optional` mode any sender could, no trusted proxy needed.
68
+ - A new source now gets a session only for a datagram that can open or continue a QUIC connection: a long-header packet in a datagram of at least 1200 bytes, as every client's first flight is (RFC 9000 §14.1), or a short-header packet for a connection ID the endpoint issued, so a client that moves to a new address keeps its connection. Other datagrams are dropped. The relay holds at most 16,384 sessions, and 256 per client IP address (the PROXY source IP behind a trusted proxy); a datagram that would open a session above a limit is dropped until idle sessions expire. Open sessions are unaffected. The endpoint behind the relay issues its connection IDs as quinn's default does, with a key it shares with the relay.
69
+ - Masquerade only the connections an nftables route forwards (smart-proxy)
70
+ - A route with `forwardingEngine: 'nftables'` and without `preserveSourceIP` installed, next to its DNAT rule, `postrouting <proto> dport <targetPort> masquerade`. That rule rewrote the source of every connection the host forwarded or sent to the target port on any address, not only the connections the route forwarded. `@push.rocks/smartnftables` 4.8.1 scopes the masquerade to connections a DNAT rule redirected (`ct status dnat`), and SmartProxy now depends on it (^4.8.1, was ^1.2.0). The `SmartNftables` calls SmartProxy makes are unchanged.
71
+
72
+ ### Maintenance
73
+
74
+ - Release tooling: pnpm 12.13.0, and the deprecated single tools move to their replacements: `@git.zone/tsbuild`, `@git.zone/tstest` and `@git.zone/tsrun` to `@git.zone/tsrepo` ^1.1.1 (`tsrepo build`, `tsrepo test`, `tsrepo docs`; tests import `@git.zone/tsrepo/tapbundle`), and `@git.zone/tsrust` ^5.0.0 to `@git.zone/rsrepo` ^1.1.1. The `.smartconfig.json` sections move with them: `@git.zone/tsdoc` to `"@git.zone/tsrepo".docs` and `@git.zone/tsrust` to `@git.zone/rsrepo`; `native-notices/` regenerates unchanged. The lock entries the Verdaccio proxy recorded with SHA-1 integrity carry the SHA-512 integrity registry.npmjs.org publishes, after each SHA-1 matched the npmjs shasum.
75
+
3
76
  ## 2026-10-18 - 30.1.0
4
77
 
5
78
  ### Features
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "format": "tsrust.build-provenance.v2",
3
- "binarySha256": "6a329b3cfb0dfab45d91cdea6290021ee8b4586a38b69719ca8580f93f713e0c",
3
+ "binarySha256": "b3113d0dee4fd0f86bc4d2ec360c9fd6db9ff6c708378efa37756a10ca4a7481",
4
4
  "buildInfo": {
5
5
  "projectName": "@push.rocks/smartproxy",
6
- "projectVersion": "30.1.0",
7
- "gitCommit": "c8090ae0da31467618f68455a11daa6b6feee485",
6
+ "projectVersion": "31.0.0",
7
+ "gitCommit": "bc65e0a56653d666082bedf6ffeeb020465e73a9",
8
8
  "gitDirty": false,
9
- "builtAt": "2026-10-18T02:48:02.369Z",
10
- "tsrustVersion": "5.0.0",
9
+ "builtAt": "2026-10-20T18:51:34.704Z",
10
+ "tsrustVersion": "1.1.1",
11
11
  "binary": "rustproxy",
12
12
  "target": "linux_amd64_musl"
13
13
  }
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "format": "tsrust.build-provenance.v2",
3
- "binarySha256": "21db1d1ac89025fbded33251113db7f9ba5340ac32adfb5cf667e079258970ca",
3
+ "binarySha256": "12283928ad30dc9b9eded4cfe936e1fa1f3a09319ed63116894799024252a0aa",
4
4
  "buildInfo": {
5
5
  "projectName": "@push.rocks/smartproxy",
6
- "projectVersion": "30.1.0",
7
- "gitCommit": "c8090ae0da31467618f68455a11daa6b6feee485",
6
+ "projectVersion": "31.0.0",
7
+ "gitCommit": "bc65e0a56653d666082bedf6ffeeb020465e73a9",
8
8
  "gitDirty": false,
9
- "builtAt": "2026-10-18T02:51:20.089Z",
10
- "tsrustVersion": "5.0.0",
9
+ "builtAt": "2026-10-20T18:54:52.852Z",
10
+ "tsrustVersion": "1.1.1",
11
11
  "binary": "rustproxy",
12
12
  "target": "linux_arm64_musl"
13
13
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartproxy',
6
- version: '30.1.0',
6
+ version: '31.0.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
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLHFQQUFxUDtDQUNuUSxDQUFBIn0=
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export { SmartProxy } from './proxies/smart-proxy/index.js';
5
5
  export { SharedRouteManager as RouteManager } from './core/routing/route-manager.js';
6
- export type { ISmartProxyOptions, ISmartProxySecurityPolicy, ISmartProxyChallengeOptions, IConnectionRecord, IRouteConfig, IRouteMatch, IRouteAction, IRouteFixedResponse, IRouteTls, IRouteContext, TDatagramHandler, IDatagramInfo, IActiveConnectionSnapshot, IActiveConnectionSnapshotOptions, IActiveConnectionSnapshotPage } from './proxies/smart-proxy/models/index.js';
6
+ export type { ISmartProxyOptions, ISmartProxySecurityPolicy, ISmartProxyChallengeOptions, IConnectionRecord, IRouteConfig, IRouteMatch, IRouteAction, IRouteFixedResponse, IRouteTls, IRouteBackendTls, IRouteContext, TDatagramHandler, IDatagramInfo, IActiveConnectionSnapshot, IActiveConnectionSnapshotOptions, IActiveConnectionSnapshotPage } from './proxies/smart-proxy/models/index.js';
7
7
  export type { TSmartProxyCertProvisionObject, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './proxies/smart-proxy/models/interfaces.js';
8
8
  export * from './proxies/smart-proxy/utils/index.js';
9
9
  export * from './core/models/common-types.js';
@@ -4,4 +4,4 @@
4
4
  export { SmartProxy } from './smart-proxy/index.js';
5
5
  export { SharedRouteManager as SmartProxyRouteManager } from '../core/routing/route-manager.js';
6
6
  export * from './smart-proxy/utils/index.js';
7
- export type { ISmartProxyOptions, IConnectionRecord, IRouteConfig, IRouteMatch, IRouteAction, IRouteTls, IRouteContext } from './smart-proxy/models/index.js';
7
+ export type { ISmartProxyOptions, IConnectionRecord, IRouteConfig, IRouteMatch, IRouteAction, IRouteTls, IRouteBackendTls, IRouteContext } from './smart-proxy/models/index.js';
@@ -30,7 +30,7 @@ export interface ISmartProxyCertStore {
30
30
  /** Remove a cert (optional) */
31
31
  remove?: (domain: string) => Promise<void>;
32
32
  }
33
- import type { IRouteConfig } from './route-types.js';
33
+ import type { IRouteBackendTls, IRouteConfig } from './route-types.js';
34
34
  export interface ISmartProxySecurityPolicy {
35
35
  blockedIps?: string[];
36
36
  blockedCidrs?: string[];
@@ -131,6 +131,11 @@ export interface ISmartProxyOptions {
131
131
  preserveSourceIP?: boolean;
132
132
  trustedProxyIPs?: string[];
133
133
  sendProxyProtocol?: boolean;
134
+ /**
135
+ * Default verification of TLS backends; a route's or target's `tls.backend` replaces it.
136
+ * `serverName` belongs to routes and targets.
137
+ */
138
+ backendTls?: Omit<IRouteBackendTls, 'serverName'>;
134
139
  defaults?: {
135
140
  target?: {
136
141
  host: string;
@@ -102,6 +102,29 @@ export interface IRouteTls {
102
102
  ciphers?: string;
103
103
  honorCipherOrder?: boolean;
104
104
  sessionTimeout?: number;
105
+ backend?: IRouteBackendTls;
106
+ }
107
+ /**
108
+ * Verification of a TLS backend the proxy connects to.
109
+ *
110
+ * The whole object applies: a target's `tls.backend`, else the route's `action.tls.backend`,
111
+ * else the proxy-wide `backendTls`, else the system root store. Without `ca` or
112
+ * `rejectUnauthorized: false`, a self-signed or private-CA backend fails verification.
113
+ */
114
+ export interface IRouteBackendTls {
115
+ /** `false` accepts any backend certificate (default: verify) */
116
+ rejectUnauthorized?: boolean;
117
+ /**
118
+ * PEM certificates that replace the system root store for this backend, like Node's `ca`.
119
+ * A certificate is trusted as an issuer, so a self-signed backend certificate must not be a
120
+ * CA certificate (`basicConstraints CA:TRUE`).
121
+ */
122
+ ca?: string;
123
+ /**
124
+ * Name sent as SNI and checked against the backend certificate. Defaults to the requested
125
+ * domain on routes with named domains, else the backend host.
126
+ */
127
+ serverName?: string;
105
128
  }
106
129
  /**
107
130
  * Authentication options
@@ -131,6 +154,10 @@ export interface IRouteSecurity {
131
154
  }>;
132
155
  ipBlockList?: string[];
133
156
  maxConnections?: number;
157
+ /**
158
+ * @deprecated Not supported: route validation refuses a route that sets it.
159
+ * Use basicAuth or jwtAuth.
160
+ */
134
161
  authentication?: IRouteAuthentication;
135
162
  rateLimit?: IRouteRateLimit;
136
163
  basicAuth?: {
@@ -1,3 +1,3 @@
1
1
  import * as plugins from '../../../plugins.js';
2
2
  // Configuration moved to models/interfaces.ts as ISmartProxyOptions
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtdHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L21vZGVscy9yb3V0ZS10eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHFCQUFxQixDQUFDO0FBNGUvQyxvRUFBb0UifQ==
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtdHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L21vZGVscy9yb3V0ZS10eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHFCQUFxQixDQUFDO0FBdWdCL0Msb0VBQW9FIn0=
@@ -45,6 +45,13 @@ export interface IRustRouteValidationErrorData {
45
45
  routes: IRustRouteValidationIssue[];
46
46
  }
47
47
  export interface IRustAcmeOptions extends Omit<IAcmeOptions, 'routeForwards'> {
48
+ /**
49
+ * Whether the engine orders certificates for `certificate: 'auto'` routes at start
50
+ * and renews them on its own timer (default: true). SmartProxy sets it to false when
51
+ * a `certProvisionFunction` owns provisioning: the engine then orders a certificate
52
+ * only when `provisionCertificate` asks for one.
53
+ */
54
+ autoProvision?: boolean;
48
55
  }
49
56
  export interface IRustChallengeOptions extends Required<Pick<ISmartProxyChallengeOptions, 'cookieSigningKey' | 'pendingCookieName' | 'clearanceCookieName' | 'reservedPathPrefix' | 'relaySocketPath' | 'relayTimeoutMs' | 'pendingTtlSeconds'>> {
50
57
  }
@@ -53,6 +60,7 @@ export interface IRustProxyOptions {
53
60
  preserveSourceIp?: boolean;
54
61
  trustedProxyIPs?: string[];
55
62
  sendProxyProtocol?: boolean;
63
+ backendTls?: ISmartProxyOptions['backendTls'];
56
64
  defaults?: IRustDefaultConfig;
57
65
  connectionTimeout?: number;
58
66
  initialDataTimeout?: number;
@@ -95,6 +103,12 @@ export interface IRustCertificateStatus {
95
103
  expiresAt: number;
96
104
  isValid: boolean;
97
105
  }
106
+ /** A certificate the engine ordered through ACME and now serves. */
107
+ export interface IRustProvisionedCertificate {
108
+ domain: string;
109
+ /** The issued certificate chain in PEM; the private key stays in the engine. */
110
+ cert: string;
111
+ }
98
112
  export interface IRustThroughputSample {
99
113
  timestampMs: number;
100
114
  bytesIn: number;
@@ -1,5 +1,5 @@
1
1
  import * as plugins from '../../plugins.js';
2
- import { type IRustCertificateStatus, type IRustChallengeOptions, type IRustMetricsSnapshot, type IRustProxyOptions, type IRustMetricsHistory, type IRustRouteConfig, type IRustStatistics } from './models/rust-types.js';
2
+ import { type IRustCertificateStatus, type IRustProvisionedCertificate, type IRustChallengeOptions, type IRustMetricsSnapshot, type IRustProxyOptions, type IRustMetricsHistory, type IRustRouteConfig, type IRustStatistics } from './models/rust-types.js';
3
3
  import type { IActiveConnectionSnapshot, IActiveConnectionSnapshotOptions, IActiveConnectionSnapshotPage, ISmartProxySecurityPolicy } from './models/interfaces.js';
4
4
  /**
5
5
  * Turn a Rust `ROUTE_VALIDATION` refusal into a `RouteValidationError` carrying the
@@ -56,7 +56,12 @@ export declare class RustProxyBridge extends plugins.EventEmitter {
56
56
  getStatistics(): Promise<IRustStatistics>;
57
57
  getActiveConnectionSnapshots(options?: IActiveConnectionSnapshotOptions): Promise<IActiveConnectionSnapshot[]>;
58
58
  getActiveConnectionSnapshotPage(options?: IActiveConnectionSnapshotOptions): Promise<IActiveConnectionSnapshotPage>;
59
- provisionCertificate(routeName: string): Promise<void>;
59
+ /**
60
+ * Order a certificate through the engine's ACME client: for `domain`, which the
61
+ * route must serve, or else for the route's first domain. `timeoutMs` overrides
62
+ * the bridge request timeout; an order can take minutes.
63
+ */
64
+ provisionCertificate(routeName: string, domain?: string, timeoutMs?: number): Promise<IRustProvisionedCertificate>;
60
65
  renewCertificate(routeName: string): Promise<void>;
61
66
  getCertificateStatus(routeName: string): Promise<IRustCertificateStatus | null>;
62
67
  getListeningPorts(): Promise<number[]>;
@@ -209,8 +209,13 @@ export class RustProxyBridge extends plugins.EventEmitter {
209
209
  validateActiveConnectionSnapshotOptions(options);
210
210
  return this.bridge.sendCommand('getActiveConnectionSnapshotPage', options);
211
211
  }
212
- async provisionCertificate(routeName) {
213
- await this.bridge.sendCommand('provisionCertificate', { routeName });
212
+ /**
213
+ * Order a certificate through the engine's ACME client: for `domain`, which the
214
+ * route must serve, or else for the route's first domain. `timeoutMs` overrides
215
+ * the bridge request timeout; an order can take minutes.
216
+ */
217
+ async provisionCertificate(routeName, domain, timeoutMs) {
218
+ return this.bridge.sendCommand('provisionCertificate', { routeName, domain }, { timeoutMs });
214
219
  }
215
220
  async renewCertificate(routeName) {
216
221
  await this.bridge.sendCommand('renewCertificate', { routeName });
@@ -241,4 +246,4 @@ export class RustProxyBridge extends plugins.EventEmitter {
241
246
  await this.bridge.sendCommand('setDatagramHandlerRelay', { socketPath });
242
247
  }
243
248
  }
244
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVzdC1wcm94eS1icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3J1c3QtcHJveHktYnJpZGdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3BELE9BQU8sRUFDTCxnQ0FBZ0MsR0FTakMsTUFBTSx3QkFBd0IsQ0FBQztBQUNoQyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUd6RSxNQUFNLDBCQUEwQixHQUFHLHFCQUEyQixDQUFDO0FBQy9ELE1BQU0sK0JBQStCLEdBQUcsR0FBRyxDQUFDO0FBRTVDLFNBQVMsdUNBQXVDLENBQUMsT0FBeUM7SUFDeEYsSUFBSSxPQUFPLENBQUMsT0FBTyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ2xDLE9BQU87SUFDVCxDQUFDO0lBQ0QsSUFBSSxPQUFPLE9BQU8sQ0FBQyxPQUFPLEtBQUssUUFBUSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUMxRSxNQUFNLElBQUksS0FBSyxDQUFDLHVFQUF1RSxDQUFDLENBQUM7SUFDM0YsQ0FBQztJQUNELElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRywwQkFBMEIsRUFBRSxDQUFDO1FBQ3pELE1BQU0sSUFBSSxLQUFLLENBQUMsK0RBQStELENBQUMsQ0FBQztJQUNuRixDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMsOEJBQThCLENBQ3JDLElBQWEsRUFDYixjQUFzQjtJQUV0QixJQUNFLE9BQU8sSUFBSSxLQUFLLFFBQVE7V0FDckIsSUFBSSxLQUFLLElBQUk7V0FDYixDQUFDLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQztXQUNuQixDQUFD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
249
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVzdC1wcm94eS1icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3J1c3QtcHJveHktYnJpZGdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3BELE9BQU8sRUFDTCxnQ0FBZ0MsR0FVakMsTUFBTSx3QkFBd0IsQ0FBQztBQUNoQyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUd6RSxNQUFNLDBCQUEwQixHQUFHLHFCQUEyQixDQUFDO0FBQy9ELE1BQU0sK0JBQStCLEdBQUcsR0FBRyxDQUFDO0FBRTVDLFNBQVMsdUNBQXVDLENBQUMsT0FBeUM7SUFDeEYsSUFBSSxPQUFPLENBQUMsT0FBTyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ2xDLE9BQU87SUFDVCxDQUFDO0lBQ0QsSUFBSSxPQUFPLE9BQU8sQ0FBQyxPQUFPLEtBQUssUUFBUSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUMxRSxNQUFNLElBQUksS0FBSyxDQUFDLHVFQUF1RSxDQUFDLENBQUM7SUFDM0YsQ0FBQztJQUNELElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRywwQkFBMEIsRUFBRSxDQUFDO1FBQ3pELE1BQU0sSUFBSSxLQUFLLENBQUMsK0RBQStELENBQUMsQ0FBQztJQUNuRixDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMsOEJBQThCLENBQ3JDLElBQWEsRUFDYixjQUFzQjtJQUV0QixJQUNFLE9BQU8sSUFBSSxLQUFLLFFBQVE7V0FDckIsSUFBSSxLQUFLLElBQUk7V0FDYixDQUFDLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQztXQUNuQixDQUFD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
@@ -130,9 +130,17 @@ export declare class SmartProxy extends plugins.EventEmitter {
130
130
  getNfTablesStatus(): plugins.smartnftables.INftStatus | null;
131
131
  private cleanupRuntimeResourcesAfterStartFailure;
132
132
  /**
133
- * Apply NFTables rules for routes using the nftables forwarding engine.
133
+ * Replace the current NFTables rules with those of `routes`. When a rule fails, the
134
+ * rules of `fallbackRoutes` are applied again before the error is rethrown.
135
+ */
136
+ private replaceNftablesRules;
137
+ /**
138
+ * Apply NFTables rules for the enabled routes using the nftables forwarding engine.
139
+ * A rule that fails removes the rules applied before it.
134
140
  */
135
141
  private applyNftablesRules;
142
+ /** Add the port-forwarding rules of each route, one per listed port and target. */
143
+ private addNftablesRules;
136
144
  /**
137
145
  * Build the Rust configuration object from TS settings.
138
146
  */
@@ -162,6 +170,7 @@ export declare class SmartProxy extends plugins.EventEmitter {
162
170
  /**
163
171
  * Record the validity window of a certificate loaded into Rust.
164
172
  * Prefers an explicit validUntil; otherwise parses the PEM.
173
+ * @returns the recorded end of validity, or undefined if it is unknown
165
174
  */
166
175
  private recordCertValidity;
167
176
  /** Whether the domain has a loaded cert that is not yet inside the renewal window. */
@@ -180,6 +189,14 @@ export declare class SmartProxy extends plugins.EventEmitter {
180
189
  * Includes per-domain timeout and shutdown checks.
181
190
  */
182
191
  private provisionSingleDomain;
192
+ /**
193
+ * Order a domain's certificate through the engine's ACME client (HTTP-01 on
194
+ * `acme.port`), for an 'http01' callback result or the ACME fallback. The engine
195
+ * serves the certificate; its recorded validity lets sweeps skip the domain until
196
+ * the renewal window.
197
+ * @returns the certificate's expiry date (ISO 8601), if its PEM parses
198
+ */
199
+ private provisionThroughRustAcme;
183
200
  /**
184
201
  * Race a promise against a timeout. Rejects with the given message if the timeout fires first.
185
202
  */