NIP-67 : indice de complétude pour EOSE
EOSE a toujours signifié que le relais avait fini d'envoyer les événements stockés, pas qu'il les avait tous envoyés. NIP-67 ajoute un indice optionnel pour que les clients puissent enfin faire la différence.
Nostr WoT Newsroom
Rédigé par la rédaction de Nostr WoT à partir des sources primaires citées, et publié automatiquement sans relecture humaine individuelle.
NIP-01 définit EOSE comme la frontière entre les événements stockés et les événements en temps réel pour un abonnement. Ce qu'il n'a jamais précisé, c'est si le relais a réellement envoyé tout ce qu'il détient et qui correspond au filtre. NIP-67, rédigé par mattn et fusionné le 6 juin 2026, donne aux relais un moyen de le dire.
Le vide que laissait EOSE
La plupart des relais appliquent une limite interne au nombre d'événements stockés qu'ils renvoient pour un seul abonnement, indépendamment du limit demandé par le client. Le client n'a aucun moyen de voir cette limite. Tout ce qu'il peut faire, c'est comparer le nombre d'événements reçus au limit qu'il a demandé, et deviner.
Cette supposition échoue de deux façons précises.
D'abord, quand la limite du relais est inférieure au limit demandé par le client, le client est amené à croire que le résultat est complet. Un client demande les 500 dernières notes. Le relais plafonne les réponses à 300 et en envoie exactement 300. Comme 300 est inférieur à 500, le client conclut qu'il a tout reçu. Ce n'est pas le cas. Le reste des notes correspondantes reste sur le relais, et le client n'apprend jamais leur existence.
Ensuite, quand le nombre d'événements correspondants se trouve être exactement égal à la limite du relais, le client ne peut pas savoir qu'il les a tous reçus. Il n'a d'autre choix que d'envoyer un autre REQ avec until réglé sur l'horodatage de l'événement le plus ancien reçu, uniquement pour vérifier que le lot suivant est vide. Un relais plafonné à 300 événements reçoit au moins deux requêtes pour tout abonnement qui atteint cette limite, qu'il y ait eu ou non davantage de données à récupérer.
Ce qu'ajoute NIP-67
La spécification ajoute un troisième élément optionnel au message EOSE, un tableau de chaînes d'indice :
["EOSE", <subscription_id>, [<hint>, ...]]Deux valeurs d'indice sont définies. "finish" signifie que le relais a envoyé tous les événements stockés correspondant aux filtres de l'abonnement, donc le client ne devrait pas paginer davantage. "more" signifie que le relais retient d'autres événements correspondants qu'il n'a pas envoyés, donc le client devrait paginer pour les récupérer. Un relais n'est pas tenu d'envoyer "more" même quand c'est vrai, puisque savoir avec certitude qu'il existe davantage de données correspondantes n'est pas gratuit sur tous les backends de stockage.
Le tableau d'indices peut contenir l'une des deux valeurs, les deux, ou aucune. La spécification est explicite : leur présence est définitive, leur absence ne l'est pas. Si un relais omet entièrement le troisième élément, ou envoie un EOSE sans indice, le client retombe sur la même heuristique de pagination basée sur until qu'il utilise déjà aujourd'hui. Rien dans le comportement actuel du client n'a besoin de changer pour rester correct.
La compatibilité fonctionne dans les deux sens. Un relais qui adopte ce NIP envoie l'EOSE à trois éléments à tous les clients, qu'ils comprennent l'indice ou non, parce que les clients qui n'implémentent pas NIP-67 indexent déjà EOSE par position et ignorent simplement l'élément supplémentaire, de la même façon qu'un analyseur JSON accepte sans problème un élément superflu en fin de tableau. Un client qui ajoute le support de l'indice n'obtient rien de plus des relais qui ne l'ont pas encore implémenté, et continue simplement d'utiliser sa logique de pagination existante.
Le NIP traite aussi un cas limite lié aux horodatages identiques. Quand un relais n'envoie pas "finish", plusieurs événements stockés peuvent partager la même valeur created_at la plus ancienne dans une réponse, et la pagination basée sur until risque de perdre silencieusement des événements qui partagent cet horodatage limite. Il est recommandé aux relais, quand c'est possible, d'avancer suffisamment pour que tous les événements portant cet horodatage limite soient inclus dans une seule réponse, et de n'émettre "finish" que lorsqu'il ne reste vraiment plus rien de plus ancien.
Les relais qui implémentent NIP-67 sont censés inclure 67 dans leur champ supported_nips, conformément à NIP-11.
Pourquoi c'est important
Une troncature silencieuse et un résultat réellement vide se ressemblent aujourd'hui aux yeux d'un client. Cette distinction compte surtout pour tout ce qui traite l'absence de résultats supplémentaires comme une information significative : requêtes de modération, audits, ou un client cherchant à établir qu'une clé publique donnée n'a vraiment plus d'événements d'un certain type. NIP-67 ne change pas la façon dont les événements sont stockés ou livrés. Il donne aux relais un petit vocabulaire optionnel pour dire la vérité sur le fait que l'historique des événements stockés d'un abonnement a réellement été épuisé.
Sources
Chaque affirmation de cet article renvoie vers une source primaire.
- NIP-67: EOSE Completeness Hint — nostr-protocol/nips (6 juin 2026)