# `@wrnexus/rpc` Define a service contract in a shared workspace package, then import that same contract from the caller and callee. ```ts import { defineService, implement, inProcessTransport, procedure, serviceClient, } from "@wrnexus/rpc"; import { v } from "@wrnexus/validation"; const greeter = defineService({ name: "greeter", procedures: { greet: procedure .input(v.object({ name: v.string() })) .output<{ message: string }>() .build(), }, }); const service = implement( greeter, { greet: async ({ name }) => ({ message: `Hello, ${name}` }) }, { selfApp: "greeter" }, ); const client = serviceClient(greeter, { app: "greeter", transport: inProcessTransport({ "greeter/greet": (input, identity) => service.invoke("greet", input, identity), }), }); await client.greet({ name: "Ada" }); ``` Service files default-export `implement(...)` from `app/services`. The development server mounts them under the private `/__wrnexus/rpc` prefix. Pass `{ as: ctx }` to `serviceClient` to propagate the subject. The signed token contains only subject and tenant identifiers; permissions are always checked by the callee. Set `WRNEXUS_RPC_SECRET` in every app, use at least 32 characters, and never reuse the session secret. Calls time out by default. Retrying is intentionally deferred; when introduced, only procedures marked `.idempotent()` may be retried. ## Deployment requirement: apps must be unreachable except through the gateway `/__wrnexus/rpc/*` is authenticated by TWO signals together: a marker header (`x-wrnexus-internal: 1`) AND the absence of any `X-Forwarded-*` header. The WrNexus gateway satisfies this by construction — it strips any inbound marker header from the public request, and it always adds `X-Forwarded-*` when proxying to an app. A direct loopback call from a sibling app process carries the marker and no forwarded headers, so it passes; anything that came through the gateway carries forwarded headers, so it's rejected even if it also carries the marker. **This check only works if the app process is unreachable except through the gateway.** If an app's port is exposed directly, or if a reverse proxy sits in front of it WITHOUT setting `X-Forwarded-*` (a bare `proxy_pass` with no `proxy_set_header X-Forwarded-For`/`X-Forwarded-Host`/`X-Forwarded-Proto`), then an external caller can set the marker header itself, arrive with no forwarded headers, and reach `/__wrnexus/rpc/*` as if it were an internal call — bypassing the gateway's edge block entirely. Requirements for any deployment: - App processes must bind to a private/loopback interface and be reachable ONLY through the gateway (or an equivalent trusted front door) — never exposed directly to the internet or an untrusted network. - Any reverse proxy placed in front of an app (nginx, a load balancer, etc.) MUST set `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto` on every request it forwards. Omitting these silently reopens the private RPC namespace to anyone who can reach the proxy.