{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://schemas.fablepool.org/v1/oer-package.json", "title": "FablePool OER Package Manifest", "description": "Manifest (manifest.json) at the root of an exported Open Educational Resource package (.fpoer, a zip archive). Packages are versioned, attributable and re-importable across FablePool instances; every referenced file is integrity-pinned by sha256.", "type": "object", "required": ["schema", "package", "contents"], "additionalProperties": false, "properties": { "schema": { "const": "fablepool.oer/1" }, "package": { "type": "object", "required": ["id", "slug", "title", "version", "license", "language", "authors", "created_at"], "additionalProperties": false, "properties": { "id": { "type": "string", "format": "uuid" }, "slug": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$" }, "title": { "type": "string", "minLength": 1, "maxLength": 300 }, "version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?$" }, "license": { "enum": ["CC-BY-SA-4.0", "CC-BY-4.0", "CC0-1.0"], "description": "Content license. CC-BY-SA-4.0 is the platform default." }, "language": { "type": "string", "pattern": "^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$", "description": "BCP 47 language tag, e.g. 'en', 'pt-BR'." }, "authors": { "type": "array", "minItems": 1, "maxItems": 100, "items": { "type": "object", "required": ["name"], "additionalProperties": false, "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "url": { "type": "string", "pattern": "^https://", "maxLength": 500 }, "username": { "type": "string", "maxLength": 64 } } } }, "created_at": { "type": "string", "format": "date-time" }, "generator": { "type": "object", "additionalProperties": false, "properties": { "name": { "type": "string", "maxLength": 100 }, "version": { "type": "string", "maxLength": 50 }, "url": { "type": "string", "pattern": "^https://", "maxLength": 500 } } } } }, "contents": { "type": "object", "additionalProperties": false, "minProperties": 1, "properties": { "courses": { "$ref": "#/$defs/fileRefList" }, "problems": { "$ref": "#/$defs/fileRefList" }, "widgets": { "$ref": "#/$defs/fileRefList" }, "media": { "type": "array", "maxItems": 2000, "items": { "type": "object", "required": ["path", "sha256", "media_type"], "additionalProperties": false, "properties": { "path": { "$ref": "#/$defs/packagePath" }, "sha256": { "$ref": "#/$defs/sha256" }, "media_type": { "type": "string", "maxLength": 100 } } } } } }, "provenance": { "type": "object", "additionalProperties": false, "description": "Attribution chain for forks/remixes; importers must preserve this.", "properties": { "source_platform": { "type": "string", "pattern": "^https://", "maxLength": 500 }, "forked_from": { "type": "object", "required": ["package_id", "version"], "additionalProperties": false, "properties": { "package_id": { "type": "string", "format": "uuid" }, "version": { "type": "string", "maxLength": 50 }, "url": { "type": "string", "pattern": "^https://", "maxLength": 500 } } } } }, "dependencies": { "type": "array", "maxItems": 50, "description": "Other OER packages this one references (e.g. shared widget packs).", "items": { "type": "object", "required": ["package_id", "version_range"], "additionalProperties": false, "properties": { "package_id": { "type": "string", "format": "uuid" }, "version_range": { "type": "string", "maxLength": 50 }, "url": { "type": "string", "pattern": "^https://", "maxLength": 500 } } } } }, "$defs": { "packagePath": { "type": "string", "pattern": "^(?!/)(?!.*\\.\\.)[A-Za-z0-9._/-]+$", "maxLength": 300, "description": "Package-relative path; no absolute paths or '..' traversal." }, "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "fileRefList": { "type": "array", "maxItems": 1000, "items": { "type": "object", "required": ["path", "sha256"], "additionalProperties": false, "properties": { "path": { "$ref": "#/$defs/packagePath" }, "sha256": { "$ref": "#/$defs/sha256" } } } } } }