Das Register abfragen

Auf dieser Seite

Dies ist ein fortgeschrittenes Thema für die Entwicklung eigener Software gegen das Plugin-Register. Wenn Sie nur Plugins auf einer EmDash-Site installieren wollen, brauchen Sie nichts davon — aktivieren Sie das Register in Ihrer Konfiguration und nutzen Sie das Admin-Dashboard.

Die Discovery-Seite des Registers ist eine öffentliche, schreibgeschützte API. Das Paket @emdash-cms/registry-client umschließt sie, sodass Sie ein Plugin-Verzeichnis, eine Suchseite oder einen Release-Feed außerhalb von EmDash bauen können. Der Client läuft überall, wo fetch verfügbar ist — Node, Workers, Browser oder eine Astro-Site. Astro-Sites können @emdash-cms/registry-loader nutzen, um dieselben Daten über eine Live Content Collection bereitzustellen.

Installieren

Der Unterpfad discovery trägt keine Authentifizierungs- oder OAuth-Abhängigkeiten. Installieren Sie den Client und pinnen Sie ihn auf eine exakte Version:

npm install @emdash-cms/registry-client@0.6.0

Packages listen und auflösen

Die folgende Astro-Seite listet jedes Plugin in einem Register:

---
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>

Der aktuelle verifizierte Handle ist vorhanden, wenn der Aggregator ihn aufgelöst hat. Behalten Sie die DID-Form als Fallback und leiten Sie sie zur aktuellen Handle-URL um, wenn eine spätere Antwort eine liefert. DID und Package-Slug bleiben die stabile Package-Identität, wenn ein Publisher den Handle wechselt.

Ein exakter q-Wert kann ein Handle, eine DID oder eine der beiden Identitäten gefolgt von /slug sein. Zum Beispiel wählt @example.com/my-gallery ein Package und example.com gibt Packages dieses Publishers zurück.

Den Astro Live Loader verwenden

Installieren Sie @emdash-cms/registry-loader und registrieren Sie den Loader dann in src/live.config.ts:

import { registryLoader } from "@emdash-cms/registry-loader";
import { defineLiveCollection } from "astro:content";

export const collections = {
	plugins: defineLiveCollection({ loader: registryLoader() }),
};

Nutzen Sie getLiveCollection("plugins", { q, limit }) für begrenzte Ergebnisse und getLiveEntry("plugins", { publisher, slug }) für ein Package. Übergeben Sie den zurückgegebenen Cache-Hinweis an Astro.cache.set(), wenn die Site einen Astro-Cache-Provider hat. Astro Live Collections geben keine Paginierungs-Metadaten zurück, daher verwenden Sie DiscoveryClient.searchPackages() direkt, wenn die Oberfläche den nächsten Cursor braucht.

Eine Package-Detailseite holt ein Plugin per DID und Slug und dann die neueste 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 };
}

Discovery-Methoden

Der Client stellt eine Methode pro Aggregator-Abfrage bereit:

  • searchPackages({ q, capability?, limit?, cursor? }) — Freitextsuche, optional gefiltert auf Packages, die eine gegebene Zugriffskategorie deklarieren. Gibt { packages, cursor? } zurück.
  • resolvePackage({ handle, slug }) — ein Package aus Handle und Slug auflösen.
  • getPackage({ did, slug }) — ein Package per DID und Slug abrufen.
  • listReleases({ did, package, limit?, cursor? }) — Releases in absteigender semantischer Versionsreihenfolge, einschließlich zurückgezogener Releases.
  • getLatestRelease({ did, package }) — die höchste nicht zurückgezogene Release, die der Aggregator ausgewählt hat.

getPackage() und resolvePackage() können historicalReleaseCount und releaseHistoryComplete zurückgeben. Diese Felder beschreiben die vom Aggregator behaltene operative Historie, nicht publisher-signierte Metadaten. Behandeln Sie eine Anzahl von eins nur dann als erste Release, wenn releaseHistoryComplete true ist. Fehlende oder unvollständige Evidenz darf eine Release-Altersrichtlinie nicht umgehen.

getPackageStatus() und resolvePackageStatus() umschließen ihre entsprechenden Package-Abfragen und mappen die sichere ListingUnavailable-Antwort auf { status: "unavailable" }. Ein erfolgreiches Ergebnis hat { status: "passed", value }. Nutzen Sie diese Methoden in einer Benutzeroberfläche, die ein indexiertes, aber nicht verfügbares Listing von einem fehlenden Package unterscheiden muss, ohne publisher-kontrollierte Fehlerinhalte zu rendern.

Nutzen Sie den Withdrawal-Helper, bevor Sie eine Release anzeigen oder auswählen:

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 ist true, wenn die geltenden Labels die Release aus der Nutzung entfernen. Ungültige Label-Daten scheitern geschlossen: withdrawn und malformed sind beide true.

Untrusted Records behandeln

Der Aggregator ist ein untrusted Index, der Records weiterleitet, die er nicht verfasst hat, daher validiert der Client jeden an der Grenze. Daraus folgen zwei Regeln:

  • Die Felder profile und release können null sein. Wenn ein weitergeleiteter Record die Validierung nicht besteht, liefert der Client ihn als null, statt den gesamten Aufruf scheitern zu lassen, sodass ein fehlerhafter Record eine Suchseite nicht leert. Prüfen Sie immer auf null, bevor Sie pkg.profile?.name oder latest.release?.artifacts.package lesen.
  • Validieren Sie URL-Schemata selbst vor dem Rendern. Die Validierung prüft Struktur, nicht URL-Sicherheit — ein uri-Feld kann ein javascript:-Schema tragen. Wenden Sie Ihre eigene http/https-Allow-List an, bevor Sie eine register-gelieferte URL in ein href oder src setzen.

Eine Nicht-2xx-Antwort wirft ClientResponseError (aus dem Paket re-exportiert) mit .error, .description, .status und .headers. Der Referenz-Aggregator gibt nur Exact-CID-Revisionen zurück, die von jeder erforderlichen Positive-Label-Quelle genehmigt wurden. Ein Header atproto-accept-labelers deklariert bare konfigurierte DIDs für Anfrage- und Cache-Identität. Der Aggregator validiert die Deklaration, aber seine konfigurierte Richtlinie bleibt maßgeblich.

Nach Host-Kompatibilität filtern

Eine Release kann Umgebungsanforderungen (einen EmDash- oder Astro-Versionsbereich) in ihrem requires-Block deklarieren. Der Unterpfad @emdash-cms/registry-client/env wertet sie aus, sodass ein Verzeichnis Releases kennzeichnen kann, die auf einem gegebenen Host nicht laufen:

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);
}

Was als Nächstes lesen