{
	"$schema": "https://json-schema.org/draft/2020-12/schema",
	"$id": "https://emdashcms.com/schemas/emdash-plugin.schema.json",
	"title": "EmDash plugin manifest",
	"description": "Hand-authored manifest for publishing a plugin to the EmDash plugin registry. Lives next to the plugin's `package.json` as `emdash-plugin.jsonc`.",
	"type": "object",
	"properties": {
		"$schema": {
			"$ref": "#/$defs/__schema0"
		},
		"slug": {
			"$ref": "#/$defs/__schema1"
		},
		"version": {
			"$ref": "#/$defs/__schema2"
		},
		"license": {
			"$ref": "#/$defs/__schema3"
		},
		"publisher": {
			"$ref": "#/$defs/__schema4"
		},
		"capabilities": {
			"$ref": "#/$defs/__schema5"
		},
		"allowedHosts": {
			"$ref": "#/$defs/__schema7"
		},
		"storage": {
			"$ref": "#/$defs/__schema9"
		},
		"admin": {
			"$ref": "#/$defs/__schema16"
		},
		"author": {
			"$ref": "#/$defs/__schema27"
		},
		"authors": {
			"$ref": "#/$defs/__schema32"
		},
		"security": {
			"$ref": "#/$defs/__schema33"
		},
		"securityContacts": {
			"$ref": "#/$defs/__schema37"
		},
		"name": {
			"$ref": "#/$defs/__schema38"
		},
		"description": {
			"$ref": "#/$defs/__schema39"
		},
		"keywords": {
			"$ref": "#/$defs/__schema40"
		},
		"sections": {
			"$ref": "#/$defs/__schema42"
		},
		"repo": {
			"$ref": "#/$defs/__schema52"
		},
		"release": {
			"$ref": "#/$defs/__schema53"
		}
	},
	"required": [
		"slug",
		"license",
		"publisher",
		"capabilities",
		"allowedHosts",
		"storage"
	],
	"additionalProperties": false,
	"$defs": {
		"__schema0": {
			"type": "string",
			"description": "Path or URL to the JSON Schema describing this file. Editors use this for completion and validation."
		},
		"__schema1": {
			"type": "string",
			"minLength": 1,
			"maxLength": 64,
			"pattern": "^[a-z][a-z0-9_-]*$",
			"title": "Slug",
			"description": "URL-safe plugin identifier within the publisher's namespace. ASCII letter then letters/digits/hyphens/underscores, max 64 characters. Combined with the publisher DID, this is the registry's primary key.",
			"examples": [
				"gallery",
				"image-resizer",
				"my-plugin"
			]
		},
		"__schema2": {
			"type": "string",
			"minLength": 1,
			"maxLength": 64,
			"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$",
			"title": "Version",
			"description": "Plugin version. Semver 2.0 subset; build-metadata `+...` is disallowed (the atproto record-key alphabet has no `+`). Bumped on every release.",
			"examples": [
				"0.1.0",
				"1.2.3",
				"1.0.0-rc.1"
			]
		},
		"__schema3": {
			"type": "string",
			"minLength": 1,
			"maxLength": 256,
			"title": "License",
			"description": "SPDX license expression (e.g. \"MIT\", \"Apache-2.0\", \"MIT OR Apache-2.0\"). Required on first publish; ignored on subsequent publishes (the existing profile wins).",
			"examples": [
				"MIT",
				"Apache-2.0",
				"MIT OR Apache-2.0"
			]
		},
		"__schema4": {
			"type": "string",
			"title": "Publisher",
			"description": "Atproto DID or handle of the publishing identity. Pinned on first publish to prevent accidental publishes from a different account. DIDs are recommended (durable); handles work but are mutable.",
			"examples": [
				"did:plc:abc123def456",
				"example.com"
			]
		},
		"__schema5": {
			"default": [],
			"maxItems": 32,
			"type": "array",
			"items": {
				"$ref": "#/$defs/__schema6"
			},
			"title": "Capabilities",
			"description": "Trust contract: what runtime APIs the plugin is allowed to use. Changing this between releases requires a version bump because installed users have consented to the old contract."
		},
		"__schema6": {
			"type": "string",
			"minLength": 1
		},
		"__schema7": {
			"default": [],
			"maxItems": 64,
			"type": "array",
			"items": {
				"$ref": "#/$defs/__schema8"
			},
			"title": "Allowed hosts",
			"description": "Allow-list of outbound host patterns when `network:request` is declared. Subdomain wildcards use a leading `*.`. Required (non-empty) when `network:request` is declared without `network:request:unrestricted`.",
			"examples": [
				[
					"api.example.com",
					"*.cdn.example.com"
				]
			]
		},
		"__schema8": {
			"type": "string",
			"minLength": 1,
			"maxLength": 256
		},
		"__schema9": {
			"default": {},
			"type": "object",
			"propertyNames": {
				"$ref": "#/$defs/__schema10"
			},
			"additionalProperties": {
				"$ref": "#/$defs/__schema11"
			},
			"title": "Storage",
			"description": "Storage collections the plugin uses. Each collection is namespaced to this plugin at runtime."
		},
		"__schema10": {
			"type": "string",
			"minLength": 1,
			"pattern": "^[a-z][a-z0-9_]*$"
		},
		"__schema11": {
			"type": "object",
			"properties": {
				"indexes": {
					"$ref": "#/$defs/__schema12"
				},
				"uniqueIndexes": {
					"$ref": "#/$defs/__schema14"
				}
			},
			"required": [
				"indexes"
			],
			"additionalProperties": false,
			"title": "Storage collection",
			"description": "Index configuration for a single storage collection. Indexes are either single field names or composite (array of field names)."
		},
		"__schema12": {
			"type": "array",
			"items": {
				"anyOf": [
					{
						"type": "string",
						"minLength": 1
					},
					{
						"minItems": 1,
						"type": "array",
						"items": {
							"$ref": "#/$defs/__schema13"
						}
					}
				]
			}
		},
		"__schema13": {
			"type": "string",
			"minLength": 1
		},
		"__schema14": {
			"type": "array",
			"items": {
				"anyOf": [
					{
						"type": "string",
						"minLength": 1
					},
					{
						"minItems": 1,
						"type": "array",
						"items": {
							"$ref": "#/$defs/__schema15"
						}
					}
				]
			}
		},
		"__schema15": {
			"type": "string",
			"minLength": 1
		},
		"__schema16": {
			"type": "object",
			"properties": {
				"pages": {
					"$ref": "#/$defs/__schema17"
				},
				"widgets": {
					"$ref": "#/$defs/__schema22"
				}
			},
			"additionalProperties": false,
			"title": "Admin surface",
			"description": "Pages and widgets the plugin exposes in the admin UI. The plugin's `admin` route handler renders Block Kit content for each path / widget id at runtime."
		},
		"__schema17": {
			"maxItems": 32,
			"type": "array",
			"items": {
				"$ref": "#/$defs/__schema18"
			}
		},
		"__schema18": {
			"type": "object",
			"properties": {
				"path": {
					"$ref": "#/$defs/__schema19"
				},
				"label": {
					"$ref": "#/$defs/__schema20"
				},
				"icon": {
					"$ref": "#/$defs/__schema21"
				}
			},
			"required": [
				"path",
				"label"
			],
			"additionalProperties": false,
			"title": "Admin page",
			"description": "A single admin page declaration. The plugin's `admin` route handler is responsible for rendering Block Kit content for this path."
		},
		"__schema19": {
			"type": "string",
			"minLength": 2,
			"maxLength": 128,
			"pattern": "^\\/[a-z0-9][a-z0-9/_-]*$"
		},
		"__schema20": {
			"type": "string",
			"minLength": 1,
			"maxLength": 128
		},
		"__schema21": {
			"type": "string",
			"minLength": 1,
			"maxLength": 64
		},
		"__schema22": {
			"maxItems": 32,
			"type": "array",
			"items": {
				"$ref": "#/$defs/__schema23"
			}
		},
		"__schema23": {
			"type": "object",
			"properties": {
				"id": {
					"$ref": "#/$defs/__schema24"
				},
				"title": {
					"$ref": "#/$defs/__schema25"
				},
				"size": {
					"$ref": "#/$defs/__schema26"
				}
			},
			"required": [
				"id"
			],
			"additionalProperties": false,
			"title": "Admin widget",
			"description": "A single dashboard widget declaration."
		},
		"__schema24": {
			"type": "string",
			"minLength": 1,
			"maxLength": 64,
			"pattern": "^[a-z][a-z0-9_-]*$"
		},
		"__schema25": {
			"type": "string",
			"minLength": 1,
			"maxLength": 128
		},
		"__schema26": {
			"type": "string",
			"enum": [
				"full",
				"half",
				"third"
			]
		},
		"__schema27": {
			"$ref": "#/$defs/__schema28"
		},
		"__schema28": {
			"type": "object",
			"properties": {
				"name": {
					"$ref": "#/$defs/__schema29"
				},
				"url": {
					"$ref": "#/$defs/__schema30"
				},
				"email": {
					"$ref": "#/$defs/__schema31"
				}
			},
			"required": [
				"name"
			],
			"additionalProperties": false,
			"title": "Author",
			"description": "A single author entry. Mirrors the lexicon's author shape."
		},
		"__schema29": {
			"type": "string",
			"minLength": 1,
			"maxLength": 256,
			"description": "Display name."
		},
		"__schema30": {
			"type": "string",
			"maxLength": 1024,
			"format": "uri",
			"description": "Author's homepage or profile URL. Either this or `email` is recommended."
		},
		"__schema31": {
			"type": "string",
			"maxLength": 256,
			"format": "email",
			"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
			"description": "Author's contact email. Either this or `url` is recommended."
		},
		"__schema32": {
			"minItems": 1,
			"maxItems": 32,
			"type": "array",
			"items": {
				"$ref": "#/$defs/__schema28"
			},
			"title": "Authors (multiple)",
			"description": "Multi-author form. Mutually exclusive with `author`. Use the singular `author` if there is only one."
		},
		"__schema33": {
			"$ref": "#/$defs/__schema34"
		},
		"__schema34": {
			"type": "object",
			"properties": {
				"url": {
					"$ref": "#/$defs/__schema35"
				},
				"email": {
					"$ref": "#/$defs/__schema36"
				}
			},
			"additionalProperties": false,
			"title": "Security contact",
			"description": "A single security contact. At least one of `url` or `email` must be present."
		},
		"__schema35": {
			"type": "string",
			"maxLength": 1024,
			"format": "uri",
			"description": "Security disclosure URL (e.g. a security.txt or vulnerability-reporting page). Either this or `email` is required."
		},
		"__schema36": {
			"type": "string",
			"maxLength": 256,
			"format": "email",
			"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
			"description": "Security contact email. Either this or `url` is required."
		},
		"__schema37": {
			"minItems": 1,
			"maxItems": 8,
			"type": "array",
			"items": {
				"$ref": "#/$defs/__schema34"
			},
			"title": "Security contacts (multiple)",
			"description": "Multi-contact form. Mutually exclusive with `security`. Use the singular `security` if there is only one."
		},
		"__schema38": {
			"type": "string",
			"minLength": 1,
			"maxLength": 1024,
			"title": "Display name",
			"description": "Human-readable name shown in directory listings. Defaults to the plugin's `id` when omitted."
		},
		"__schema39": {
			"type": "string",
			"minLength": 1,
			"maxLength": 1024,
			"title": "Description",
			"description": "Short description (<= 140 graphemes by FAIR convention). Aggregators may truncate longer values when displaying in compact lists."
		},
		"__schema40": {
			"maxItems": 5,
			"type": "array",
			"items": {
				"$ref": "#/$defs/__schema41"
			},
			"title": "Keywords",
			"description": "Search keywords (<= 5 entries, FAIR convention)."
		},
		"__schema41": {
			"type": "string",
			"minLength": 1,
			"maxLength": 128
		},
		"__schema42": {
			"type": "object",
			"properties": {
				"description": {
					"$ref": "#/$defs/__schema43"
				},
				"installation": {
					"$ref": "#/$defs/__schema48"
				},
				"faq": {
					"$ref": "#/$defs/__schema49"
				},
				"changelog": {
					"$ref": "#/$defs/__schema50"
				},
				"security": {
					"$ref": "#/$defs/__schema51"
				}
			},
			"additionalProperties": false,
			"title": "Profile sections",
			"description": "Long-form package documentation (description / installation / faq / changelog / security). Each value is CommonMark Markdown (inline or a `{ file }` ref) capped at 20000 bytes / 2000 graphemes. Rendered on the package's registry page."
		},
		"__schema43": {
			"$ref": "#/$defs/__schema44"
		},
		"__schema44": {
			"anyOf": [
				{
					"$ref": "#/$defs/__schema45"
				},
				{
					"$ref": "#/$defs/__schema46"
				}
			],
			"title": "Section value",
			"description": "Either inline CommonMark Markdown or a `{ file }` reference to a sibling Markdown file."
		},
		"__schema45": {
			"type": "string",
			"description": "Inline CommonMark Markdown for this section. Capped at 20000 bytes / 2000 graphemes."
		},
		"__schema46": {
			"type": "object",
			"properties": {
				"file": {
					"$ref": "#/$defs/__schema47"
				}
			},
			"required": [
				"file"
			],
			"additionalProperties": false,
			"title": "Section file reference",
			"description": "Loads the section's Markdown from a sibling file instead of inlining it in the manifest."
		},
		"__schema47": {
			"type": "string",
			"minLength": 1,
			"maxLength": 1024,
			"description": "Path to a CommonMark Markdown file, relative to the manifest. Its content is read inline into the section at publish time."
		},
		"__schema48": {
			"$ref": "#/$defs/__schema44"
		},
		"__schema49": {
			"$ref": "#/$defs/__schema44"
		},
		"__schema50": {
			"$ref": "#/$defs/__schema44"
		},
		"__schema51": {
			"$ref": "#/$defs/__schema44"
		},
		"__schema52": {
			"type": "string",
			"maxLength": 1024,
			"format": "uri",
			"pattern": "^https:\\/\\/",
			"title": "Source repository",
			"description": "HTTPS URL of the plugin's source repository. Surfaced in registry listings.",
			"examples": [
				"https://github.com/emdash-cms/plugin-gallery"
			]
		},
		"__schema53": {
			"type": "object",
			"properties": {
				"requires": {
					"$ref": "#/$defs/__schema54"
				},
				"artifacts": {
					"$ref": "#/$defs/__schema57"
				}
			},
			"additionalProperties": false,
			"title": "Release",
			"description": "Per-release fields: environment constraints (`requires`) and media artifacts (icon / screenshot / banner)."
		},
		"__schema54": {
			"type": "object",
			"propertyNames": {
				"$ref": "#/$defs/__schema55"
			},
			"additionalProperties": {
				"$ref": "#/$defs/__schema56"
			},
			"title": "Environment requirements",
			"description": "Host environment constraints for this release, keyed by `env:*` (e.g. \"env:astro\", \"env:emdash\") with semver-range values. EmDash refuses to install a release whose constraints the host does not satisfy.",
			"examples": [
				{
					"env:emdash": ">=1.0.0",
					"env:astro": ">=4.16"
				}
			]
		},
		"__schema55": {
			"type": "string"
		},
		"__schema56": {
			"type": "string",
			"minLength": 1
		},
		"__schema57": {
			"type": "object",
			"properties": {
				"icon": {
					"$ref": "#/$defs/__schema58"
				},
				"banner": {
					"$ref": "#/$defs/__schema62"
				},
				"screenshots": {
					"$ref": "#/$defs/__schema63"
				}
			},
			"additionalProperties": false,
			"title": "Artifacts",
			"description": "Release media artifacts. `icon` and `banner` are single images; `screenshots` is a gallery array."
		},
		"__schema58": {
			"$ref": "#/$defs/__schema59"
		},
		"__schema59": {
			"type": "object",
			"properties": {
				"file": {
					"$ref": "#/$defs/__schema60"
				},
				"lang": {
					"$ref": "#/$defs/__schema61"
				}
			},
			"required": [
				"file"
			],
			"additionalProperties": false,
			"title": "Artifact file reference",
			"description": "A media file (PNG / JPEG / WebP / GIF / AVIF) bundled into a release as an icon, screenshot, or banner."
		},
		"__schema60": {
			"type": "string",
			"minLength": 1,
			"maxLength": 1024,
			"description": "Path to the image file, relative to the manifest. Resolved, hashed, measured, and uploaded at publish time."
		},
		"__schema61": {
			"type": "string",
			"minLength": 2,
			"maxLength": 64,
			"description": "BCP 47 language tag for a localised artifact (e.g. \"en\", \"pt-BR\").",
			"examples": [
				"en",
				"pt-BR"
			]
		},
		"__schema62": {
			"$ref": "#/$defs/__schema59"
		},
		"__schema63": {
			"minItems": 1,
			"maxItems": 8,
			"type": "array",
			"items": {
				"$ref": "#/$defs/__schema59"
			},
			"title": "Screenshots",
			"description": "Screenshot gallery for the plugin's detail page (<= 8 entries)."
		}
	}
}
