Ceci est un sujet avancé pour construire votre propre logiciel contre le registre de plugins. Si vous voulez seulement installer des plugins sur un site EmDash, vous n’avez besoin d’aucun de ceci — activez le registre dans votre configuration et utilisez le tableau de bord d’administration.
Le côté découverte du registre est une API publique en lecture seule. Le paquet @emdash-cms/registry-client l’enveloppe, afin que vous puissiez construire un annuaire de plugins, une page de recherche ou un flux de releases en dehors d’EmDash. Le client s’exécute partout où fetch est disponible — Node, Workers, le navigateur ou un site Astro. Les sites Astro peuvent utiliser @emdash-cms/registry-loader pour exposer les mêmes données via une live content collection.
Installer
Le sous-chemin discovery ne porte aucune dépendance d’authentification ou OAuth. Installez le client et épinglez-le sur une version exacte :
npm install @emdash-cms/registry-client@0.6.0
Lister et résoudre les packages
La page Astro suivante liste chaque plugin d’un registre :
---
import { DiscoveryClient } from "@emdash-cms/registry-client/discovery";
const discovery = new DiscoveryClient({
aggregatorUrl: "https://registry.emdashcms.com",
});
const { packages } = await discovery.searchPackages({ q: "", limit: 50 });
---
<ul>
{
packages.map((pkg) => (
<li>
<a href={`/plugins/${pkg.handle ? `@${pkg.handle}` : pkg.did}/${pkg.slug}`}>
{pkg.profile?.name ?? pkg.slug}
</a>
{pkg.latestVersion && <span>v{pkg.latestVersion}</span>}
<p>{pkg.profile?.description}</p>
</li>
))
}
</ul>
Le handle vérifié actuel est présent lorsque l’agrégateur l’a résolu. Gardez la forme DID comme secours et redirigez-la vers l’URL du handle actuel lorsqu’une réponse ultérieure en fournit un. Un DID et le slug du package restent l’identité stable du package lorsqu’un éditeur change de handle.
Une valeur exacte de q peut être un handle, un DID, ou l’une des deux identités suivie de /slug. Par exemple, @example.com/my-gallery sélectionne un package et example.com renvoie les packages de cet éditeur.
Utiliser le live loader Astro
Installez @emdash-cms/registry-loader, puis enregistrez le loader dans src/live.config.ts :
import { registryLoader } from "@emdash-cms/registry-loader";
import { defineLiveCollection } from "astro:content";
export const collections = {
plugins: defineLiveCollection({ loader: registryLoader() }),
};
Utilisez getLiveCollection("plugins", { q, limit }) pour des résultats bornés et getLiveEntry("plugins", { publisher, slug }) pour un package. Passez l’indice de cache renvoyé à Astro.cache.set() lorsque le site a un fournisseur de cache Astro. Les live collections Astro ne renvoient pas de métadonnées de pagination, utilisez donc DiscoveryClient.searchPackages() directement lorsque l’interface a besoin du curseur suivant.
Une page de détail de package récupère un plugin par son DID et son slug, puis récupère la dernière release :
import { DiscoveryClient } from "@emdash-cms/registry-client/discovery";
const discovery = new DiscoveryClient({
aggregatorUrl: "https://registry.emdashcms.com",
});
export async function getPlugin(did: string, slug: string) {
const pkg = await discovery.getPackage({ did, slug });
const latest = await discovery.getLatestRelease({
did: pkg.did,
package: pkg.slug,
});
return { pkg, latest };
}
Méthodes de découverte
Le client expose une méthode par requête d’agrégateur :
searchPackages({ q, capability?, limit?, cursor? })— recherche en texte libre, éventuellement filtrée aux packages déclarant une catégorie d’accès donnée. Renvoie{ packages, cursor? }.resolvePackage({ handle, slug })— résoudre un package à partir d’un handle et d’un slug.getPackage({ did, slug })— récupérer un package par son DID et son slug.listReleases({ did, package, limit?, cursor? })— releases en ordre décroissant de version sémantique, y compris les releases retirées.getLatestRelease({ did, package })— la release non retirée la plus élevée sélectionnée par l’agrégateur.
getPackage() et resolvePackage() peuvent renvoyer historicalReleaseCount et
releaseHistoryComplete. Ces champs décrivent l’historique opérationnel retenu par l’agrégateur,
pas des métadonnées signées par l’éditeur. Traitez un compte de un comme première release uniquement lorsque
releaseHistoryComplete est true. Une évidence manquante ou incomplète ne doit pas contourner une politique d’âge de
release.
getPackageStatus() et resolvePackageStatus() encapsulent leurs requêtes de package correspondantes et
mappent la réponse sûre ListingUnavailable vers { status: "unavailable" }. Un résultat réussi a
{ status: "passed", value }. Utilisez ces méthodes dans une interface utilisateur qui doit distinguer une
fiche indexée mais indisponible d’un package manquant sans rendre de contenu d’erreur contrôlé par
l’éditeur.
Utilisez l’aide au retrait avant d’afficher ou de sélectionner une release :
import {
DiscoveryClient,
type ValidatedReleaseView,
} from "@emdash-cms/registry-client/discovery";
import { evaluateRegistryReleaseWithdrawal } from "@emdash-cms/registry-client/withdrawal";
const discovery = new DiscoveryClient({
aggregatorUrl: "https://registry.emdashcms.com",
});
export function canShowRelease(release: ValidatedReleaseView) {
const result = evaluateRegistryReleaseWithdrawal(release, discovery.labelerPolicy);
return release.release !== null && !result.withdrawn;
}
withdrawn est true lorsque les labels applicables retirent la release de l’usage. Des données de label invalides
échouent en fermeture : withdrawn et malformed sont tous deux true.
Gérer les enregistrements non fiables
L’agrégateur est un index non fiable qui relaie des enregistrements qu’il n’a pas écrits, donc le client valide chacun à la frontière. Deux règles en découlent :
- Les champs
profileetreleasepeuvent êtrenull. Lorsqu’un enregistrement relayé échoue à la validation, le client le présente commenullplutôt que de faire échouer tout l’appel, de sorte qu’un enregistrement malformé ne vide pas une page de recherche. Vérifiez toujours null avant de lirepkg.profile?.nameoulatest.release?.artifacts.package. - Validez vous-même les schémas d’URL avant le rendu. La validation vérifie la structure, pas la sécurité de l’URL — un champ
uripeut porter un schémajavascript:. Appliquez votre propre liste d’autorisationhttp/httpsavant de mettre une URL fournie par le registre dans unhrefousrc.
Une réponse non 2xx lance ClientResponseError (réexporté du paquet), portant .error, .description, .status et .headers. L’agrégateur de référence ne renvoie que des révisions CID exactes approuvées par chaque source d’étiquette positive requise. Un en-tête atproto-accept-labelers déclare des DID configurés bare pour l’identité de requête et de cache. L’agrégateur valide la déclaration, mais sa politique configurée reste autoritaire.
Filtrer par compatibilité d’hôte
Une release peut déclarer des exigences d’environnement (une plage de version EmDash ou Astro) dans son bloc requires. Le sous-chemin @emdash-cms/registry-client/env les évalue, afin qu’un annuaire puisse signaler les releases qui ne s’exécuteront pas sur un hôte donné :
import { checkEnvCompatibility, hostEnvFromVersions } from "@emdash-cms/registry-client/env";
import type { ValidatedReleaseView } from "@emdash-cms/registry-client/discovery";
const host = hostEnvFromVersions("0.37.0", "7.0.0");
// Pass a getLatestRelease() result. The returned array is empty when the
// release runs on this host.
export function envMismatches(latest: ValidatedReleaseView) {
return checkEnvCompatibility(latest.release?.requires, host);
}
Suite de lecture
- Le registre de plugins — activer et utiliser le registre sur un site EmDash
- Empaqueter et publier — publier un plugin sur le registre