mirror of
https://git.openapi.site/https://github.com/desirecore/registry.git
synced 2026-09-05 19:13:34 +08:00
feat: 建立统一目录元数据与获取契约 (#5)
* feat: 建立 Registry 目录元数据验证基础 * feat: 迁移 Registry 应用目录元数据 * test: 解耦目录迁移进度断言 * feat: 迁移 Registry 服务目录元数据 * fix(catalog): 强制 Registry 目录元数据 * fix(catalog): 兼容 Registry v4 外部集成
This commit is contained in:
262
schemas/catalog-metadata.v1.schema.json
Normal file
262
schemas/catalog-metadata.v1.schema.json
Normal file
@@ -0,0 +1,262 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://github.com/desirecore/registry/schemas/catalog-metadata.v1.schema.json",
|
||||
"title": "DesireCore Registry catalog metadata v1 sidecar",
|
||||
"description": "CatalogItemV1 的 Registry 来源事实子集。受信 catalogSourceId、catalog provenance 和 official 身份由客户端同步器注入,禁止写入本文档。",
|
||||
"type": "object",
|
||||
"required": ["schemaVersion", "identity", "presentation", "release", "timestamps", "provenance", "governance", "compatibility", "spec"],
|
||||
"properties": {
|
||||
"$schema": { "const": "../../schemas/catalog-metadata.v1.schema.json" },
|
||||
"schemaVersion": { "const": 1 },
|
||||
"identity": {
|
||||
"type": "object",
|
||||
"required": ["kind", "id"],
|
||||
"properties": {
|
||||
"kind": { "enum": ["app", "service"], "description": "canonical 条目类型;Registry mcp/http-api 都归一为 service。" },
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$", "description": "来源内条目 ID;受信来源 ID 不属于 sidecar。" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"presentation": {
|
||||
"type": "object",
|
||||
"required": ["defaultLocale", "i18n", "tags"],
|
||||
"properties": {
|
||||
"defaultLocale": { "type": "string", "pattern": "^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$" },
|
||||
"i18n": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"propertyNames": { "pattern": "^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$" },
|
||||
"additionalProperties": { "$ref": "#/$defs/localeText" }
|
||||
},
|
||||
"tags": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 }, "uniqueItems": true }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"release": { "$ref": "#/$defs/release" },
|
||||
"timestamps": {
|
||||
"type": "object",
|
||||
"required": ["catalogUpdatedAt", "releasePublishedAt", "reviewedAt", "upstreamObservedAt"],
|
||||
"properties": {
|
||||
"catalogUpdatedAt": { "$ref": "#/$defs/timestamp" },
|
||||
"releasePublishedAt": { "$ref": "#/$defs/timestamp" },
|
||||
"reviewedAt": { "$ref": "#/$defs/timestamp" },
|
||||
"upstreamObservedAt": { "$ref": "#/$defs/timestamp" }
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"description": "目录修改、内容发布、审核和上游观察时间彼此独立;syncedAt 不属于上游元数据。"
|
||||
},
|
||||
"provenance": {
|
||||
"type": "object",
|
||||
"properties": { "content": { "$ref": "#/$defs/contentSource" } },
|
||||
"additionalProperties": false,
|
||||
"description": "只声明内容来源。Catalog 仓库来源由同步器根据受信 repo 上下文注入。"
|
||||
},
|
||||
"governance": {
|
||||
"type": "object",
|
||||
"required": ["availability", "license", "redistribution"],
|
||||
"properties": {
|
||||
"availability": { "enum": ["listing-only", "installable"] },
|
||||
"stewardship": { "enum": ["partner", "community", "pointer"], "description": "正文不得自报 official;受信官方身份只能由同步器注入。" },
|
||||
"license": { "$ref": "#/$defs/license" },
|
||||
"redistribution": { "enum": ["allowed", "source-pointer-only", "verify-package-terms"] },
|
||||
"listingMaintainer": { "$ref": "#/$defs/maintainer" },
|
||||
"upstreamMaintainer": { "$ref": "#/$defs/maintainer" },
|
||||
"branding": { "$ref": "#/$defs/branding" },
|
||||
"compliance": { "$ref": "#/$defs/compliance" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"compatibility": {
|
||||
"type": "object",
|
||||
"required": ["platforms"],
|
||||
"properties": {
|
||||
"platforms": { "$ref": "#/$defs/platforms" },
|
||||
"requiredClientVersion": {
|
||||
"type": "string",
|
||||
"pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"spec": { "oneOf": [{ "$ref": "#/$defs/appSpec" }, { "$ref": "#/$defs/serviceSpec" }] }
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"$defs": {
|
||||
"localeText": {
|
||||
"type": "object",
|
||||
"required": ["name", "summary"],
|
||||
"properties": {
|
||||
"name": { "type": "string", "minLength": 1 },
|
||||
"summary": { "type": "string", "minLength": 1 },
|
||||
"description": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"release": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["state"],
|
||||
"properties": { "state": { "const": "unknown" } },
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["state", "version", "versionScheme"],
|
||||
"properties": {
|
||||
"state": { "const": "known" },
|
||||
"version": { "type": "string", "minLength": 1, "maxLength": 160 },
|
||||
"versionScheme": { "enum": ["semver", "calver", "opaque"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"timestamp": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["state"],
|
||||
"properties": { "state": { "const": "unknown" } },
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["state", "value", "precision"],
|
||||
"properties": {
|
||||
"state": { "const": "known" },
|
||||
"value": { "type": "string" },
|
||||
"precision": { "enum": ["day", "second"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"contentSource": {
|
||||
"type": "object",
|
||||
"required": ["kind", "url"],
|
||||
"properties": {
|
||||
"kind": { "enum": ["git", "web", "zip", "release", "package", "container"] },
|
||||
"url": { "type": "string", "format": "uri" },
|
||||
"ref": { "type": "string", "minLength": 1, "maxLength": 500 },
|
||||
"sha256": { "type": "string", "pattern": "^[a-fA-F0-9]{64}$" },
|
||||
"path": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"license": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["state"],
|
||||
"properties": { "state": { "const": "unknown" } },
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["state", "value"],
|
||||
"properties": {
|
||||
"state": { "const": "known" },
|
||||
"value": { "type": "string", "minLength": 1, "maxLength": 240 },
|
||||
"evidencePath": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"maintainer": {
|
||||
"type": "object",
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": { "type": "string", "minLength": 1 },
|
||||
"url": { "type": "string", "format": "uri" },
|
||||
"verified": { "type": "boolean", "description": "身份是否已验证;不代表许可证授权或官方身份。" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"branding": {
|
||||
"type": "object",
|
||||
"required": ["relationship", "nameUsage", "logoStatus"],
|
||||
"properties": {
|
||||
"relationship": { "enum": ["partner", "independent-listing"], "description": "sidecar 不接受 official 自报。" },
|
||||
"nameUsage": { "enum": ["owned", "licensed", "nominative"] },
|
||||
"logoStatus": { "enum": ["not-used", "license-covered", "trademark-policy-allowed", "permission-obtained"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"compliance": {
|
||||
"type": "object",
|
||||
"required": ["licenseEvidencePath", "reviewedRef", "reviewedAt", "reviewedBy", "upstreamEndorsed"],
|
||||
"properties": {
|
||||
"licenseEvidencePath": { "type": "string", "minLength": 1 },
|
||||
"noticePath": { "type": "string", "minLength": 1 },
|
||||
"reviewedRef": { "type": "string", "minLength": 1 },
|
||||
"reviewedAt": { "type": "string" },
|
||||
"reviewedBy": { "type": "string", "minLength": 1 },
|
||||
"upstreamEndorsed": { "type": "boolean" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"platforms": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["state", "values"],
|
||||
"properties": {
|
||||
"state": { "const": "known" },
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": { "enum": ["macos", "windows", "linux", "web", "ios", "android"] },
|
||||
"minItems": 1,
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["state"],
|
||||
"properties": { "state": { "enum": ["all", "unknown"] } },
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"placementPolicy": {
|
||||
"type": "object",
|
||||
"required": ["showInMyApps", "allowNavPin", "allowAgentBinding"],
|
||||
"properties": {
|
||||
"showInMyApps": { "type": "boolean" },
|
||||
"allowNavPin": { "type": "boolean" },
|
||||
"allowAgentBinding": { "type": "boolean" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"appSpec": {
|
||||
"type": "object",
|
||||
"required": ["kind"],
|
||||
"properties": {
|
||||
"kind": { "const": "app" },
|
||||
"category": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"entrypointKinds": {
|
||||
"type": "array",
|
||||
"items": { "enum": ["builtin", "embedded-web", "external"] },
|
||||
"uniqueItems": true
|
||||
},
|
||||
"placementPolicy": { "$ref": "#/$defs/placementPolicy" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"serviceSpec": {
|
||||
"type": "object",
|
||||
"required": ["kind", "protocol"],
|
||||
"properties": {
|
||||
"kind": { "const": "service" },
|
||||
"protocol": { "enum": ["mcp", "http"] },
|
||||
"authType": { "enum": ["none", "bearer", "header", "query", "oauth", "unknown"] },
|
||||
"capabilities": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 160 }, "uniqueItems": true },
|
||||
"toolCount": { "type": "integer", "minimum": 0 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
162
schemas/registry-entry.v3.schema.json
Normal file
162
schemas/registry-entry.v3.schema.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://github.com/desirecore/registry/schemas/registry-entry.v3.schema.json",
|
||||
"title": "DesireCore Registry legacy entry v3",
|
||||
"description": "现有 entries/<id>/manifest.json 的兼容 Schema。Catalog sidecar 是增量契约,不替换本格式。",
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/dockerApp" },
|
||||
{ "$ref": "#/$defs/mcp" },
|
||||
{ "$ref": "#/$defs/httpApi" }
|
||||
],
|
||||
"$defs": {
|
||||
"nonEmptyString": { "type": "string", "minLength": 1 },
|
||||
"stringArray": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true },
|
||||
"platformArray": {
|
||||
"type": "array",
|
||||
"items": { "enum": ["macos", "windows", "linux"] },
|
||||
"minItems": 1,
|
||||
"uniqueItems": true
|
||||
},
|
||||
"common": {
|
||||
"type": "object",
|
||||
"required": ["id", "name", "type", "version", "description"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"name": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"type": { "enum": ["docker-app", "mcp", "http-api"] },
|
||||
"version": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"author": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"description": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"tags": { "$ref": "#/$defs/stringArray" },
|
||||
"icon": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"platformSupport": { "$ref": "#/$defs/platformArray" },
|
||||
"sourceAppId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"sourceAppName": { "$ref": "#/$defs/nonEmptyString" }
|
||||
}
|
||||
},
|
||||
"dockerRequirements": {
|
||||
"type": "object",
|
||||
"required": ["docker", "minMemory", "minDisk", "ports"],
|
||||
"properties": {
|
||||
"docker": { "type": "boolean" },
|
||||
"minMemory": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"minDisk": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"ports": { "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 65535 }, "uniqueItems": true }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"dockerInstall": {
|
||||
"type": "object",
|
||||
"required": ["method", "requirements"],
|
||||
"properties": {
|
||||
"method": { "enum": ["docker", "docker-compose"] },
|
||||
"requirements": { "$ref": "#/$defs/dockerRequirements" },
|
||||
"configNeeded": { "$ref": "#/$defs/stringArray" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"expose": {
|
||||
"type": "object",
|
||||
"required": ["type"],
|
||||
"properties": {
|
||||
"type": { "enum": ["mcp", "http-api"] },
|
||||
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
||||
"path": { "type": "string", "minLength": 1 },
|
||||
"name": { "$ref": "#/$defs/nonEmptyString" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"mcpInstall": {
|
||||
"type": "object",
|
||||
"required": ["method"],
|
||||
"properties": {
|
||||
"method": { "enum": ["npx", "pip", "uvx", "docker", "binary", "go"] },
|
||||
"packageName": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"command": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"args": { "type": "array", "items": { "type": "string" } },
|
||||
"postInstall": { "$ref": "#/$defs/stringArray" },
|
||||
"env": { "type": "object", "additionalProperties": { "type": "string" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"connection": {
|
||||
"type": "object",
|
||||
"required": ["transport"],
|
||||
"properties": {
|
||||
"transport": { "enum": ["stdio", "streamable-http", "sse"] },
|
||||
"command": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"args": { "type": "array", "items": { "type": "string" } },
|
||||
"url": { "type": "string", "format": "uri" },
|
||||
"headers": { "type": "object", "additionalProperties": { "type": "string" } },
|
||||
"env": { "type": "object", "additionalProperties": { "type": "string" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"dockerApp": {
|
||||
"type": "object",
|
||||
"required": ["id", "name", "type", "version", "description", "category", "shortDesc", "fullDesc", "install"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"name": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"type": { "const": "docker-app" },
|
||||
"version": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"author": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"description": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"tags": { "$ref": "#/$defs/stringArray" },
|
||||
"icon": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"iconLetter": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"platformSupport": { "$ref": "#/$defs/platformArray" },
|
||||
"category": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"shortDesc": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"fullDesc": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"stars": { "type": "number", "minimum": 0 },
|
||||
"githubUrl": { "type": "string", "format": "uri" },
|
||||
"install": { "$ref": "#/$defs/dockerInstall" },
|
||||
"exposes": { "type": "array", "items": { "$ref": "#/$defs/expose" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"mcp": {
|
||||
"type": "object",
|
||||
"required": ["id", "name", "type", "version", "description", "capabilities", "connection"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"name": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"type": { "const": "mcp" },
|
||||
"version": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"author": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"description": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"tags": { "$ref": "#/$defs/stringArray" },
|
||||
"icon": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"platformSupport": { "$ref": "#/$defs/platformArray" },
|
||||
"capabilities": { "$ref": "#/$defs/stringArray" },
|
||||
"toolCount": { "type": "integer", "minimum": 0 },
|
||||
"install": { "$ref": "#/$defs/mcpInstall" },
|
||||
"connection": { "$ref": "#/$defs/connection" },
|
||||
"sourceAppId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"sourceAppName": { "$ref": "#/$defs/nonEmptyString" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"httpApi": {
|
||||
"type": "object",
|
||||
"required": ["id", "name", "type", "version", "description", "endpoint", "capabilities"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"name": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"type": { "const": "http-api" },
|
||||
"version": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"author": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"description": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"tags": { "$ref": "#/$defs/stringArray" },
|
||||
"icon": { "$ref": "#/$defs/nonEmptyString" },
|
||||
"platformSupport": { "$ref": "#/$defs/platformArray" },
|
||||
"endpoint": { "type": "string", "format": "uri" },
|
||||
"capabilities": { "$ref": "#/$defs/stringArray" },
|
||||
"sourceAppId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
"sourceAppName": { "$ref": "#/$defs/nonEmptyString" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
46
schemas/registry-manifest.v3.schema.json
Normal file
46
schemas/registry-manifest.v3.schema.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://github.com/desirecore/registry/schemas/registry-manifest.v3.schema.json",
|
||||
"title": "DesireCore Registry manifest v3",
|
||||
"description": "Registry 仓库级元数据。catalogMetadata 只广告可选 sidecar 能力,不改变 legacy 条目的读取方式。",
|
||||
"type": "object",
|
||||
"required": ["id", "version", "name", "description", "maintainer", "repository", "lastUpdated", "stats", "dataVersion"],
|
||||
"properties": {
|
||||
"$schema": { "type": "string", "description": "JSON Schema 标识或路径。" },
|
||||
"id": { "const": "desirecore-registry-manifest", "description": "Registry 仓库固定标识。" },
|
||||
"version": { "type": "string", "minLength": 1, "description": "Registry 数据格式版本。" },
|
||||
"name": { "type": "string", "minLength": 1, "description": "Registry 显示名称。" },
|
||||
"description": { "type": "string", "minLength": 1, "description": "Registry 用途说明。" },
|
||||
"maintainer": { "type": "string", "minLength": 1, "description": "Registry 目录维护者。" },
|
||||
"repository": { "type": "string", "format": "uri", "description": "Registry 仓库地址。" },
|
||||
"lastUpdated": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "仓库目录元数据最后修改日期,不表示条目内容发布时间。" },
|
||||
"stats": {
|
||||
"type": "object",
|
||||
"description": "必须与 entries/ 实际内容完全一致的统计。",
|
||||
"required": ["totalEntries", "dockerApps", "mcpServices", "httpApis"],
|
||||
"properties": {
|
||||
"totalEntries": { "type": "integer", "minimum": 0 },
|
||||
"dockerApps": { "type": "integer", "minimum": 0 },
|
||||
"mcpServices": { "type": "integer", "minimum": 0 },
|
||||
"httpApis": { "type": "integer", "minimum": 0 },
|
||||
"externalIntegrations": { "type": "integer", "minimum": 0 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"dataVersion": { "type": "string", "minLength": 1, "description": "仓库数据版本;旧客户端继续按原字段读取。" },
|
||||
"catalogMetadata": {
|
||||
"type": "object",
|
||||
"description": "Catalog metadata v1 的兼容广告。sidecar 在迁移窗口内可选,legacy manifest 始终保留。",
|
||||
"required": ["version", "schema", "sidecarPath", "required", "legacyFallback"],
|
||||
"properties": {
|
||||
"version": { "const": "1.0.0" },
|
||||
"schema": { "const": "schemas/catalog-metadata.v1.schema.json" },
|
||||
"sidecarPath": { "const": "entries/<id>/catalog-metadata.v1.json" },
|
||||
"required": { "type": "boolean", "description": "是否要求每个 entry 都具备 sidecar。迁移完成前为 false。" },
|
||||
"legacyFallback": { "const": true, "description": "旧客户端和缺 sidecar 条目继续读取 manifest.json。" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
Reference in New Issue
Block a user