payload: Dict[str, Any] = {"catalog_name": catalog, "retrieve_all_trains": True} if category: payload["categories"] = [category] # v2.1.2: TrueNAS 25.10 исторически делал POST /app/available, но в новых билдах # многие эндпоинты переехали на GET. _rest_request сам делает POST→GET fallback # при 405, поэтому здесь используем _post — он сам разберётся. # Дополнительно пробуем GET напрямую для надёжности. endpoints = [ "app/available", # новый (Electric Eel+) "app.available", "chart/release/names", "chart.release.names", "chart_release/names", "catalog/items", # fallback "catalog.items", "catalog_items", "app/available_apps", "app/list_apps", ] apps: List[Dict[str, Any]] = [] used_ep = None used_method = None for ep in endpoints: # Сначала GET (часто работает на 25.10) try: r = requests.get( f"{self._base}/api/v2.0/{ep}", headers=self._headers, params=payload if payload else None, timeout=self.valves.request_timeout, verify=self.valves.verify_ssl, ) if r.status_code == 200: try: data = r.json() if isinstance(data, list): apps = data used_ep = ep used_method = "GET" break if isinstance(data, dict): for key in ("items", "applications", "releases", "apps"): if key in data and isinstance(data[key], list): apps = data[key] used_ep = ep used_method = "GET" break if apps: break except Exception: pass except Exception: pass # Затем POST (через _rest_request — у него есть fallback на GET при 405) res = self._post(ep, payload, timeout=self.valves.request_timeout) if res is not None: if isinstance(res, list): apps = res used_ep = ep used_method = "POST" break if isinstance(res, dict): for key in ("items", "applications", "releases", "apps"): if key in res and isinstance(res[key], list): apps = res[key] used_ep = ep used_method = res.get("_via", "POST") break if apps: break