---
title: "Référence d'API — nodefony/client — realtime"
source: docs/api/core/sous-chemin-client-realtime.md
url: https://nodefony.github.io/nodefony-core/docs/api/core/sous-chemin-client-realtime/
---


[Documentation](../../../) › [Référence d'API](../../) › [`nodefony`](../) › sous-chemin-client-realtime

> Générée depuis les déclarations de types publiées de `nodefony` **10.0.0-beta.6** : exactement ce que reçoit une application qui l'installe. Cette page n'existe dans aucun dépôt — pour la corriger, on corrige le TSDoc du code.

## `nodefony/client`

`import { … } from "nodefony/client"` — 86 symboles.

### Classes (2)

#### `JsonRpcPeer`

```ts
class JsonRpcPeer<Emit extends EventsMap = DefaultEventsMap, Listen extends EventsMap = DefaultEventsMap, Actions extends ActionsMap = DefaultActionsMap> implements IRealtimePeer<Emit, Actions>
```

- `constructor(opts: JsonRpcPeerOptions<Emit, Listen, Actions>)`
- `get codec(): IFrameCodec` — Codec de la connexion — celui qui encode les émissions (sortie `write`) et relit l'entrée (`decode`).
- `set codec(codec: IFrameCodec)` — Codec de la connexion — celui qui encode les émissions (sortie `write`) et relit l'entrée (`decode`).
- `decode(data: string | Uint8Array): unknown` — Relit une trame reçue avec le codec courant — la frame rendue se confie ensuite à `receive`.
- `register<K extends ActionNames<Actions>>(method: K, handler: TypedRpcActionHandler<Actions, K>): void` — Expose une action (requête entrante `method`+`id` → `result`).
- `registerHandler(method: string, handler: RpcActionHandler): void` — Expose une action sous un nom quelconque — la forme non typée de `JsonRpcPeer.register`, pour qui tient le peer sans son contrat (la socket client, qui le type par ses propres signatures).
- `unregister(method: ActionNames<Actions>): void` — Retire une action.
- `get methods(): string[]` — Liste des actions exposées (pour annoncer au handshake, découverte côté pair).
- `request<K extends ActionNames<Actions>>(method: K, params?: ActionParams<Actions, K>, timeoutMs?: number): Promise<ActionResult<Actions, K>>` — Requête SORTANTE — `Promise` résolue avec le `result` (rejette sur `error`/timeout).
- `requestAs<A extends ActionsMap, K extends ActionNames<A>>(method: K, params?: ActionParams<A, K>, timeoutMs?: number): Promise<ActionResult<A, K>>` — Requête SORTANTE typée par un contrat que l'APPELANT déclare — pour qui tient ce pair sous son contrat effacé et connaît celui de son interlocuteur.
- `requestTracedAs<A extends ActionsMap, K extends ActionNames<A>>(method: K, params?: ActionParams<A, K>, timeoutMs?: number): Promise<RpcTracedResult<ActionResult<A, K>>>` — Requête SORTANTE **tracée** typée par un contrat que l'APPELANT déclare — `requestAs` qui garde la méta serveur, comme `requestTraced`.
- `requestTraced<K extends ActionNames<Actions>>(method: K, params?: ActionParams<Actions, K>, timeoutMs?: number): Promise<RpcTracedResult<ActionResult<Actions, K>>>` — Requête SORTANTE **tracée** — rend `{ result, meta }` au lieu du `result` nu.
- `static buildNotification(method: string, params?: unknown): JsonRpcNotification` — Frame d'une notification sortante — **source unique** de sa forme.
- `notify<K extends EventNames<Emit>>(method: K, params?: EventPayload<Emit, K>): boolean` — Notification SORTANTE (pas de réponse attendue).
- `receive(msg: unknown): JsonRpcFrameKind` — Ingestion d'une frame ENTRANTE déjà parsée → classe (request/notification/ response) et route.
- `dispose(reason?: string): void` — Annule tous les pending (fermeture du transport).

#### `RpcError`

```ts
class RpcError extends Error
```

Erreur RPC **applicative** — l'exception VOLONTAIRE au principe « throw → `-32603` générique » : un handler qui rejette avec une `RpcError` choisit explicitement d'exposer `code`/`message`/`data` au pair (404 d'un path invoqué, 403 d'un voter…). Tout autre throw reste opaque (Zero Trust).

- `readonly name = "RpcError"`
- `readonly data?: unknown`
- `constructor(message: string, code?: number, data?: unknown)`

### Fonctions (11)

#### `createIdempotencyKey`

```ts
function createIdempotencyKey(): string
```

Une clé d'idempotence neuve : UUID v4 quand l'environnement l'offre, sinon une chaîne horodatée et aléatoire (page servie hors contexte sécurisé, où `crypto.randomUUID` n'existe pas).

#### `createThroughputPayload`

```ts
function createThroughputPayload(size: number, seed?: number): Uint8Array<ArrayBuffer>
```

Fabrique la charge de la sonde : `size` octets pseudo-aléatoires, toujours les mêmes pour une même graine.

#### `fromLittleEndianBytes`

```ts
function fromLittleEndianBytes<T extends NumericArray>(bytes: Uint8Array<ArrayBuffer>, ctor: INumericArrayConstructor<T>, littleEndian?: boolean): T
```

Relit une série émise par `toLittleEndianBytes`.

#### `isPlatformChannel`

```ts
function isPlatformChannel(name: string): boolean
```

Le nom désigne-t-il une surface de la plateforme (canal OU méthode) ?

#### `isRateChannel`

```ts
function isRateChannel(channel: string, base: string): boolean
```

Vrai si `channel` est le canal de base nu OU une de ses variantes cadencées `base:<ms>`.

#### `isRealtimePayload`

```ts
function isRealtimePayload(value: unknown): value is object
```

Dit si une valeur est une charge realtime admise : absente, un objet, un tableau ou des octets — jamais un nombre, une chaîne, un booléen ni `null`.

#### `isThroughputPayloadSize`

```ts
function isThroughputPayloadSize(value: unknown): value is ThroughputPayloadSize
```

`true` si `value` est une taille admise par la sonde de débit.

#### `parseRate`

```ts
function parseRate(channel: string, base: string, bounds: RateBounds): number
```

Résout la cadence (ms) d'un canal cadencé connu, côté serveur. Le serveur connaît la `base` qu'il vient de matcher ; ce helper en extrait le suffixe `:<ms>`, **borne** dans `bounds` et retombe sur `bounds.default` pour le canal de base nu ou un suffixe invalide.

#### `rateChannel`

```ts
function rateChannel(base: string, intervalMs?: number, defaultMs?: number): string
```

Construit le nom d'un canal cadencé à partir de sa base et de la cadence demandée.

#### `textCodecForMarker`

```ts
function textCodecForMarker(marker: unknown): IFrameCodec
```

Le codec JSON qui relit un texte selon le marqueur que son émetteur a annoncé — champ `bytes` de l'accueil sur la socket, en-tête `BYTES_MARKER_HEADER` sur le REST. Une seule règle pour les deux transports : la convention n'est relue que si elle est annoncée, sinon un objet applicatif `{"$bytes": …}` changerait de nature.

#### `toLittleEndianBytes`

```ts
function toLittleEndianBytes(view: NumericArray, littleEndian?: boolean): Uint8Array<ArrayBuffer>
```

Rend les octets petit-boutistes d'un tableau typé, prêts à voyager.

### Constantes (12)

#### `BYTES_MARKER_HEADER`

```ts
const BYTES_MARKER_HEADER = "x-nodefony-bytes"
```

En-tête HTTP par lequel une réponse REST annonce la convention d'octets — le pendant du champ `bytes` de `realtime:welcome` sur la socket. Absent, le corps est du JSON natif : un objet `{"$bytes": …}` y reste un objet (ADR-0022 §2).

#### `JSON_PROTOCOL`

```ts
const JSON_PROTOCOL = "nodefony.jsonrpc.v1"
```

Sous-protocole WebSocket (RFC 6455 §1.9) du codec texte — le format d'une connexion qui n'en a négocié aucun (décision 1 de #630). Nom versionné : une enveloppe qui change ajoute `v2`, jamais ne renomme `v1`.

#### `NODEFONY_CHANNEL_NAMESPACE`

```ts
const NODEFONY_CHANNEL_NAMESPACE = "nodefony:"
```

Marque des surfaces de plateforme sur la socket. Un canal qui commence par ce préfixe décrit le serveur, jamais le métier de l'application.

#### `PLATFORM_CHANNELS`

```ts
const PLATFORM_CHANNELS: { readonly syslog: "nodefony:syslog"; readonly audit: "nodefony:audit"; readonly dashboard: "nodefony:dashboard"; readonly supervision: "nodefony:supervision"; readonly debugbar: "nodefony:debugbar"; readonly socket: "nodefony:socket"; readonly ormHealth: "nodefony:orm:health"; readonly ormFlow: "nodefony:orm:flow"; readonly ormRich: "nodefony:orm:rich"; readonly scaffoldJ …
```

Canaux de **diffusion** de la plateforme (le serveur pousse, les écrans regardent).

#### `PLATFORM_EVENTS`

```ts
const PLATFORM_EVENTS: { readonly hmr: "nodefony:hmr"; readonly debugbarSelect: "nodefony:debugbar:select"; }
```

Événements **DOM** de la plateforme (`window`), dans le même espace de nommage.

#### `PLATFORM_INBOUND`

```ts
const PLATFORM_INBOUND: { readonly syslogUplink: "nodefony:syslog:uplink"; }
```

Canaux **MONTANTS** de la plateforme (le navigateur pousse, le pod reçoit).

#### `PLATFORM_LITTLE_ENDIAN`

```ts
const PLATFORM_LITTLE_ENDIAN: boolean
```

`true` si la machine range ses nombres en petit-boutiste (constaté, pas déduit).

#### `PLATFORM_METHODS`

```ts
const PLATFORM_METHODS: { readonly ping: "nodefony:kernel:ping"; readonly gc: "nodefony:kernel:gc"; readonly scaffoldPreview: "nodefony:scaffold:preview"; readonly scaffoldRun: "nodefony:scaffold:run"; readonly scaffoldCancel: "nodefony:scaffold:cancel"; readonly throughput: "nodefony:realtime:throughput"; }
```

Méthodes **RPC** de la plateforme (le client demande, le serveur répond).

#### `SUPERVISION_HISTORY_COLUMNS`

```ts
const SUPERVISION_HISTORY_COLUMNS: readonly [ "ts", "cpuPercent", "eventLoopMeanMs", "eluUtilization", "heapUsed", "rss" ]
```

Séries de l'historique, dans l'ordre des colonnes de `values` (`Float64`).

#### `SUPERVISION_LOOP_BANDS`

```ts
const SUPERVISION_LOOP_BANDS: readonly [ "p50", "p90", "p99", "max" ]
```

Bandes du retard de la boucle, dans l'ordre des colonnes de `loop` (`Float32`, ms). Des percentiles et non les cases de l'histogramme : `monitorEventLoopDelay` n'expose pas ses cases (#618 D5).

#### `THROUGHPUT_PAYLOAD_SIZES`

```ts
const THROUGHPUT_PAYLOAD_SIZES: readonly [ 1024, 65536, 1048576 ]
```

Tailles admises, en octets : 1 Ko, 64 Ko, 1 Mo. Fermées : une taille libre ferait de l'action un amplificateur que le client dimensionne. 1 Mo reste sous `maxPayload` (1 MiB) une fois l'enveloppe ajoutée côté CBOR, et le sens est serveur → client seulement.

#### `TransportState`

```ts
const TransportState: { readonly CONNECTING: 0; readonly OPEN: 1; readonly CLOSING: 2; readonly CLOSED: 3; }
```

États d'un transport — alignés sur les constantes `WebSocket`.

### Interfaces (30)

#### `IBackplaneInfo`

```ts
interface IBackplaneInfo
```

**Carte d'identité** d'un backplane — descripteur de DONNÉE (pas un log) décrivant l'état du fond de panier. Source unique alimentant trois sorties cohérentes : la ligne stdout au boot, le champ `backplane` de la sonde (`/api/health`) et la vue Studio. Réutilisable par les tests / un agent IA sans dupliquer la connaissance « c'est quoi ce backplane ».

- `driver: string` — Nom du driver (clé du registre).
- `kind: string` — Nature du transport.
- `originId: string` — Identité de CE pair (process/pod).
- `crossPod: boolean` — `true` si le fan-out franchit les frontières de pod (multi-host).
- `channel?: string` — Canal/topic de transport, si applicable (canal Redis, topic Kafka).
- `sealed?: boolean` — Les messages sont-ils **scellés** (authenticité de l'émetteur vérifiée) ?
- `sealRejectedTotal?: number` — Messages reçus du bus dont le sceau est refusé — unité : un message reçu d'un exemplaire, jeté parce que son sceau ne se vérifie pas (ADR-0021 S6, S9).
- `queue?: IBackplaneQueueInfo` — État de la **file d'envoi** vers le bus (octets en vol, seuil, jetés).
- `bytes?: boolean` — Les octets d'une charge traversent-ils le bus intacts (`IBackplane.enableBytes`) ?

#### `IBackplaneQueueInfo`

```ts
interface IBackplaneQueueInfo
```

Compteurs de la **file d'envoi** d'un backplane à transport réseau : ce qui est publié mais pas encore acquitté par le bus. Sans borne, cette file (interne au client réseau) grossit sans limite sous rafale — d'où le seuil et ses compteurs, exposés jusqu'à la sonde et Studio. Cf `BackplanePublishQueue`.

- `bytes: number` — Octets publiés en attente d'acquittement par le transport (instantané).
- `maxBytes: number` — Seuil au-dessus duquel une publication est jetée ; `0` = illimité.
- `droppedTotal: number` — Publications JETÉES faute de place (monotone).
- `failedTotal: number` — Publications REFUSÉES par le transport (bus coupé…) (monotone).

#### `IChannelStats`

```ts
interface IChannelStats
```

Compteurs d'un canal — **génériques**, calculés au point d'arrivée des frames donc fiables et réutilisables par toute app. (`NodefonySocket.MessageStats` en est l'alias.)

- `method: string` — Méthode JSON-RPC == nom du canal pub/sub.
- `msgCount: number` — Total de notifications reçues sur ce canal.
- `lastMessage: number | null` — Timestamp (ms) de la dernière notification, `null` si aucune.
- `rate: number` — Débit instantané (msg/s), échantillonné 1×/s.
- `series: number[]` — Historique du débit (VU-mètre) — fenêtre glissante.

#### `IContractRoute`

```ts
interface IContractRoute
```

Une route servie par le pont, vue par le contrat : le schéma de son corps et de sa query — la VALEUR que la route valide, référencée par `typeof`, jamais recopiée —, et ce qu'elle rend.

- `body?: IStandardSchemaV1` — Schéma du corps (`schema: { body }` de la route).
- `query?: IStandardSchemaV1` — Schéma de la query (`schema: { query }` de la route).
- `params?: IStandardSchemaV1` — Schéma des paramètres de chemin (`schema: { params }` de la route) ; absent, leurs noms sont lus dans le gabarit de la clé (`{id}`).
- `result: unknown` — Ce que l'action rend.

#### `IFrameCodec`

```ts
interface IFrameCodec
```

Codec de frame de la socket temps réel : remplace, par frame, le `JSON.stringify` à l'envoi et le `JSON.parse` à la réception — aucun appel de plus.

- `readonly protocol: string` — Nom du sous-protocole offert par le client et annoncé dans `realtime:welcome`.
- `encode(frame: unknown): string | Uint8Array<ArrayBuffer>` — Sérialise une frame JSON-RPC pour le fil.
- `decode(data: string | Uint8Array): unknown` — Relit une trame reçue.
- `readonly textCodec?: IFrameCodec` — Pour un codec BINAIRE : le codec texte qui l'accompagne quand une connexion reste en `nodefony.jsonrpc.v1` — le JSON à convention d'octets (ADR-0022 §2).
- `readonly bytesMarker?: string` — Pour un codec TEXTE : le marqueur de la convention d'octets qu'il émet et réanime (`$bytes`).

#### `IInstanceErrorHealth`

```ts
interface IInstanceErrorHealth
```

Santé **erreurs per-instance** — compteurs Syslog monotones (cf `Syslog.errorTotal` / `Syslog.criticTotal`). Permet une carte « erreurs par worker » + un taux d'erreur pod (delta côté lecteur). Lecture pure d'entiers, 0 scan du ring buffer.

- `errorTotal: number` — Logs ERROR/CRITIC/ALERT/EMERGENCY cumulés (sévérité 0–3) (monotone).
- `criticTotal: number` — Sous-ensemble CRITIQUE : CRITIC/ALERT/EMERGENCY (sévérité 0–2) (monotone).

#### `IJsonRpcFrameSink`

```ts
interface IJsonRpcFrameSink
```

Sortie d'un pair qui laisse la SÉRIALISATION à son transport : il reçoit la frame en objet. Forme historique, conservée pour les transports qui ne parlent pas de codec (relais en mémoire, tests).

- `send: (frame: unknown) => boolean | void` — Envoie une frame sérialisable sur le transport (le peer ignore le transport).
- `write?: never`
- `admit?: never`
- `codec?: never`

#### `IJsonRpcPeerHooks`

```ts
interface IJsonRpcPeerHooks<Emit extends EventsMap = DefaultEventsMap, Listen extends EventsMap = DefaultEventsMap, Actions extends ActionsMap = DefaultActionsMap>
```

Crochets d'un pair JSON-RPC, communs aux deux formes de sortie.

- `onNotification?: RpcNotificationHandler<Listen>` — Notifications entrantes (`method` sans `id`) : pub/sub côté client, subscribe/unsubscribe côté serveur.
- `onError?: (context: string, err: unknown) => void` — Erreur interne — détail JAMAIS renvoyé au pair (journalisé ici) : un handler qui lève, une réponse ou une notification que le codec ne sait pas encoder.
- `beforeDispatch?: (frame: IJsonRpcRequest | IJsonRpcNotification, peer: IRealtimePeer<Emit, Actions>) => boolean` — **Seam sécurité 1/5 (P13 → P6)** — gate `beforeDispatch` appelé AVANT le dispatch d'une frame entrante (request ET notification — pas les responses, passives).
- `onFrameAudit?: (reason: FrameAuditReason, frame: unknown, peer: IRealtimePeer<Emit, Actions>) => void` — **Seam audit 5/5 (P13 → P6.14)** — fire-and-forget sur évènements protocolaires notables (cf `FrameAuditReason`).

#### `IJsonRpcWireSink`

```ts
interface IJsonRpcWireSink
```

Sortie d'un pair qui SÉRIALISE lui-même, avec son codec courant (ADR-0022 §4, ligne (i) : les codecs vivent dans le pair partagé, jamais dans le client ni dans le contrôleur). Le transport ne reçoit que des données prêtes pour le fil.

- `write: (data: string | Uint8Array<ArrayBuffer>, frame: unknown) => boolean | void` — Écrit une frame DÉJÀ encodée sur le transport.
- `admit?: () => boolean` — Contre-pression AVANT l'encodage : `false` → la frame n'est ni encodée ni écrite, et compte comme non émise.
- `codec?: IFrameCodec` — Codec du début de connexion — le texte `nodefony.jsonrpc.v1` par défaut, celui de l'accueil.
- `send?: never`

#### `INumericArrayConstructor`

```ts
interface INumericArrayConstructor<T extends NumericArray>
```

Constructeur d'un `NumericArray` — `Float64Array`, `Uint32Array`…

- `readonly BYTES_PER_ELEMENT: number` — Taille d'un élément, en octets.
- `new (buffer: ArrayBuffer, byteOffset?: number, length?: number): T`

#### `IOrmLeanHealth`

```ts
interface IOrmLeanHealth
```

Santé ORM **agrégée per-instance** (lean) — somme process-wide de tous les connecteurs enregistrés, dérivée des singletons `queryFlowMonitor` + `connectionMonitor` (0 ping, 0 `toSQL`, O(N connecteurs)). Rejoint le report de sonde du worker à chaque tick (≥ 1 s). Tous les cumuls sont **monotones** → débit/s dérivé côté lecteur (delta/ts, comme le CPU%).

- `connectors: number` — Connecteurs ORM enregistrés (registre).
- `connected: number` — Connecteurs actuellement connectés (`isConnected()`).
- `assumed: number` — Parmi les connectés, ceux dont l'état est **SUPPOSÉ** et non constaté : leur adapter n'a aucun signal de cycle de vie à traduire (base embarquée, driver muet), donc « connecté » y veut seulement dire …
- `queryTotal: number` — Requêtes ORM cumulées, tous connecteurs (monotone ; 0 si flux OFF en prod).
- `slowTotal: number` — Requêtes lentes cumulées (au-dessus du seuil `slowMs`) (monotone).
- `errorTotal: number` — Erreurs de connexion ORM cumulées (monotone).
- `reconnectTotal: number` — Reconnexions ORM cumulées (monotone).
- `maxEwmaMs: number | null` — Pire latence EWMA (ms) parmi les connecteurs (instantané), ou `null` si non observé.

#### `IPlatformRealtimeContract`

```ts
interface IPlatformRealtimeContract extends IRealtimeContract
```

Contrat des canaux `nodefony:*`. Une application l'ÉTEND pour ajouter les siens ; c'est la seule façon de typer, sur une même socket, les canaux de la plateforme et ceux de son métier.

- `serverToClient: PlatformServerToClient` — Canaux poussés par la plateforme (cf `PlatformServerToClient`).

#### `IProcessHealth`

```ts
interface IProcessHealth
```

Santé PROCESS d'un worker — lue par `ProcessProbe`, agrégée par worker dans le snapshot pod (cf `ClusterProbeAggregator`). Volontairement **lean** (sérialisée par worker à chaque tick de report ≥ 1 s) : juste de quoi peupler une grille « salle des machines » (1 carte/worker). Les sondes lourdes (GC, heap-spaces, ctx-switches) restent au canal `nodefony:supervision` per-process pour le drill-down.

- `pid: number` — PID du worker (= instanceId de la vue pod).
- `uptime: number` — Uptime du process (secondes).
- `cpuPercent: number` — % d'UN cœur sur l'intervalle (comme `top` : un Node mono-thread sature ~100).
- `eventLoopMs: number` — Retard moyen de la boucle sur l'intervalle (ms), période d'échantillonnage retranchée : 0 sur une boucle libre.
- `eventLoopMaxMs: number` — Pire retard de la boucle sur l'intervalle (ms) : le plus long blocage.
- `eluUtilization: number` — Saturation de la boucle (ELU) sur l'intervalle, 0–1 (~1 = thread saturé).
- `rss: number` — Resident Set Size (octets).
- `heapUsed: number` — Heap V8 utilisé (octets).
- `heapTotal: number` — Heap V8 total (octets).
- `heapLimit: number` — Plafond heap V8 (octets, constant) — pour `heapUsed/heapLimit` (% avant OOM).
- `external: number` — Mémoire hors-heap (buffers, etc.) (octets).
- `ts: number` — Horodatage de la mesure.

#### `IProcessRich`

```ts
interface IProcessRich
```

Sonde process **riche** d'un worker — le complément du lean `IProcessHealth` pour le drill-down (Phase 2). Ne contient QUE ce qui manque au lean : pression GC, répartition du heap V8, ressources actives, ELU active/idle (ms) et changements de contexte OS. Fusionné côté front avec le lean déjà présent dans le snapshot pod.

- `gc: { count: number; pauseMs: number; major: number; minor: number; }` — Pression GC sur l'intervalle (cycles, pause totale ms, majeurs/mineurs).
- `heapSpaces: { name: string; used: number; size: number; }[]` — Répartition mémoire V8 par espace (new/old/code/large_object…), octets.
- `handles: { total: number; byType: Record<string, number>; }` — Ressources actives qui tiennent la boucle, total + par type.
- `elu: { active: number; idle: number; }` — Saturation de la boucle sur l'intervalle (ms actifs / idle ; utilization est dans le lean).
- `ctx: { voluntary: number; involuntary: number; }` — Changements de contexte OS sur l'intervalle (volontaires = cède, involontaires = préempté).
- `loadavg: [ number, number, number ]` — Load average système (1/5/15 min).
- `heapLimit: number` — Limite de heap V8 du process (octets) — constante.
- `cpuCount: number` — Nombre de cœurs vus par le process — constante.
- `ts: number` — Horodatage de la mesure.

#### `IRealtimeChannel`

```ts
interface IRealtimeChannel
```

Handle d'UN canal — vue par-canal d'un sous-flux duplex multiplexé sur la `IRealtimeSocket`. Forme naturelle des canaux à état (un appel SIP, une connexion bridgée) : il porte son nom, sa nature et son cycle de vie. C'est le **point d'accroche** des couches à venir (codec de protocole, cadence AIMD, politique `drop|coalesce|batch`) — elles enrichiront ce handle SANS retoucher la socket.

- `readonly name: string` — Nom du canal (clé de multiplexage == method JSON-RPC des notifications).
- `readonly kind?: string` — Nature du backing serveur (`pubsub` | `protocol` | `bridge` | `proxy` | …), annoncée par le serveur.
- `on(handler: RealtimeHandler): () => void` — Branche un handler de réception sur ce canal.
- `send(payload?: object): void` — Émet sur ce canal (duplex, one-way) — même charge admise que `IRealtimeSocket.publish`.
- `open(): void` — Ouvre le flux : `subscribe` ref-compté (demande au pair de pousser).
- `close(): void` — Ferme : `unsubscribe` ref-compté + retire les handlers branchés via ce handle.

#### `IRealtimeChannelStat`

```ts
interface IRealtimeChannelStat
```

Stat per-canal du hub (fan-out).

- `channel: string` — Nom du canal (suffixe `:<ms>` de granularité inclus).
- `subscribers: number` — Abonnés locaux vivants (sinks) — instantané.
- `messages: number` — Publications cumulées sur ce canal (monotone) → débit dérivé côté lecteur.

#### `IRealtimeClosed`

```ts
interface IRealtimeClosed
```

Payload de la notification système `realtime:closed` — poussée par le serveur quand il met fin, de lui-même, à un abonnement en cours (ADR-0021 S4, ADR-0022 §6 décision 3).

- `channel: string` — Canal dont l'abonnement vient de prendre fin.
- `reason: RealtimeClosedReason` — Pourquoi (cf `RealtimeClosedReason`) — jamais le détail de la décision.

#### `IRealtimeClusterHealth`

```ts
interface IRealtimeClusterHealth
```

Vue **POD agrégée** de la socket (mode cluster) — la santé de TOUS les workers du pod consolidée. Servie par n'importe quel worker via l'endpoint santé quand le master pousse le snapshot agrégé (sinon on retombe sur `IRealtimeHealth` per-instance).

- `cluster: true` — Discriminant : vue agrégée multi-worker (≠ `IRealtimeHealth` per-instance).
- `ts: number` — Horodatage du snapshot agrégé (ms epoch).
- `instanceCount: number` — Nombre de workers présents dans l'agrégat.
- `instances: IRealtimeHealth[]` — Santé par worker (détail per-instance pour le drill-down).
- `totals: { channelCount: number; publishTotal: number; fanoutTotal: number; inboundTotal: number; ingressRejectedTotal: number; localOnlyTotal: number; connectionCount: number; bytesSentTotal: number; …` — Totaux pod (sommes des scalaires ; backpressure max = pire worker).

#### `IRealtimeContract`

```ts
interface IRealtimeContract
```

Le moule du contrat temps réel d'une application — déclaré UNE fois, dans un fichier partagé par ses deux côtés, et lu par chacun dans SA direction.

- `serverToClient?: EventsMap` — Événements poussés par le serveur (socket, flux SSE, webhook).
- `clientToServer?: EventsMap` — Événements envoyés par le client.
- `serverMethods?: ActionsMap` — Méthodes du serveur : le client appelle, le serveur répond.
- `clientMethods?: ActionsMap` — Méthodes du client : le serveur appelle, le client répond.
- `serverRoutes?: RoutesMap` — Routes servies par le pont `api.request` : `"<VERBE> <chemin>"` → schéma du corps et de la query (`typeof` du schéma que la route VALIDE — une seule source) et résultat.

#### `IRealtimeDenied`

```ts
interface IRealtimeDenied
```

Payload de la notification système `realtime:denied` — poussée par le serveur quand une frame `subscribe`/inbound est REFUSÉE par le verrou d'autorisation (P6). Rend le refus OBSERVABLE côté client (une notification, contrairement à une requête, serait sinon droppée en silence → le client resterait aveugle).

- `channel: string` — Canal (ou méthode inbound) refusé(e).
- `reason: RealtimeDeniedReason` — Motif générique (cf `RealtimeDeniedReason`) — jamais le détail de la policy.
- `detail?: string` — Ce qui s'est passé, en clair — **hors production UNIQUEMENT**.
- `retryAfterMs?: number` — Délai minimal, en millisecondes, avant de réessayer — posé seulement avec `reason: "unavailable"`, quand le serveur sait combien de temps il restera indisponible (coupe-circuit ouvert).

#### `IRealtimeHealth`

```ts
interface IRealtimeHealth extends IRealtimeProbe
```

Snapshot enrichi de l'identité d'instance — santé per-instance d'un worker/pod.

- `instanceId: string` — Identifiant de CE process/pod (per-instance).
- `process?: IProcessHealth` — Santé PROCESS du worker (CPU/mém/event-loop) — additif : la grille « salle des machines » de la vue pod lit `instances[].process` par worker.
- `rich?: IProcessRich` — Sonde process **riche** (GC/heap-spaces/handles/ELU active-idle/ctx-switches) — présente UNIQUEMENT pendant un drill-down de CE worker (le master a envoyé `nf:probe:enrich` à ce pid).
- `orm?: IOrmLeanHealth` — Santé ORM **lean** du worker (connecteurs/requêtes/erreurs/latence EWMA) — additif, comme `process`.
- `errors?: IInstanceErrorHealth` — Compteurs d'erreurs Syslog du worker (ERROR/CRITIC cumulés) — additif.
- `backplaneDrivers?: string[]` — Drivers de backplane **enregistrés dans ce process** (clés du registre ouvert : natifs + ceux qu'une application a ajoutés par `registerBackplaneDriver`).
- `ormRich?: unknown` — Diagnostic ORM **riche** du worker (par connecteur : ping/latence/stockage/pool + flux requêtes) — blob OPAQUE `{ health, flow }` produit par le driver, présent UNIQUEMENT pendant un drill ORM de CE w …

#### `IRealtimePeer`

```ts
interface IRealtimePeer<Emit extends EventsMap = DefaultEventsMap, Actions extends ActionsMap = DefaultActionsMap>
```

- `request<K extends ActionNames<Actions>>(method: K, params?: ActionParams<Actions, K>, timeoutMs?: number): Promise<ActionResult<Actions, K>>` — Requête sortante → `Promise` du `result` (rejette sur `error`/timeout).
- `notify<K extends EventNames<Emit>>(method: K, params?: EventPayload<Emit, K>): void` — Notification sortante (pas de réponse).
- `register<K extends ActionNames<Actions>>(method: K, handler: TypedRpcActionHandler<Actions, K>): void` — Expose une action appelable par le pair (requête entrante → `result`).
- `unregister(method: ActionNames<Actions>): void` — Retire une action.
- `receive(frame: unknown): JsonRpcFrameKind` — Ingestion d'une frame ENTRANTE (déjà parsée) → classe + route.
- `readonly methods: string[]` — Actions exposées (découverte).
- `dispose(reason?: string): void` — Annule les requêtes en attente (fermeture transport).

#### `IRealtimeProbe`

```ts
interface IRealtimeProbe
```

Snapshot PUR du hub (sans identité process) — ce que renvoie `RealtimeHub.probe()`. Per-instance/pod (cloud-native) ; l'agrégat multi-pod = backplane Redis / Prometheus.

- `ts: number` — Horodatage du snapshot (ms epoch) — base du calcul de débit côté lecteur.
- `channels: IRealtimeChannelStat[]` — Canaux actifs (≥ 1 abonné) avec abonnés + publications cumulées.
- `channelCount: number` — Nombre de canaux actifs (= 1 provider/canal/pod).
- `publishTotal: number` — Appels `publish` cumulés (monotone).
- `fanoutTotal: number` — Livraisons cumulées (`publish` × abonnés) — vrai coût de fan-out (monotone).
- `inboundTotal: number` — Frames entrantes full-duplex cumulées (canaux gated SIP/bridge) (monotone).
- `ingressRejectedTotal: number` — Messages d'ingress backplane REFUSÉS (canal non déclaré broadcast) — monotone.
- `localOnlyTotal: number` — Publications restées sur CE serveur alors qu'un bus est branché — canal non déclaré diffusable (`@RealtimeBroadcast`) — monotone ; toujours 0 sans bus.
- `systemFloorDeniedTotal: number` — Abonnements clients REFUSÉS par le plancher des canaux de plateforme — monotone.
- `sealRejectedTotal: number` — Messages du bus REFUSÉS parce que leur sceau ne se vérifie pas — monotone, unité : un message reçu d'un exemplaire.
- `frameRateRejectedTotal: number` — Trames entrantes ÉCARTÉES par la borne de débit, avant tout décodage — monotone, unité : une trame reçue.
- `allowTimedOutTotal: number` — Appels d'`allow` restés SANS RÉPONSE dans `allowTimeoutMs` — monotone, unité : un appel d'`allow`.
- `allowSaturatedTotal: number` — Demandes d'abonnement rendues `unavailable` SANS appel d'`allow` — monotone, unité : une demande.
- `authenticateTimedOutTotal: number` — Poignées de main fermées en `1013` faute d'authentification dans `authenticateTimeoutMs` — monotone, unité : une poignée de main.
- `binaryDiscardedTotal: number` — Trames BINAIRES reçues et écartées faute de lecteur — monotone, unité : une trame reçue.
- `malformedDiscardedTotal: number` — Trames reçues et écartées parce qu'illisibles par le codec de la connexion — JSON invalide, CBOR tronqué — monotone, unité : une trame reçue.
- `connectionCount: number` — Connexions realtime vivantes.
- `bytesSentTotal: number` — Somme cumulée des octets envoyés, toutes connexions, fermées comprises (monotone).
- `messagesSentTotal: number` — Somme cumulée des frames envoyées, toutes connexions, fermées comprises (monotone).
- `backpressure: { maxBufferedAmount: number; totalBufferedAmount: number; slowConsumers: number; drops: number; }` — Backpressure agrégée (instantanée) — risque #1.
- `backplane?: IBackplaneInfo` — Carte d'identité du backplane effectif (driver, transport, cross-pod, canal).

#### `IRealtimeSocket`

```ts
interface IRealtimeSocket<Emit extends EventsMap = DefaultEventsMap, Listen extends EventsMap = DefaultEventsMap>
```

Contrat de « la socket Nodefony » — voir le bloc de tête du fichier. Implémenté par `NodefonySocket` (front) et, à terme, par une façade serveur au-dessus du hub.

- `subscribe(channel: EventNames<Listen> | (string & {})): void` — S'abonne à un canal (ref-compté) : émet la demande au pair UNIQUEMENT au 1ᵉʳ consommateur ; ré-émise automatiquement à chaque (re)connexion.
- `unsubscribe(channel: EventNames<Listen> | (string & {})): void` — Désabonne un consommateur (ref-compté) : coupe le flux réseau au DERNIER.
- `on<K extends string>(channel: K, handler: K extends EventNames<Listen> ? (payload: EventPayload<Listen, K>) => void : RealtimeHandler): () => void` — Branche un handler sur un canal (réception).
- `off<K extends string>(channel: K, handler: K extends EventNames<Listen> ? (payload: EventPayload<Listen, K>) => void : RealtimeHandler): void` — Retire un handler d'un canal.
- `publish<K extends string>(channel: K, payload?: K extends EventNames<Emit> ? EventPayload<Emit, K> : object): void` — Émet sur un canal (one-way, pas de réponse).
- `channel(name: string): IRealtimeChannel` — Vue par-canal — voir `IRealtimeChannel`.
- `getStats(): IChannelStats[]` — Snapshot des compteurs par canal (refs internes — à LIRE, pas à muter).
- `getChannelStats(channel: string): IChannelStats` — Compteurs d'un canal précis (== method JSON-RPC) ou `undefined`.
- `readonly subscribedChannels: string[]` — Canaux actuellement abonnés (≥ 1 consommateur).

#### `IRealtimeSubscribed`

```ts
interface IRealtimeSubscribed
```

Payload de la notification système `realtime:subscribed` — poussée par le serveur quand un `subscribe` est ACCEPTÉ, y compris pour un canal que la connexion suivait déjà (sans quoi un `subscribe` réémis attendrait un acquittement qui ne vient jamais).

- `channel: string` — Canal dont l'abonnement est désormais effectif sur cette connexion.
- `imposed?: true` — `true` quand c'est le SERVEUR qui a abonné la connexion (abonnement imposé, ADR-0022 §6 décision 2) — absent pour la réponse à un `subscribe` du client.

#### `IRealtimeTransport`

```ts
interface IRealtimeTransport
```

- `connect(): void` — Ouvre le transport (asynchrone — l'ouverture effective est signalée par `onOpen`).
- `send(raw: RealtimeOutboundData): void` — Envoie une frame brute (texte sérialisé ou octets).
- `close(code?: number, reason?: string): void` — Ferme le transport (déclenche `onClose`).
- `readonly readyState: number` — État courant (0..3, cf `TransportState`).
- `readonly bufferedAmount?: number` — Octets en attente d'envoi (`WebSocket.bufferedAmount`) ; absent = inconnu, lu comme `0` — la contre-pression du client ne refuse alors jamais.
- `onOpen(cb: () => void): void` — Branche le handler d'ouverture (le owner relance subscribe/heartbeat).
- `onMessage(cb: (raw: RealtimeFrameData) => void): void` — Branche le pump entrant : appelé pour CHAQUE frame brute reçue, texte ou binaire — jamais filtrée ici (cf `RealtimeFrameData`).
- `onClose(cb: (code: number, reason: string) => void): void` — Branche la fermeture (le owner relance le backoff ou nettoie).
- `onError(cb: (err: unknown) => void): void` — Branche les erreurs transport (la fermeture qui suit gère le reconnect).

#### `IRealtimeWelcome`

```ts
interface IRealtimeWelcome
```

Payload de la notification système `realtime:welcome` — **1ʳᵉ frame** poussée par le serveur juste après le handshake. Annonce le protocole, les canaux/actions **découvrables** de l'endpoint et l'`RealtimeIdentity` résolue de la connexion. Cold path (1×/connexion).

- `ts: number` — Timestamp serveur (ms epoch).
- `protocol: string` — Étiquette de protocole (`"jsonrpc-2.0"`).
- `channels: string[]` — Canaux pub/sub annoncés par l'endpoint (découverte).
- `methods: string[]` — Actions RPC exposées par l'endpoint (découverte).
- `identity: RealtimeIdentity` — Identité résolue de CETTE connexion (cf `RealtimeIdentity`).
- `env?: string` — Mode d'exécution du serveur — **posé UNIQUEMENT hors production**.
- `subscriptionAcks?: boolean` — Le serveur ACQUITTE chaque abonnement accepté (`realtime:subscribed`, cf `IRealtimeSubscribed`).
- `codec?: string` — Sous-protocole du codec retenu pour les frames qui SUIVENT cet accueil — l'un de ceux que le client a offerts au handshake (ADR-0022 §2, cf `IFrameCodec`).
- `bytes?: string` — Marqueur de la convention d'octets (`$bytes`) que le serveur émet sur cette connexion TEXTE — posé quand il a activé un codec binaire que le client n'a pas pris (ADR-0022 §2).

#### `ISupervisionHistory`

```ts
interface ISupervisionHistory
```

Historique tel qu'il voyage : séries linéarisées du plus ancien au plus récent, colonne après colonne, en octets petit-boutistes (relire par `fromLittleEndianBytes`). La colonne `c` occupe les éléments `[c × length, (c + 1) × length)` de la série relue.

- `intervalMs: number` — Cadence d'échantillonnage, en ms.
- `capacity: number` — Points retenus au plus par série.
- `length: number` — Points présents (≤ `capacity`) — 0 à la première visite.
- `columns: readonly string[]` — Nom des colonnes de `values` (`SUPERVISION_HISTORY_COLUMNS`).
- `values: Uint8Array<ArrayBuffer>` — `Float64` petit-boutiste, `columns.length × length` éléments.
- `loopColumns: readonly string[]` — Nom des colonnes de `loop` (`SUPERVISION_LOOP_BANDS`).
- `loop: Uint8Array<ArrayBuffer>` — `Float32` petit-boutiste, `loopColumns.length × length` éléments (ms).

#### `RateBounds`

```ts
interface RateBounds
```

Bornes de cadence d'un canal cadencé (toutes en millisecondes).

- `readonly default: number` — Cadence par défaut — celle du canal de base nu (sans suffixe).
- `readonly min: number` — Borne basse (cadence minimale autorisée, anti-DoS event-loop).
- `readonly max: number` — Borne haute (cadence maximale autorisée).

#### `RealtimeIdentity`

```ts
interface RealtimeIdentity
```

Identité d'une connexion temps réel, telle que **résolue par le serveur au handshake** (token neutre `IRealtimeToken` côté back) et **annoncée au client** dans la notification système `realtime:welcome`.

- `type: string` — Type de token résolu (`"anonymous"`, `"session"`, `"jwt"`, …) — discriminator.
- `authenticated: boolean` — `false` pour un visiteur anonyme (Zero Trust : toujours présent, jamais `null`).
- `id: string | null` — Identifiant STABLE et OPAQUE du compte — la clé des canaux personnels (`user:${id}`) ; `null` pour l'anonyme, et pour un authentificateur qui ne produit pas d'identité d'admission (`IRealtimeToken.get …
- `userIdentifier: string` — Identifiant logique du porteur (`"anonymous"`, `"user-42"`, …) — affichage et audit, jamais une clé de canal.
- `roles: readonly string[]` — Rôles **plats** (RBAC, sans hiérarchie résolue) — `["ROLE_ANONYMOUS"]` si anonyme.
- `scopes: readonly string[]` — Scopes accordés (clés API / OAuth) — `[]` en session BFF web.

### Types (31)

#### `BridgeVerb`

```ts
type BridgeVerb = "GET" | "POST" | "PUT" | "PATCH" | "DELETE"
```

Verbe HTTP d'une action servie par le pont `api.request` — le pont n'en sert pas d'autre.

#### `ContractClientActions`

```ts
type ContractClientActions<C extends IRealtimeContract> = MethodsSeenBy<ContractSide<C, "serverMethods", ActionsMap>, "out"> & MethodsSeenBy<ContractSide<C, "clientMethods", ActionsMap>, "in">
```

Les méthodes du client vues par `NodefonySocket` : `serverMethods` qu'il appelle (`request`, résultat lu par `Jsonify`) et `clientMethods` qu'il implémente (`register`, paramètres lus par `Jsonify`). La socket range les deux sous un seul générique `Actions` : une méthode déclarée des deux côtés sous le même nom n'a pas de sens, le contrat ne la sépare pas.

#### `ContractClientEmit`

```ts
type ContractClientEmit<C extends IRealtimeContract> = ContractSide<C, "clientToServer", EventsMap>
```

Ce que le client ÉMET : `clientToServer`, tel que déclaré.

#### `ContractClientListen`

```ts
type ContractClientListen<C extends IRealtimeContract> = ReceivedEvents<ContractSide<C, "serverToClient", EventsMap>>
```

Ce que le client REÇOIT : `serverToClient`, lu par `Jsonify`.

#### `ContractClientRoutes`

```ts
type ContractClientRoutes<C extends IRealtimeContract> = ContractSide<C, "serverRoutes", RoutesMap>
```

Les routes du pont qu'un client appelle — `serverRoutes` du contrat, ou la carte permissive si le contrat n'en déclare pas.

#### `ContractRouteBody`

```ts
type ContractRouteBody<R extends RoutesMap, K extends string> = K extends DeclaredRouteKeys<R> ? RoutePart<R, K, "body"> : unknown
```

Le corps qu'accepte une route du pont : l'entrée de son schéma quand la clé `K` (`"<VERBE> <chemin>"`) appartient au contrat, `undefined` si la route déclarée n'a pas de corps, libre (`unknown`) hors contrat.

#### `ContractRouteParams`

```ts
type ContractRouteParams<R extends RoutesMap, K extends string, P extends string> = K extends DeclaredRouteKeys<R> ? "params" extends keyof R[K & keyof R] ? RoutePart<R, K & keyof R, "params"> : TemplateParams<P> : TemplateParams<P>
```

Les paramètres de chemin qu'accepte une route du pont : l'entrée de son schéma `params` quand la route déclarée en a un, sinon une valeur par `{nom}` du gabarit `P` — sous contrat comme hors contrat.

#### `ContractRouteQuery`

```ts
type ContractRouteQuery<R extends RoutesMap, K extends string> = K extends DeclaredRouteKeys<R> ? RoutePart<R, K, "query"> : unknown
```

La query qu'accepte une route du pont — pendant de `ContractRouteBody`.

#### `ContractRouteResult`

```ts
type ContractRouteResult<R extends RoutesMap, K extends string, T> = K extends DeclaredRouteKeys<R> ? R[K & keyof R] extends { result: infer X; } ? Jsonify<X> : unknown : T
```

Ce que rend une route du pont, lu par `Jsonify` (il a traversé le fil) quand `K` appartient au contrat ; sinon le `T` que l'appelant demande.

#### `JsonRpcErrorObject`

```ts
type JsonRpcErrorObject = IJsonRpcErrorObject
```

Erreur JSON-RPC 2.0 (objet `error` d'une réponse).

#### `JsonRpcPeerOptions`

```ts
type JsonRpcPeerOptions<Emit extends EventsMap = DefaultEventsMap, Listen extends EventsMap = DefaultEventsMap, Actions extends ActionsMap = DefaultActionsMap> = IJsonRpcPeerHooks<Emit, Listen, Actions> & (IJsonRpcFrameSink | IJsonRpcWireSink)
```

Options d'un `JsonRpcPeer` : ses crochets, et UNE sortie — `send` (le transport sérialise) ou `write` (le pair encode avec son codec).

#### `Jsonify`

```ts
type Jsonify<T, D extends number = 10> = unknown extends T ? T : [ D ] extends [ never ] ? unknown : T extends Uint8Array ? T : T extends { toJSON(...args: never[]): infer R; } ? Jsonify<R, JsonifyDepth[D]> : T extends JsonPrimitive | void ? T : T extends bigint | symbol | (...args: never[]) => unknown ? never : T extends readonly unknown[] ? { [I in keyof T]: JsonifyItem<T[I], JsonifyDepth[D]>; } …
```

Le type qu'un pair REÇOIT quand l'autre a envoyé un `T` : ce que JSON en fait.

#### `NumericArray`

```ts
type NumericArray = Float64Array<ArrayBuffer> | Float32Array<ArrayBuffer> | Uint32Array<ArrayBuffer> | Int32Array<ArrayBuffer> | Uint16Array<ArrayBuffer> | Int16Array<ArrayBuffer>
```

Tableaux typés numériques transportables (un élément = taille fixe).

#### `PlatformChannel`

```ts
type PlatformChannel = (typeof PLATFORM_CHANNELS)[keyof typeof PLATFORM_CHANNELS]
```

Nom d'un canal de plateforme (valeur de `PLATFORM_CHANNELS`).

#### `PlatformInboundChannel`

```ts
type PlatformInboundChannel = (typeof PLATFORM_INBOUND)[keyof typeof PLATFORM_INBOUND]
```

Nom d'un canal montant de plateforme (valeur de `PLATFORM_INBOUND`).

#### `PlatformMethod`

```ts
type PlatformMethod = (typeof PLATFORM_METHODS)[keyof typeof PLATFORM_METHODS]
```

Nom d'une méthode RPC de plateforme (valeur de `PLATFORM_METHODS`).

#### `PlatformServerToClient`

```ts
type PlatformServerToClient = { [K in (typeof PLATFORM_CHANNELS)["socket"]]: RealtimeHealthReport; }
```

Canaux de plateforme : nom → charge poussée par le serveur.

#### `RealtimeClosedReason`

```ts
type RealtimeClosedReason = "ended" | "evicted"
```

Motif d'un `realtime:closed`. Fermé exprès, comme `RealtimeDeniedReason` : le client doit pouvoir traiter tous les cas.

#### `RealtimeDeniedReason`

```ts
type RealtimeDeniedReason = "forbidden" | "limit" | "unknown" | "unavailable"
```

Motif d'un `realtime:denied`. Fermé exprès : le client doit pouvoir traiter TOUS les cas (le compilateur le lui rappelle), et un motif inventé côté serveur ne doit pas atteindre un écran qui ne sait pas le dire.

#### `RealtimeFrameData`

```ts
type RealtimeFrameData = string | Uint8Array<ArrayBuffer>
```

Une frame brute telle que le transport la reçoit : du texte, ou des octets.

#### `RealtimeHandler`

```ts
type RealtimeHandler = { handle(...args: unknown[]): void; }["handle"]
```

Handler d'un canal pub/sub — reçoit le `params` de la notification (ou `(method, params)` sur `"*"`).

#### `RealtimeHealthReport`

```ts
type RealtimeHealthReport = IRealtimeClusterHealth | IRealtimeHealth
```

Ce que publie `nodefony:socket` et ce que rend `/nodefony/realtime/api/health` : la vue POD agrégée en mode cluster, sinon la santé du seul worker qui répond. Le discriminant est `cluster: true`.

#### `RealtimeOutboundData`

```ts
type RealtimeOutboundData = RealtimeFrameData
```

Ce qu'un transport accepte d'émettre : une frame texte déjà sérialisée, ou des octets tels quels — le même type qu'en réception (cf `RealtimeFrameData`).

#### `RealtimeTransportFactory`

```ts
type RealtimeTransportFactory = (url: string, protocols?: readonly string[]) => IRealtimeTransport
```

Fabrique d'un transport pour une URL — injectable (tests, transports alternatifs).

#### `RoutePathParamNames`

```ts
type RoutePathParamNames<P extends string> = P extends `${string}{${infer Name}}${infer Rest}` ? Name | RoutePathParamNames<Rest> : never
```

Noms des variables d'un gabarit de chemin — `"/a/{id}/b/{slug}"` → `"id" | "slug"` ; `never` sans variable. Même lecture que `routePathParams` (`runtime/routePath.ts`).

#### `RoutesMap`

```ts
type RoutesMap = Record<`${BridgeVerb} /${string}`, IContractRoute>
```

Carte des routes du pont : `"<VERBE> <chemin>"` → `IContractRoute`. Le chemin est celui de la route montée, préfixe du contrôleur compris.

#### `RpcActionHandler`

```ts
type RpcActionHandler = { handle(params: unknown): unknown; }["handle"]
```

Handler d'une action (requête→réponse). Sync ou async ; throw → `-32603`.

#### `RpcNotificationHandler`

```ts
type RpcNotificationHandler<Listen extends EventsMap = DefaultEventsMap> = <K extends EventNames<Listen>>(method: K, params: EventPayload<Listen, K>) => void
```

Handler des notifications entrantes (pas de réponse). Paramétrable par `Listen` (map des notifications REÇUES par ce peer). Défaut permissif → comportement pré-types-partagés inchangé.

#### `SupervisionHistoryPoint`

```ts
type SupervisionHistoryPoint = Record<(typeof SUPERVISION_HISTORY_COLUMNS)[number] | (typeof SUPERVISION_LOOP_BANDS)[number], number>
```

Un point de l'historique — une valeur par colonne et par bande.

#### `ThroughputPayloadSize`

```ts
type ThroughputPayloadSize = (typeof THROUGHPUT_PAYLOAD_SIZES)[number]
```

Une des tailles de `THROUGHPUT_PAYLOAD_SIZES`.

#### `TransportStateValue`

```ts
type TransportStateValue = (typeof TransportState)[keyof typeof TransportState]
```

---

[← Toutes les références d'API](../../)
