{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openspatials.com/developers/spec/0.5/openspatials-ownership.schema.json",
  "title": "OpenSpatials ownership manifest: Universal Manifest v0.4 with OpenSpatials conventions",
  "description": "Spec: src/spec/core/OWNERSHIP-AND-UM.md. The character file's ownership link points to a signed Universal Manifest v0.4 manifest (Signature Profile A). A manifest grants rights only when signature.keyRef names the game that issued it, as <address of its openspatials-world.json>#<key id>, and that game lists the key in signingKeys in its profile. src/ownership/index.js checks this, not this schema. This schema is the copied Universal Manifest v0.4 schema plus our conventions: Ed25519 only; no code-like fields; a character facet's @id and ref are the character file's absolute URL; an item facet's @id is <character URL>#item-<id>; entity @type includes openspatials:Character or openspatials:Item. Consent purpose openspatials:game-crossing and scope words show, use and copy are checked by src/ownership/index.js, not here, because a manifest may carry consents for other purposes. Limit 64 KiB and no duplicate JSON keys, checked on the bytes. Every failure here maps to ownership-unreadable.",
  "x-openspatials-reason": "ownership-unreadable",
  "allOf": [
    {
      "$ref": "https://universalmanifest.net/ns/universal-manifest/v0.4/schema.json"
    },
    {
      "$ref": "#/$defs/noCode"
    },
    {
      "type": "object",
      "required": [
        "signature"
      ],
      "properties": {
        "manifestVersion": {
          "const": "0.4"
        },
        "signature": {
          "type": "object",
          "required": [
            "algorithm",
            "canonicalization",
            "keyRef",
            "value"
          ],
          "properties": {
            "algorithm": {
              "description": "Signature Profile A only.",
              "const": "Ed25519"
            },
            "canonicalization": {
              "const": "JCS-RFC8785"
            },
            "keyRef": {
              "description": "Who signed: <address of the issuing game's openspatials-world.json>#<key id> for a record that can grant rights (04 section 5). A did:key or any other form names no issuer, so the record is shown only."
            },
            "publicKeySpkiB64": {
              "description": "Optional. When keyRef names an issuer, it must be the issuer's listed key; when keyRef is a did:key, it must be that key (both checked by src/ownership/index.js). A key carried in the record never confirms the record on its own.",
              "type": "string"
            }
          }
        },
        "facets": {
          "type": "array",
          "maxItems": 64,
          "items": {
            "allOf": [
              {
                "if": {
                  "properties": {
                    "entity": {
                      "type": "object",
                      "required": [
                        "@type"
                      ],
                      "properties": {
                        "@type": {
                          "anyOf": [
                            {
                              "const": "openspatials:Character"
                            },
                            {
                              "type": "array",
                              "contains": {
                                "const": "openspatials:Character"
                              }
                            }
                          ]
                        }
                      }
                    }
                  },
                  "required": [
                    "entity"
                  ]
                },
                "then": {
                  "properties": {
                    "@id": {
                      "$ref": "#/$defs/characterUrl"
                    },
                    "ref": {
                      "$ref": "#/$defs/characterUrl"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "entity": {
                      "type": "object",
                      "required": [
                        "@type"
                      ],
                      "properties": {
                        "@type": {
                          "anyOf": [
                            {
                              "const": "openspatials:Item"
                            },
                            {
                              "type": "array",
                              "contains": {
                                "const": "openspatials:Item"
                              }
                            }
                          ]
                        }
                      }
                    }
                  },
                  "required": [
                    "entity"
                  ]
                },
                "then": {
                  "properties": {
                    "@id": {
                      "$ref": "#/$defs/itemFacetId"
                    }
                  }
                }
              }
            ]
          }
        },
        "consents": {
          "type": "array",
          "maxItems": 256
        }
      }
    }
  ],
  "$defs": {
    "characterUrl": {
      "description": "The character file's absolute URL.",
      "type": "string",
      "maxLength": 2048,
      "pattern": "^https?://[^\\s#]+$"
    },
    "itemFacetId": {
      "description": "<character URL>#item-<item id>.",
      "type": "string",
      "maxLength": 2200,
      "pattern": "^https?://[^\\s#]+#item-[A-Za-z0-9._-]{1,64}$"
    },
    "noCode": {
      "description": "04 section 1, closed list, at any depth: a key named script, scripts, eval or javascript; a key that is 'on' followed by a capital letter; a string value starting with javascript:, vbscript: or data:text/html (any case, after leading white space).",
      "x-openspatials-reason": "unsafe-file",
      "propertyNames": {
        "not": {
          "pattern": "^(?:script|scripts|eval|javascript|on[A-Z].*)$"
        }
      },
      "additionalProperties": {
        "$ref": "#/$defs/noCode"
      },
      "items": {
        "$ref": "#/$defs/noCode"
      },
      "not": {
        "type": "string",
        "pattern": "^\\s*(?:[Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt]:|[Vv][Bb][Ss][Cc][Rr][Ii][Pp][Tt]:|[Dd][Aa][Tt][Aa]:[Tt][Ee][Xx][Tt]/[Hh][Tt][Mm][Ll])"
      }
    }
  }
}
