Apache Maka Runtime Host: Understanding the Public Client/Protocol Boundary
The packages/runtime-host module in Apache Maka exposes a stable, JSON-based API over WebSocket, separating external client communication into a Protocol layer (types and validation) and a Transport layer (WebSocket implementation).
The runtime-host package serves as the public edge of the Apache Maka runtime, enabling external clients—such as web front-ends, SDKs, and microservices—to communicate with the execution host without accessing internal implementation details. This boundary is explicitly defined by two architectural layers that enforce message schemas, size limits, and error handling while hiding the complexity of the underlying execution engine.
Architecture of the Public Boundary
The boundary is strictly partitioned into declarative types and concrete transport logic. This separation allows the host to evolve its internal session management and policy engines while maintaining backward compatibility for connected clients.
Protocol Definition Layer
The Protocol layer declares the wire format using TypeScript types, constants, and error classes. It defines the JSON schema that all messages must follow, enforces UTF-8 validity, and specifies size constraints.
Key exported symbols from src/protocol/index.ts include:
EncodedProtocolMessage– The TypeScript type representing a serialized protocol messageRUNTIME_HOST_MAX_MESSAGE_BYTES– The hard limit on incoming message payload sizeRuntimeHostProtocolError– Thrown when frames contain invalid JSON, oversized payloads, or malformed structureRuntimeHostTransportError– Raised for transport-level failures such as queue saturation
According to the Apache Maka source code, these definitions ensure that any compliant client can generate valid messages using only the protocol exports, without importing transport internals.
Transport Implementation Layer
The Transport layer implements the bidirectional WebSocket channel that reads, writes, and validates protocol messages. The primary implementation resides in src/transport/websocket-transport.ts and extends the abstract FramedTransport base class from src/transport/framed-transport.ts.
Core components include:
WebSocketTransport– The concrete class implementing theRuntimeHostMessageTransportinterface defined insrc/transport/message-transport.ts- Back-pressure management – Enforces
MAX_PENDING_WRITE_BYTESto prevent memory exhaustion - Graceful shutdown – Provides
closeAfterFlush()to drain pending writes before closing andabort()for immediate termination
How Messages Flow Across the Boundary
The client-to-host interaction follows a strict sequence that isolates protocol validation from socket management:
-
Connection establishment – The client opens a WebSocket to the host endpoint (e.g.,
ws://<host>/runtime). -
Transport instantiation – The host creates a
WebSocketTransportinstance, wiring the socket’smessage,error, andcloseevents. -
Inbound decoding – All incoming frames pass through
decodeMessagein the protocol layer. This function:- Validates UTF-8 encoding
- Parses JSON into an
EncodedProtocolMessageobject - Throws
RuntimeHostProtocolErrorfor malformed or oversized payloads
-
Outbound encoding – Responses are encoded as
Uint8Array(orBuffer) and passed toWebSocketTransport.write. The transport checks the pending-write queue againstMAX_PENDING_WRITE_BYTES, raising aRuntimeHostTransportErrorwith codeoutbound_queue_fullif the buffer is saturated. -
Lifecycle management – The transport supports
closeAfterFlush()for graceful shutdowns that complete pending writes, orabort()to terminate the connection immediately and propagate transport-level failures.
Implementing a Client for the Public Boundary
Clients interact with the boundary using standard WebSocket clients and the protocol exports. The following examples demonstrate compliant interaction patterns.
Connecting and Sending Messages
Clients must respect RUNTIME_HOST_MAX_MESSAGE_BYTES when serializing payloads:
import WebSocket from 'ws';
import {
RUNTIME_HOST_MAX_MESSAGE_BYTES,
type EncodedProtocolMessage,
} from '@apache-maka/runtime-host/protocol';
const socket = new WebSocket('ws://localhost:8080/runtime');
function encode(msg: unknown): EncodedProtocolMessage {
const json = JSON.stringify(msg);
const size = new TextEncoder().encode(json).byteLength;
if (size > RUNTIME_HOST_MAX_MESSAGE_BYTES) {
throw new Error('Message exceeds host maximum size');
}
return Buffer.from(json);
}
socket.on('open', () => {
const request = { operation: 'session.start', params: {} };
socket.send(encode(request));
});
Receiving and Decoding Messages
Inbound messages should be validated against the protocol schema:
socket.on('message', (data) => {
try {
const text = data.toString('utf8');
const message = JSON.parse(text); // Mirrors host decodeMessage
console.log('Received:', message);
} catch (e) {
console.error('Protocol violation:', e);
}
});
Server-Side Transport Handling
Host implementations use the WebSocketTransport class directly to manage client sessions:
import { WebSocketTransport } from '@apache-maka/runtime-host/transport';
// `ws` is a connected WebSocket instance from a client
const transport = new WebSocketTransport(ws);
// Read with a 5-second timeout
transport.read(5000)
.then(msg => {
console.log('Client message:', msg);
return transport.write(encode({ echo: msg }));
})
.catch(err => {
if (err instanceof RuntimeHostTransportError) {
console.error('Transport failure:', err);
}
});
Key Source Files in the Runtime Host Package
The boundary is implemented across five critical files in the packages/runtime-host directory:
| File Path | Responsibility |
|---|---|
src/protocol/index.ts |
Defines EncodedProtocolMessage, size constants, and protocol-level error constructors |
src/protocol/errors.ts |
Implements RuntimeHostProtocolError and RuntimeHostTransportError classes |
src/transport/message-transport.ts |
Declares the RuntimeHostMessageTransport interface abstracting read/write operations |
src/transport/websocket-transport.ts |
Concrete WebSocket implementation enforcing protocol limits and connection lifecycle |
src/transport/framed-transport.ts |
Base class providing low-level framing and transport error handling |
Summary
- The public client/protocol boundary in
packages/runtime-hostconsists of a Protocol layer (types and validation) and a Transport layer (WebSocket implementation). - Protocol enforcement occurs in
src/protocol/index.ts, which validates UTF-8, JSON structure, and payload sizes againstRUNTIME_HOST_MAX_MESSAGE_BYTES. WebSocketTransportinsrc/transport/websocket-transport.tsmanages the physical connection, back-pressure viaMAX_PENDING_WRITE_BYTES, and graceful shutdown throughcloseAfterFlush().- Clients communicate using standard WebSockets and JSON payloads, relying on
EncodedProtocolMessagetypes for type safety without requiring internal host dependencies.
Frequently Asked Questions
What is the maximum message size for the Maka Runtime Host protocol?
The host enforces a hard limit defined by RUNTIME_HOST_MAX_MESSAGE_BYTES (exported from src/protocol/index.ts). Clients must ensure serialized JSON payloads do not exceed this threshold, or the host will throw a RuntimeHostProtocolError upon receipt.
How does the host handle malformed or invalid client messages?
All inbound frames pass through the decodeMessage function, which validates UTF-8 encoding and JSON syntax. If validation fails, the host raises a RuntimeHostProtocolError before the message reaches internal business logic, ensuring the execution engine remains isolated from malformed input.
Can I implement a custom transport other than WebSocket?
Yes. The RuntimeHostMessageTransport interface (defined in src/transport/message-transport.ts) abstracts the transport mechanism. While WebSocketTransport is the reference implementation, any class implementing read() and write() methods adhering to the interface can substitute for WebSocket in specialized deployment scenarios.
What happens when the outbound message queue is full?
If pending writes exceed MAX_PENDING_WRITE_BYTES, the transport raises a RuntimeHostTransportError with the specific code outbound_queue_full. This back-pressure mechanism prevents memory exhaustion and signals to the host that it should apply flow control or shed load.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →