Référence d'API — nodefony/client — realtime
stable
Documentation › Référence d’API › nodefony › sous-chemin-client-realtime
Générée depuis les déclarations de types publiées de
nodefony10.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#
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 (sortiewrite) et relit l’entrée (decode).set codec(codec: IFrameCodec)— Codec de la connexion — celui qui encode les émissions (sortiewrite) 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 entrantemethod+id→result).registerHandler(method: string, handler: RpcActionHandler): void— Expose une action sous un nom quelconque — la forme non typée deJsonRpcPeer.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 —Promiserésolue avec leresult(rejette surerror/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 —requestAsqui garde la méta serveur, commerequestTraced.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 duresultnu.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#
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?: unknownconstructor(message: string, code?: number, data?: unknown)
Fonctions (11)#
createIdempotencyKey#
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#
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#
function fromLittleEndianBytes<T extends NumericArray>(bytes: Uint8Array<ArrayBuffer>, ctor: INumericArrayConstructor<T>, littleEndian?: boolean): T
Relit une série émise par toLittleEndianBytes.
isPlatformChannel#
function isPlatformChannel(name: string): boolean
Le nom désigne-t-il une surface de la plateforme (canal OU méthode) ?
isRateChannel#
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#
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#
function isThroughputPayloadSize(value: unknown): value is ThroughputPayloadSize
true si value est une taille admise par la sonde de débit.
parseRate#
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#
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#
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#
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#
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#
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#
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#
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#
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#
const PLATFORM_INBOUND: { readonly syslogUplink: "nodefony:syslog:uplink"; }
Canaux MONTANTS de la plateforme (le navigateur pousse, le pod reçoit).
PLATFORM_LITTLE_ENDIAN#
const PLATFORM_LITTLE_ENDIAN: boolean
true si la machine range ses nombres en petit-boutiste (constaté, pas déduit).
PLATFORM_METHODS#
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#
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#
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#
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#
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#
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—truesi 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#
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#
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,nullsi aucune.rate: number— Débit instantané (msg/s), échantillonné 1×/s.series: number[]— Historique du débit (VU-mètre) — fenêtre glissante.
IContractRoute#
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#
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é dansrealtime: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 ennodefony.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#
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#
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?: neveradmit?: nevercodec?: never
IJsonRpcPeerHooks#
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 (methodsansid) : 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) — gatebeforeDispatchappelé 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 (cfFrameAuditReason).
IJsonRpcWireSink#
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 textenodefony.jsonrpc.v1par défaut, celui de l’accueil.send?: never
INumericArrayConstructor#
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#
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 seuilslowMs) (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é), ounullsi non observé.
IPlatformRealtimeContract#
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 (cfPlatformServerToClient).
IProcessHealth#
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 (commetop: 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) — pourheapUsed/heapLimit(% avant OOM).external: number— Mémoire hors-heap (buffers, etc.) (octets).ts: number— Horodatage de la mesure.
IProcessRich#
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#
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 queIRealtimeSocket.publish.open(): void— Ouvre le flux :subscriberef-compté (demande au pair de pousser).close(): void— Ferme :unsubscriberef-compté + retire les handlers branchés via ce handle.
IRealtimeChannelStat#
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#
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 (cfRealtimeClosedReason) — jamais le détail de la décision.
IRealtimeClusterHealth#
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 (≠IRealtimeHealthper-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#
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 pontapi.request:"<VERBE> <chemin>"→ schéma du corps et de la query (typeofdu schéma que la route VALIDE — une seule source) et résultat.
IRealtimeDenied#
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 (cfRealtimeDeniedReason) — 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 avecreason: "unavailable", quand le serveur sait combien de temps il restera indisponible (coupe-circuit ouvert).
IRealtimeHealth#
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 litinstances[].processpar 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, commeprocess.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 parregisterBackplaneDriver).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#
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 →Promiseduresult(rejette surerror/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#
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— Appelspublishcumulé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’allowrestés SANS RÉPONSE dansallowTimeoutMs— monotone, unité : un appel d’allow.allowSaturatedTotal: number— Demandes d’abonnement renduesunavailableSANS appel d’allow— monotone, unité : une demande.authenticateTimedOutTotal: number— Poignées de main fermées en1013faute d’authentification dansauthenticateTimeoutMs— 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#
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 — voirIRealtimeChannel.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) ouundefined.readonly subscribedChannels: string[]— Canaux actuellement abonnés (≥ 1 consommateur).
IRealtimeSubscribed#
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—truequand c’est le SERVEUR qui a abonné la connexion (abonnement imposé, ADR-0022 §6 décision 2) — absent pour la réponse à unsubscribedu client.
IRealtimeTransport#
interface IRealtimeTransport
connect(): void— Ouvre le transport (asynchrone — l’ouverture effective est signalée paronOpen).send(raw: RealtimeOutboundData): void— Envoie une frame brute (texte sérialisé ou octets).close(code?: number, reason?: string): void— Ferme le transport (déclencheonClose).readonly readyState: number— État courant (0…3, cfTransportState).readonly bufferedAmount?: number— Octets en attente d’envoi (WebSocket.bufferedAmount) ; absent = inconnu, lu comme0— 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 (cfRealtimeFrameData).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#
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 (cfRealtimeIdentity).env?: string— Mode d’exécution du serveur — posé UNIQUEMENT hors production.subscriptionAcks?: boolean— Le serveur ACQUITTE chaque abonnement accepté (realtime:subscribed, cfIRealtimeSubscribed).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, cfIFrameCodec).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#
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 devalues(SUPERVISION_HISTORY_COLUMNS).values: Uint8Array<ArrayBuffer>—Float64petit-boutiste,columns.length × lengthéléments.loopColumns: readonly string[]— Nom des colonnes deloop(SUPERVISION_LOOP_BANDS).loop: Uint8Array<ArrayBuffer>—Float32petit-boutiste,loopColumns.length × lengthéléments (ms).
RateBounds#
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#
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—falsepour un visiteur anonyme (Zero Trust : toujours présent, jamaisnull).id: string | null— Identifiant STABLE et OPAQUE du compte — la clé des canaux personnels (user:${id}) ;nullpour 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#
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#
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#
type ContractClientEmit<C extends IRealtimeContract> = ContractSide<C, "clientToServer", EventsMap>
Ce que le client ÉMET : clientToServer, tel que déclaré.
ContractClientListen#
type ContractClientListen<C extends IRealtimeContract> = ReceivedEvents<ContractSide<C, "serverToClient", EventsMap>>
Ce que le client REÇOIT : serverToClient, lu par Jsonify.
ContractClientRoutes#
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#
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#
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#
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#
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#
type JsonRpcErrorObject = IJsonRpcErrorObject
Erreur JSON-RPC 2.0 (objet error d’une réponse).
JsonRpcPeerOptions#
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#
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#
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#
type PlatformChannel = (typeof PLATFORM_CHANNELS)[keyof typeof PLATFORM_CHANNELS]
Nom d’un canal de plateforme (valeur de PLATFORM_CHANNELS).
PlatformInboundChannel#
type PlatformInboundChannel = (typeof PLATFORM_INBOUND)[keyof typeof PLATFORM_INBOUND]
Nom d’un canal montant de plateforme (valeur de PLATFORM_INBOUND).
PlatformMethod#
type PlatformMethod = (typeof PLATFORM_METHODS)[keyof typeof PLATFORM_METHODS]
Nom d’une méthode RPC de plateforme (valeur de PLATFORM_METHODS).
PlatformServerToClient#
type PlatformServerToClient = { [K in (typeof PLATFORM_CHANNELS)["socket"]]: RealtimeHealthReport; }
Canaux de plateforme : nom → charge poussée par le serveur.
RealtimeClosedReason#
type RealtimeClosedReason = "ended" | "evicted"
Motif d’un realtime:closed. Fermé exprès, comme RealtimeDeniedReason : le client doit pouvoir traiter tous les cas.
RealtimeDeniedReason#
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#
type RealtimeFrameData = string | Uint8Array<ArrayBuffer>
Une frame brute telle que le transport la reçoit : du texte, ou des octets.
RealtimeHandler#
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#
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#
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#
type RealtimeTransportFactory = (url: string, protocols?: readonly string[]) => IRealtimeTransport
Fabrique d’un transport pour une URL — injectable (tests, transports alternatifs).
RoutePathParamNames#
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#
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#
type RpcActionHandler = { handle(params: unknown): unknown; }["handle"]
Handler d’une action (requête→réponse). Sync ou async ; throw → -32603.
RpcNotificationHandler#
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#
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#
type ThroughputPayloadSize = (typeof THROUGHPUT_PAYLOAD_SIZES)[number]
Une des tailles de THROUGHPUT_PAYLOAD_SIZES.
TransportStateValue#
type TransportStateValue = (typeof TransportState)[keyof typeof TransportState]