Skip to main content

Netron RPC

Netron is the RPC plane Titan ships. It does one thing: take a TypeScript class, expose its methods over the wire, dispatch incoming calls back to the methods. The wire format is binary msgpack; the contract is the TypeScript interface.

This page is the Netron entry point. The mechanics live in:

PageTopic
ServicesDefining @Service classes, descriptors, peers
TransportsHTTP / WebSocket / TCP / Unix — when to choose what
MiddlewarePer-call wrapping (auth, rate limit, tracing)
AuthenticationIdentity, claims, policies
StreamingAsyncIterable methods, backpressure
Multi-backendClient → many servers, failover, load balancing
SerializationWire format, msgpack, custom codecs

The short tour

Server — define the service, then bind a transport server on the running Netron instance:

import { Service, Public } from '@omnitron-dev/titan/decorators';
import { HttpTransport } from '@omnitron-dev/titan/netron/transport/http';

@Service('users@1.0.0')
class UsersService {
@Public() async findById(id: string): Promise<User | null> { /* … */ }
}

const app = await Application.create(AppModule);
await app.start();

app.netron!.registerTransport('http', () => new HttpTransport());
await app.netron!.registerTransportServer('http', { name: 'api', options: { port: 3000 } });

Client — connect to get a RemotePeer, then resolve a typed proxy:

const peer = await app.netron!.connect('ws://localhost:3001');
const users = await peer.queryInterface<UsersService>('users@1.0.0');
const user = await users.findById('u_42');

That is the core API surface. Versioning, routing, serialisation, error mapping, and trace propagation all happen behind it.

The in-browser client is a separate package (@omnitron-dev/netron-browser) with its own connection API; this page covers the server-side @omnitron-dev/titan/netron runtime.

What Netron is

A few specific things, each with a deliberate scope:

  • A service descriptor system. @Service registers a typed contract; clients resolve it by name and version.
  • A transport abstraction. Four transports built in, all sharing the same service surface; pluggable for custom ones.
  • A middleware pipeline (HTTP transport). Per-call wrapping for cross-cutting concerns — auth, rate limiting, tracing, logging. The persistent transports (WS/TCP/Unix) enforce auth inline at dispatch rather than through the pipeline.
  • An auth policy framework. Authentication and authorisation are separate concerns with composable policies via BuiltInPolicies (requireRole, requireAnyRole, requirePermission, …).
  • A multi-backend client. One client can route to many servers with health-aware failover, circuit breaking, and per-service routing rules.
  • A streaming primitive. NetronReadableStream / NetronWritableStream (Node Web Streams) carry long-lived data over WebSocket / TCP / Unix. An async * generator method is auto-wrapped into a stream for remote callers.

What Netron is not

  • Not a service mesh. Discovery, mTLS, traffic shaping at cluster scope are out of scope. Use a real mesh (Linkerd, Istio, Consul Connect) for that.
  • Not a queue. Netron calls are request/response; the response may be a stream. For decoupled work, use titan-events or titan-notifications.
  • Not a schema language. The TypeScript interface is the schema. No .proto files, no OpenAPI YAML.

Performance characteristics

Per-call cost on a warmed-up connection (HTTP/1.1, localhost, no middleware):

OpApprox cost
msgpack encode (small payload)5–10 µs
Service descriptor lookup<1 µs
Validation (typical schema)1–5 µs
Method invocation (your code)varies
msgpack decode5–10 µs
HTTP framing50–200 µs

For sustained throughput, use WebSocket (no per-call HTTP framing cost) or TCP. For bursty short-lived clients, HTTP is fine and works through any reverse proxy.

→ Read on: Services.