Consultar o registro

Nesta página

Este é um tópico avançado para construir seu próprio software contra o registro de plugins. Se você só quer instalar plugins em um site EmDash, não precisa de nada disso — habilite o registro na sua configuração e use o painel de administração.

O lado de descoberta do registro é uma API pública somente leitura. O pacote @emdash-cms/registry-client a envolve, para que você possa criar um diretório de plugins, uma página de busca ou um feed de releases fora do EmDash. O cliente roda onde houver fetch — Node, Workers, o navegador ou um site Astro. Sites Astro podem usar @emdash-cms/registry-loader para expor os mesmos dados por uma live content collection.

Instalar

O subcaminho discovery não carrega dependências de autenticação ou OAuth. Instale o cliente e fixe-o em uma versão exata:

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

Listar e resolver pacotes

A seguinte página Astro lista cada plugin em um registro:

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

O handle verificado atual está presente quando o agregador o resolveu. Mantenha a forma DID como fallback e redirecione-a para a URL do handle atual quando uma resposta posterior fornecer uma. Um DID e o slug do pacote permanecem a identidade estável do pacote quando um publisher muda de handle.

Um valor exato de q pode ser um handle, um DID, ou qualquer uma das duas identidades seguida de /slug. Por exemplo, @example.com/my-gallery seleciona um pacote e example.com retorna pacotes desse publisher.

Usar o live loader do Astro

Instale @emdash-cms/registry-loader e então registre o loader em src/live.config.ts:

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

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

Use getLiveCollection("plugins", { q, limit }) para resultados limitados e getLiveEntry("plugins", { publisher, slug }) para um pacote. Passe a dica de cache retornada a Astro.cache.set() quando o site tiver um provedor de cache Astro. Live collections do Astro não retornam metadados de paginação, então use DiscoveryClient.searchPackages() diretamente quando a interface precisar do próximo cursor.

Uma página de detalhe do pacote busca um plugin pelo DID e slug, e então busca a release mais recente:

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étodos de descoberta

O cliente expõe um método por consulta do agregador:

  • searchPackages({ q, capability?, limit?, cursor? }) — busca de texto livre, opcionalmente filtrada a pacotes que declaram uma categoria de acesso dada. Retorna { packages, cursor? }.
  • resolvePackage({ handle, slug }) — resolver um pacote a partir de um handle e um slug.
  • getPackage({ did, slug }) — buscar um pacote pelo DID e slug.
  • listReleases({ did, package, limit?, cursor? }) — releases em ordem decrescente de versão semântica, incluindo releases retiradas.
  • getLatestRelease({ did, package }) — a release não retirada mais alta selecionada pelo agregador.

getPackage() e resolvePackage() podem retornar historicalReleaseCount e releaseHistoryComplete. Esses campos descrevem o histórico operacional retido pelo agregador, não metadados assinados pelo publisher. Trate uma contagem de um como primeira release somente quando releaseHistoryComplete for true. Evidência ausente ou incompleta não deve contornar uma política de idade de release.

getPackageStatus() e resolvePackageStatus() envolvem suas consultas de pacote correspondentes e mapeiam a resposta segura ListingUnavailable para { status: "unavailable" }. Um resultado bem-sucedido tem { status: "passed", value }. Use esses métodos em uma interface de usuário que precise distinguir um listagem indexada mas indisponível de um pacote ausente sem renderizar conteúdo de erro controlado pelo publisher.

Use o helper de retirada antes de mostrar ou selecionar uma 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 é true quando os rótulos aplicáveis removem a release do uso. Dados de rótulo inválidos falham em fechamento: withdrawn e malformed são ambos true.

Lidar com registros não confiáveis

O agregador é um índice não confiável que retransmite registros que não autorou, então o cliente valida cada um na fronteira. Duas regras seguem disso:

  • Os campos profile e release podem ser null. Quando um registro retransmitido falha na validação, o cliente o apresenta como null em vez de falhar toda a chamada, de modo que um registro malformado não esvazie uma página de busca. Sempre verifique null antes de ler pkg.profile?.name ou latest.release?.artifacts.package.
  • Valide você mesmo os esquemas de URL antes de renderizar. A validação verifica estrutura, não segurança de URL — um campo uri pode carregar um esquema javascript:. Aplique sua própria lista de permissão http/https antes de colocar qualquer URL fornecida pelo registro em um href ou src.

Uma resposta não 2xx lança ClientResponseError (reexportado do pacote), carregando .error, .description, .status e .headers. O agregador de referência retorna apenas revisões de CID exato aprovadas por cada fonte de rótulo positivo exigida. Um cabeçalho atproto-accept-labelers declara DIDs configurados bare para identidade de solicitação e cache. O agregador valida a declaração, mas sua política configurada permanece autoritativa.

Filtrar por compatibilidade de host

Uma release pode declarar requisitos de ambiente (um intervalo de versão EmDash ou Astro) em seu bloco requires. O subcaminho @emdash-cms/registry-client/env os avalia, para que um diretório possa marcar releases que não rodarão em um host dado:

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

O que ler a seguir