Eventual RSVP – Core#
Événements, lieux et organisateurs dans les collections natives EmDash, dates récurrentes, flux publics et vues calendrier sans JavaScript.
Installation et prérequis EmDash
Requiert EmDash >=1.2.0 <2.0.0 (testé sur 1.2.0 et 1.4.0 ; EmDash 1.4.0 est recommandé car il corrige les formulaires Block Kit imbriqués et les mutations de plugins sur Cloudflare). Les outils de compilation source requièrent Node 24+.
- Installez Eventual RSVP – Core depuis le registre d’extensions EmDash (éditeur vermeulen.solutions). Un paquet npm pour les installations par
astro.config.mjs suivra dans une prochaine version.
- Dans Event settings, reliez vos collections de contenu EmDash pour
events, venues et organizers (les schémas peuvent être exportés via scripts/export-native-schema.mjs).
- Laissez Afficher les anciens événements enregistrés dans l’extension (
legacyReads) désactivé, sauf pendant une migration depuis 0.12.x. Les collections natives restent la source de vérité pour les titres, textes enrichis, images, brouillons et traductions.
- Notez l’identifiant installé du plugin : les sites configurés par code utilisent généralement
eventual, tandis que les installations depuis le registre reçoivent un identifiant déterministe r_… affiché dans Admin → Extensions. Passez toujours l’identifiant réel aux URL d’API et à l’option pluginId.
Routes publiques et assistants Astro
Le module eventual/astro fournit fetchPublicFeed, <EventList showCalendarLinks={true} /> (zéro JavaScript côté navigateur), sept mises en page via paramètre d’URL (?view=list|timeline|cards|schedule|dates|month|locations), buildCalendarLinks (Google Calendar, Outlook Web, Office 365 et téléchargement direct .ics Apple/bureau) ainsi que eventToJsonLd et serializeJsonLd (Schema.org). Ces outils arrivent avec le paquet npm de Core, qui suivra dans une prochaine version ; d’ici là, un site lit les mêmes données depuis la route publique publicEvents.
strict=true masque les événements dépourvus de traduction dans la langue demandée.
strict=false (par défaut) se replie sur une autre langue avec un préfixe [FR] / [EN].
- À partir de
0.15.0 sur EmDash >=1.4.0, les réponses portent des métadonnées de dépendance et d’expiration de cache opt-in (durée résiduelle plafonnée à 15 secondes, sans servir de contenu périmé).
- À partir de
0.16.0, imageMedia expose les dimensions natives et les clés de stockage directes (/_emdash/api/media/file/<clé>) tout en conservant imageUrl.
Réglages, permissions et limites
Dépannage (Core)
- Les titres affichent
[EN] ou [FR] de façon inattendue : vérifiez que les traductions natives sont publiées et reliées dans EmDash, ou passez strict=true au flux public.
- Le flux public renvoie une erreur après mise à jour
0.14.0+ : les lectures publiques refusent volontairement de retomber sur l’ancien stockage interne. Reliez votre collection events dans Event settings.
- Installation depuis le registre introuvable sous
/eventual/… : remplacez eventual par l’identifiant r_… affiché dans l’administration EmDash.
Eventual RSVP – Registrations#
Configuration, réglages, composants Astro, variables CSS --eventual-*, e-mails, tâches planifiées, contrat de confiance et limites d’Eventual RSVP – Registrations.
Configuration et réglages de Registrations
Eventual RSVP – Registrations lit les événements publiés depuis les collections EmDash (aucune donnée des participants ne quitte votre base). Par défaut, les inscriptions sont fermées sur chaque événement jusqu’à ce que celui-ci soit publié, que inventory_mode vaille rsvp (ou reste absent) et que Ouvrir les inscriptions soit activé dans le panneau Registrations de l’éditeur.
Page globale des réglages (/attendance/settings)
- Collections contenant des événements : liste séparée par des virgules (par défaut
events, par exemple camps, school_series) ; la première sert de valeur par défaut.
- Les réponses aux e-mails vont à (facultatif) : adresse par défaut pour les réponses et les avis d’approbation (
New request: …), surchargeable par événement.
- Envoyer un rappel ce nombre d’heures avant l’événement (0 = pas de rappel) :
24 par défaut.
- Langue des e-mails quand le formulaire ne la précise pas : repli
en ou fr lorsqu’une inscription n’enregistre pas de langue d’interface.
- Chemin de la page de gestion : URL publique de la page obligatoire d’annulation et de réclamation (par défaut
/rsvp/manage).
- Durée de conservation (
retentionDays) : fenêtre d’effacement automatique après la fin d’une séance passée (30–3650 jours, 365 par défaut).
- Configuration du site / Turnstile (panneau replié) : clés site et secrète Cloudflare Turnstile stockées dans le KV du plugin (aucune clé
EMDASH_ENCRYPTION_KEY requise), plus boutons pour vérifier et réparer les tâches planifiées.
Panneau par événement (event-attendance)
- La capacité par date (
0 = illimité) et le commutateur de liste d’attente (allow_waitlist) s’éditent dans le formulaire de l’événement lorsque les champs eventual-capacity sont appliqués, ou directement dans le panneau sinon.
- Nombre maximal de places par inscription (
maxQuantity), Approuver chaque inscription vous-même (requireApproval, 1–720 heures pour décider, 48 par défaut) et Questions du formulaire d’inscription sous forme de lignes : question, type de réponse en mots, choix seulement pour une liste, réponse obligatoire ; enregistrer, supprimer et déplacer vers le haut.
Composants et propriétés (@vermeulen.solutions/eventual-attendance/astro/*)
Personnalisation visuelle (--eventual-*)
Les styles des composants se trouvent dans la couche CSS @layer eventual. Avec Tailwind CSS 4, placez eventual avant components dans votre déclaration de couches :
@layer theme, base, eventual, components, utilities;
Ou thèmez de façon indépendante des couches via variables CSS sur un conteneur englobant <RsvpForm> et <RsvpManage> :
Sur un thème sombre, définissez toujours --eventual-text et --eventual-field-bg ensemble pour éviter un texte clair sur un fond de saisie blanc par défaut.
E-mails, fuseaux horaires et tâches planifiées
Tous les e-mails destinés aux visiteurs (confirmation, mise en liste d’attente, offre retenue 2 h, avis d’approbation et rappels) sont rédigés dans la langue enregistrée lors de l’inscription (fr ou en) avec l’heure formatée dans le fuseau IANA de l’événement via formatInZone (repli UTC explicite) et un lien direct .ics vers la route calendar.
Sécurité, permissions et limites pour grands événements
- Capacités déclarées :
content:read, email:send, network:request (allowedHosts: ["challenges.cloudflare.com", "cdn.jsdelivr.net"] : Cloudflare uniquement si vous activez Turnstile ; jsDelivr pour les paquets de langue vérifiés par empreinte).
- Protection anti-abus : champ pot de miel et contrôle de durée sur chaque formulaire. Lorsque Turnstile est désactivé et qu’EmDash transmet l’IP, Registrations limite à 10 inscriptions par période de 10 minutes via une empreinte HMAC
ipHash (32 caractères hexadécimaux — jamais l’IP brute).
- Limites documentées (sous la limite standard EmDash de 10 appels / 50 ms CPU) :
- Le rapprochement automatique d’une séance analyse au plus ~500 fiches (participants + liste d’attente) ; au-delà, il consigne
TOO_LARGE et ignore jusqu’à découpage par date.
- Les exports liste d’accueil HTML/CSV sont plafonnés à 700 lignes avec mention en tête ; filtrez par événement et par date pour les séances plus vastes.
- Aucune limite artificielle dans le code, aucune clé de licence et aucune clé
EMDASH_ENCRYPTION_KEY requise.
Dépannage (Registrations)
- Aucun e-mail ne part : vérifiez qu’une extension d’envoi d’e-mails EmDash est installée. L’inscription reste enregistrée (
email: "none") et affiche le lien d’annulation directe à l’écran.
- Les rappels ou offres d’attente ne s’envoient pas : ouvrez Admin → Registrations une fois pour réenregistrer les 6 tâches, et vérifiez que le déclencheur cron de votre hébergeur Cloudflare est actif.
Route not found sur une installation registre : reprenez le préfixe r_… exact indiqué dans Site setup et passez-le à <RsvpForm apiEndpoint="…" /> et <RsvpManage apiBase="…" />.
- Erreur publique
TRY_AGAIN : consultez les journaux EmDash ; la collection d’événements n’est probablement pas encore raccordée.
Eventual RSVP – Tickets#
Documentation complète d’Eventual RSVP – Tickets : Stripe Checkout, catégories de billets, paiement sur facture, espace commande avec code QR, contrôle à l’entrée, variables --et-*, licence hors ligne et limites.
Prérequis de configuration et chiffrement
Eventual RSVP – Tickets ne vend des billets que sur les événements publiés dont le champ inventory_mode (issu d’eventual-capacity) vaut explicitement tickets. Registrations et Tickets ne peuvent donc jamais vendre la même séance en double.
- Billets gratuits et paiement sur facture fonctionnent sans clé : la clé de signature interne (
state:signing-key) est créée automatiquement dans le KV du plugin sans EMDASH_ENCRYPTION_KEY.
- Paiement par carte (Stripe Checkout) : définissez
EMDASH_ENCRYPTION_KEY dans votre environnement (npx emdash secrets generate ou wrangler secret put EMDASH_ENCRYPTION_KEY) afin de chiffrer en AES-GCM votre clé secrète Stripe (sk_test_…, sk_live_… ou clé restreinte rk_…) et votre secret de signature webhook (whsec_…).
- Dans Admin → Tickets, consultez la liste de contrôle, copiez l’URL de webhook affichée vers Stripe, abonnez-la à
checkout.session.completed, checkout.session.async_payment_succeeded, checkout.session.async_payment_failed, checkout.session.expired et charge.refunded, puis collez vos secrets ainsi que votre clé de licence evt1.… (sur domaine de production).
Types de billets, tarifs et parcours d’achat
Dans le panneau latéral Tickets de l’éditeur (event-tickets), créez jusqu’à 20 types de billets sous forme de lignes (nom, prix en devise ou Gratuit, plafond optionnel par date dans la capacité globale, maximum par commande de 1 à 50, fenêtre de vente), des lignes de questions et les instructions Proposer le paiement par facture ou virement (≤ 2000 caractères texte). Renommer un type conserve son identifiant et ses ventes.
- Retenue de 30–31 minutes : Stripe impose au minimum 30 minutes d’expiration (
S-1). Tickets fixe expires_at à +31 min, réserve les places par compare-and-set atomique et vérifie amount_total et currency sur les octets bruts du webhook (stripe-signature).
- Paiement sur facture : bloque les places aussitôt (
pending_invoice), envoie les coordonnées bancaires avec la référence (ord_…) et le lien de commande, puis délivre les billets QR lorsque vous cliquez sur Mark paid.
- Abandon ou délai expiré :
<TicketCheckoutReturn /> appelle checkout/release sur annulation (result=cancelled) ou vérifie l’état Stripe sur retour (result=success) ; en secours, la tâche tickets-hold-sweep interroge Stripe avant de libérer une retenue échue.
Composants Astro (@vermeulen.solutions/eventual-tickets/astro/*)
Personnalisation visuelle (--et-*)
Les classes .eventual-tickets-widget, .et-*, .etr-*, .eto-* et .etc-* lisent vos variables personnalisées sur un élément parent :
- Couleurs :
--et-primary, --et-primary-hover, --et-on-primary, --et-bg, --et-field-bg, --et-border, --et-text, --et-muted, --et-success, --et-success-bg, --et-warning, --et-warning-bg, --et-error, --et-error-bg, --et-info-bg.
- Rayons & focus :
--et-radius, --et-control-radius, --et-button-radius, --et-focus, --et-focus-ring.
- Définissez ensemble
--et-text et --et-field-bg sur un thème sombre.
Clé de licence hors ligne, e-mails, tâches et limites
- Vérification hors ligne (
D17) : signature Ed25519 via Web Crypto dans le Worker (zéro appel réseau sortant). Les hôtes de développement et d’aperçu (localhost, 127.0.0.1, [::1], *.localhost, *.workers.dev, *.pages.dev) ne nécessitent aucune clé. Sans clé valide en production, seules les nouvelles commandes sont bloquées (LICENCE_REQUIRED / LICENCE_EXPIRED) ; les commandes existantes, webhooks, pages de billets, contrôle à l’entrée, exports CSV et remboursements restent pleinement actifs.
- Langues (
fr et en) et fuseaux : les confirmations, instructions de facture et remboursements utilisent formatInZone dans le fuseau local de l’événement. Le panneau de l’événement, la page Commandes et la page de configuration suivent la langue de l’administration EmDash (français ou anglais) ; les verdicts de contrôle restent en anglais et les libellés de la barre latérale viennent du manifeste anglais.
- Capacités & hôtes sortants :
content:read, email:send, network:request limité à ["api.stripe.com", "challenges.cloudflare.com", "cdn.jsdelivr.net", "licences.eventual.rsvp"] (paquets de langue via jsDelivr ; le service de licences seulement quand un administrateur clique sur Activer, Actualiser ou Désactiver).
- Export CSV des commandes : limité à ~700 commandes par téléchargement avec neutralisation anti-injection de formules (
= + - @) ; filtrez par événement et date pour les saisons plus importantes.
Dépannage (Tickets)
- Paiement par carte grisé : vérifiez
EMDASH_ENCRYPTION_KEY, la clé secrète Stripe et le secret webhook dans Admin → Tickets. Les billets gratuits et virements restent disponibles sans clé Stripe.
- Un remboursement Stripe n’apparaît pas encore dans Commandes : attendez le webhook
charge.refunded ou vérifiez l’URL et le secret du webhook dans Admin → Tickets.
- Pas de lecteur caméra sur certains navigateurs : la prise en charge de
BarcodeDetector dépend du navigateur ; l’équipe peut toujours scanner le QR avec l’appareil photo standard du téléphone (qui ouvre /tickets/check#code=…) ou saisir le code de 64 caractères.
eventual-capacity (Bibliothèque partagée)#
Registre sans survente partagé, garde-fou de 10 appels hôte, pack de champs de capacité, fuseaux horaires et harnais de test.
Architecture : code partagé, zéro état partagé
@vermeulen.solutions/eventual-capacity est une bibliothèque utilitaire pure, pas une extension EmDash. Elle ne déclare ni manifeste, ni table, ni route, ni permission. Registrations et Tickets l’intègrent sous devDependencies afin que l’outil EmDash l’inclue dans chaque bundle tout en conservant l’isolation totale de chaque stockage KV/SQLite (P3, P16).
Modules fournis
Export du pack de champs
Appliquez toujours les champs de schéma de façon additive et contrôlée :
npx -p @vermeulen.solutions/eventual-capacity eventual-capacity-fields --merge eventual-schema.json --output eventual-schema-with-capacity.json
Omettez --merge pour imprimer uniquement les trois champs (inventory_mode, capacity, allow_waitlist) et les comparer à votre collection existante.
Isolation et conception sous contrainte
- Budget de 10 appels et 50 ms CPU (
P1) : toutes les routes publiques, webhooks et tâches planifiées sont conçus pour fonctionner sans demander à l’hébergeur d’augmenter les plafonds Worker.
- Aucun appel sortant propre à la bibliothèque : la vérification Turnstile n’est appelée que lorsqu’une extension consommatrice lui transmet ses clés configurées.
- Preuves de test vérifiées : parcours navigateur Playwright, navigation au clavier seul, audits d’accessibilité WCAG 2.2 AA
axe-core, captures d’e-mails en français/anglais et tests de concurrence sur le véritable hôte d’exécution EmDash.