@opsimathically/forwarddynamic-node
Typed, fail-closed access to request metadata produced by ForwardDynamic. The
package does not implement the mTLS backhaul; the core has no runtime
dependencies, while the Fastify subpath uses fastify-plugin to preserve hook
encapsulation semantics. It supports Node.js 22, 24, and 26 and is ESM-only in
v1.
Install
npm install @opsimathically/forwarddynamic-node
Express 5 and Fastify 5 are optional peer dependencies. Install only the
framework adapter your application uses. The native Node integration has no
framework peer requirement. TypeScript projects should use node16, nodenext,
or bundler module resolution; legacy node resolution does not understand
package export maps.
Native Node example
import { createServer } from "node:http";
import { createForwardDynamicIntegration } from "@opsimathically/forwarddynamic-node";
import {
requireForwardDynamicContext,
writeForwardDynamicError,
} from "@opsimathically/forwarddynamic-node/native";
const integration = createForwardDynamicIntegration({
mode: "required",
requiredContractVersion: 1,
expectedServiceIds: ["photos"],
expectedPublicAuthorities: ["photos.example.com"],
});
createServer((request, response) => {
try {
const context = requireForwardDynamicContext(request, integration);
response.end(`request ${context.requestId}`);
} catch (error) {
if (!writeForwardDynamicError(response, error)) response.destroy();
}
}).listen(3000, "127.0.0.1");
trusted: true means the metadata followed the expected ForwardDynamic path.
It does not authenticate the visitor, hostname, Cloudflare account, or user.
The package accepts the immediate proxy only on loopback; keep the application
bound to loopback and keep the service agent's management endpoint private.
Modes are explicit:
disabledignores every reserved header and is safe before migration or during a complete Rust rollback.optionalreturns an untrusted result for absent context or a non-loopback peer, but rejects malformed or partial context arriving from loopback.requiredfails closed for every missing, untrusted, malformed, wrong-service, or wrong-authority request.
The parser never consults Forwarded, X-Forwarded-*, X-Real-IP, or raw
Cloudflare headers. Express middleware does not set trust proxy; Fastify does
not change global server options. Import adapters from their dedicated export
paths. Lifecycle helpers install no signal handlers and never consume bodies.
Public module import paths (not HTTP routes)
The paths below are JavaScript and TypeScript package exports used in import
statements. They are not URL paths or automatically registered HTTP routes.
Installing this package does not create a server, open a port, or expose an
endpoint to the internet.
- The package root creates and parses the versioned context.
/nativeprovides nativenode:httpparsing, required-mode, error-writing, and handler helpers./expressand/fastifyprovide framework adapters without changing global proxy-trust settings./healthprovides bounded readiness, contract-probe, and drain controllers./servervalidates and applies defensive native HTTP server settings./manifestvalidates an application manifest against the authoritative deployment description emitted by the Rust CLI./testingcreates synthetic contract headers for unit tests only. These headers never authenticate a production request and must not be used as an end-to-end ForwardDynamic test substitute.
The health and contract-probe modules return handler functions but do not mount them. A handler becomes reachable only if the application explicitly attaches it to an HTTP route. Keep operational health routes on a private management listener or protect them with appropriate access controls; mounting one on an internet-facing server makes it reachable according to that server's routing and authorization policy.
Manifest validation
The manifest records hostPolicy (origin, preserve, or override) and
hostOverridePresent; validation fails when these differ from the authoritative
Rust service configuration. The declared origin must be loopback.
Rust remains the only TOML parser:
forwarddynamic config inspect --forward forward.toml --service service.toml \
--format json > forwarddynamic-deployment.json
forwarddynamic-node validate-manifest --manifest forwarddynamic.app.json \
--deployment forwarddynamic-deployment.json
See contracts/application-proxy/v1 in the ForwardDynamic repository for the
normative contract and docs/APPLICATION_PROXY_ROLLOUT.md for rollout and
rollback order.
Support and source
Source, issues, the normative contract, and integration evidence live in the ForwardDynamic repository. The package is dual-licensed under MIT or Apache-2.0.