Référence d'API — @nodefony/realtime — server
stable
Documentation › Référence d’API › @nodefony/realtime › server
Générée depuis les déclarations de types publiées de
@nodefony/realtime10.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/realtime#
import { … } from "@nodefony/realtime" — 28 symboles.
Classes (6)#
ChannelFrame#
class ChannelFrame
Frame d’UNE publication diffusée à plusieurs abonnés, encodée au plus une fois par codec (ADR-0022 §2) : un canal suivi par des connexions texte et CBOR paie deux encodages, jamais un par connexion. L’encodage est paresseux — un codec qu’aucun abonné n’utilise ne coûte rien.
constructor(message: unknown)encodeFor(codec: IFrameCodec): RealtimeFrameData— Rend la frame encodée pour un codec, en l’encodant à la première demande.claimFailure(codec: IFrameCodec): boolean— Réclame l’échec d’encodage de cette frame pour un codec :trueau PREMIER abonné qui le demande,falseensuite.
ContractRealtimeControllerBase#
abstract class ContractRealtimeControllerBase<C extends IRealtimeContract> extends RealtimeController<ContractServerEmit<C>, ContractServerActions<C>, ContractServerListen<C>>
Socle commun des deux formes de ContractRealtimeController : l’étiquette de contrat et les canaux annoncés. Les actions y gardent le défaut de la base ({}) — un contrat SANS serverMethods n’a rien à écrire.
readonly [contractType]?: C— Étiquette de TYPE : relie la classe à son contrat pour que@RealtimePolicyle retrouve.protected realtimeChannels(): EventNames<ContractServerEmit<C>>[]— Canaux annoncés au handshake, contraints aux noms deserverToClient.
ContractRealtimeControllerStrict#
abstract class ContractRealtimeControllerStrict<C extends IRealtimeContract> extends ContractRealtimeControllerBase<C>
Forme stricte de ContractRealtimeController, retenue quand le contrat déclare des serverMethods : realtimeActions() y devient ABSTRAITE et typée par le contrat — la seule construction qui fait d’une méthode OUBLIÉE une erreur de compilation (un décorateur ne voit jamais la classe entière).
protected abstract realtimeActions(): ContractRealtimeMethodHandlers<C>— Les méthodes du contrat servies par ce contrôleur — toutes, et par cette table SEULE : une action servie ici ne se décore pas en plus de@RealtimeAction(handler fabriqué puis écrasé à chaque connex …
RealtimeController#
abstract class RealtimeController<Emit extends EventsMap = DefaultEventsMap, Actions extends ActionsMap = DefaultActionsMap, Listen extends EventsMap = DefaultEventsMap> extends Controller implements IRealtimeController
RealtimeController — base d’un endpoint WebSocket temps réel SERVEUR (JSON-RPC 2.0).
static scope: ControllerScope— Une instance PAR CONNEXION, par construction — le défautsingletondes contrôleurs ne s’applique pas ici.static assertScope(): void— Refuse qu’une sous-classe se déclare singleton — au démarrage (Router.setController), et au constructeur pour qui construit parnewhors du routeur (harnais de test).constructor(name: string, context: ContextType)createRealtimeChannel(_channel: string, _publish: RealtimePublish): () => void | null— Crée le provider d’un canal (listener/ticker →publish) et renvoie sondispose.protected realtimeActions(): Record<string, RealtimeActionHandler>— Actions RPC exposées (requête→réponse).protected realtimeChannels(): string[]— Canaux annoncés au handshake.protected realtimeBroadcastChannels(): string[]— Préfixes de canaux broadcast (cross-process) de cet endpoint.protected realtimeInbound(): RealtimeInboundHandlers<Listen, Emit>— Canaux FULL-DUPLEX acceptant une entrée client (method= nom du canal).protected realtimeApiRequest(): boolean— Opt-in du pont API (une action, deux transports) :true→ la connexion expose la méthode RPCapi.request {path}qui re-route le path porté par le message vers l’action controller correspondant …protected handleRealtime(message: string | Uint8Array | null): void— Point d’entrée à appeler depuis la route WS du contrôleur.protected onRealtimeBinary?(data: Uint8Array): void— Lit les trames BINAIRES de cette connexion — le point d’extension d’un protocole binaire écrit par l’application, à côté du JSON-RPC ; pendant serveur deNodefonySocket.onBinary.protected requestClient<K extends ActionNames<Actions>>(method: K, params?: ActionParams<Actions, K>, timeoutMs?: number): Promise<ActionResult<Actions, K>>— L1 — duplex serveur→client. Émet une REQUÊTE vers le client de CETTE connexion (sur une action qu’il a exposée viaclient.register(...)) et attend sa réponse.protected notifyClient<K extends EventNames<Emit>>(method: K, params?: EventPayload<Emit, K>): void— Notification CIBLÉE serveur→client (sans réponse) vers CETTE connexion, hors canal pub/sub — pendant fire-and-forget derequestClient.protected sendBinaryToClient(data: Uint8Array): boolean— Émet une trame BINAIRE vers CETTE connexion, sans la sérialiser — pendant sortant deonRealtimeBinary, et deNodefonySocket.sendBinarycôté client.
RealtimeHub#
class RealtimeHub
RealtimeHub — broker temps réel PAR INSTANCE (1 pod = 1 process = 1 hub local).
readonly admissionBudget: AdmissionBudget— Budget des admissions de l’exemplaire (appels d’allowen vol, coupe-circuit,allowTimedOutTotal/allowSaturatedTotal) — partagé par les files de toutes les connexions.subscribeClient(channel: string, sink: ChannelSink, factory: ChannelFactory, buildFrame?: ChannelFrameBuilder, member?: RealtimeConnection): boolean— Abonnement demandé par une connexion cliente — même chose quesubscribe, plus le plancher des canaux de plateforme.subscribe(channel: string, sink: ChannelSink, factory: ChannelFactory, buildFrame?: ChannelFrameBuilder): boolean— Abonne un consommateur qui répond du canal : il apporte lafactory, donc la réponse à « ce canal existe-t-il, et qui le produit ?listen(channel: string, sink: ChannelSink): void— Écoute passive — un service du serveur reçoit ce qui passe sur un canal sans prétendre le produire.isChannelOwned(channel: string): boolean— Le canal a-t-il un propriétaire (une fabrique a fourni son provider) ?unsubscribe(channel: string, sink: ChannelSink): void— Désabonne une connexion d’un canal.channelMembers(channel: string): IRealtimeConnection[]— Les connexions abonnées à un canal par un client — local à ce pod : les membres servis par un autre exemplaire n’y figurent pas.subscribeConnection(channel: string, connection: IRealtimeConnection): Promise<boolean>— Abonne d’office une connexion à un canal — local à ce pod : seule une connexion acceptée par ce processus peut l’être.evictConnection(channel: string, connection: IRealtimeConnection): boolean— Retire une connexion d’un canal — local à ce pod ; elle reçoitrealtime:closed { reason: "evicted" }.closeChannel(channel: string): number— Termine un canal pour tous ses membres, sur tous les serveurs : chacun reçoitrealtime:closed { reason: "ended" }, et le producteur est libéré.evictUser(channel: string, user: string): number— Éjecte un compte d’un canal, sur tous les serveurs : chacune de ses connexions membres reçoitrealtime:closed { reason: "evicted" }.publish(channel: string, payload?: object): void— Publie une charge sur un canal : fan-out local + propagation conditionnelle auIBackplane(autres workers/pods).publishToUser(userId: string, payload?: object): void— Livre une charge à UNE identité — tous ses onglets, tous les serveurs, et personne d’autre (ADR-0022 §6, D1).broadcastPrefixes(): readonly string[]— Préfixes déclarés diffusables entre serveurs, dans l’ordre de déclaration — lu par la ligne de démarrage.publishLocal(channel: string, payload: unknown): void— Fan-out d’une charge aux seuls abonnés locaux d’un canal (process courant).markBroadcastChannel(prefix: string): void— Déclare un préfixe de canal broadcast : ses publications traversent leIBackplane(cross-process).setBackplane(backplane: IBackplane): IBackplane— Branche leIBackplanecross-process (cluster IPC, Redis…) et câble son ingress (#admitFromBackplane) : un message reçu d’un autre pair est réinjecté en fan-out local uniquement (publishLocal…get backplane(): IBackplane | null— Backplane cross-process branché, ounullen mono-process (lecture/tests/sonde).subscriberCount(channel: string): number— Nombre d’abonnés locaux d’un canal (observabilité / tests).registerConnection(conn: IRealtimeConnProbe): void— Inscrit une connexion au registre de la sonde (au handshake).unregisterConnection(conn: IRealtimeConnProbe): void— Retire une connexion du registre de la sonde (au close) et verse ses cumuls à ceux des connexions fermées : les totaux deproberestent monotones.registerRevocable(entry: IRevocableConnection): void— Inscrit une connexion à identité RÉVOCABLE au registre de re-validation (F4, revue 0.6).unregisterRevocable(entry: IRevocableConnection): void— Retire une connexion du registre de révocation (au close).revalidateRevocable(): Promise<void>— Re-valide toutes les connexions révocables et ferme (4001) celles dont l’identité est morte : session détruite ou passée à un autre compte, jeton expiré ou révoqué.refreshIdentity(identifier: string): number— Ferme tout de suite les connexions qui ont figé cette identité — ses droits ont changé (IDENTITY_CHANGED_EVENT).recordInbound(): void— Compte une frame entrante full-duplex (canaux gated SIP/bridge).probe(): IRealtimeProbe— Snapshot d’auto-observabilité de la socket (per-instance).get activeChannels(): string[]— Canaux actifs (≥ 1 abonné).useAuthenticator(matcher: IRealtimeAuthenticatorMatcher, authenticator: IRealtimeAuthenticator): void— Seam #2 (P13 → P6) — enregistre un authenticator pour les handshakes WS dont l’URL matchematcher.resolveAuthenticator(handshake: IRealtimeHandshake): IRealtimeAuthenticator | null— Résout l’authenticator capturant ce handshake (1ʳᵉ matcher qui matche), ounullsi aucun (le RealtimeController posera un token anonyme).setOriginGuard(guard: OriginGuard | null): void— Seam #4 (P13 → P6) — pose la politique Origin (RFC 6455 §10.2).checkOrigin(origin: string): boolean— Vérifie qu’une origin est autorisée (politique CSRF).setMaxChannelsPerConnection(max: number | null): void— F6a (revue 0.6) — plafond de canaux par connexion (anti-OOM).get maxChannelsPerConnection(): number | null— Plafond courant de canaux par connexion (null= illimité).setSlowConsumerBytes(bytes: number): void— F9 (revue 0.6) — pose le seuil de comptage des consommateurs lents (probe()).get frameCodecs(): IFrameCodecSet— Les codecs de frame du serveur (ADR-0022 §2) : le texte, et le codec binaire accordé aux clients qui l’offrent —nulltant que la configuration n’en active aucun.setFrameCodec(codec?: IFrameCodec): void— Pose le codec binaire du serveur — 1× au boot parRealtimeService.init(), depuis la clécodecde la configuration.get textFrameCodec(): IFrameCodec— Le codec des connexions texte — celui qu’emprunte aussi le REST du plan d’administration, pour qu’une valeur lue parGETsoit celle que la socket livre (#618 D9).setAdmissionLimits(limits: IAdmissionLimits): void— Pose les bornes des admissions (authenticateTimeoutMs,allowTimeoutMs,maxPendingAllowsPerConnection,maxPendingAllowsTotal) — 1× au boot parRealtimeService.init().setTokenForPeer(peer: JsonRpcPeer, token: IRealtimeToken): void— Associe un token au peer (posé parRealtimeController.onHandshake()après succèsauthenticator.authenticate()ou fallback anonyme).getTokenForPeer(peer: JsonRpcPeer): IRealtimeToken— Renvoie le token associé au peer, ouANONYMOUS_REALTIME_TOKENsi aucun (cas Zero Trust : la lecture ne renvoie JAMAISnull— slot #6 audit lookup garanti, voters P6 ne se posent jamais la question …setFrameAuthorizer(authorizer: FrameAuthorizer | null, options?: { readonly silentProbe?: FrameAuthorizer | null; }): void— Seam #1 (P13 → P6) — pose le verrou de frame (cfFrameAuthorizer).hasFrameAuthorizer(): boolean— Un verrou de frame est-il posé ?onPlatformNotice(notify: (message: string, severity: "WARNING" | "INFO") => void): void— Branche l’alerte du plancher système — tirée une seule fois, au premier canal de plateforme refusé faute de module de sécurité.isClosedBySystemFloor(channel: string): boolean— Ce canal serait-il fermé par le plancher système ?hasUnenforcedChannelPolicies(): boolean— F1 (revue 0.6) — des politiques de canal sont-elles DÉCLARÉES (@RealtimeChannelavecroles/scopes/authenticated) sansframeAuthorizerpour les faire respecter ?registerChannelPolicy(name: string, policy: IChannelPolicy, admission?: IChannelAdmission): void— Seam #1b — déclare la politique d’autorisation d’un canal/méthode (@RealtimeChannel/@RealtimeInboundavec opts).static readonly MAX_PATTERN_WILDCARDS = 3— Nombre maximum de*dans un motif.resolveChannelPolicy(name: string): IChannelPolicy | null— Politique déclarée pour ce canal/méthode, ounullsi aucune.resolveChannelAdmission(name: string): IChannelAdmissionRule | null— Règle d’admission prête à appeler pour ce canal —nulls’il ne déclare pasallow.hasPolicyOwner(owner: object): boolean— Les politiques de cette classe de contrôleur sont-elles déjà inscrites ?addPolicyOwner(owner: object): void— Marque les politiques de cette classe comme inscrites — APRÈS l’inscription réussie, jamais avant : une politique refusée doit l’être de nouveau à la poignée de main suivante, pas laisser le canal ouv …hasExactChannelPolicy(name: string): boolean— Une politique est-elle déclarée sous ce nom EXACT — motifs ignorés ?hasChannelPolicies(): boolean— Des politiques de canal sont-elles déclarées (au moins une) ?noticeUnguardedDynamicChannel(channel: string): void— Avertit — une seule fois — qu’un canal servi par une fabrique DYNAMIQUE n’est couvert par aucune politique déclarée, alors que d’autres canaux du module en portent une.registerSystemChannel(channel: string, factory: ChannelFactory): void— Enregistre la factory d’un canal système (plateforme) — un module bas niveau (ex.setClientLogsLimits(limits: IClientLogsLimits | null): void— Ouvre (ou referme) la réception des journaux du navigateur, avec ses bornes.get clientLogsLimits(): IClientLogsLimits | null— Bornes en vigueur, ounullsi le canal montant est fermé.runAuthorizer(frame: unknown, peer: JsonRpcPeer): booleantrackRetainedVerdicts(state: IRealtimeConnectionState): void— Inscrit une connexion qui vient de retenir son premier « oui » du verrou.untrackRetainedVerdicts(state: IRealtimeConnectionState): void— Retire une connexion fermée du registre des verdicts retenus.probeChannel(channel: string, peer: JsonRpcPeer): boolean— Ce peer pourrait-il s’abonner à ce canal ?get registeredAuthenticators(): ReadonlyArray<IRealtimeAuthenticator>— Authenticators enregistrés (debug / tests).clear(): void— Dispose tous les providers et vide le hub (arrêt process / reset de test).
ServerRealtimeSocket#
class ServerRealtimeSocket<Emit extends EventsMap = DefaultEventsMap, Listen extends EventsMap = DefaultEventsMap, Actions extends ActionsMap = DefaultActionsMap> implements IRealtimeSocket<Emit, Listen>
L4 — façade serveur « la socket Nodefony ». Un handle SERVEUR qui implémente le contrat ISOMORPHE IRealtimeSocket au-dessus du RealtimeHub : un service back code comme une page front (publish / subscribe / on / channel) — il tient UN handle, ignore le fan-out et le backplane.
constructor(hub?: import("./RealtimeHub").RealtimeHub)publish<K extends string>(channel: K, payload?: K extends EventNames<Emit> ? EventPayload<Emit, K> : object): void— Émet sur un canal — fan-out aux abonnés via le hub (+ backplane si broadcast).subscribe(channel: EventNames<Listen> | (string & {})): void— S’abonne (ref-compté) à un canal pour le RECEVOIR.unsubscribe(channel: EventNames<Listen> | (string & {})): void— Désabonne (ref-compté) : coupe le sink du hub au DERNIER consommateur.on<K extends string>(channel: K, handler: K extends EventNames<Listen> ? (payload: EventPayload<Listen, K>) => void : RealtimeHandler): () => void— Branche un handler de réception sur un canal.off<K extends string>(channel: K, handler: K extends EventNames<Listen> ? (payload: EventPayload<Listen, K>) => void : RealtimeHandler): void— Retire un handler d’un canal — même frontière queon.request<K extends string, T = unknown>(_method: K, _params?: ContractParams<Actions, K>, _timeoutMs?: number): Promise<ContractResult<Actions, K, T>>— Non supporté : rejette toujours.channel(name: string): IRealtimeChannel— Vue par-canal (IRealtimeChannel) — fine liaison sur les primitives.getStats(): IChannelStats[]— Snapshot des compteurs par canal (refs internes — à LIRE).getChannelStats(channel: string): IChannelStats— Compteurs d’un canal précis ouundefined.get subscribedChannels(): string[]— Canaux actuellement abonnés (≥ 1 consommateur).
Fonctions (6)#
buildOwnHealth#
function buildOwnHealth(): IRealtimeHealth
buildRealtimeHealth#
function buildRealtimeHealth(): Promise<IRealtimeHealth | IRealtimeClusterHealth>
Construit la santé de la socket servie par l’endpoint/le canal nodefony:socket : la vue POD agrégée si la sonde cluster est branchée et a reçu un snapshot du master (Phase 4c, push), sinon la vue per-instance (mono-process, sonde désactivée, ou cold start). Lecture pure, jamais throw. Async pour matcher la signature des tickers broker.
createRealtimeAdminApi#
function createRealtimeAdminApi(): IAdminApi
Construit le producteur IAdminApi de la socket (namespace "realtime").
createSyslogUplinkHandler#
function createSyslogUplinkHandler(opts: SyslogUplinkHandlerOptions): RealtimeInboundHandler
Fabrique le handler du canal montant des journaux.
getRealtimeHub#
function getRealtimeHub(): RealtimeHub
function getRealtimeHub<C extends IRealtimeContract>(): IContractRealtimeHub<C>
Renvoie le hub realtime du process (singleton lazy) — forme LIBRE : tout nom de canal, toute charge objet. Renvoie le hub realtime du process lu à travers le contrat C : la diffusion d’un service, d’un job ou d’une boucle de jeu est vérifiée par le contrat partagé avec le navigateur. Même objet que la forme libre : 0 octet, 0 ns.
serverSocket#
function serverSocket<Emit extends EventsMap = DefaultEventsMap, Listen extends EventsMap = DefaultEventsMap, Actions extends ActionsMap = DefaultActionsMap>(): ServerRealtimeSocket<Emit, Listen, Actions>
Crée un handle serveur (ServerRealtimeSocket) sur le hub courant.
Constantes (7)#
ANONYMOUS_REALTIME_TOKEN#
const ANONYMOUS_REALTIME_TOKEN: IRealtimeToken
Token realtime ANONYME — fallback Zero Trust quand aucun matcher IRealtimeAuthenticatorMatcher ne capture le handshake.
ANONYMOUS_SUBSCRIBER_IDENTITY#
const ANONYMOUS_SUBSCRIBER_IDENTITY: ISubscriberIdentity
Identité d’admission de l’ANONYME — gelée et partagée par toutes les connexions non authentifiées (0 allocation par connexion).
ContractRealtimeController#
const ContractRealtimeController: ContractRealtimeControllerConstructor
L’instance d’un contrôleur de contrat : forme stricte si C déclare des serverMethods, socle sinon. Base d’un contrôleur qui IMPLÉMENTE un contrat temps réel — la porte du serveur. Le contrat s’écrit UNE fois, sur extends ; la direction du serveur en est dérivée (il émet serverToClient, écoute clientToServer, appelle clientMethods) et il DOIT servir chaque méthode de serverMethods.
MAX_CLIENT_SEVERITY#
const MAX_CLIENT_SEVERITY = 3
Sévérité la plus grave qu’un client puisse obtenir (3 = ERROR). Au-dessus vivent CRITIC, ALERT et EMERGENCY — des niveaux d’exploitation qu’un onglet ne décide pas.
RESERVED_SYSTEM_PREFIXES#
const RESERVED_SYSTEM_PREFIXES: readonly [ "nodefony:" ]
Namespace de canaux RÉSERVÉ À LA PLATEFORME — un seul préfixe, nodefony:.
SLOW_CONSUMER_BYTES#
const SLOW_CONSUMER_BYTES: number
Seuil d’alerte slow-consumer (octets de bufferedAmount). Au-delà, la connexion est comptée comme « lente » par la sonde (PAS encore de drop/close — la sonde MESURE avant qu’on optimise : stringify unique → seuil de drop → coalescing). 1 MiB = websocket.maxPayload par défaut : une file qui dépasse une frame max pleine est déjà anormale pour des canaux d’ÉTAT (latest-wins).
isReservedSystemChannel#
const isReservedSystemChannel: typeof isPlatformChannel
Le canal appartient-il au namespace réservé à la plateforme ?
Interfaces (2)#
IContractRealtimeHub#
interface IContractRealtimeHub<C extends IRealtimeContract> extends Omit<RealtimeHub, "publish" | "publishToUser">
Le hub lu à travers le contrat C : mêmes méthodes que RealtimeHub, mais publish n’accepte que les canaux de serverToClient, chacun avec la charge qu’il déclare. C’est le MÊME objet que le hub libre — une vue de type, sans un octet ni une instruction de plus.
publishToUser(userId: string, payload: UserChannelPayload<ContractServerEmit<C>> & object): void— Livre à UNE identité la charge que le contrat déclare pour le canal personnel (clé gabarit[k: `user:${string}`]: …deserverToClient) — cfRealtimeHub.publishToUser.publish<K extends EventNames<ContractServerEmit<C>>>(channel: K, payload: EventPayload<ContractServerEmit<C>, K> & object): void— Publie sur un canal déclaré par le contrat (fan-out local, puis backplane si le canal est broadcast) — cfRealtimeHub.publish.
SyslogUplinkHandlerOptions#
interface SyslogUplinkHandlerOptions
syslog: Syslog— Le journal du pod où réinjecter.maxEntriesPerBatch?: number— Entrées retenues par lot.maxEntriesPerWindow?: number— Entrées retenues par fenêtre et par connexion.windowMs?: number— Durée de la fenêtre de débit, en ms.maxStringLength?: number— Longueur maximale d’une chaîne acceptée.maxRequestIdLength?: number— Longueur maximale d’unrequestIdaccepté.
Types (7)#
ChannelFactory#
type ChannelFactory = (channel: string, publish: RealtimePublish) => () => void | null
Fabrique le provider PARTAGÉ d’un canal (listener/ticker qui pousse via publish). Appelée UNE fois, au 1ᵉʳ abonné. Renvoie son dispose (appelé au dernier désabonné) ou null si le canal est inconnu. Le provider doit capturer des deps long-lived (kernel/syslog/broker, valeurs simples) — JAMAIS la connexion qui a déclenché la création (elle peut fermer alors que le provider partagé survit).
ChannelFrameBuilder#
type ChannelFrameBuilder = (payload: unknown) => unknown
Fabrique la frame protocolaire d’un canal (l’objet, pas ses octets), fournie par l’abonné : le hub ignore tout du protocole. Appelée au plus une fois par publication, jamais par abonné ; l’encodage, lui, se fait une fois par codec.
ChannelSink#
type ChannelSink = (payload: unknown, frame?: ChannelFrame) => void
Sink d’un canal : pousse une charge vers UNE connexion abonnée (son peer.notify). 1 sink = 1 connexion. Le hub fan-out la charge à tous les sinks d’un canal.
ClientSeverity#
type ClientSeverity = 3 | 4 | 5 | 6 | 7
Les seules sévérités qu’une entrée cliente peut porter, une fois plafonnée.
ContractPolicyNames#
type ContractPolicyNames<C extends IRealtimeContract> = ContractActionNames<ContractServerMethods<C>> | EventNames<ContractServerEmit<C>> | EventNames<ContractClientEmit<C>>
Noms qu’un contrat déclare et qu’une politique peut garder : ses méthodes serveur et les canaux de ses deux directions. Un canal déclaré par gabarit (user:${string}) admet aussi son motif (user:*). Direction non déclarée : tout nom.
ContractRealtimeMethodHandlers#
type ContractRealtimeMethodHandlers<C extends IRealtimeContract> = { [K in ContractActionNames<ContractServerMethods<C>>]: TypedRpcActionHandler<ContractServerMethods<C>, K>; }
Table COMPLÈTE des méthodes que le serveur doit au contrat : une entrée par nom de serverMethods, chacune recevant ses paramètres lus par Jsonify et rendant le résultat déclaré. Une méthode oubliée, un nom hors contrat ou une forme fausse ne compilent pas.
RealtimeContractOf#
type RealtimeContractOf<T> = T extends abstract new (...args: never[]) => { readonly [contractType]?: infer C; } ? unknown extends C ? never : C extends IRealtimeContract ? C : never : never
Le contrat qu’une classe de contrôleur implémente, lu sur son étiquette de type ; never pour un contrôleur sans contrat.