레지스트리 조회

이 페이지

이것은 플러그인 레지스트리에 대해 자체 소프트웨어를 구축하기 위한 고급 주제입니다. EmDash 사이트에 플러그인을 설치하기만 하면 된다면, 이것은 필요하지 않습니다. 구성에서 레지스트리를 활성화하고 관리 대시보드를 사용하세요.

레지스트리의 디스커버리 측은 공개 읽기 전용 API입니다. @emdash-cms/registry-client 패키지가 이를 래핑하므로 EmDash 외부에서 플러그인 디렉터리, 검색 페이지, 릴리스 피드를 만들 수 있습니다. 클라이언트는 fetch가 사용 가능한 곳이라면 어디서나 실행됩니다(Node, Workers, 브라우저, Astro 사이트). Astro 사이트는 @emdash-cms/registry-loader를 사용해 동일한 데이터를 라이브 콘텐츠 컬렉션을 통해 노출할 수 있습니다.

설치

discovery 서브패스에는 인증 또는 OAuth 종속성이 없습니다. 클라이언트를 설치하고 정확한 버전으로 고정합니다:

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

패키지 나열 및 확인

다음 Astro 페이지는 레지스트리의 모든 플러그인을 나열합니다:

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

현재 검증된 핸들은 애그리게이터가 해결한 경우 표시됩니다. DID 형식을 폴백으로 유지하고, 이후 응답이 제공되면 현재 핸들 URL로 리디렉션하세요. 퍼블리셔가 핸들을 변경하더라도 DID와 패키지 슬러그는 안정적인 패키지 식별자로 남습니다.

정확한 q 값은 핸들, DID 또는 둘 중 하나 뒤에 /slug가 따라오는 식별자일 수 있습니다. 예를 들어, @example.com/my-gallery는 하나의 패키지를 선택하고 example.com은 해당 퍼블리셔의 패키지를 반환합니다.

Astro 라이브 로더 사용

@emdash-cms/registry-loader를 설치한 다음 src/live.config.ts에 로더를 등록합니다:

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

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

제한된 결과에는 getLiveCollection("plugins", { q, limit })를 사용하고, 하나의 패키지에는 getLiveEntry("plugins", { publisher, slug })를 사용합니다. 사이트에 Astro 캐시 공급자가 있는 경우 반환된 캐시 힌트를 Astro.cache.set()에 전달합니다. Astro 라이브 컬렉션은 페이지네이션 메타데이터를 반환하지 않으므로 인터페이스에 다음 커서가 필요한 경우 DiscoveryClient.searchPackages()를 직접 사용하세요.

패키지 세부 정보 페이지는 DID와 슬러그로 플러그인을 가져온 다음 최신 릴리스를 가져옵니다:

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

디스커버리 메서드

클라이언트는 애그리게이터 쿼리당 하나의 메서드를 노출합니다:

  • searchPackages({ q, capability?, limit?, cursor? }) — 자유 텍스트 검색이며, 선택적으로 주어진 액세스 카테고리를 선언하는 패키지로 필터링됩니다. { packages, cursor? }를 반환합니다.
  • resolvePackage({ handle, slug }) — 핸들과 슬러그에서 패키지를 확인합니다.
  • getPackage({ did, slug }) — DID와 슬러그로 패키지를 가져옵니다.
  • listReleases({ did, package, limit?, cursor? }) — 내림차순 시맨틱 버전 순서로 릴리스를 가져오며, yanked된 릴리스를 포함합니다.
  • getLatestRelease({ did, package }) — 애그리게이터에서 선택한 최고의 yanked되지 않은 릴리스입니다.

getPackage()와 resolvePackage()는 historicalReleaseCount와 releaseHistoryComplete를 반환할 수 있습니다. 이러한 필드는 퍼블리셔가 서명한 메타데이터가 아니라 애그리게이터가 보유한 운영 기록을 설명합니다. releaseHistoryComplete가 true인 경우에만 카운트가 1인 것을 첫 번째 릴리스로 취급하세요. 누락되거나 불완전한 증거는 릴리스 에이지 정책을 우회해서는 안 됩니다.

getPackageStatus()와 resolvePackageStatus()는 해당 패키지 쿼리를 래핑하고 안전한 ListingUnavailable 응답을 { status: "unavailable" }에 매핑합니다. 성공적인 결과는 { status: "passed", value }를 가집니다. 퍼블리셔가 제어하는 오류 콘텐츠를 렌더링하지 않고 인덱싱되었지만 사용할 수 없는 리스팅과 누락된 패키지를 구별해야 하는 사용자 인터페이스에서 이러한 메서드를 사용하세요.

릴리스를 표시하거나 선택하기 전에 철회 헬퍼를 사용하세요:

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입니다. 잘못된 레이블 데이터는 닫힌 상태로 실패합니다: withdrawn과 malformed가 모두 true입니다.

신뢰할 수 없는 레코드 처리

애그리게이터는 자신이 작성하지 않은 레코드를 릴레이하는 신뢰할 수 없는 인덱스이므로 클라이언트는 경계에서 각 레코드를 검증합니다. 여기서 두 가지 규칙이 나옵니다:

  • profile 및 release 필드는 null일 수 있습니다. 릴레이된 레코드가 검증에 실패하면 클라이언트는 전체 호출을 실패시키는 대신 null로 표시하므로 하나의 잘못된 레코드가 검색 페이지를 공백으로 만들지 않습니다. pkg.profile?.name 또는 latest.release?.artifacts.package를 읽기 전에 항상 null 검사를 수행하세요.
  • 렌더링하기 전에 URL 스키마를 직접 검증하세요. 검증은 구조를 확인하지 URL 안전성은 확인하지 않습니다. uri 필드에는 javascript: 스키마가 포함될 수 있습니다. 레지스트리에서 제공하는 URL을 href 또는 src에 넣기 전에 자체 http/https 허용 목록을 적용하세요.

2xx가 아닌 응답은 .error, .description, .status, .headers를 포함하는 ClientResponseError(패키지에서 다시 내보낸)를 발생시킵니다. 참조 애그리게이터는 필요한 모든 양수 레이블 소스에서 승인된 정확한 CID 개정판만 반환합니다. atproto-accept-labelers 헤더는 요청 및 캐시 ID에 대해 구성된 베어 DID를 선언합니다. 애그리게이터는 선언을 검증하지만 구성된 정책이 권위를 유지합니다.

호스트 호환성별 필터링

릴리스는 requires 블록에서 환경 요구 사항(EmDash 또는 Astro 버전 범위)을 선언할 수 있습니다. @emdash-cms/registry-client/env 서브패스가 이를 평가하므로 디렉터리는 주어진 호스트에서 실행되지 않는 릴리스에 플래그를 지정할 수 있습니다:

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

// getLatestRelease() 결과를 전달합니다. 반환된 배열은
// 이 호스트에서 릴리스가 실행될 때 비어 있습니다.
export function envMismatches(latest: ValidatedReleaseView) {
  return checkEnvCompatibility(latest.release?.requires, host);
}

다음에 읽을 내용