From 0d2db7d8c3d11723f72c43030692a22336b60b1e Mon Sep 17 00:00:00 2001 From: danstotts-ops Date: Fri, 14 Aug 2026 16:51:01 -0500 Subject: [PATCH 1/2] Add Runpod docs API catalog --- .github/workflows/validate-tooltips.yml | 3 ++ api-catalog.json | 50 ++++++++++++++++++++ docs.json | 4 ++ scripts/validate-api-catalog.py | 63 +++++++++++++++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 api-catalog.json create mode 100644 scripts/validate-api-catalog.py diff --git a/.github/workflows/validate-tooltips.yml b/.github/workflows/validate-tooltips.yml index 47e2602eb..e1917da90 100644 --- a/.github/workflows/validate-tooltips.yml +++ b/.github/workflows/validate-tooltips.yml @@ -25,3 +25,6 @@ jobs: - name: Validate tooltip imports run: node scripts/validate-tooltips.js + + - name: Validate API catalog + run: python3 scripts/validate-api-catalog.py diff --git a/api-catalog.json b/api-catalog.json new file mode 100644 index 000000000..43982a50d --- /dev/null +++ b/api-catalog.json @@ -0,0 +1,50 @@ +{ + "linkset": [ + { + "anchor": "https://rest.runpod.io/v1", + "service-desc": [ + { + "href": "https://docs.runpod.io/api-reference/openapi.json", + "type": "application/vnd.oai.openapi+json", + "title": "Runpod REST API OpenAPI schema" + } + ], + "service-doc": [ + { + "href": "https://docs.runpod.io/api-reference/overview", + "type": "text/html", + "title": "Runpod REST API documentation" + } + ], + "status": [ + { + "href": "https://uptime.runpod.io/", + "type": "text/html", + "title": "Runpod status page" + } + ] + }, + { + "anchor": "https://api.runpod.ai/v2", + "service-doc": [ + { + "href": "https://docs.runpod.io/serverless/endpoints/send-requests", + "type": "text/html", + "title": "Runpod Serverless endpoint request operations" + }, + { + "href": "https://docs.runpod.io/serverless/endpoints/job-states", + "type": "text/html", + "title": "Runpod Serverless job states and metrics" + } + ], + "status": [ + { + "href": "https://uptime.runpod.io/", + "type": "text/html", + "title": "Runpod status page" + } + ] + } + ] +} diff --git a/docs.json b/docs.json index edbed49b4..6c06fd985 100644 --- a/docs.json +++ b/docs.json @@ -731,6 +731,10 @@ } }, "redirects": [ + { + "source": "/.well-known/api-catalog", + "destination": "/api-catalog.json" + }, { "source": "/public-endpoints/models/seedance-1-pro", "destination": "/public-endpoints/overview" diff --git a/scripts/validate-api-catalog.py b/scripts/validate-api-catalog.py new file mode 100644 index 000000000..0e36e1536 --- /dev/null +++ b/scripts/validate-api-catalog.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +"""Validate the static RFC 9727 API catalog and its Mintlify route.""" + +from __future__ import annotations + +import json +from pathlib import Path +from urllib.parse import urlparse + + +ROOT = Path(__file__).resolve().parents[1] +CATALOG_PATH = ROOT / "api-catalog.json" +CONFIG_PATH = ROOT / "docs.json" +SOURCE_PATH = "/.well-known/api-catalog" +DESTINATION_PATH = "/api-catalog.json" + + +def require_https(value: str, label: str) -> None: + parsed = urlparse(value) + if parsed.scheme != "https" or not parsed.netloc: + raise ValueError(f"{label} must be an absolute HTTPS URL: {value!r}") + + +def main() -> None: + catalog = json.loads(CATALOG_PATH.read_text()) + linkset = catalog.get("linkset") + if not isinstance(linkset, list) or not linkset: + raise ValueError("api-catalog.json must contain a non-empty linkset array") + + for index, entry in enumerate(linkset): + if not isinstance(entry, dict): + raise ValueError(f"linkset[{index}] must be an object") + require_https(entry.get("anchor", ""), f"linkset[{index}].anchor") + relations = [key for key in entry if key != "anchor"] + if not relations: + raise ValueError(f"linkset[{index}] must expose at least one relation") + for relation in relations: + links = entry[relation] + if not isinstance(links, list) or not links: + raise ValueError(f"linkset[{index}].{relation} must be non-empty") + for link_index, link in enumerate(links): + if not isinstance(link, dict): + raise ValueError( + f"linkset[{index}].{relation}[{link_index}] must be an object" + ) + require_https( + link.get("href", ""), + f"linkset[{index}].{relation}[{link_index}].href", + ) + + config = json.loads(CONFIG_PATH.read_text()) + redirects = config.get("redirects", []) + matches = [item for item in redirects if item.get("source") == SOURCE_PATH] + if matches != [{"source": SOURCE_PATH, "destination": DESTINATION_PATH}]: + raise ValueError( + f"docs.json must permanently redirect {SOURCE_PATH} to {DESTINATION_PATH}" + ) + + print(f"Validated {len(linkset)} API catalog entries and the Mintlify redirect.") + + +if __name__ == "__main__": + main() From f089ec38f62d600b28c523122d54cd0166d295e6 Mon Sep 17 00:00:00 2001 From: danstotts-ops Date: Mon, 17 Aug 2026 17:41:58 -0600 Subject: [PATCH 2/2] Use Mintlify native API catalog --- .github/workflows/validate-tooltips.yml | 3 -- api-catalog.json | 50 -------------------- docs.json | 7 +-- scripts/validate-api-catalog.py | 63 ------------------------- 4 files changed, 2 insertions(+), 121 deletions(-) delete mode 100644 api-catalog.json delete mode 100644 scripts/validate-api-catalog.py diff --git a/.github/workflows/validate-tooltips.yml b/.github/workflows/validate-tooltips.yml index e1917da90..47e2602eb 100644 --- a/.github/workflows/validate-tooltips.yml +++ b/.github/workflows/validate-tooltips.yml @@ -25,6 +25,3 @@ jobs: - name: Validate tooltip imports run: node scripts/validate-tooltips.js - - - name: Validate API catalog - run: python3 scripts/validate-api-catalog.py diff --git a/api-catalog.json b/api-catalog.json deleted file mode 100644 index 43982a50d..000000000 --- a/api-catalog.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "linkset": [ - { - "anchor": "https://rest.runpod.io/v1", - "service-desc": [ - { - "href": "https://docs.runpod.io/api-reference/openapi.json", - "type": "application/vnd.oai.openapi+json", - "title": "Runpod REST API OpenAPI schema" - } - ], - "service-doc": [ - { - "href": "https://docs.runpod.io/api-reference/overview", - "type": "text/html", - "title": "Runpod REST API documentation" - } - ], - "status": [ - { - "href": "https://uptime.runpod.io/", - "type": "text/html", - "title": "Runpod status page" - } - ] - }, - { - "anchor": "https://api.runpod.ai/v2", - "service-doc": [ - { - "href": "https://docs.runpod.io/serverless/endpoints/send-requests", - "type": "text/html", - "title": "Runpod Serverless endpoint request operations" - }, - { - "href": "https://docs.runpod.io/serverless/endpoints/job-states", - "type": "text/html", - "title": "Runpod Serverless job states and metrics" - } - ], - "status": [ - { - "href": "https://uptime.runpod.io/", - "type": "text/html", - "title": "Runpod status page" - } - ] - } - ] -} diff --git a/docs.json b/docs.json index 6c06fd985..f43b7c7f3 100644 --- a/docs.json +++ b/docs.json @@ -35,7 +35,8 @@ "cursor", "vscode", "perplexity", - "mcp" + "mcp", + "download-spec" ] }, "navigation": { @@ -731,10 +732,6 @@ } }, "redirects": [ - { - "source": "/.well-known/api-catalog", - "destination": "/api-catalog.json" - }, { "source": "/public-endpoints/models/seedance-1-pro", "destination": "/public-endpoints/overview" diff --git a/scripts/validate-api-catalog.py b/scripts/validate-api-catalog.py deleted file mode 100644 index 0e36e1536..000000000 --- a/scripts/validate-api-catalog.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -"""Validate the static RFC 9727 API catalog and its Mintlify route.""" - -from __future__ import annotations - -import json -from pathlib import Path -from urllib.parse import urlparse - - -ROOT = Path(__file__).resolve().parents[1] -CATALOG_PATH = ROOT / "api-catalog.json" -CONFIG_PATH = ROOT / "docs.json" -SOURCE_PATH = "/.well-known/api-catalog" -DESTINATION_PATH = "/api-catalog.json" - - -def require_https(value: str, label: str) -> None: - parsed = urlparse(value) - if parsed.scheme != "https" or not parsed.netloc: - raise ValueError(f"{label} must be an absolute HTTPS URL: {value!r}") - - -def main() -> None: - catalog = json.loads(CATALOG_PATH.read_text()) - linkset = catalog.get("linkset") - if not isinstance(linkset, list) or not linkset: - raise ValueError("api-catalog.json must contain a non-empty linkset array") - - for index, entry in enumerate(linkset): - if not isinstance(entry, dict): - raise ValueError(f"linkset[{index}] must be an object") - require_https(entry.get("anchor", ""), f"linkset[{index}].anchor") - relations = [key for key in entry if key != "anchor"] - if not relations: - raise ValueError(f"linkset[{index}] must expose at least one relation") - for relation in relations: - links = entry[relation] - if not isinstance(links, list) or not links: - raise ValueError(f"linkset[{index}].{relation} must be non-empty") - for link_index, link in enumerate(links): - if not isinstance(link, dict): - raise ValueError( - f"linkset[{index}].{relation}[{link_index}] must be an object" - ) - require_https( - link.get("href", ""), - f"linkset[{index}].{relation}[{link_index}].href", - ) - - config = json.loads(CONFIG_PATH.read_text()) - redirects = config.get("redirects", []) - matches = [item for item in redirects if item.get("source") == SOURCE_PATH] - if matches != [{"source": SOURCE_PATH, "destination": DESTINATION_PATH}]: - raise ValueError( - f"docs.json must permanently redirect {SOURCE_PATH} to {DESTINATION_PATH}" - ) - - print(f"Validated {len(linkset)} API catalog entries and the Mintlify redirect.") - - -if __name__ == "__main__": - main()