{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cms.kuaiz.net/contracts/extension-manifest-v1.json",
  "title": "Kuaiz CMS Extension Manifest v1",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema",
    "id",
    "name",
    "version",
    "description",
    "type",
    "execution",
    "entrypoint",
    "migrations",
    "requires",
    "permissions",
    "routes",
    "events",
    "theme_slots",
    "content_types",
    "data_policy",
    "network"
  ],
  "properties": {
    "schema": {"const": "kuaiz-cms-extension/v1"},
    "id": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$",
      "maxLength": 80
    },
    "name": {"type": "string", "minLength": 1, "maxLength": 80},
    "version": {"type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"},
    "description": {"type": "string", "maxLength": 500},
    "type": {"enum": ["content", "business", "connector"]},
    "execution": {"enum": ["declarative", "official-signed-php"]},
    "entrypoint": {
      "oneOf": [
        {"type": "null"},
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["file", "class"],
          "properties": {
            "file": {"type": "string", "pattern": "^src/[A-Z][A-Za-z0-9/]*\\.php$", "maxLength": 160},
            "class": {"type": "string", "pattern": "^[A-Z][A-Za-z0-9]*(?:\\\\[A-Z][A-Za-z0-9]*)+$", "maxLength": 160}
          }
        }
      ]
    },
    "migrations": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "file", "sha256"],
        "properties": {
          "id": {"type": "string", "pattern": "^[0-9]{4}_[a-z][a-z0-9_]{0,50}$"},
          "file": {"type": "string", "pattern": "^migrations/[0-9]{4}_[a-z][a-z0-9_]{0,50}\\.sql$", "maxLength": 80},
          "sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}
        }
      }
    },
    "requires": {
      "type": "object",
      "additionalProperties": false,
      "required": ["cms", "php"],
      "properties": {
        "cms": {"type": "string", "pattern": "^>=[0-9]+\\.[0-9]+\\.[0-9]+ <[0-9]+\\.[0-9]+\\.[0-9]+$"},
        "php": {"type": "string", "pattern": "^>=[0-9]+\\.[0-9]+$"}
      }
    },
    "permissions": {
      "type": "array",
      "uniqueItems": true,
      "maxItems": 32,
      "items": {
        "enum": [
          "content.read",
          "content.write",
          "media.read",
          "media.write",
          "mail.send",
          "jobs.schedule",
          "webhook.emit",
          "members.read",
          "members.write"
        ]
      }
    },
    "routes": {
      "type": "array",
      "maxItems": 32,
      "items": {"$ref": "#/$defs/route"}
    },
    "events": {
      "type": "object",
      "additionalProperties": false,
      "required": ["subscribes", "publishes"],
      "properties": {
        "subscribes": {"$ref": "#/$defs/events"},
        "publishes": {"$ref": "#/$defs/events"}
      }
    },
    "theme_slots": {
      "type": "array",
      "uniqueItems": true,
      "maxItems": 32,
      "items": {"type": "string", "pattern": "^[a-z][a-z0-9.-]{2,119}$"}
    },
    "content_types": {
      "type": "array",
      "maxItems": 32,
      "items": {"$ref": "#/$defs/contentType"}
    },
    "data_policy": {
      "type": "object",
      "additionalProperties": false,
      "required": ["personal_data", "retention_days", "exportable", "deletable"],
      "properties": {
        "personal_data": {
          "type": "array",
          "uniqueItems": true,
          "items": {"enum": ["contact", "identity", "appointment", "member_profile", "custom"]}
        },
        "retention_days": {"type": "integer", "minimum": 0, "maximum": 3650},
        "exportable": {"type": "boolean"},
        "deletable": {"type": "boolean"}
      }
    },
    "network": {
      "type": "object",
      "additionalProperties": false,
      "required": ["outbound_hosts"],
      "properties": {
        "outbound_hosts": {
          "type": "array",
          "uniqueItems": true,
          "maxItems": 16,
          "items": {
            "type": "string",
            "pattern": "^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$"
          }
        }
      }
    }
  },
  "$defs": {
    "events": {
      "type": "array",
      "uniqueItems": true,
      "maxItems": 32,
      "items": {"type": "string", "pattern": "^[a-z][a-z0-9]*(?:\\.[a-z0-9_]+)+$", "maxLength": 120}
    },
    "route": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "path", "methods", "access", "content_type"],
      "properties": {
        "id": {"type": "string", "pattern": "^[a-z][a-z0-9_-]{0,39}$"},
        "path": {"type": "string", "pattern": "^/(?:[a-z0-9][a-z0-9_-]*|\\{(?:slug|id)\\})(?:/(?:[a-z0-9][a-z0-9_-]*|\\{(?:slug|id)\\}))*$", "maxLength": 120},
        "methods": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {"enum": ["GET", "POST", "PUT", "PATCH", "DELETE"]}
        },
        "access": {"enum": ["public", "member", "admin"]},
        "content_type": {"type": ["string", "null"], "pattern": "^[a-z][a-z0-9_-]{0,39}$"}
      }
    },
    "contentType": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "label", "route", "fields"],
      "properties": {
        "id": {"type": "string", "pattern": "^[a-z][a-z0-9_-]{0,39}$"},
        "label": {"type": "string", "minLength": 1, "maxLength": 80},
        "route": {"type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,62}$"},
        "fields": {
          "type": "array",
          "minItems": 1,
          "maxItems": 64,
          "items": {"$ref": "#/$defs/field"}
        }
      }
    },
    "field": {
      "type": "object",
      "additionalProperties": false,
      "required": ["key", "label", "type", "required", "searchable"],
      "properties": {
        "key": {"type": "string", "pattern": "^[a-z][a-z0-9_]{0,39}$"},
        "label": {"type": "string", "minLength": 1, "maxLength": 80},
        "type": {"enum": ["text", "long_text", "number", "boolean", "date", "datetime", "image", "url"]},
        "required": {"type": "boolean"},
        "searchable": {"type": "boolean"}
      }
    }
  }
}
