{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://plugins.geolibre.app/schemas/registry-entry.schema.json",
  "title": "GeoLibre plugin registry entry",
  "description": "One plugin's entry in registry/<id>.json. plugin-registry.json is generated from these files.",
  "type": "object",
  "additionalProperties": false,
  "required": ["id", "name", "version", "manifestUrl"],
  "properties": {
    "id": {
      "description": "Unique plugin id. Must match the file name, the manifest, and the exported plugin.",
      "type": "string",
      "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$",
      "maxLength": 64,
      "$comment": "must be lowercase letters and digits, separated by single . _ or - characters"
    },
    "name": {
      "description": "Display name shown in the marketplace.",
      "type": "string",
      "$ref": "#/$defs/trimmedString",
      "maxLength": 80
    },
    "version": {
      "description": "Plugin version. Must match the manifest.",
      "$ref": "#/$defs/semver"
    },
    "description": {
      "description": "Short summary shown on the plugin card.",
      "type": "string",
      "$ref": "#/$defs/trimmedString",
      "maxLength": 500
    },
    "author": {
      "type": "string",
      "$ref": "#/$defs/trimmedString",
      "maxLength": 120
    },
    "homepage": {
      "type": "string",
      "pattern": "^https?://\\S+$",
      "$comment": "must be an http:// or https:// URL"
    },
    "repository": {
      "description": "The plugin's source repository, linked from its catalog page.",
      "type": "string",
      "pattern": "^https://\\S+$",
      "$comment": "must be an https:// URL"
    },
    "issues": {
      "description": "Where to report problems with the plugin, linked from its catalog page.",
      "type": "string",
      "pattern": "^https://\\S+$",
      "$comment": "must be an https:// URL"
    },
    "license": {
      "description": "The plugin's license, as an SPDX identifier or expression such as MIT or Apache-2.0 OR MIT.",
      "type": "string",
      "maxLength": 100,
      "pattern": "^[A-Za-z0-9.+-]+(?: (?:AND|OR|WITH) [A-Za-z0-9.+-]+)*$",
      "$comment": "must be an SPDX license identifier or expression, e.g. MIT or Apache-2.0 OR MIT"
    },
    "manifestUrl": {
      "description": "plugins/<dir>/plugin.json, or an absolute HTTPS URL for a plugin hosted elsewhere.",
      "type": "string",
      "pattern": "^(?:https://\\S+|(?!.*\\.\\.)plugins/[^/\\s]+/\\S+\\.json)$",
      "$comment": "must be plugins/<dir>/<file>.json (no .. segments) or an https:// URL"
    },
    "source": {
      "description": "The plugin's release zip, for a plugin whose code isn't committed here. CI downloads it, checks sha256, and serves it from plugins/<id>/. manifestUrl must then be plugins/<dir>/plugin.json: plugins/<id>/ for a new plugin, or the folder a migrated plugin was served from.",
      "type": "object",
      "additionalProperties": false,
      "required": ["url", "sha256"],
      "properties": {
        "url": {
          "type": "string",
          "pattern": "^https://\\S+$",
          "$comment": "must be an https:// URL"
        },
        "sha256": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$",
          "$comment": "must be the zip's SHA-256 as 64 lowercase hex characters"
        }
      }
    },
    "categories": {
      "description": "One to four categories from the fixed list.",
      "type": "array",
      "minItems": 1,
      "maxItems": 4,
      "uniqueItems": true,
      "items": {
        "$ref": "#/$defs/category"
      }
    },
    "minGeoLibreVersion": {
      "description": "Lowest GeoLibre version the plugin supports.",
      "$ref": "#/$defs/semver"
    },
    "publishableSettings": {
      "description": "Project-state keys that survive \"Strip credentials\" and shared exports: true keeps the plugin's whole state, an array keeps only those keys.",
      "$comment": "must be true or a non-empty array of up to 64 unique key names",
      "oneOf": [
        {
          "const": true
        },
        {
          "type": "array",
          "minItems": 1,
          "maxItems": 64,
          "uniqueItems": true,
          "items": {
            "type": "string",
            "$ref": "#/$defs/trimmedString",
            "maxLength": 128
          }
        }
      ]
    },
    "screenshots": {
      "description": "Up to four screenshots shown on the plugin's catalog page. Each path is a PNG, JPEG or WebP file inside the release zip (relative to plugin.json), so it needs a source.",
      "type": "array",
      "minItems": 1,
      "maxItems": 4,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["path", "caption"],
        "properties": {
          "path": {
            "type": "string",
            "maxLength": 200,
            "pattern": "^(?!.*(?:^|/)\\.\\.?(?:/|$))[A-Za-z0-9._@+-]+(?:/[A-Za-z0-9._@+-]+)*\\.(?:png|jpe?g|webp)$",
            "$comment": "must be a relative path to a .png, .jpg, .jpeg or .webp file in the release zip, without . or .. segments"
          },
          "caption": {
            "description": "What the screenshot shows; also its alternative text.",
            "type": "string",
            "$ref": "#/$defs/trimmedString",
            "maxLength": 200
          }
        }
      }
    }
  },
  "$defs": {
    "trimmedString": {
      "type": "string",
      "pattern": "^\\S(?:[\\s\\S]*\\S)?$",
      "$comment": "must not be empty or start or end with whitespace"
    },
    "semver": {
      "type": "string",
      "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-]*))*)?(?:\\+[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*)?$",
      "$comment": "must be a SemVer 2.0 version such as 1.2.3 or 1.2.3-beta.1"
    },
    "category": {
      "enum": [
        "Analysis",
        "Archaeology",
        "Basemaps",
        "Cartography",
        "Climate",
        "Data",
        "Ecology",
        "Example",
        "Hydrology",
        "Imagery",
        "Oceans",
        "Raster",
        "Terrain",
        "Utilities",
        "Vector",
        "Visualization"
      ]
    }
  }
}
