Reaktor Mesh
Mesh is the live-channel part of the Data layer. Durable jobs, recordings and processing handoffs follow Queues and Workflows; a live socket does not provide durable intent or recovery.
Data-layer alignment (11 September 2026). This module participates in the unified data infrastructure through the same Service contracts and main graph identities. Delivery/session mechanisms retain their own guarantees; operation, publication, commit, projection and device-delivery receipts are distinct. The generalized Service interfaces are proposed, not implied to ship with this module.
Reaktor Mesh is the live connectivity layer for Reaktor.
It is the place for peer sessions, realtime data channels, media tracks, presence, WebRTC negotiation, TURN credential issuance, SFU routing, and graph-visible realtime topology.
It is not the durable bus. It does not own replay, outbox, DLQ, or long-lived event retention. When a realtime interaction must become an auditable business fact, the mesh hands that fact to Reaktor Bus or a typed service.
1. Why Mesh Exists
Many product features need live links, not durable queues:
- calls;
- screenshare;
- collaborative cursors;
- low-latency game state;
- presence;
- nearby or peer device sync;
- live debugging sessions;
- control-plane streams;
- realtime media processing;
- temporary peer-to-peer data movement.
These interactions have different constraints from bus messages:
- low latency matters more than replay;
- session lifecycle matters more than retention;
- network topology is part of the product behavior;
- backpressure and disconnect are normal;
- credentials must be short-lived;
- not every packet should become a database row.
Reaktor Mesh gives those links the same architectural treatment as services, data, and bus routes: typed contracts, graph nodes, explicit policy, and inspectable runtime state.
2. Boundaries
| System | Owns | Does not own |
|---|---|---|
reaktor-service | Request/response operations and endpoint identity. | Long-lived peer session topology. |
| Reaktor Bus | Durable events/jobs, queues, Pub/Sub, outbox, DLQ, replay. | Live media/data transport. |
reaktor-work | Scheduled/background execution. | Realtime session routing. |
| Reaktor Mesh | WebRTC, TURN, SFU sessions/tracks, DataChannels, presence, ICE state, peer topology. | Durable event history or background job ownership. |
| Distributed actors | Server-side placement, mailboxes, supervision, actor remoting. | Browser/mobile WebRTC session lifecycle. |
Practical rule:
If it must survive disconnect and be replayed, use Bus or a service write. If it must be live, low-latency, and session-scoped, use Mesh.
3. Provider Roles
Reaktor will use three Cloudflare realtime capabilities differently.
| Provider capability | Reaktor role | Notes |
|---|---|---|
| Cloudflare TURN | Connectivity fallback and ICE server credential issuance. | TURN keys stay server-side. Clients receive short-lived credentials only. |
| Cloudflare Realtime SFU | Serverless WebRTC sessions, media tracks, and global track routing. | Good for calls, broadcast, media rooms, and session-based data transport. |
| Cloudflare Realtime DataChannels | Low-latency arbitrary data to many subscribers. | Good for cursor state, game state, control messages, and collaboration. |
Mesh may also use:
- direct WebRTC between peers when allowed by network policy;
- Durable Objects for room/session directory and authorization;
- Worker service bindings for credential issuance and privileged calls;
- Bus for durable facts that should outlive a session.
4. TURN Credential Model
TURN credentials are security-sensitive.
Cloudflare TURN keys must never be embedded in a browser, mobile app, desktop app, or public config. The application backend uses the TURN key to mint short-lived credentials, and the client uses only those generated ICE server credentials.
The Reaktor shape:
interface MeshCredentialService {
suspend fun issueIceServers(scope: MeshCredentialScope): IceServerBundle
}
data class MeshCredentialScope(
val tenantId: String?,
val principalId: String,
val sessionId: String,
val allowedTransports: Set<MeshTransport>,
val ttlSeconds: Int,
)
data class IceServerBundle(
val iceServers: List<IceServer>,
val expiresAtEpochMillis: Long,
)
data class IceServer(
val urls: List<String>,
val username: String? = null,
val credential: String? = null,
)
Rules:
- TURN key is stored only in a server-side secret store.
- Credentials are scoped to the authenticated user/session.
- Credentials have short TTLs.
- The backend returns the provider
iceServersshape the WebRTC client can pass toRTCPeerConnection. - Browser clients should not be handed TURN URLs that browsers cannot use reliably.
- Credential issuance is audited as a service operation and projected into the graph.
This replaces product-specific realtime token endpoints with a framework surface that can support chat, calls, collaborative tools, and control-plane sessions.
5. Cloudflare Realtime SFU Model
Cloudflare Realtime SFU gives Reaktor a serverless WebRTC media/data plane.
Provider concepts map cleanly into Reaktor graph concepts:
| Cloudflare concept | Reaktor concept |
|---|---|
| Application | MeshApplicationNode |
| Session | MeshSessionNode; maps to one WebRTC PeerConnection to Cloudflare. |
| Track | MeshTrackNode; maps to a MediaStreamTrack and has a globally usable id. |
| DataChannel | MeshDataChannelNode; low-latency arbitrary data path. |
| Track subscription | MeshTrackSubscriptionEdge. |
| Anycast location | MeshRegionNode or runtime attribute on session. |
Key provider facts to encode:
- A Session maps to a WebRTC
PeerConnection. - Cloudflare anycast connects the client to a nearby data center.
- Tracks map to WebRTC
MediaStreamTrackobjects. - Tracks have global ids and can be made available to other sessions.
- API calls are scoped per session and limited to 50 calls per second per session.
- A single API call can include up to 64 tracks.
- Tracks are garbage-collected after 30 seconds of inactivity.
- PeerConnection must be connected; some operations wait up to 5 seconds for connection.
- Applications should implement reconnection strategy.
- Client-to-Cloudflare media/data ingress is free; Cloudflare-to-client egress has a free monthly allotment and then billing.
The adapter must surface these facts in configuration and telemetry. A graph that hides session churn, track count, or reconnect loops is not useful for operating realtime systems.
6. DataChannels
DataChannels carry arbitrary low-latency data through the realtime session.
Use DataChannels for:
- collaborative cursors;
- editor awareness;
- transient game state;
- call controls;
- realtime debug/control messages;
- room-local presence updates;
- mesh control-plane heartbeats.
Do not use DataChannels for:
- durable business events;
- large file transfer without a separate reliability protocol;
- payment/order/inventory state;
- anything that needs DLQ or replay.
Cloudflare Realtime DataChannels can scale one producer to many subscribers. The provider also has a waitForAck option that helps prevent the first message from being lost; when enabled, the subscriber must acknowledge within 15 seconds.
Reaktor should expose the reliability mode explicitly:
enum class MeshChannelDurability {
Ephemeral,
AckBeforeFirstMessage,
MirrorToBus,
}
data class MeshDataChannelOptions(
val label: String,
val ordered: Boolean = false,
val maxPacketLifeTimeMillis: Int? = null,
val durability: MeshChannelDurability = MeshChannelDurability.Ephemeral,
val mirrorKind: String? = null,
)
MirrorToBus does not make the DataChannel durable. It means the application also publishes selected semantic messages to Reaktor Bus.
7. Core API
The mesh API should be session-first.
interface ReaktorMesh {
suspend fun issueIceServers(scope: MeshCredentialScope): IceServerBundle
suspend fun openSession(
identity: MeshIdentity,
options: MeshSessionOptions = MeshSessionOptions(),
): MeshSession
suspend fun publishTrack(
sessionId: String,
track: MeshTrackDescriptor,
): MeshTrackRef
suspend fun subscribeTrack(
sessionId: String,
trackId: String,
options: MeshTrackSubscribeOptions = MeshTrackSubscribeOptions(),
): MeshSubscription
suspend fun openDataChannel(
sessionId: String,
options: MeshDataChannelOptions,
): MeshDataChannel
suspend fun closeSession(sessionId: String, reason: String? = null)
}
data class MeshIdentity(
val tenantId: String?,
val principalId: String,
val deviceId: String?,
val graphNodeId: String,
)
data class MeshSessionOptions(
val roomId: String? = null,
val preferredRegion: String? = null,
val requireTurn: Boolean = false,
val allowDirectPeer: Boolean = true,
val allowSfu: Boolean = true,
)
The API should not expose provider-specific objects at the application boundary. Provider details live in adapters and diagnostics.
8. Session Lifecycle
A mesh session has a lifecycle distinct from component lifecycle and bus delivery lifecycle.
Requested
-> CredentialIssued
-> Signaling
-> Connecting
-> Connected
-> Degraded
-> Reconnecting
-> Closed
Events:
| Event | Meaning |
|---|---|
onCredentialIssued | ICE/TURN bundle created. |
onSignalOffer | Local offer created or received. |
onSignalAnswer | Remote answer created or received. |
onIceCandidate | ICE candidate observed. |
onConnected | PeerConnection or provider session connected. |
onTrackPublished | Local track became available. |
onTrackSubscribed | Remote track subscription attached. |
onDataChannelOpen | DataChannel ready for messages. |
onDegraded | RTT, packet loss, reconnect, or provider error crossed threshold. |
onReconnecting | Session attempting recovery. |
onClosed | Session closed intentionally or permanently failed. |
The lifecycle should be graph-native: a connected session changes graph state, not just a callback in UI code.
9. Signaling And Directory
Mesh needs a signaling and directory plane, but it should stay separate from the media/data plane.
Responsibilities:
- authenticate session requests;
- authorize room/session access;
- issue TURN credentials;
- create or join provider sessions;
- exchange offers, answers, and ICE candidates when direct WebRTC is used;
- map product room ids to mesh session ids;
- expose presence and connection state;
- write durable facts to Bus when required.
Good first substrate:
- Cloudflare Worker route for credential/session APIs;
- Durable Object per room for directory, presence, and signaling;
- Cloudflare Realtime SFU for media/data when direct peer paths are not enough;
- Reaktor Bus for durable facts like
Call.Started,Call.Ended,Presence.Changed, orMesh.SessionFailed.
10. Graph Projection
Mesh is graph-visible. These nodes reach a workbench over Reaktor Graph Protocol, like every other runtime's graph.
| Graph node | Meaning |
|---|---|
MeshNode | Logical mesh subsystem for an app/service. |
MeshRoomNode | Product room/call/collaboration space. |
MeshSessionNode | One live peer/provider session. |
PeerNode | User/device/service participant. |
TurnCredentialNode | Short-lived ICE credential issuance record. |
SfuNode | Provider SFU application/session resource. |
MeshTrackNode | Audio/video/screen/data media track. |
MeshDataChannelNode | Low-latency data channel. |
RelayNode | TURN/SFU relay path. |
MeshMetricNode | RTT, packet loss, bitrate, reconnect count, jitter, error budget. |
Edges:
issuesCredential;joinsRoom;connectsTo;publishesTrack;subscribesTrack;opensDataChannel;relaysThrough;mirrorsToBus;signalsThrough;degrades;disconnects.
Workbench overlays should show:
- active sessions by room;
- ICE state;
- direct vs TURN vs SFU path;
- RTT and packet loss;
- reconnect loops;
- media track bitrate and resolution;
- DataChannel message rate;
- sessions with expired or near-expired credentials;
- mesh messages mirrored into Bus.
11. Mesh To Bus Handoff
Mesh messages are ephemeral by default. Some effects must be durable.
Examples:
| Live mesh action | Durable bus/service fact |
|---|---|
| User joins a call | Call.ParticipantJoined |
| User leaves a call | Call.ParticipantLeft |
| Screen share starts | Call.ScreenShareStarted |
| Collaboration patch accepted | Document.PatchCommitted |
| Session fails after retries | Mesh.SessionFailed |
| Presence changes | Presence.Changed with coalescing policy |
Rules:
- Do not mirror every packet.
- Mirror semantic facts.
- Coalesce noisy presence/awareness updates.
- Write through a service when the fact changes authoritative state.
- Publish to Bus when the fact fans out or triggers work.
12. Security
Mesh is a security boundary.
Required controls:
- authenticate every credential/session request;
- authorize access to the room/session/track;
- keep TURN keys server-side;
- issue short-lived ICE credentials;
- bind credentials to principal, tenant, session, and device when possible;
- validate track subscription rights;
- avoid logging raw SDP, tokens, or ICE credentials;
- redact mesh metadata in graph exports when needed;
- rate-limit credential issuance and session APIs;
- treat DataChannel messages as untrusted input;
- mirror durable facts through normal service/bus authorization.
DataChannels are not a trust shortcut. A peer that can send a realtime packet has not earned permission to mutate durable state.
13. Failure Semantics
Mesh failure is expected.
Failure modes:
- TURN credential expired;
- ICE gathering failed;
- direct peer path blocked;
- TURN relay required;
- SFU session not connected;
- track inactive and garbage-collected;
- DataChannel first message lost without ack;
- subscriber joined after ephemeral message was sent;
- mobile app paused or backgrounded;
- network switched from Wi-Fi to cellular;
- room Durable Object restarted;
- provider rate limit hit.
Reaktor must surface these as typed states, not unstructured console logs.
Policy examples:
| Failure | Default policy |
|---|---|
| Direct path fails | Retry through TURN or SFU. |
| Credential expired | Re-issue if auth/session still valid. |
| DataChannel first message important | Use AckBeforeFirstMessage or mirror semantic fact to Bus. |
| Track inactive | Re-publish or close subscription after grace period. |
| Reconnect loop | Mark session Degraded, emit telemetry, optionally publish Mesh.SessionFailed. |
| Provider rate limit | Back off and surface graph warning. |
14. Implementation Plan
Build Mesh in layers:
reaktor-mesh-core: identity, credential scope, session model, lifecycle events, graph nodes.reaktor-mesh-webrtc: common WebRTC client abstractions for browser/mobile/desktop.reaktor-mesh-cloudflare-turn: server-side TURN credential adapter.reaktor-mesh-cloudflare-realtime: SFU sessions, tracks, subscriptions, DataChannels.reaktor-mesh-signaling: Durable Object/Worker signaling and room directory helpers.reaktor-mesh-bus: semantic event mirror and mesh-to-bus policy.reaktor-mesh-graph: workbench projection and overlays.- Product migration: replace BestBuds-specific realtime token and room state with mesh primitives.
Keep ServiceTransport.PEER as endpoint identity. The runtime implementation belongs in Mesh.
15. Acceptance Tests
A real implementation is not done until these pass:
- TURN credentials are issued only by authenticated server-side code;
- TURN key never appears in client bundles or logs;
- issued ICE credentials have bounded TTL and include expected
iceServers; - unauthorized principal cannot join a mesh room;
- session lifecycle emits graph events in order;
- direct peer path can fall back to TURN/SFU;
- SFU session creates and publishes a track descriptor;
- another session can subscribe to the track;
- DataChannel
AckBeforeFirstMessagewaits for subscriber acknowledgement; - DataChannel ephemeral messages are not treated as durable facts;
MirrorToBuspublishes only semantic messages;- graph export shows peers, sessions, TURN/SFU path, tracks, channels, metrics, and bus mirror edges;
- reconnect loop becomes a typed degraded state and telemetry span;
- provider limits are represented as adapter constants and covered by tests.
16. Provider References
Use current provider docs while implementing adapters:
- Cloudflare Realtime TURN credential generation
- Cloudflare Realtime SFU overview
- Cloudflare Realtime sessions and tracks
- Cloudflare Realtime DataChannels
- Cloudflare Realtime SFU limits
Related Docs
- Reaktor Bus - Durable events, jobs, queues, Pub/Sub, outbox, DLQ, and replay.
- Service Layer - Operation contracts and endpoint identity.
- Distributed Actors - Server-side actor placement and remoting.
- Component Lifecycle - Component and graph lifecycle hooks.
- Graph Hierarchical UI - How mesh topology appears in scoped graph views.
- Unified Graph - Whole-system graph projection across runtime and cloud resources.