플러그인 매니페스트

이 페이지

모든 샌드박스 플러그인은 package.json 옆에 emdash-plugin.jsonc를 가지고 있습니다. 수동으로 편집되며 플러그인의 아이덴티티, 신뢰 계약(기능, 호스트, 스토리지), 레지스트리에 표시되는 프로필 필드를 포함합니다. emdash-plugin init이 스캐폴드를 생성합니다. CLI는 build, dev, validate, bundle, publish에서 ./emdash-plugin.jsonc를 자동으로 읽습니다.

파일은 JSONC입니다: 주석과 후행 쉼표가 허용됩니다.

다음 예제는 이미지 갤러리 플러그인의 완전한 매니페스트를 보여줍니다:

{
	"$schema": "./node_modules/@emdash-cms/plugin-cli/schemas/emdash-plugin.schema.json",

	"slug": "gallery",
	"publisher": "did:plc:abc123def456",

	"license": "MIT",
	"author": { "name": "Jane Doe", "url": "https://example.com" },
	"security": { "email": "[email protected]" },

	// 선택적 프로필
	"name": "Gallery",
	"description": "EmDash용 이미지 갤러리 블록.",
	"keywords": ["gallery", "images"],
	"repo": "https://github.com/example/plugin-gallery",

	// 신뢰 계약
	"capabilities": ["content:read"],
	"allowedHosts": [],
	"storage": {}
}

아이덴티티

필드필수비고
slug퍼블리셔 네임스페이스 내의 URL 안전 ID. /^[a-z][a-z0-9_-]*$/, 최대 64자.
publisherAtmosphere 계정의 DID 또는 핸들. 퍼블리셔 피닝 참조.
version아니오빌드 메타데이터 없는 Semver 2.0. 보통 생략 — 아래 참조.

slugpublisher가 합쳐져 패키지의 아이덴티티가 됩니다. EmDash는 이들로부터 패키지의 전체 식별자를 자동으로 도출합니다.

versionpackage.json에 둡니다

빌드는 매니페스트의 versionpackage.json#version과 대조합니다:

  • 둘 다 설정되어 있고 같음 → 정상.
  • 둘 다 설정되어 있고 다름 → 하드 에러.
  • 하나만 설정 → 해당 값이 우선.
  • 둘 다 미설정 → 하드 에러.

npm 배포 플러그인의 권장 패턴은 매니페스트에서 version을 생략하고 package.json을 유일한 진실의 원천으로 삼는 것입니다(릴리스 도구가 이미 거기서 버전을 올립니다). package.json이 없는 레지스트리 전용 플러그인은 매니페스트에 version을 설정해야 합니다 — 다른 곳에 둘 수 없습니다.

프로필

이들은 레지스트리 목록에 반영됩니다. license, 저자(author 또는 authors), 보안 연락처(security 또는 securityContacts)는 필수입니다. 나머지는 선택 사항입니다.

필드필수비고
licenseSPDX 표현식("MIT", "Apache-2.0", "MIT OR Apache-2.0"). 첫 번째 게시 시 사용; 이후 게시에서는 기존 프로필이 우선.
author / authors둘 중 하나. author: { name, url?, email? }는 단일 저자용; authors: [...] (≤ 32)은 여러 저자용. 둘 다 설정하면 에러.
security / securityContacts둘 중 하나. 각 연락처는 최소 email 또는 url이 필요. securityContacts: [...] (≤ 8)은 여러 개용. 둘 다 설정하면 에러.
name아니오표시 이름. 기본값은 slug.
description아니오짧게 유지(약 140자). 긴 값은 목록에서 잘릴 수 있음.
keywords아니오≤ 5개 항목.
repo아니오소스 저장소의 https:// URL.

실제로 여러 명이 아닌 한 단수형 author / security를 사용하세요 — 이것이 일반적인 경우이며 스캐폴드도 이렇게 출력합니다.

신뢰 계약

신뢰 계약은 capabilities, allowedHosts, storage입니다. 세 가지 모두 기본값은 비어 있으므로, 추가 권한이 필요 없는 플러그인은 완전히 생략할 수 있습니다.

{
	"capabilities": ["network:request", "content:read"],
	"allowedHosts": ["api.example.com", "*.cdn.example.com"],
	"storage": {
		"events": { "indexes": ["timestamp"] },
		"submissions": { "indexes": ["email"], "uniqueIndexes": ["token"] }
	}
}

기능

인식되는 이름:

기능허용하는 것
content:read / content:writectx를 통한 사이트 콘텐츠 읽기 / 변경.
taxonomies:read택소노미 정의 및 용어 읽기(읽기 전용).
media:read / media:write미디어 읽기 / 쓰기.
users:read사용자 레코드 읽기.
email:sendctx를 통한 이메일 전송.
network:requestctx.http를 통한 아웃바운드 HTTP, allowedHosts로 제한.
network:request:unrestricted모든 호스트로의 아웃바운드 HTTP. network:request 대신 사용.
hooks.email-transport:register이메일 전송 훅 등록.
hooks.email-events:register이메일 라이프사이클 훅 등록.
hooks.page-fragments:registerpage:fragments 훅 등록(네이티브만).

CLI가 강제하는 두 가지 교차 필드 규칙(에디터의 JSON-Schema 검사에서는 강제되지 않음 — emdash-plugin validate를 실행하세요):

  • network:request는 비어 있지 않은 allowedHosts필요로 합니다. 플러그인이 정말로 모든 호스트에 도달해야 하면, 대신 network:request:unrestricted를 사용하세요.
  • network:request:unrestrictedallowedHosts가 비어 있을 것을 필요로 합니다 — 무제한 기능이 이미 모든 호스트를 허용하므로, 목록은 모순됩니다.

호스트 패턴은 베어 호스트명입니다(스킴, 경로, 공백 없음). 앞에 *.을 붙이면 하위 도메인을 허용합니다: *.cdn.example.com.

스토리지

컬렉션 이름 → 인덱스 설정의 맵. 컬렉션 이름은 같은 /^[a-z][a-z0-9_]*$/ 규칙을 따릅니다(런타임은 이름을 SQL 테이블 접미사로 사용). 인덱스는 필드 이름 또는 복합 배열입니다. uniqueIndexes도 쿼리 가능합니다 — indexes에 추가로 나열하지 마세요.

"storage": {
	"events": { "indexes": ["timestamp", ["collection", "timestamp"]] }
}

관리 화면

선택 사항. 샌드박스 플러그인은 Block Kit을 통해 관리 페이지와 대시보드 위젯을 렌더링합니다. 매니페스트는 어디에 나타나는지만 선언합니다. 플러그인에 관리 UI가 없으면 admin 키를 완전히 생략하세요.

"admin": {
	"pages": [{ "path": "/gallery", "label": "갤러리", "icon": "image" }],
	"widgets": [{ "id": "recent-uploads", "title": "최근 업로드", "size": "half" }]
}

admin.pages 또는 admin.widgets를 선언하는 플러그인은 src/plugin.ts에서 Block Kit 콘텐츠를 렌더링하는 admin 라우트도 제공해야 합니다 — 스키마가 이를 강제할 수 없지만(라우트 이름은 매니페스트가 아닌 소스에서 탐색됨), 런타임이 확인합니다.

퍼블리셔 피닝

publisher는 게시 아이덴티티를 고정하여 실수로 잘못된 계정으로 플러그인을 게시하는 것을 방지합니다.

첫 번째 성공적인 게시 시, 매니페스트의 publisher가 활성 세션과 일치하면 그대로 유지됩니다. emdash-plugin init으로 스캐폴드를 생성하고 비워 둔 경우, CLI가 활성 세션의 DID를 매니페스트에 다시 씁니다.

다음 예제는 CLI가 쓰는 줄을 보여주며, 가독성을 위해 해결된 핸들이 주석으로 추가되었습니다:

"publisher": "did:plc:abc123def456", // jane.example.com

이후 각 게시 시, CLI는 활성 세션과 고정된 publisher를 DID로 해결하여 비교합니다. 불일치는 MANIFEST_PUBLISHER_MISMATCH로 즉시 실패합니다 — 오버라이드 플래그가 없습니다. 의도적으로 해결하세요:

  • 잘못된 세션: emdash-plugin switch <did> 후 다시 게시.
  • 플러그인을 새 퍼블리셔에게 정식 이전: 매니페스트의 publisher를 편집.

게시 없이 유효성 검사

emdash-plugin validate          # ./emdash-plugin.jsonc
emdash-plugin validate path/    # 특정 디렉토리

교차 필드 규칙을 포함한 tsc 스타일 파일:줄:열 진단이 있는 오프라인 스키마 검사. 프리커밋 훅이나 CI 단계에 적합합니다. 중복 키와 알 수 없는 키는 에러입니다(엄격 모드는 "licens" 같은 오타를 잡습니다).

CLI 플래그가 항상 우선

명시적 플래그(--license, --author-name, …)는 둘 다 설정된 경우 매니페스트 값을 덮어씁니다 — CI 오버라이드에 유용합니다. --no-manifest는 매니페스트를 완전히 건너뜁니다(기본 경로에 존재하면 경고하여 퍼블리셔 핀 보안 스토리가 보이도록 합니다).

다음