diff --git a/astrbot/dashboard/api/plugins.py b/astrbot/dashboard/api/plugins.py index a5086ce859..4cdf0fccfa 100644 --- a/astrbot/dashboard/api/plugins.py +++ b/astrbot/dashboard/api/plugins.py @@ -5,6 +5,7 @@ from typing import Any from urllib.parse import quote +import jwt from fastapi import APIRouter, Body, Depends, Query, Request from fastapi.responses import PlainTextResponse, Response @@ -16,7 +17,7 @@ call_request_view, ) from astrbot.dashboard.async_utils import run_maybe_async -from astrbot.dashboard.responses import error, ok +from astrbot.dashboard.responses import ApiError, error, ok from astrbot.dashboard.schemas import ( EnabledPatch, PluginByIdRequest, @@ -38,6 +39,7 @@ ConfigFileService, ) from astrbot.dashboard.services.plugin_page_service import ( + PLUGIN_PAGE_ASSET_TOKEN_TYPE, PluginPageContentPayload, PluginPageService, PluginPageServiceError, @@ -59,6 +61,47 @@ require_plugin_scope = ScopeDependency("plugin") +async def require_plugin_view_token(request: Request) -> str: + """Validate the scoped token embedded in a plugin view asset path. + + V1 routes are not covered by the dashboard auth middleware, so path-token + view URLs authenticate here instead. The token must be a plugin page asset + token scoped to exactly the plugin and page named in the path. + + Args: + request: Current FastAPI request with plugin_id/view_name/token path + params. + + Returns: + The username the token was issued to. + + Raises: + ApiError: 401 when the token is missing, invalid, expired, or scoped + to a different plugin or page. + """ + token = request.path_params.get("token", "") + try: + payload = jwt.decode( + token, + request.app.state.jwt_secret, + algorithms=["HS256"], + ) + except jwt.InvalidTokenError as exc: + raise ApiError("Token 无效", status_code=401) from exc + + if ( + payload.get("token_type") != PLUGIN_PAGE_ASSET_TOKEN_TYPE + or payload.get("plugin_name") != request.path_params.get("plugin_id") + or payload.get("page_name") != request.path_params.get("view_name") + ): + raise ApiError("Token 无效", status_code=401) + + username = payload.get("username") + if not isinstance(username, str) or not username.strip(): + raise ApiError("Token 无效", status_code=401) + return username + + def get_service(request: Request) -> PluginService: return request.app.state.services.plugins @@ -261,30 +304,6 @@ def _plugin_page_payload_response(payload: PluginPageContentPayload): ) -async def _serve_plugin_page_content( - *, - request: Request, - page_service: PluginPageService, - username: str | None, - plugin_id: str, - page_name: str, - asset_path: str, -): - try: - payload = await page_service.serve_page_content( - plugin_name=plugin_id, - page_name=page_name, - asset_path=asset_path, - asset_token=request.query_params.get("asset_token", "").strip(), - username=username, - locale=_get_request_locale(request), - theme=_get_request_theme(request), - ) - except PluginPageServiceError as exc: - return _plugin_page_error_response(exc.status_code, exc.public_message) - return _plugin_page_payload_response(payload) - - async def _serve_plugin_page_bridge_sdk( *, request: Request, @@ -307,13 +326,13 @@ async def _get_plugin_page_entry_config( page_service: PluginPageService, username: str | None, plugin_id: str | None, - page_name: str | None, + view_name: str | None, ): try: return ok( await page_service.get_plugin_page_entry_config( plugin_name=plugin_id, - page_name=page_name, + view_name=view_name, username=username, locale=_get_request_locale(request), ) @@ -863,8 +882,8 @@ async def set_plugin_enabled_by_id( ) -@router.get("/plugins/pages") @router.get("/plugins/views") +@router.get("/plugins/pages") # deprecated alias async def list_plugin_pages_by_id( plugin_id: str = Query(...), _auth: AuthContext = Depends(require_plugin_scope), @@ -878,8 +897,8 @@ async def list_plugin_pages_by_id( ) -@router.get("/plugins/page") @router.get("/plugins/view") +@router.get("/plugins/page") # deprecated alias async def get_plugin_page_by_id( request: Request, plugin_id: str = Query(...), @@ -892,27 +911,7 @@ async def get_plugin_page_by_id( page_service=page_service, username=auth.username, plugin_id=plugin_id, - page_name=page_name, - ) - - -@router.get("/plugins/page/assets") -@router.get("/plugins/view/assets") -async def get_plugin_page_asset_by_id( - request: Request, - plugin_id: str = Query(...), - page_name: str = Query(...), - asset_path: str = Query(...), - auth: AuthContext = Depends(require_plugin_scope), - page_service: PluginPageService = Depends(get_page_service), -): - return await _serve_plugin_page_content( - request=request, - page_service=page_service, - username=auth.username, - plugin_id=plugin_id, - page_name=page_name, - asset_path=asset_path, + view_name=page_name, ) @@ -1157,8 +1156,8 @@ async def update_plugin( ) -@router.get("/plugins/{plugin_id}/pages") @router.get("/plugins/{plugin_id}/views") +@router.get("/plugins/{plugin_id}/pages") # deprecated alias async def list_plugin_pages( plugin_id: str, _auth: AuthContext = Depends(require_plugin_scope), @@ -1172,11 +1171,11 @@ async def list_plugin_pages( ) -@router.get("/plugins/{plugin_id}/pages/{page_name}") -@router.get("/plugins/{plugin_id}/views/{page_name}") +@router.get("/plugins/{plugin_id}/views/{view_name}") +@router.get("/plugins/{plugin_id}/pages/{view_name}") # deprecated alias async def get_plugin_page( plugin_id: str, - page_name: str, + view_name: str, request: Request, auth: AuthContext = Depends(require_plugin_scope), page_service: PluginPageService = Depends(get_page_service), @@ -1186,28 +1185,39 @@ async def get_plugin_page( page_service=page_service, username=auth.username, plugin_id=plugin_id, - page_name=page_name, + view_name=view_name, ) -@router.get("/plugins/{plugin_id}/pages/{page_name}/assets/{asset_path:path}") -@router.get("/plugins/{plugin_id}/views/{page_name}/assets/{asset_path:path}") -async def get_plugin_page_asset( +@router.get("/plugins/{plugin_id}/views/{view_name}/_t/{token}/") +@router.get("/plugins/{plugin_id}/views/{view_name}/_t/{token}/{asset_path:path}") +async def get_plugin_view_token_asset( plugin_id: str, - page_name: str, - asset_path: str, + view_name: str, + token: str, request: Request, - auth: AuthContext = Depends(require_plugin_scope), + asset_path: str = "", + username: str = Depends(require_plugin_view_token), page_service: PluginPageService = Depends(get_page_service), ): - return await _serve_plugin_page_content( - request=request, - page_service=page_service, - username=auth.username, - plugin_id=plugin_id, - page_name=page_name, - asset_path=asset_path, - ) + """Serve plugin view assets authenticated by a scoped path token. + + Assets are served without URL rewriting because relative URLs inherit the + token through normal path resolution. + """ + try: + payload = await page_service.serve_page_content( + plugin_name=plugin_id, + view_name=view_name, + asset_path=asset_path, + asset_token=request.query_params.get("asset_token", "").strip() or token, + username=username, + locale=_get_request_locale(request), + theme=_get_request_theme(request), + ) + except PluginPageServiceError as exc: + return _plugin_page_error_response(exc.status_code, exc.public_message) + return _plugin_page_payload_response(payload) @legacy_router.get("/api/plugin/get") @@ -1258,7 +1268,7 @@ async def dashboard_get_plugin_page_entry_config( page_service=page_service, username=username, plugin_id=request.query_params.get("name"), - page_name=request.query_params.get("page"), + view_name=request.query_params.get("page"), ) @@ -1472,43 +1482,6 @@ async def dashboard_get_plugin_page_bridge_sdk( ) -@legacy_router.get("/api/plugin/page/content/{plugin_id}/{page_name}/") -async def dashboard_get_plugin_page_entry( - plugin_id: str, - page_name: str, - request: Request, - username: str = Depends(require_dashboard_user), - page_service: PluginPageService = Depends(get_page_service), -): - return await _serve_plugin_page_content( - request=request, - page_service=page_service, - username=username, - plugin_id=plugin_id, - page_name=page_name, - asset_path="", - ) - - -@legacy_router.get("/api/plugin/page/content/{plugin_id}/{page_name}/{asset_path:path}") -async def dashboard_get_plugin_page_asset( - plugin_id: str, - page_name: str, - asset_path: str, - request: Request, - username: str = Depends(require_dashboard_user), - page_service: PluginPageService = Depends(get_page_service), -): - return await _serve_plugin_page_content( - request=request, - page_service=page_service, - username=username, - plugin_id=plugin_id, - page_name=page_name, - asset_path=asset_path, - ) - - @legacy_router.api_route("/api/plug/{plugin_path:path}", methods=["GET", "POST"]) async def dashboard_plugin_extension_route( plugin_path: str, diff --git a/astrbot/dashboard/plugin_page_auth.py b/astrbot/dashboard/plugin_page_auth.py index cb60df1a94..368dfc4681 100644 --- a/astrbot/dashboard/plugin_page_auth.py +++ b/astrbot/dashboard/plugin_page_auth.py @@ -1,16 +1,18 @@ -from urllib.parse import unquote - -PLUGIN_PAGE_CONTENT_PREFIX = "/api/plugin/page/content/" PLUGIN_PAGE_BRIDGE_PATH = "/api/plugin/page/bridge-sdk.js" PLUGIN_PAGE_TOKEN_TYPE = "plugin_page_asset" class PluginPageAuth: + """Auth helpers for plugin view requests handled by the auth middleware. + + View assets authenticate through scoped path tokens validated by the v1 + route dependency (v1 paths bypass this middleware). Only the shared + bridge SDK script still authenticates here, via a query token. + """ + @staticmethod def is_protected_path(path: str) -> bool: - return path.startswith(PLUGIN_PAGE_CONTENT_PREFIX) or path.startswith( - PLUGIN_PAGE_BRIDGE_PATH - ) + return path.startswith(PLUGIN_PAGE_BRIDGE_PATH) @staticmethod def is_asset_token(payload: dict) -> bool: @@ -21,44 +23,8 @@ def extract_asset_token(query_params) -> str | None: query_asset_token = query_params.get("asset_token", "").strip() return query_asset_token or None - @staticmethod - def extract_plugin_name_from_path(path: str) -> str | None: - if not path.startswith(PLUGIN_PAGE_CONTENT_PREFIX): - return None - remainder = path[len(PLUGIN_PAGE_CONTENT_PREFIX) :] - plugin_part = remainder.split("/", 1)[0] if remainder else "" - return unquote(plugin_part) if plugin_part else None - - @staticmethod - def extract_page_name_from_path(path: str) -> str | None: - if not path.startswith(PLUGIN_PAGE_CONTENT_PREFIX): - return None - remainder = path[len(PLUGIN_PAGE_CONTENT_PREFIX) :] - parts = remainder.split("/", 2) - page_part = parts[1] if len(parts) > 1 else "" - return unquote(page_part) if page_part else None - @classmethod def is_scope_valid(cls, payload: dict, path: str) -> bool: - if not cls.is_protected_path(path): - return False - if path.startswith(PLUGIN_PAGE_BRIDGE_PATH): - return True - - token_plugin_name = payload.get("plugin_name") - token_page_name = payload.get("page_name") - request_plugin_name = cls.extract_plugin_name_from_path(path) - request_page_name = cls.extract_page_name_from_path(path) - if ( - not isinstance(token_plugin_name, str) - or not token_plugin_name - or not isinstance(token_page_name, str) - or not token_page_name - or not request_plugin_name - or not request_page_name - ): - return False - return ( - token_plugin_name == request_plugin_name - and token_page_name == request_page_name - ) + # The bridge SDK is shared across views, so any view token may fetch + # it; every other path rejects scoped asset tokens. + return cls.is_protected_path(path) diff --git a/astrbot/dashboard/services/plugin_page_service.py b/astrbot/dashboard/services/plugin_page_service.py index 03081d374c..a8dc272796 100644 --- a/astrbot/dashboard/services/plugin_page_service.py +++ b/astrbot/dashboard/services/plugin_page_service.py @@ -9,7 +9,7 @@ from datetime import datetime, timedelta, timezone from pathlib import Path from typing import cast -from urllib.parse import parse_qsl, quote, urlencode, urlsplit, urlunsplit +from urllib.parse import quote, urlencode, urlunsplit import aiofiles import jwt @@ -21,7 +21,9 @@ from astrbot.core.star.star_manager import PluginManager PLUGIN_PAGE_ASSET_TOKEN_TYPE = "plugin_page_asset" -PLUGIN_PAGE_ASSET_TOKEN_TTL_SECONDS = 60 +# Aligned with the dashboard session lifetime (7 days): a plugin view +# cannot outlive its parent dashboard page anyway. +PLUGIN_PAGE_ASSET_TOKEN_TTL_SECONDS = 7 * 24 * 60 * 60 # Directory names that hold plugin views inside a plugin package, in # preference order. "views" is preferred; "pages" stays as an alias. PLUGIN_PAGE_ROOT_DIR_NAMES = ("views", "pages") @@ -34,22 +36,6 @@ r"(?Psrc|href)=(?P[\"\'])(?P.*?)(?P=quote)", re.IGNORECASE, ) -_CSS_URL_RE = re.compile( - r"url\(\s*(?P[\"\']?)(?P.*?)(?P=quote)\s*\)", - re.IGNORECASE, -) -_JS_DYNAMIC_IMPORT_RE = re.compile( - r"(?P\bimport\s*\(\s*)(?P[\"\'])(?P.*?)(?P=quote)(?P\s*\))", - re.IGNORECASE, -) -_JS_MODULE_FROM_RE = re.compile( - r"(?P\b(?:import|export)\s+(?:[^;]*?\s+from\s+))(?P[\"\'])(?P.*?)(?P=quote)", - re.IGNORECASE | re.DOTALL, -) -_JS_SIDE_EFFECT_IMPORT_RE = re.compile( - r"(?P\bimport\s+)(?P[\"\'])(?P[^\"'\r\n]+)(?P=quote)", - re.IGNORECASE, -) @dataclass @@ -178,8 +164,8 @@ def build_initial_context( return None plugin_name = payload.get("plugin_name") - page_name = payload.get("page_name") - if not isinstance(plugin_name, str) or not isinstance(page_name, str): + view_name = payload.get("page_name") + if not isinstance(plugin_name, str) or not isinstance(view_name, str): return None plugin = self.get_plugin_metadata_by_name(plugin_name) @@ -207,15 +193,15 @@ def build_initial_context( ) page_title = ( # "views" is the preferred i18n key prefix; "pages" stays as an alias. - self.get_by_path(locale_data, f"views.{page_name}.title") - or self.get_by_path(locale_data, f"pages.{page_name}.title") - or page_name + self.get_by_path(locale_data, f"views.{view_name}.title") + or self.get_by_path(locale_data, f"pages.{view_name}.title") + or view_name ) return { "pluginName": plugin.name, "displayName": display_name, - "pageName": page_name, + "pageName": view_name, "pageTitle": page_title, "locale": resolved_locale, "i18n": plugin_i18n, @@ -226,15 +212,15 @@ async def get_plugin_page_entry_config( self, *, plugin_name: str | None, - page_name: str | None, + view_name: str | None, jwt_secret: str | None = None, username: str | None, locale: str, ) -> dict: if not plugin_name: raise PluginPageServiceError("缺少插件名") - if not page_name: - raise PluginPageServiceError("缺少 Page 名称") + if not view_name: + raise PluginPageServiceError("缺少 View 名称") plugin = self.get_plugin_metadata_by_name(plugin_name) if not plugin: @@ -244,20 +230,20 @@ async def get_plugin_page_entry_config( page = await self.serialize_plugin_page_for_request( plugin, - page_name, + view_name, include_content_path=True, jwt_secret=jwt_secret, username=username, locale=locale, ) if not page: - raise PluginPageServiceError("插件 Page 不存在") + raise PluginPageServiceError("插件 View 不存在") return page async def serialize_plugin_page_for_request( self, plugin: StarMetadata, - page_name: str, + view_name: str, *, include_content_path: bool = False, jwt_secret: str | None = None, @@ -270,7 +256,7 @@ async def serialize_plugin_page_for_request( asset_token = ( self.issue_plugin_page_asset_token( plugin_name=plugin_name, - page_name=page_name, + view_name=view_name, jwt_secret=jwt_secret or self._jwt_secret(), username=username, locale=locale, @@ -279,7 +265,7 @@ async def serialize_plugin_page_for_request( ) return await self.serialize_plugin_page( plugin, - page_name, + view_name, include_content_path=include_content_path, asset_token=asset_token, ) @@ -287,7 +273,7 @@ async def serialize_plugin_page_for_request( def prepare_plugin_page_query_params( self, plugin_name: str, - page_name: str, + view_name: str, *, asset_token: str, jwt_secret: str | None = None, @@ -299,7 +285,7 @@ def prepare_plugin_page_query_params( asset_token = ( self.issue_plugin_page_asset_token( plugin_name=plugin_name, - page_name=page_name, + view_name=view_name, jwt_secret=jwt_secret or self._jwt_secret(), username=username, locale=locale, @@ -327,7 +313,7 @@ async def serve_bridge_sdk( ) -> PluginPageContentPayload: if not self.bridge_file.is_file(): raise PluginPageServiceError( - "Plugin Page bridge SDK not found", + "Plugin view bridge SDK not found", status_code=404, ) bridge_js = await self.read_plugin_page_text(self.bridge_file) @@ -351,7 +337,7 @@ async def serve_page_content( self, *, plugin_name: str, - page_name: str, + view_name: str, asset_path: str, asset_token: str, jwt_secret: str | None = None, @@ -366,7 +352,7 @@ async def serve_page_content( raise PluginPageServiceError("Plugin is disabled", status_code=403) try: - page = await self.get_plugin_page(plugin, page_name) + page = await self.get_plugin_page(plugin, view_name) file_path = await self.resolve_plugin_page_file( plugin, page.name, @@ -374,7 +360,7 @@ async def serve_page_content( ) except (FileNotFoundError, ValueError) as exc: raise PluginPageServiceError( - "Plugin Page asset not found", + "Plugin view asset not found", status_code=404, ) from exc @@ -387,44 +373,21 @@ async def serve_page_content( locale=locale, theme=theme, ) - served_asset_path = asset_path or page.entry_file suffix = file_path.suffix.lower() if suffix == ".html": html_text = await self.read_plugin_page_text(file_path) return PluginPageContentPayload( - content=self.rewrite_plugin_page_html( + content=self.process_plugin_page_html( html_text, - plugin_name, - page.name, - served_asset_path, theme=theme, extra_query_params=extra_query_params, ), content_type="text/html; charset=utf-8", ) - if suffix == ".css": - css_text = await self.read_plugin_page_text(file_path) - return PluginPageContentPayload( - content=self.rewrite_plugin_page_css( - css_text, - plugin_name, - page.name, - served_asset_path, - extra_query_params=extra_query_params, - ), - content_type="text/css; charset=utf-8", - ) - if suffix in {".js", ".mjs"}: - js_text = await self.read_plugin_page_text(file_path) + if suffix in {".css", ".js", ".mjs"}: return PluginPageContentPayload( - content=self.rewrite_plugin_page_js( - js_text, - plugin_name, - page.name, - served_asset_path, - extra_query_params=extra_query_params, - ), - content_type="application/javascript; charset=utf-8", + content=await self.read_plugin_page_text(file_path), + content_type=self.guess_plugin_page_mime_type(file_path), ) return PluginPageContentPayload( content=await self.read_plugin_page_binary(file_path), @@ -452,40 +415,37 @@ def build_security_headers() -> dict[str, str]: def normalize_plugin_page_path( raw_path: str, *, - base_dir: str | None = None, allow_empty: bool = False, ) -> str: path = raw_path.replace("\\", "/").strip() - if base_dir: - path = posixpath.join(base_dir, path) normalized = posixpath.normpath(path) if normalized in {"", "."}: if allow_empty: return "" - raise ValueError("Invalid plugin Page asset path") + raise ValueError("Invalid plugin view asset path") if ( normalized.startswith("../") or normalized == ".." or normalized.startswith("/") ): - raise ValueError("Invalid plugin Page asset path") + raise ValueError("Invalid plugin view asset path") return normalized @staticmethod def normalize_plugin_page_name(raw_name: str) -> str: - page_name = raw_name.strip() - if not page_name: - raise ValueError("Invalid plugin Page name") - normalized = posixpath.normpath(page_name.replace("\\", "/")) + view_name = raw_name.strip() + if not view_name: + raise ValueError("Invalid plugin view name") + normalized = posixpath.normpath(view_name.replace("\\", "/")) if ( - normalized != page_name + normalized != view_name or normalized in {".", ".."} or normalized.startswith(".") - or "/" in page_name - or "\\" in page_name + or "/" in view_name + or "\\" in view_name ): - raise ValueError("Invalid plugin Page name") - return page_name + raise ValueError("Invalid plugin view name") + return view_name def get_plugin_root_dir(self, plugin: StarMetadata) -> Path: if not plugin.root_dir_name: @@ -528,7 +488,7 @@ async def discover_plugin_pages(self, plugin: StarMetadata) -> list[PluginPage]: for page_dir in page_dirs: try: - page_name = self.normalize_plugin_page_name(page_dir.name) + view_name = self.normalize_plugin_page_name(page_dir.name) except ValueError: continue entry_path = page_dir / PLUGIN_PAGE_ENTRY_FILE_NAME @@ -536,8 +496,8 @@ async def discover_plugin_pages(self, plugin: StarMetadata) -> list[PluginPage]: continue pages.append( PluginPage( - name=page_name, - title=page_name, + name=view_name, + title=view_name, entry_file=PLUGIN_PAGE_ENTRY_FILE_NAME, ) ) @@ -546,34 +506,34 @@ async def discover_plugin_pages(self, plugin: StarMetadata) -> list[PluginPage]: async def get_plugin_page( self, plugin: StarMetadata, - page_name: str, + view_name: str, ) -> PluginPage: - normalized_name = self.normalize_plugin_page_name(page_name) + normalized_name = self.normalize_plugin_page_name(view_name) for page in await self.discover_plugin_pages(plugin): if page.name == normalized_name: return page - raise FileNotFoundError("Plugin Page entry not found") + raise FileNotFoundError("Plugin view entry not found") async def resolve_plugin_page_root( self, plugin: StarMetadata, - page_name: str, + view_name: str, ) -> Path: - normalized_name = self.normalize_plugin_page_name(page_name) + normalized_name = self.normalize_plugin_page_name(view_name) pages_root = await self.resolve_plugin_pages_root(plugin) page_root = (pages_root / normalized_name).resolve(strict=False) page_root.relative_to(pages_root) if not await aio_ospath.isdir(str(page_root)): - raise FileNotFoundError("Plugin Page root directory does not exist") + raise FileNotFoundError("Plugin view root directory does not exist") return page_root async def resolve_plugin_page_file( self, plugin: StarMetadata, - page_name: str, + view_name: str, asset_path: str, ) -> Path: - page = await self.get_plugin_page(plugin, page_name) + page = await self.get_plugin_page(plugin, view_name) page_root = await self.resolve_plugin_page_root(plugin, page.name) target_name = ( self.normalize_plugin_page_path(asset_path, allow_empty=True) @@ -582,83 +542,32 @@ async def resolve_plugin_page_file( target_path = (page_root / target_name).resolve(strict=False) target_path.relative_to(page_root) if not await aio_ospath.isfile(str(target_path)): - raise FileNotFoundError("Plugin Page asset not found") + raise FileNotFoundError("Plugin view asset not found") return target_path @staticmethod - def is_rewritable_asset_url(raw_url: str) -> bool: - value = raw_url.strip() - lower = value.lower() - if not value: - return False - if value.startswith(("#", "/#")): - return False - if lower.startswith( - ( - "http://", - "https://", - "//", - "data:", - "javascript:", - "mailto:", - "tel:", - "blob:", - ) - ): - return False - return True - - @staticmethod - def resolve_referenced_asset_path( - base_asset_path: str, - referenced_url: str, - ) -> str: - parts = urlsplit(referenced_url) - referenced_path = parts.path.strip() - if not referenced_path: - raise ValueError("Plugin Page referenced asset path is empty") - base_dir = posixpath.dirname(base_asset_path) if base_asset_path else "" - normalized = PluginPageService.normalize_plugin_page_path( - referenced_path, - base_dir=base_dir, - ) - if not normalized: - raise ValueError("Plugin Page referenced asset path is invalid") - return normalized - - def build_plugin_page_asset_url( - self, - plugin_name: str, - page_name: str, - asset_path: str, - original_query: str = "", - original_fragment: str = "", - extra_query_params: dict[str, str] | None = None, - ) -> str: - path = self.build_plugin_page_content_path(plugin_name, page_name, asset_path) - query_dict = dict(parse_qsl(original_query, keep_blank_values=True)) - if extra_query_params: - for key, value in extra_query_params.items(): - if value: - query_dict[key] = value - query = urlencode(query_dict) - return urlunsplit(("", "", path, query, original_fragment)) - - @staticmethod - def build_plugin_page_content_path( + def build_plugin_page_view_content_path( plugin_name: str, - page_name: str, + view_name: str, + token: str, asset_path: str = "", ) -> str: + """Build a path-token view content URL. + + The token travels in the path so relative URLs inside the view inherit + it through normal URL resolution, without content rewriting. + """ encoded_plugin_name = quote(plugin_name, safe="") - encoded_page_name = quote( - PluginPageService.normalize_plugin_page_name(page_name), + encoded_view_name = quote( + PluginPageService.normalize_plugin_page_name(view_name), safe="", ) + base = ( + f"/api/v1/plugins/{encoded_plugin_name}/views/" + f"{encoded_view_name}/_t/{quote(token, safe='')}" + ) if not asset_path: - return ( - f"/api/plugin/page/content/{encoded_plugin_name}/{encoded_page_name}/" - ) + return base + "/" safe_asset_path = PluginPageService.normalize_plugin_page_path( asset_path, allow_empty=True, @@ -666,10 +575,7 @@ def build_plugin_page_content_path( encoded_path = "/".join( quote(part, safe="") for part in safe_asset_path.split("/") ) - return ( - f"/api/plugin/page/content/{encoded_plugin_name}/" - f"{encoded_page_name}/{encoded_path}" - ) + return f"{base}/{encoded_path}" @staticmethod def get_plugin_page_bridge_sdk_url( @@ -678,170 +584,39 @@ def get_plugin_page_bridge_sdk_url( query = urlencode(extra_query_params or {}) return urlunsplit(("", "", "/api/plugin/page/bridge-sdk.js", query, "")) - @staticmethod - def is_js_relative_module_specifier(raw_url: str) -> bool: - value = raw_url.strip() - return value.startswith(("./", "../", "/")) - - def rewrite_relative_asset_url( - self, - raw_url: str, - base_asset_path: str, - plugin_name: str, - page_name: str, - extra_query_params: dict[str, str] | None = None, - ) -> str | None: - candidate = raw_url.strip() - if not self.is_rewritable_asset_url(candidate): - return None - parts = urlsplit(candidate) - asset_path = self.resolve_referenced_asset_path(base_asset_path, candidate) - return self.build_plugin_page_asset_url( - plugin_name, - page_name, - asset_path, - original_query=parts.query, - original_fragment=parts.fragment, - extra_query_params=extra_query_params, - ) - - def rewrite_plugin_page_html( + def process_plugin_page_html( self, html_text: str, - plugin_name: str, - page_name: str, - entry_asset_path: str, *, theme: str | None, extra_query_params: dict[str, str] | None = None, ) -> str: - def replace_attr(match: re.Match[str]) -> str: - raw_url = match.group("url") - attr = match.group("attr") - quote_char = match.group("quote") - - if raw_url.strip() == "/api/plugin/page/bridge-sdk.js": - url = self.get_plugin_page_bridge_sdk_url(extra_query_params) - return f"{attr}={quote_char}{url}{quote_char}" + """Process view HTML before serving. - if not self.is_rewritable_asset_url(raw_url): - return match.group(0) + Applies the theme and injects (or retargets) the bridge SDK script. + Relative asset URLs are left untouched: view assets are served from + path-token URLs, so relative references resolve correctly on their own. + """ - try: - rewritten_url = self.rewrite_relative_asset_url( - raw_url, - entry_asset_path, - plugin_name, - page_name, - extra_query_params=extra_query_params, - ) - if not rewritten_url: - return match.group(0) - return f"{attr}={quote_char}{rewritten_url}{quote_char}" - except ValueError: + def replace_bridge_url(match: re.Match[str]) -> str: + raw_url = match.group("url") + if raw_url.strip() != "/api/plugin/page/bridge-sdk.js": return match.group(0) + url = self.get_plugin_page_bridge_sdk_url(extra_query_params) + return f"{match.group('attr')}={match.group('quote')}{url}{match.group('quote')}" - rewritten_html = _HTML_ASSET_ATTR_RE.sub(replace_attr, html_text) + processed_html = _HTML_ASSET_ATTR_RE.sub(replace_bridge_url, html_text) if theme: - rewritten_html = self.apply_theme_to_html(rewritten_html, theme) - if "/api/plugin/page/bridge-sdk.js" not in rewritten_html: + processed_html = self.apply_theme_to_html(processed_html, theme) + if "/api/plugin/page/bridge-sdk.js" not in processed_html: bridge_tag = f'' - if "" in rewritten_html: - rewritten_html = rewritten_html.replace( + if "" in processed_html: + processed_html = processed_html.replace( "", f"{bridge_tag}", 1 ) else: - rewritten_html += bridge_tag - return rewritten_html - - def rewrite_plugin_page_css( - self, - css_text: str, - plugin_name: str, - page_name: str, - css_asset_path: str, - extra_query_params: dict[str, str] | None = None, - ) -> str: - def replace_url(match: re.Match[str]) -> str: - raw_url = match.group("url").strip() - quote_char = match.group("quote") or "" - try: - rewritten_url = self.rewrite_relative_asset_url( - raw_url, - css_asset_path, - plugin_name, - page_name, - extra_query_params=extra_query_params, - ) - if not rewritten_url: - return match.group(0) - return f"url({quote_char}{rewritten_url}{quote_char})" - except ValueError: - return match.group(0) - - return _CSS_URL_RE.sub(replace_url, css_text) - - def rewrite_plugin_page_js( - self, - js_text: str, - plugin_name: str, - page_name: str, - js_asset_path: str, - extra_query_params: dict[str, str] | None = None, - ) -> str: - def rewrite_specifier(raw_url: str) -> str: - if not self.is_js_relative_module_specifier(raw_url): - return raw_url - if not self.is_rewritable_asset_url(raw_url): - return raw_url - rewritten = self.rewrite_relative_asset_url( - raw_url, - js_asset_path, - plugin_name, - page_name, - extra_query_params=extra_query_params, - ) - return rewritten or raw_url - - def replace_dynamic(match: re.Match[str]) -> str: - raw_url = match.group("url") - try: - rewritten = rewrite_specifier(raw_url) - except ValueError: - return match.group(0) - return ( - f"{match.group('prefix')}{match.group('quote')}{rewritten}" - f"{match.group('quote')}{match.group('suffix')}" - ) - - def replace_from(match: re.Match[str]) -> str: - raw_url = match.group("url") - try: - rewritten = rewrite_specifier(raw_url) - except ValueError: - return match.group(0) - return ( - f"{match.group('prefix')}{match.group('quote')}" - f"{rewritten}{match.group('quote')}" - ) - - rewritten_js = _JS_DYNAMIC_IMPORT_RE.sub(replace_dynamic, js_text) - rewritten_js = _JS_MODULE_FROM_RE.sub(replace_from, rewritten_js) - - def replace_side_effect(match: re.Match[str]) -> str: - raw_url = match.group("url") - if raw_url.startswith(("{", "*")): - return match.group(0) - try: - rewritten = rewrite_specifier(raw_url) - except ValueError: - return match.group(0) - return ( - f"{match.group('prefix')}{match.group('quote')}" - f"{rewritten}{match.group('quote')}" - ) - - return _JS_SIDE_EFFECT_IMPORT_RE.sub(replace_side_effect, rewritten_js) + processed_html += bridge_tag + return processed_html @staticmethod async def read_plugin_page_text(file_path: Path) -> str: @@ -860,7 +635,7 @@ def guess_plugin_page_mime_type(file_path: Path) -> str: async def serialize_plugin_page( self, plugin: StarMetadata, - page_name: str, + view_name: str, *, include_content_path: bool = False, asset_token: str = "", @@ -869,7 +644,7 @@ async def serialize_plugin_page( if not plugin_name: return None try: - page = await self.get_plugin_page(plugin, page_name) + page = await self.get_plugin_page(plugin, view_name) await self.resolve_plugin_page_file(plugin, page.name, "") except (FileNotFoundError, ValueError): return None @@ -879,13 +654,16 @@ async def serialize_plugin_page( "title": page.title, "i18n_key": f"pages.{page.name}", } - if include_content_path: - extra_query_params = {"asset_token": asset_token} if asset_token else None - page_data["content_path"] = self.build_plugin_page_asset_url( - plugin_name, - page.name, - "", - extra_query_params=extra_query_params, + if include_content_path and asset_token: + page_data["content_path"] = ( + self.build_plugin_page_view_content_path( + plugin_name, + page.name, + asset_token, + ) + # Kept as a query echo for view scripts that read the token + # from location.search. + + f"?asset_token={quote(asset_token, safe='')}" ) return page_data @@ -901,7 +679,7 @@ def issue_plugin_page_asset_token( self, *, plugin_name: str, - page_name: str, + view_name: str, jwt_secret: str | None = None, username: str | None, locale: str, @@ -916,8 +694,11 @@ def issue_plugin_page_asset_token( payload = { "username": username, "token_type": PLUGIN_PAGE_ASSET_TOKEN_TYPE, + # Distinguishes long-lived view-session tokens from future + # one-shot presigned tokens (e.g. direct downloads). + "purpose": "page_session", "plugin_name": plugin_name, - "page_name": page_name, + "page_name": view_name, "locale": locale, "iat": now, "exp": now + timedelta(seconds=PLUGIN_PAGE_ASSET_TOKEN_TTL_SECONDS), diff --git a/dashboard/src/api/generated/openapi-v1/sdk.gen.ts b/dashboard/src/api/generated/openapi-v1/sdk.gen.ts index 00c85e29c8..0d7c6ad917 100644 --- a/dashboard/src/api/generated/openapi-v1/sdk.gen.ts +++ b/dashboard/src/api/generated/openapi-v1/sdk.gen.ts @@ -1,7 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts import { createClient, createConfig, type OptionsLegacyParser, formDataBodySerializer } from '@hey-api/client-axios'; -import type { LoginData, LoginError, LoginResponse, LogoutError, LogoutResponse, GetAuthSetupStatusError, GetAuthSetupStatusResponse, SetupAuthData, SetupAuthError, SetupAuthResponse, SetupTotpData, SetupTotpError, SetupTotpResponse, RecoverTotpError, RecoverTotpResponse, UpdateAuthAccountData, UpdateAuthAccountError, UpdateAuthAccountResponse, ListApiKeysError, ListApiKeysResponse, CreateApiKeyData, CreateApiKeyError, CreateApiKeyResponse, RevokeApiKeyData, RevokeApiKeyError, RevokeApiKeyResponse, DeleteApiKeyData, DeleteApiKeyError, DeleteApiKeyResponse, GetSystemConfigSchemaError, GetSystemConfigSchemaResponse, GetSystemConfigError, GetSystemConfigResponse, UpdateSystemConfigData, UpdateSystemConfigError, UpdateSystemConfigResponse, GetSystemConfigRuntimeError, GetSystemConfigRuntimeResponse, GetConfigProfileSchemaError, GetConfigProfileSchemaResponse, ListConfigProfilesError, ListConfigProfilesResponse, CreateConfigProfileData, CreateConfigProfileError, CreateConfigProfileResponse, GetConfigProfileData, GetConfigProfileError, GetConfigProfileResponse, UpdateConfigProfileContentData, UpdateConfigProfileContentError, UpdateConfigProfileContentResponse, RenameConfigProfileData, RenameConfigProfileError, RenameConfigProfileResponse, DeleteConfigProfileData, DeleteConfigProfileError, DeleteConfigProfileResponse, ListConfigRoutesError, ListConfigRoutesResponse, ReplaceConfigRoutesData, ReplaceConfigRoutesError, ReplaceConfigRoutesResponse, UpsertConfigRouteData, UpsertConfigRouteError, UpsertConfigRouteResponse, DeleteConfigRouteData, DeleteConfigRouteError, DeleteConfigRouteResponse, ListBotTypesError, ListBotTypesResponse, RegisterBotTypeData, RegisterBotTypeError, RegisterBotTypeResponse, ListBotsData, ListBotsError, ListBotsResponse, CreateBotData, CreateBotError, CreateBotResponse, ListBotStatsError, ListBotStatsResponse, GetBotByIdData, GetBotByIdError, GetBotByIdResponse, UpdateBotByIdData, UpdateBotByIdError, UpdateBotByIdResponse, DeleteBotByIdData, DeleteBotByIdError, DeleteBotByIdResponse, SetBotEnabledByIdData, SetBotEnabledByIdError, SetBotEnabledByIdResponse, TestBotByIdData, TestBotByIdError, TestBotByIdResponse, GetBotData, GetBotError, GetBotResponse, UpdateBotData, UpdateBotError, UpdateBotResponse, DeleteBotData, DeleteBotError, DeleteBotResponse, SetBotEnabledData, SetBotEnabledError, SetBotEnabledResponse, TestBotData, TestBotError, TestBotResponse, GetProviderSchemaError, GetProviderSchemaResponse, ListProviderSourcesError, ListProviderSourcesResponse, CreateProviderSourceData, CreateProviderSourceError, CreateProviderSourceResponse, GetProviderSourceByIdData, GetProviderSourceByIdError, GetProviderSourceByIdResponse, UpsertProviderSourceByIdData, UpsertProviderSourceByIdError, UpsertProviderSourceByIdResponse, DeleteProviderSourceByIdData, DeleteProviderSourceByIdError, DeleteProviderSourceByIdResponse, ListProviderSourceModelsByIdData, ListProviderSourceModelsByIdError, ListProviderSourceModelsByIdResponse, ListProvidersBySourceIdData, ListProvidersBySourceIdError, ListProvidersBySourceIdResponse, CreateProviderInSourceByIdData, CreateProviderInSourceByIdError, CreateProviderInSourceByIdResponse, GetProviderSourceData, GetProviderSourceError, GetProviderSourceResponse, UpsertProviderSourceData, UpsertProviderSourceError, UpsertProviderSourceResponse, DeleteProviderSourceData, DeleteProviderSourceError, DeleteProviderSourceResponse, ListProviderSourceModelsData, ListProviderSourceModelsError, ListProviderSourceModelsResponse, ListProvidersBySourceData, ListProvidersBySourceError, ListProvidersBySourceResponse, CreateProviderInSourceData, CreateProviderInSourceError, CreateProviderInSourceResponse, ListProvidersData, ListProvidersError, ListProvidersResponse, CreateProviderData, CreateProviderError, CreateProviderResponse, GetProviderByIdData, GetProviderByIdError, GetProviderByIdResponse, UpdateProviderByIdData, UpdateProviderByIdError, UpdateProviderByIdResponse, DeleteProviderByIdData, DeleteProviderByIdError, DeleteProviderByIdResponse, SetProviderEnabledByIdData, SetProviderEnabledByIdError, SetProviderEnabledByIdResponse, TestProviderByIdData, TestProviderByIdError, TestProviderByIdResponse, GetProviderEmbeddingDimensionByIdData, GetProviderEmbeddingDimensionByIdError, GetProviderEmbeddingDimensionByIdResponse, GetProviderData, GetProviderError, GetProviderResponse, UpdateProviderData, UpdateProviderError, UpdateProviderResponse, DeleteProviderData, DeleteProviderError, DeleteProviderResponse, SetProviderEnabledData, SetProviderEnabledError, SetProviderEnabledResponse, TestProviderData, TestProviderError, TestProviderResponse, GetProviderEmbeddingDimensionData, GetProviderEmbeddingDimensionError, GetProviderEmbeddingDimensionResponse, SendChatMessageData, SendChatMessageError, SendChatMessageResponse, OpenChatWebSocketData, OpenLiveChatWebSocketData, OpenUnifiedChatWebSocketData, ListChatSessionsData, ListChatSessionsError, ListChatSessionsResponse, CreateChatSessionData, CreateChatSessionError, CreateChatSessionResponse, BatchDeleteChatSessionsData, BatchDeleteChatSessionsError, BatchDeleteChatSessionsResponse, GetChatSessionData, GetChatSessionError, GetChatSessionResponse, UpdateChatSessionData, UpdateChatSessionError, UpdateChatSessionResponse, DeleteChatSessionData, DeleteChatSessionError, DeleteChatSessionResponse, StopChatSessionData, StopChatSessionError, StopChatSessionResponse, ResumeChatRunData, ResumeChatRunError, ResumeChatRunResponse, UpdateChatMessageData, UpdateChatMessageError, UpdateChatMessageResponse, RegenerateChatMessageData, RegenerateChatMessageError, RegenerateChatMessageResponse, ListChatConfigsError, ListChatConfigsResponse, CreateChatThreadData, CreateChatThreadError, CreateChatThreadResponse, GetChatThreadData, GetChatThreadError, GetChatThreadResponse, DeleteChatThreadData, DeleteChatThreadError, DeleteChatThreadResponse, SendChatThreadMessageData, SendChatThreadMessageError, SendChatThreadMessageResponse, ListChatProjectsError, ListChatProjectsResponse, CreateChatProjectData, CreateChatProjectError, CreateChatProjectResponse, GetChatProjectData, GetChatProjectError, GetChatProjectResponse, UpdateChatProjectData, UpdateChatProjectError, UpdateChatProjectResponse, DeleteChatProjectData, DeleteChatProjectError, DeleteChatProjectResponse, ListChatProjectSessionsData, ListChatProjectSessionsError, ListChatProjectSessionsResponse, ListChatProjectWorkspaceFilesData, ListChatProjectWorkspaceFilesError, ListChatProjectWorkspaceFilesResponse, GetChatProjectWorkspaceFileData, GetChatProjectWorkspaceFileError, GetChatProjectWorkspaceFileResponse, DownloadChatProjectWorkspaceFileData, DownloadChatProjectWorkspaceFileError, DownloadChatProjectWorkspaceFileResponse, AddChatProjectSessionData, AddChatProjectSessionError, AddChatProjectSessionResponse, RemoveChatProjectSessionData, RemoveChatProjectSessionError, RemoveChatProjectSessionResponse, SendImMessageData, SendImMessageError, SendImMessageResponse, ListImBotsError, ListImBotsResponse, UploadFileData, UploadFileError, UploadFileResponse, InitFileUploadData, InitFileUploadError, InitFileUploadResponse, UploadFileChunkData, UploadFileChunkError, UploadFileChunkResponse, CompleteFileUploadData, CompleteFileUploadError, CompleteFileUploadResponse, AbortFileUploadData, AbortFileUploadError, AbortFileUploadResponse, StatusFileUploadData, StatusFileUploadError, StatusFileUploadResponse, UploadOpenApiFileData, UploadOpenApiFileError, UploadOpenApiFileResponse, DownloadOpenApiFileData, DownloadOpenApiFileError, DownloadOpenApiFileResponse, GetFileByNameData, GetFileByNameError, GetFileByNameResponse, GetTokenFileData, GetTokenFileError, GetTokenFileResponse, GetAttachmentData, GetAttachmentError, GetAttachmentResponse, DeleteAttachmentData, DeleteAttachmentError, DeleteAttachmentResponse, DownloadAttachmentData, DownloadAttachmentError, DownloadAttachmentResponse, ListPluginsData, ListPluginsError, ListPluginsResponse, GetPluginByIdData, GetPluginByIdError, GetPluginByIdResponse, UninstallPluginByIdData, UninstallPluginByIdError, UninstallPluginByIdResponse, GetPluginConfigByIdData, GetPluginConfigByIdError, GetPluginConfigByIdResponse, UpdatePluginConfigByIdData, UpdatePluginConfigByIdError, UpdatePluginConfigByIdResponse, GetPluginConfigSchemaByIdData, GetPluginConfigSchemaByIdError, GetPluginConfigSchemaByIdResponse, ListPluginConfigFilesByIdData, ListPluginConfigFilesByIdError, ListPluginConfigFilesByIdResponse, UploadPluginConfigFilesByIdData, UploadPluginConfigFilesByIdError, UploadPluginConfigFilesByIdResponse, DeletePluginConfigFileByIdData, DeletePluginConfigFileByIdError, DeletePluginConfigFileByIdResponse, GetPluginReadmeByIdData, GetPluginReadmeByIdError, GetPluginReadmeByIdResponse, GetPluginChangelogByIdData, GetPluginChangelogByIdError, GetPluginChangelogByIdResponse, ReloadPluginByIdData, ReloadPluginByIdError, ReloadPluginByIdResponse, SetPluginEnabledByIdData, SetPluginEnabledByIdError, SetPluginEnabledByIdResponse, ListPluginPagesByIdData, ListPluginPagesByIdError, ListPluginPagesByIdResponse, GetPluginPageByIdData, GetPluginPageByIdError, GetPluginPageByIdResponse, GetPluginPageAssetByIdData, GetPluginPageAssetByIdError, GetPluginPageAssetByIdResponse, GetPluginData, GetPluginError, GetPluginResponse, UninstallPluginData, UninstallPluginError, UninstallPluginResponse, GetPluginConfigData, GetPluginConfigError, GetPluginConfigResponse, UpdatePluginConfigData, UpdatePluginConfigError, UpdatePluginConfigResponse, UpdatePluginLogLevelData, UpdatePluginLogLevelError, UpdatePluginLogLevelResponse, GetPluginConfigSchemaData, GetPluginConfigSchemaError, GetPluginConfigSchemaResponse, ListPluginConfigFilesData, ListPluginConfigFilesError, ListPluginConfigFilesResponse, UploadPluginConfigFilesData, UploadPluginConfigFilesError, UploadPluginConfigFilesResponse, DeletePluginConfigFileData, DeletePluginConfigFileError, DeletePluginConfigFileResponse, GetPluginReadmeData, GetPluginReadmeError, GetPluginReadmeResponse, GetPluginChangelogData, GetPluginChangelogError, GetPluginChangelogResponse, ReloadPluginData, ReloadPluginError, ReloadPluginResponse, BindPluginSourceData, BindPluginSourceError, BindPluginSourceResponse, SetPluginEnabledData, SetPluginEnabledError, SetPluginEnabledResponse, UpdatePluginData, UpdatePluginError, UpdatePluginResponse, UpdatePluginsData, UpdatePluginsError, UpdatePluginsResponse, CheckPluginVersionSupportData, CheckPluginVersionSupportError, CheckPluginVersionSupportResponse, ValidatePluginRepoData, ValidatePluginRepoError, ValidatePluginRepoResponse, ListFailedPluginsError, ListFailedPluginsResponse, UninstallFailedPluginData, UninstallFailedPluginError, UninstallFailedPluginResponse, ReloadFailedPluginData, ReloadFailedPluginError, ReloadFailedPluginResponse, InstallPluginFromGithubData, InstallPluginFromGithubError, InstallPluginFromGithubResponse, InstallPluginFromGitData, InstallPluginFromGitError, InstallPluginFromGitResponse, InstallPluginFromUrlData, InstallPluginFromUrlError, InstallPluginFromUrlResponse, InstallPluginFromUploadData, InstallPluginFromUploadError, InstallPluginFromUploadResponse, ListPluginMarketData, ListPluginMarketError, ListPluginMarketResponse, ListPluginMarketCategoriesError, ListPluginMarketCategoriesResponse, ListPluginSourcesError, ListPluginSourcesResponse, CreatePluginSourceData, CreatePluginSourceError, CreatePluginSourceResponse, ReplacePluginSourcesData, ReplacePluginSourcesError, ReplacePluginSourcesResponse, DeletePluginSourceData, DeletePluginSourceError, DeletePluginSourceResponse, DeletePluginSourceByIdData, DeletePluginSourceByIdError, DeletePluginSourceByIdResponse, ListPluginPagesData, ListPluginPagesError, ListPluginPagesResponse, GetPluginPageData, GetPluginPageError, GetPluginPageResponse, GetPluginPageAssetData, GetPluginPageAssetError, GetPluginPageAssetResponse, ListPluginViewsByIdData, ListPluginViewsByIdError, ListPluginViewsByIdResponse, GetPluginViewByIdData, GetPluginViewByIdError, GetPluginViewByIdResponse, GetPluginViewAssetByIdData, GetPluginViewAssetByIdError, GetPluginViewAssetByIdResponse, ListPluginViewsData, ListPluginViewsError, ListPluginViewsResponse, GetPluginViewData, GetPluginViewError, GetPluginViewResponse, GetPluginViewAssetData, GetPluginViewAssetError, GetPluginViewAssetResponse, GetPluginPageBridgeSdkError, GetPluginPageBridgeSdkResponse, GetPluginExtensionRouteData, GetPluginExtensionRouteError, GetPluginExtensionRouteResponse, PostPluginExtensionRouteData, PostPluginExtensionRouteError, PostPluginExtensionRouteResponse, PutPluginExtensionRouteData, PutPluginExtensionRouteError, PutPluginExtensionRouteResponse, PatchPluginExtensionRouteData, PatchPluginExtensionRouteError, PatchPluginExtensionRouteResponse, DeletePluginExtensionRouteData, DeletePluginExtensionRouteError, DeletePluginExtensionRouteResponse, ListCommandsData, ListCommandsError, ListCommandsResponse, UpdateCommandData, UpdateCommandError, UpdateCommandResponse, ListCommandConflictsError, ListCommandConflictsResponse, ListToolsData, ListToolsError, ListToolsResponse, SetToolEnabledData, SetToolEnabledError, SetToolEnabledResponse, SetToolPermissionData, SetToolPermissionError, SetToolPermissionResponse, ListMcpServersError, ListMcpServersResponse, CreateMcpServerData, CreateMcpServerError, CreateMcpServerResponse, UpdateMcpServerByNameData, UpdateMcpServerByNameError, UpdateMcpServerByNameResponse, DeleteMcpServerByNameData, DeleteMcpServerByNameError, DeleteMcpServerByNameResponse, SetMcpServerEnabledByNameData, SetMcpServerEnabledByNameError, SetMcpServerEnabledByNameResponse, TestMcpServerByNameData, TestMcpServerByNameError, TestMcpServerByNameResponse, UpdateMcpServerData, UpdateMcpServerError, UpdateMcpServerResponse, DeleteMcpServerData, DeleteMcpServerError, DeleteMcpServerResponse, SetMcpServerEnabledData, SetMcpServerEnabledError, SetMcpServerEnabledResponse, TestMcpServerData, TestMcpServerError, TestMcpServerResponse, SyncModelScopeMcpServersData, SyncModelScopeMcpServersError, SyncModelScopeMcpServersResponse, ListSkillsData, ListSkillsError, ListSkillsResponse, UploadSkillData, UploadSkillError, UploadSkillResponse, UploadSkillsBatchData, UploadSkillsBatchError, UploadSkillsBatchResponse, UpdateSkillByNameData, UpdateSkillByNameError, UpdateSkillByNameResponse, DeleteSkillByNameData, DeleteSkillByNameError, DeleteSkillByNameResponse, DownloadSkillByNameData, DownloadSkillByNameError, DownloadSkillByNameResponse, ListSkillFilesByNameData, ListSkillFilesByNameError, ListSkillFilesByNameResponse, GetSkillFileByNameData, GetSkillFileByNameError, GetSkillFileByNameResponse, UpdateSkillFileByNameData, UpdateSkillFileByNameError, UpdateSkillFileByNameResponse, UpdateSkillData, UpdateSkillError, UpdateSkillResponse, DeleteSkillData, DeleteSkillError, DeleteSkillResponse, DownloadSkillData, DownloadSkillError, DownloadSkillResponse, ListSkillFilesData, ListSkillFilesError, ListSkillFilesResponse, GetSkillFileData, GetSkillFileError, GetSkillFileResponse, UpdateSkillFileData, UpdateSkillFileError, UpdateSkillFileResponse, ListNeoSkillCandidatesData, ListNeoSkillCandidatesError, ListNeoSkillCandidatesResponse, ListNeoSkillReleasesData, ListNeoSkillReleasesError, ListNeoSkillReleasesResponse, GetNeoSkillPayloadData, GetNeoSkillPayloadError, GetNeoSkillPayloadResponse, EvaluateNeoSkillCandidateData, EvaluateNeoSkillCandidateError, EvaluateNeoSkillCandidateResponse, PromoteNeoSkillCandidateData, PromoteNeoSkillCandidateError, PromoteNeoSkillCandidateResponse, RollbackNeoSkillReleaseData, RollbackNeoSkillReleaseError, RollbackNeoSkillReleaseResponse, SyncNeoSkillReleaseData, SyncNeoSkillReleaseError, SyncNeoSkillReleaseResponse, DeleteNeoSkillCandidateData, DeleteNeoSkillCandidateError, DeleteNeoSkillCandidateResponse, DeleteNeoSkillReleaseData, DeleteNeoSkillReleaseError, DeleteNeoSkillReleaseResponse, ListKnowledgeBasesData, ListKnowledgeBasesError, ListKnowledgeBasesResponse, CreateKnowledgeBaseData, CreateKnowledgeBaseError, CreateKnowledgeBaseResponse, GetKnowledgeBaseData, GetKnowledgeBaseError, GetKnowledgeBaseResponse, UpdateKnowledgeBaseData, UpdateKnowledgeBaseError, UpdateKnowledgeBaseResponse, DeleteKnowledgeBaseData, DeleteKnowledgeBaseError, DeleteKnowledgeBaseResponse, GetKnowledgeBaseStatsData, GetKnowledgeBaseStatsError, GetKnowledgeBaseStatsResponse, ListKnowledgeDocumentsData, ListKnowledgeDocumentsError, ListKnowledgeDocumentsResponse, UploadKnowledgeDocumentData, UploadKnowledgeDocumentError, UploadKnowledgeDocumentResponse, ImportKnowledgeDocumentsData, ImportKnowledgeDocumentsError, ImportKnowledgeDocumentsResponse, ImportKnowledgeDocumentFromUrlData, ImportKnowledgeDocumentFromUrlError, ImportKnowledgeDocumentFromUrlResponse, GetKnowledgeDocumentData, GetKnowledgeDocumentError, GetKnowledgeDocumentResponse, DeleteKnowledgeDocumentData, DeleteKnowledgeDocumentError, DeleteKnowledgeDocumentResponse, ListKnowledgeChunksData, ListKnowledgeChunksError, ListKnowledgeChunksResponse, DeleteKnowledgeChunkData, DeleteKnowledgeChunkError, DeleteKnowledgeChunkResponse, RetrieveKnowledgeBaseData, RetrieveKnowledgeBaseError, RetrieveKnowledgeBaseResponse, GetKnowledgeTaskData, GetKnowledgeTaskError, GetKnowledgeTaskResponse, GetPersonaTreeError, GetPersonaTreeResponse, ListPersonasData, ListPersonasError, ListPersonasResponse, CreatePersonaData, CreatePersonaError, CreatePersonaResponse, GetPersonaByIdData, GetPersonaByIdError, GetPersonaByIdResponse, UpdatePersonaByIdData, UpdatePersonaByIdError, UpdatePersonaByIdResponse, DeletePersonaByIdData, DeletePersonaByIdError, DeletePersonaByIdResponse, GetPersonaData, GetPersonaError, GetPersonaResponse, UpdatePersonaData, UpdatePersonaError, UpdatePersonaResponse, DeletePersonaData, DeletePersonaError, DeletePersonaResponse, ListPersonaFoldersData, ListPersonaFoldersError, ListPersonaFoldersResponse, CreatePersonaFolderData, CreatePersonaFolderError, CreatePersonaFolderResponse, UpdatePersonaFolderData, UpdatePersonaFolderError, UpdatePersonaFolderResponse, DeletePersonaFolderData, DeletePersonaFolderError, DeletePersonaFolderResponse, MovePersonaItemData, MovePersonaItemError, MovePersonaItemResponse, ReorderPersonaItemsData, ReorderPersonaItemsError, ReorderPersonaItemsResponse, ListSessionsData, ListSessionsError, ListSessionsResponse, ListActiveUmosError, ListActiveUmosResponse, ListSessionRulesData, ListSessionRulesError, ListSessionRulesResponse, UpsertSessionRuleData, UpsertSessionRuleError, UpsertSessionRuleResponse, DeleteSessionRulesData, DeleteSessionRulesError, DeleteSessionRulesResponse, BatchUpdateSessionProviderData, BatchUpdateSessionProviderError, BatchUpdateSessionProviderResponse, BatchUpdateSessionServiceData, BatchUpdateSessionServiceError, BatchUpdateSessionServiceResponse, ListSessionGroupsError, ListSessionGroupsResponse, CreateSessionGroupData, CreateSessionGroupError, CreateSessionGroupResponse, UpdateSessionGroupData, UpdateSessionGroupError, UpdateSessionGroupResponse, DeleteSessionGroupData, DeleteSessionGroupError, DeleteSessionGroupResponse, ListConversationsData, ListConversationsError, ListConversationsResponse, GetConversationFilterOptionsError, GetConversationFilterOptionsResponse, BatchDeleteConversationsData, BatchDeleteConversationsError, BatchDeleteConversationsResponse, GetConversationData, GetConversationError, GetConversationResponse, UpdateConversationData, UpdateConversationError, UpdateConversationResponse, DeleteConversationData, DeleteConversationError, DeleteConversationResponse, ReplaceConversationMessagesData, ReplaceConversationMessagesError, ReplaceConversationMessagesResponse, ExportConversationsData, ExportConversationsError, ExportConversationsResponse, GetStatsData, GetStatsError, GetStatsResponse, GetProviderTokenStatsData, GetProviderTokenStatsError, GetProviderTokenStatsResponse, GetVersionError, GetVersionResponse, GetPublicVersionsError, GetPublicVersionsResponse, GetFirstNoticeData, GetFirstNoticeError, GetFirstNoticeResponse, TestGhproxyConnectionData, TestGhproxyConnectionError, TestGhproxyConnectionResponse, ListChangelogVersionsError, ListChangelogVersionsResponse, GetChangelogData, GetChangelogError, GetChangelogResponse, GetStartTimeError, GetStartTimeResponse, GetStorageStatusError, GetStorageStatusResponse, CleanupStorageData, CleanupStorageError, CleanupStorageResponse, RestartCoreError, RestartCoreResponse, ListBackupsData, ListBackupsError, ListBackupsResponse, CreateBackupData, CreateBackupError, CreateBackupResponse, UploadBackupData, UploadBackupError, UploadBackupResponse, InitBackupUploadData, InitBackupUploadError, InitBackupUploadResponse, UploadBackupChunkData, UploadBackupChunkError, UploadBackupChunkResponse, CompleteBackupUploadData, CompleteBackupUploadError, CompleteBackupUploadResponse, AbortBackupUploadData, AbortBackupUploadError, AbortBackupUploadResponse, StatusBackupUploadData, StatusBackupUploadError, StatusBackupUploadResponse, GetBackupProgressData, GetBackupProgressError, GetBackupProgressResponse, DownloadBackupData, DownloadBackupError, DownloadBackupResponse, RenameBackupData, RenameBackupError, RenameBackupResponse, DeleteBackupData, DeleteBackupError, DeleteBackupResponse, CheckBackupData, CheckBackupError, CheckBackupResponse, ImportBackupData, ImportBackupError, ImportBackupResponse, CheckUpdateError, CheckUpdateResponse, ListReleasesData, ListReleasesError, ListReleasesResponse, UpdateCoreData, UpdateCoreError, UpdateCoreResponse, UpdateDashboardData, UpdateDashboardError, UpdateDashboardResponse, GetUpdateProgressData, GetUpdateProgressError, GetUpdateProgressResponse, InstallPipPackageData, InstallPipPackageError, InstallPipPackageResponse, ListCronJobsData, ListCronJobsError, ListCronJobsResponse, CreateCronJobData, CreateCronJobError, CreateCronJobResponse, UpdateCronJobData, UpdateCronJobError, UpdateCronJobResponse, DeleteCronJobData, DeleteCronJobError, DeleteCronJobResponse, RunCronJobData, RunCronJobError, RunCronJobResponse, StreamLiveLogsError, StreamLiveLogsResponse, GetLogHistoryError, GetLogHistoryResponse, GetTraceSettingsError, GetTraceSettingsResponse, UpdateTraceSettingsData, UpdateTraceSettingsError, UpdateTraceSettingsResponse, ListT2iTemplatesError, ListT2iTemplatesResponse, CreateT2iTemplateData, CreateT2iTemplateError, CreateT2iTemplateResponse, GetActiveT2iTemplateError, GetActiveT2iTemplateResponse, SetActiveT2iTemplateData, SetActiveT2iTemplateError, SetActiveT2iTemplateResponse, ResetDefaultT2iTemplateError, ResetDefaultT2iTemplateResponse, GetT2iTemplateData, GetT2iTemplateError, GetT2iTemplateResponse, UpdateT2iTemplateData, UpdateT2iTemplateError, UpdateT2iTemplateResponse, DeleteT2iTemplateData, DeleteT2iTemplateError, DeleteT2iTemplateResponse, GetSubagentConfigError, GetSubagentConfigResponse, UpdateSubagentConfigData, UpdateSubagentConfigError, UpdateSubagentConfigResponse, ListSubagentAvailableToolsError, ListSubagentAvailableToolsResponse, VerifyPlatformWebhookData, VerifyPlatformWebhookError, VerifyPlatformWebhookResponse, ReceivePlatformWebhookData, ReceivePlatformWebhookError, ReceivePlatformWebhookResponse } from './types.gen'; +import type { LoginData, LoginError, LoginResponse, LogoutError, LogoutResponse, GetAuthSetupStatusError, GetAuthSetupStatusResponse, SetupAuthData, SetupAuthError, SetupAuthResponse, SetupTotpData, SetupTotpError, SetupTotpResponse, RecoverTotpError, RecoverTotpResponse, UpdateAuthAccountData, UpdateAuthAccountError, UpdateAuthAccountResponse, ListApiKeysError, ListApiKeysResponse, CreateApiKeyData, CreateApiKeyError, CreateApiKeyResponse, RevokeApiKeyData, RevokeApiKeyError, RevokeApiKeyResponse, DeleteApiKeyData, DeleteApiKeyError, DeleteApiKeyResponse, GetSystemConfigSchemaError, GetSystemConfigSchemaResponse, GetSystemConfigError, GetSystemConfigResponse, UpdateSystemConfigData, UpdateSystemConfigError, UpdateSystemConfigResponse, GetSystemConfigRuntimeError, GetSystemConfigRuntimeResponse, GetConfigProfileSchemaError, GetConfigProfileSchemaResponse, ListConfigProfilesError, ListConfigProfilesResponse, CreateConfigProfileData, CreateConfigProfileError, CreateConfigProfileResponse, GetConfigProfileData, GetConfigProfileError, GetConfigProfileResponse, UpdateConfigProfileContentData, UpdateConfigProfileContentError, UpdateConfigProfileContentResponse, RenameConfigProfileData, RenameConfigProfileError, RenameConfigProfileResponse, DeleteConfigProfileData, DeleteConfigProfileError, DeleteConfigProfileResponse, ListConfigRoutesError, ListConfigRoutesResponse, ReplaceConfigRoutesData, ReplaceConfigRoutesError, ReplaceConfigRoutesResponse, UpsertConfigRouteData, UpsertConfigRouteError, UpsertConfigRouteResponse, DeleteConfigRouteData, DeleteConfigRouteError, DeleteConfigRouteResponse, ListBotTypesError, ListBotTypesResponse, RegisterBotTypeData, RegisterBotTypeError, RegisterBotTypeResponse, ListBotsData, ListBotsError, ListBotsResponse, CreateBotData, CreateBotError, CreateBotResponse, ListBotStatsError, ListBotStatsResponse, GetBotByIdData, GetBotByIdError, GetBotByIdResponse, UpdateBotByIdData, UpdateBotByIdError, UpdateBotByIdResponse, DeleteBotByIdData, DeleteBotByIdError, DeleteBotByIdResponse, SetBotEnabledByIdData, SetBotEnabledByIdError, SetBotEnabledByIdResponse, TestBotByIdData, TestBotByIdError, TestBotByIdResponse, GetBotData, GetBotError, GetBotResponse, UpdateBotData, UpdateBotError, UpdateBotResponse, DeleteBotData, DeleteBotError, DeleteBotResponse, SetBotEnabledData, SetBotEnabledError, SetBotEnabledResponse, TestBotData, TestBotError, TestBotResponse, GetProviderSchemaError, GetProviderSchemaResponse, ListProviderSourcesError, ListProviderSourcesResponse, CreateProviderSourceData, CreateProviderSourceError, CreateProviderSourceResponse, GetProviderSourceByIdData, GetProviderSourceByIdError, GetProviderSourceByIdResponse, UpsertProviderSourceByIdData, UpsertProviderSourceByIdError, UpsertProviderSourceByIdResponse, DeleteProviderSourceByIdData, DeleteProviderSourceByIdError, DeleteProviderSourceByIdResponse, ListProviderSourceModelsByIdData, ListProviderSourceModelsByIdError, ListProviderSourceModelsByIdResponse, ListProvidersBySourceIdData, ListProvidersBySourceIdError, ListProvidersBySourceIdResponse, CreateProviderInSourceByIdData, CreateProviderInSourceByIdError, CreateProviderInSourceByIdResponse, GetProviderSourceData, GetProviderSourceError, GetProviderSourceResponse, UpsertProviderSourceData, UpsertProviderSourceError, UpsertProviderSourceResponse, DeleteProviderSourceData, DeleteProviderSourceError, DeleteProviderSourceResponse, ListProviderSourceModelsData, ListProviderSourceModelsError, ListProviderSourceModelsResponse, ListProvidersBySourceData, ListProvidersBySourceError, ListProvidersBySourceResponse, CreateProviderInSourceData, CreateProviderInSourceError, CreateProviderInSourceResponse, ListProvidersData, ListProvidersError, ListProvidersResponse, CreateProviderData, CreateProviderError, CreateProviderResponse, GetProviderByIdData, GetProviderByIdError, GetProviderByIdResponse, UpdateProviderByIdData, UpdateProviderByIdError, UpdateProviderByIdResponse, DeleteProviderByIdData, DeleteProviderByIdError, DeleteProviderByIdResponse, SetProviderEnabledByIdData, SetProviderEnabledByIdError, SetProviderEnabledByIdResponse, TestProviderByIdData, TestProviderByIdError, TestProviderByIdResponse, GetProviderEmbeddingDimensionByIdData, GetProviderEmbeddingDimensionByIdError, GetProviderEmbeddingDimensionByIdResponse, GetProviderData, GetProviderError, GetProviderResponse, UpdateProviderData, UpdateProviderError, UpdateProviderResponse, DeleteProviderData, DeleteProviderError, DeleteProviderResponse, SetProviderEnabledData, SetProviderEnabledError, SetProviderEnabledResponse, TestProviderData, TestProviderError, TestProviderResponse, GetProviderEmbeddingDimensionData, GetProviderEmbeddingDimensionError, GetProviderEmbeddingDimensionResponse, SendChatMessageData, SendChatMessageError, SendChatMessageResponse, OpenChatWebSocketData, OpenLiveChatWebSocketData, OpenUnifiedChatWebSocketData, ListChatSessionsData, ListChatSessionsError, ListChatSessionsResponse, CreateChatSessionData, CreateChatSessionError, CreateChatSessionResponse, BatchDeleteChatSessionsData, BatchDeleteChatSessionsError, BatchDeleteChatSessionsResponse, GetChatSessionData, GetChatSessionError, GetChatSessionResponse, UpdateChatSessionData, UpdateChatSessionError, UpdateChatSessionResponse, DeleteChatSessionData, DeleteChatSessionError, DeleteChatSessionResponse, StopChatSessionData, StopChatSessionError, StopChatSessionResponse, ResumeChatRunData, ResumeChatRunError, ResumeChatRunResponse, UpdateChatMessageData, UpdateChatMessageError, UpdateChatMessageResponse, RegenerateChatMessageData, RegenerateChatMessageError, RegenerateChatMessageResponse, ListChatConfigsError, ListChatConfigsResponse, CreateChatThreadData, CreateChatThreadError, CreateChatThreadResponse, GetChatThreadData, GetChatThreadError, GetChatThreadResponse, DeleteChatThreadData, DeleteChatThreadError, DeleteChatThreadResponse, SendChatThreadMessageData, SendChatThreadMessageError, SendChatThreadMessageResponse, ListChatProjectsError, ListChatProjectsResponse, CreateChatProjectData, CreateChatProjectError, CreateChatProjectResponse, GetChatProjectData, GetChatProjectError, GetChatProjectResponse, UpdateChatProjectData, UpdateChatProjectError, UpdateChatProjectResponse, DeleteChatProjectData, DeleteChatProjectError, DeleteChatProjectResponse, ListChatProjectSessionsData, ListChatProjectSessionsError, ListChatProjectSessionsResponse, ListChatProjectWorkspaceFilesData, ListChatProjectWorkspaceFilesError, ListChatProjectWorkspaceFilesResponse, GetChatProjectWorkspaceFileData, GetChatProjectWorkspaceFileError, GetChatProjectWorkspaceFileResponse, DownloadChatProjectWorkspaceFileData, DownloadChatProjectWorkspaceFileError, DownloadChatProjectWorkspaceFileResponse, AddChatProjectSessionData, AddChatProjectSessionError, AddChatProjectSessionResponse, RemoveChatProjectSessionData, RemoveChatProjectSessionError, RemoveChatProjectSessionResponse, SendImMessageData, SendImMessageError, SendImMessageResponse, ListImBotsError, ListImBotsResponse, UploadFileData, UploadFileError, UploadFileResponse, InitFileUploadData, InitFileUploadError, InitFileUploadResponse, UploadFileChunkData, UploadFileChunkError, UploadFileChunkResponse, CompleteFileUploadData, CompleteFileUploadError, CompleteFileUploadResponse, AbortFileUploadData, AbortFileUploadError, AbortFileUploadResponse, StatusFileUploadData, StatusFileUploadError, StatusFileUploadResponse, UploadOpenApiFileData, UploadOpenApiFileError, UploadOpenApiFileResponse, DownloadOpenApiFileData, DownloadOpenApiFileError, DownloadOpenApiFileResponse, GetFileByNameData, GetFileByNameError, GetFileByNameResponse, GetTokenFileData, GetTokenFileError, GetTokenFileResponse, GetAttachmentData, GetAttachmentError, GetAttachmentResponse, DeleteAttachmentData, DeleteAttachmentError, DeleteAttachmentResponse, DownloadAttachmentData, DownloadAttachmentError, DownloadAttachmentResponse, ListPluginsData, ListPluginsError, ListPluginsResponse, GetPluginByIdData, GetPluginByIdError, GetPluginByIdResponse, UninstallPluginByIdData, UninstallPluginByIdError, UninstallPluginByIdResponse, GetPluginConfigByIdData, GetPluginConfigByIdError, GetPluginConfigByIdResponse, UpdatePluginConfigByIdData, UpdatePluginConfigByIdError, UpdatePluginConfigByIdResponse, GetPluginConfigSchemaByIdData, GetPluginConfigSchemaByIdError, GetPluginConfigSchemaByIdResponse, ListPluginConfigFilesByIdData, ListPluginConfigFilesByIdError, ListPluginConfigFilesByIdResponse, UploadPluginConfigFilesByIdData, UploadPluginConfigFilesByIdError, UploadPluginConfigFilesByIdResponse, DeletePluginConfigFileByIdData, DeletePluginConfigFileByIdError, DeletePluginConfigFileByIdResponse, GetPluginReadmeByIdData, GetPluginReadmeByIdError, GetPluginReadmeByIdResponse, GetPluginChangelogByIdData, GetPluginChangelogByIdError, GetPluginChangelogByIdResponse, ReloadPluginByIdData, ReloadPluginByIdError, ReloadPluginByIdResponse, SetPluginEnabledByIdData, SetPluginEnabledByIdError, SetPluginEnabledByIdResponse, GetPluginData, GetPluginError, GetPluginResponse, UninstallPluginData, UninstallPluginError, UninstallPluginResponse, GetPluginConfigData, GetPluginConfigError, GetPluginConfigResponse, UpdatePluginConfigData, UpdatePluginConfigError, UpdatePluginConfigResponse, UpdatePluginLogLevelData, UpdatePluginLogLevelError, UpdatePluginLogLevelResponse, GetPluginConfigSchemaData, GetPluginConfigSchemaError, GetPluginConfigSchemaResponse, ListPluginConfigFilesData, ListPluginConfigFilesError, ListPluginConfigFilesResponse, UploadPluginConfigFilesData, UploadPluginConfigFilesError, UploadPluginConfigFilesResponse, DeletePluginConfigFileData, DeletePluginConfigFileError, DeletePluginConfigFileResponse, GetPluginReadmeData, GetPluginReadmeError, GetPluginReadmeResponse, GetPluginChangelogData, GetPluginChangelogError, GetPluginChangelogResponse, ReloadPluginData, ReloadPluginError, ReloadPluginResponse, BindPluginSourceData, BindPluginSourceError, BindPluginSourceResponse, SetPluginEnabledData, SetPluginEnabledError, SetPluginEnabledResponse, UpdatePluginData, UpdatePluginError, UpdatePluginResponse, UpdatePluginsData, UpdatePluginsError, UpdatePluginsResponse, CheckPluginVersionSupportData, CheckPluginVersionSupportError, CheckPluginVersionSupportResponse, ValidatePluginRepoData, ValidatePluginRepoError, ValidatePluginRepoResponse, ListFailedPluginsError, ListFailedPluginsResponse, UninstallFailedPluginData, UninstallFailedPluginError, UninstallFailedPluginResponse, ReloadFailedPluginData, ReloadFailedPluginError, ReloadFailedPluginResponse, InstallPluginFromGithubData, InstallPluginFromGithubError, InstallPluginFromGithubResponse, InstallPluginFromGitData, InstallPluginFromGitError, InstallPluginFromGitResponse, InstallPluginFromUrlData, InstallPluginFromUrlError, InstallPluginFromUrlResponse, InstallPluginFromUploadData, InstallPluginFromUploadError, InstallPluginFromUploadResponse, ListPluginMarketData, ListPluginMarketError, ListPluginMarketResponse, ListPluginMarketCategoriesError, ListPluginMarketCategoriesResponse, ListPluginSourcesError, ListPluginSourcesResponse, CreatePluginSourceData, CreatePluginSourceError, CreatePluginSourceResponse, ReplacePluginSourcesData, ReplacePluginSourcesError, ReplacePluginSourcesResponse, DeletePluginSourceData, DeletePluginSourceError, DeletePluginSourceResponse, DeletePluginSourceByIdData, DeletePluginSourceByIdError, DeletePluginSourceByIdResponse, ListPluginViewsByIdData, ListPluginViewsByIdError, ListPluginViewsByIdResponse, ListPluginPagesByIdData, ListPluginPagesByIdError, ListPluginPagesByIdResponse, GetPluginViewByIdData, GetPluginViewByIdError, GetPluginViewByIdResponse, GetPluginPageByIdData, GetPluginPageByIdError, GetPluginPageByIdResponse, ListPluginViewsData, ListPluginViewsError, ListPluginViewsResponse, ListPluginPagesData, ListPluginPagesError, ListPluginPagesResponse, GetPluginViewData, GetPluginViewError, GetPluginViewResponse, GetPluginPageData, GetPluginPageError, GetPluginPageResponse, GetPluginViewTokenAssetData, GetPluginViewTokenAssetError, GetPluginViewTokenAssetResponse, GetPluginPageBridgeSdkError, GetPluginPageBridgeSdkResponse, GetPluginExtensionRouteData, GetPluginExtensionRouteError, GetPluginExtensionRouteResponse, PostPluginExtensionRouteData, PostPluginExtensionRouteError, PostPluginExtensionRouteResponse, PutPluginExtensionRouteData, PutPluginExtensionRouteError, PutPluginExtensionRouteResponse, PatchPluginExtensionRouteData, PatchPluginExtensionRouteError, PatchPluginExtensionRouteResponse, DeletePluginExtensionRouteData, DeletePluginExtensionRouteError, DeletePluginExtensionRouteResponse, ListCommandsData, ListCommandsError, ListCommandsResponse, UpdateCommandData, UpdateCommandError, UpdateCommandResponse, ListCommandConflictsError, ListCommandConflictsResponse, ListToolsData, ListToolsError, ListToolsResponse, SetToolEnabledData, SetToolEnabledError, SetToolEnabledResponse, SetToolPermissionData, SetToolPermissionError, SetToolPermissionResponse, ListMcpServersError, ListMcpServersResponse, CreateMcpServerData, CreateMcpServerError, CreateMcpServerResponse, UpdateMcpServerByNameData, UpdateMcpServerByNameError, UpdateMcpServerByNameResponse, DeleteMcpServerByNameData, DeleteMcpServerByNameError, DeleteMcpServerByNameResponse, SetMcpServerEnabledByNameData, SetMcpServerEnabledByNameError, SetMcpServerEnabledByNameResponse, TestMcpServerByNameData, TestMcpServerByNameError, TestMcpServerByNameResponse, UpdateMcpServerData, UpdateMcpServerError, UpdateMcpServerResponse, DeleteMcpServerData, DeleteMcpServerError, DeleteMcpServerResponse, SetMcpServerEnabledData, SetMcpServerEnabledError, SetMcpServerEnabledResponse, TestMcpServerData, TestMcpServerError, TestMcpServerResponse, SyncModelScopeMcpServersData, SyncModelScopeMcpServersError, SyncModelScopeMcpServersResponse, ListSkillsData, ListSkillsError, ListSkillsResponse, UploadSkillData, UploadSkillError, UploadSkillResponse, UploadSkillsBatchData, UploadSkillsBatchError, UploadSkillsBatchResponse, UpdateSkillByNameData, UpdateSkillByNameError, UpdateSkillByNameResponse, DeleteSkillByNameData, DeleteSkillByNameError, DeleteSkillByNameResponse, DownloadSkillByNameData, DownloadSkillByNameError, DownloadSkillByNameResponse, ListSkillFilesByNameData, ListSkillFilesByNameError, ListSkillFilesByNameResponse, GetSkillFileByNameData, GetSkillFileByNameError, GetSkillFileByNameResponse, UpdateSkillFileByNameData, UpdateSkillFileByNameError, UpdateSkillFileByNameResponse, UpdateSkillData, UpdateSkillError, UpdateSkillResponse, DeleteSkillData, DeleteSkillError, DeleteSkillResponse, DownloadSkillData, DownloadSkillError, DownloadSkillResponse, ListSkillFilesData, ListSkillFilesError, ListSkillFilesResponse, GetSkillFileData, GetSkillFileError, GetSkillFileResponse, UpdateSkillFileData, UpdateSkillFileError, UpdateSkillFileResponse, ListNeoSkillCandidatesData, ListNeoSkillCandidatesError, ListNeoSkillCandidatesResponse, ListNeoSkillReleasesData, ListNeoSkillReleasesError, ListNeoSkillReleasesResponse, GetNeoSkillPayloadData, GetNeoSkillPayloadError, GetNeoSkillPayloadResponse, EvaluateNeoSkillCandidateData, EvaluateNeoSkillCandidateError, EvaluateNeoSkillCandidateResponse, PromoteNeoSkillCandidateData, PromoteNeoSkillCandidateError, PromoteNeoSkillCandidateResponse, RollbackNeoSkillReleaseData, RollbackNeoSkillReleaseError, RollbackNeoSkillReleaseResponse, SyncNeoSkillReleaseData, SyncNeoSkillReleaseError, SyncNeoSkillReleaseResponse, DeleteNeoSkillCandidateData, DeleteNeoSkillCandidateError, DeleteNeoSkillCandidateResponse, DeleteNeoSkillReleaseData, DeleteNeoSkillReleaseError, DeleteNeoSkillReleaseResponse, ListKnowledgeBasesData, ListKnowledgeBasesError, ListKnowledgeBasesResponse, CreateKnowledgeBaseData, CreateKnowledgeBaseError, CreateKnowledgeBaseResponse, GetKnowledgeBaseData, GetKnowledgeBaseError, GetKnowledgeBaseResponse, UpdateKnowledgeBaseData, UpdateKnowledgeBaseError, UpdateKnowledgeBaseResponse, DeleteKnowledgeBaseData, DeleteKnowledgeBaseError, DeleteKnowledgeBaseResponse, GetKnowledgeBaseStatsData, GetKnowledgeBaseStatsError, GetKnowledgeBaseStatsResponse, ListKnowledgeDocumentsData, ListKnowledgeDocumentsError, ListKnowledgeDocumentsResponse, UploadKnowledgeDocumentData, UploadKnowledgeDocumentError, UploadKnowledgeDocumentResponse, ImportKnowledgeDocumentsData, ImportKnowledgeDocumentsError, ImportKnowledgeDocumentsResponse, ImportKnowledgeDocumentFromUrlData, ImportKnowledgeDocumentFromUrlError, ImportKnowledgeDocumentFromUrlResponse, GetKnowledgeDocumentData, GetKnowledgeDocumentError, GetKnowledgeDocumentResponse, DeleteKnowledgeDocumentData, DeleteKnowledgeDocumentError, DeleteKnowledgeDocumentResponse, ListKnowledgeChunksData, ListKnowledgeChunksError, ListKnowledgeChunksResponse, DeleteKnowledgeChunkData, DeleteKnowledgeChunkError, DeleteKnowledgeChunkResponse, RetrieveKnowledgeBaseData, RetrieveKnowledgeBaseError, RetrieveKnowledgeBaseResponse, GetKnowledgeTaskData, GetKnowledgeTaskError, GetKnowledgeTaskResponse, GetPersonaTreeError, GetPersonaTreeResponse, ListPersonasData, ListPersonasError, ListPersonasResponse, CreatePersonaData, CreatePersonaError, CreatePersonaResponse, GetPersonaByIdData, GetPersonaByIdError, GetPersonaByIdResponse, UpdatePersonaByIdData, UpdatePersonaByIdError, UpdatePersonaByIdResponse, DeletePersonaByIdData, DeletePersonaByIdError, DeletePersonaByIdResponse, GetPersonaData, GetPersonaError, GetPersonaResponse, UpdatePersonaData, UpdatePersonaError, UpdatePersonaResponse, DeletePersonaData, DeletePersonaError, DeletePersonaResponse, ListPersonaFoldersData, ListPersonaFoldersError, ListPersonaFoldersResponse, CreatePersonaFolderData, CreatePersonaFolderError, CreatePersonaFolderResponse, UpdatePersonaFolderData, UpdatePersonaFolderError, UpdatePersonaFolderResponse, DeletePersonaFolderData, DeletePersonaFolderError, DeletePersonaFolderResponse, MovePersonaItemData, MovePersonaItemError, MovePersonaItemResponse, ReorderPersonaItemsData, ReorderPersonaItemsError, ReorderPersonaItemsResponse, ListSessionsData, ListSessionsError, ListSessionsResponse, ListActiveUmosError, ListActiveUmosResponse, ListSessionRulesData, ListSessionRulesError, ListSessionRulesResponse, UpsertSessionRuleData, UpsertSessionRuleError, UpsertSessionRuleResponse, DeleteSessionRulesData, DeleteSessionRulesError, DeleteSessionRulesResponse, BatchUpdateSessionProviderData, BatchUpdateSessionProviderError, BatchUpdateSessionProviderResponse, BatchUpdateSessionServiceData, BatchUpdateSessionServiceError, BatchUpdateSessionServiceResponse, ListSessionGroupsError, ListSessionGroupsResponse, CreateSessionGroupData, CreateSessionGroupError, CreateSessionGroupResponse, UpdateSessionGroupData, UpdateSessionGroupError, UpdateSessionGroupResponse, DeleteSessionGroupData, DeleteSessionGroupError, DeleteSessionGroupResponse, ListConversationsData, ListConversationsError, ListConversationsResponse, GetConversationFilterOptionsError, GetConversationFilterOptionsResponse, BatchDeleteConversationsData, BatchDeleteConversationsError, BatchDeleteConversationsResponse, GetConversationData, GetConversationError, GetConversationResponse, UpdateConversationData, UpdateConversationError, UpdateConversationResponse, DeleteConversationData, DeleteConversationError, DeleteConversationResponse, ReplaceConversationMessagesData, ReplaceConversationMessagesError, ReplaceConversationMessagesResponse, ExportConversationsData, ExportConversationsError, ExportConversationsResponse, GetStatsData, GetStatsError, GetStatsResponse, GetProviderTokenStatsData, GetProviderTokenStatsError, GetProviderTokenStatsResponse, GetVersionError, GetVersionResponse, GetPublicVersionsError, GetPublicVersionsResponse, GetFirstNoticeData, GetFirstNoticeError, GetFirstNoticeResponse, TestGhproxyConnectionData, TestGhproxyConnectionError, TestGhproxyConnectionResponse, ListChangelogVersionsError, ListChangelogVersionsResponse, GetChangelogData, GetChangelogError, GetChangelogResponse, GetStartTimeError, GetStartTimeResponse, GetStorageStatusError, GetStorageStatusResponse, CleanupStorageData, CleanupStorageError, CleanupStorageResponse, RestartCoreError, RestartCoreResponse, ListBackupsData, ListBackupsError, ListBackupsResponse, CreateBackupData, CreateBackupError, CreateBackupResponse, UploadBackupData, UploadBackupError, UploadBackupResponse, InitBackupUploadData, InitBackupUploadError, InitBackupUploadResponse, UploadBackupChunkData, UploadBackupChunkError, UploadBackupChunkResponse, CompleteBackupUploadData, CompleteBackupUploadError, CompleteBackupUploadResponse, AbortBackupUploadData, AbortBackupUploadError, AbortBackupUploadResponse, StatusBackupUploadData, StatusBackupUploadError, StatusBackupUploadResponse, GetBackupProgressData, GetBackupProgressError, GetBackupProgressResponse, DownloadBackupData, DownloadBackupError, DownloadBackupResponse, RenameBackupData, RenameBackupError, RenameBackupResponse, DeleteBackupData, DeleteBackupError, DeleteBackupResponse, CheckBackupData, CheckBackupError, CheckBackupResponse, ImportBackupData, ImportBackupError, ImportBackupResponse, CheckUpdateError, CheckUpdateResponse, ListReleasesData, ListReleasesError, ListReleasesResponse, UpdateCoreData, UpdateCoreError, UpdateCoreResponse, UpdateDashboardData, UpdateDashboardError, UpdateDashboardResponse, GetUpdateProgressData, GetUpdateProgressError, GetUpdateProgressResponse, InstallPipPackageData, InstallPipPackageError, InstallPipPackageResponse, ListCronJobsData, ListCronJobsError, ListCronJobsResponse, CreateCronJobData, CreateCronJobError, CreateCronJobResponse, UpdateCronJobData, UpdateCronJobError, UpdateCronJobResponse, DeleteCronJobData, DeleteCronJobError, DeleteCronJobResponse, RunCronJobData, RunCronJobError, RunCronJobResponse, StreamLiveLogsError, StreamLiveLogsResponse, GetLogHistoryError, GetLogHistoryResponse, GetTraceSettingsError, GetTraceSettingsResponse, UpdateTraceSettingsData, UpdateTraceSettingsError, UpdateTraceSettingsResponse, ListT2iTemplatesError, ListT2iTemplatesResponse, CreateT2iTemplateData, CreateT2iTemplateError, CreateT2iTemplateResponse, GetActiveT2iTemplateError, GetActiveT2iTemplateResponse, SetActiveT2iTemplateData, SetActiveT2iTemplateError, SetActiveT2iTemplateResponse, ResetDefaultT2iTemplateError, ResetDefaultT2iTemplateResponse, GetT2iTemplateData, GetT2iTemplateError, GetT2iTemplateResponse, UpdateT2iTemplateData, UpdateT2iTemplateError, UpdateT2iTemplateResponse, DeleteT2iTemplateData, DeleteT2iTemplateError, DeleteT2iTemplateResponse, GetSubagentConfigError, GetSubagentConfigResponse, UpdateSubagentConfigData, UpdateSubagentConfigError, UpdateSubagentConfigResponse, ListSubagentAvailableToolsError, ListSubagentAvailableToolsResponse, VerifyPlatformWebhookData, VerifyPlatformWebhookError, VerifyPlatformWebhookResponse, ReceivePlatformWebhookData, ReceivePlatformWebhookError, ReceivePlatformWebhookResponse } from './types.gen'; export const client = createClient(createConfig()); @@ -1307,36 +1307,6 @@ export const setPluginEnabledById = (optio }); }; -/** - * List plugin pages by query ID - */ -export const listPluginPagesById = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ - ...options, - url: '/api/v1/plugins/pages' - }); -}; - -/** - * Get plugin page entry HTML by query ID - */ -export const getPluginPageById = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ - ...options, - url: '/api/v1/plugins/page' - }); -}; - -/** - * Get a plugin page asset by query ID - */ -export const getPluginPageAssetById = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ - ...options, - url: '/api/v1/plugins/page/assets' - }); -}; - /** * Get plugin details */ @@ -1669,92 +1639,101 @@ export const deletePluginSourceById = (opt }; /** - * List plugin pages + * List plugin views by query ID */ -export const listPluginPages = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const listPluginViewsById = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/{plugin_id}/pages' + url: '/api/v1/plugins/views' }); }; /** - * Get plugin page entry HTML + * @deprecated + * List plugin views by query ID (alias of /plugins/views) + * Deprecated compatibility alias kept for a transition period. New clients should use /plugins/views. */ -export const getPluginPage = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const listPluginPagesById = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/{plugin_id}/pages/{page_name}' + url: '/api/v1/plugins/pages' }); }; /** - * Get a plugin page asset + * Get plugin view entry HTML by query ID */ -export const getPluginPageAsset = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const getPluginViewById = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/{plugin_id}/pages/{page_name}/assets/{asset_path}' + url: '/api/v1/plugins/view' }); }; /** - * List plugin views by query ID (alias of /plugins/pages) + * @deprecated + * Get plugin view entry HTML by query ID (alias of /plugins/view) + * Deprecated compatibility alias kept for a transition period. New clients should use /plugins/view. */ -export const listPluginViewsById = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const getPluginPageById = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/views' + url: '/api/v1/plugins/page' }); }; /** - * Get plugin view entry HTML by query ID (alias of /plugins/page) + * List plugin views */ -export const getPluginViewById = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const listPluginViews = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/view' + url: '/api/v1/plugins/{plugin_id}/views' }); }; /** - * Get a plugin view asset by query ID (alias of /plugins/page/assets) + * @deprecated + * List plugin views (alias of /plugins/{plugin_id}/views) + * Deprecated compatibility alias kept for a transition period. New clients should use /plugins/{plugin_id}/views. */ -export const getPluginViewAssetById = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const listPluginPages = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/view/assets' + url: '/api/v1/plugins/{plugin_id}/pages' }); }; /** - * List plugin views (alias of /plugins/{plugin_id}/pages) + * Get plugin view entry HTML */ -export const listPluginViews = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const getPluginView = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/{plugin_id}/views' + url: '/api/v1/plugins/{plugin_id}/views/{view_name}' }); }; /** - * Get plugin view entry HTML (alias of /plugins/{plugin_id}/pages/{page_name}) + * @deprecated + * Get plugin view entry HTML (alias of /plugins/{plugin_id}/views/{view_name}) + * Deprecated compatibility alias kept for a transition period. New clients should use /plugins/{plugin_id}/views/{view_name}. */ -export const getPluginView = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const getPluginPage = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/{plugin_id}/views/{page_name}' + url: '/api/v1/plugins/{plugin_id}/pages/{view_name}' }); }; /** - * Get a plugin view asset (alias of /plugins/{plugin_id}/pages/{page_name}/assets/{asset_path}) + * Get a plugin view asset via a scoped path token + * Serves plugin view assets without URL rewriting. The token is a plugin-page-scoped JWT issued by the view entry config endpoint and travels in the path so relative URLs inherit it through normal path resolution. Use an empty asset_path (trailing slash) for the entry document. */ -export const getPluginViewAsset = (options: OptionsLegacyParser) => { - return (options?.client ?? client).get({ +export const getPluginViewTokenAsset = (options: OptionsLegacyParser) => { + return (options?.client ?? client).get({ ...options, - url: '/api/v1/plugins/{plugin_id}/views/{page_name}/assets/{asset_path}' + url: '/api/v1/plugins/{plugin_id}/views/{view_name}/_t/{token}/{asset_path}' }); }; diff --git a/dashboard/src/api/generated/openapi-v1/types.gen.ts b/dashboard/src/api/generated/openapi-v1/types.gen.ts index 80720abd81..abeb86d58c 100644 --- a/dashboard/src/api/generated/openapi-v1/types.gen.ts +++ b/dashboard/src/api/generated/openapi-v1/types.gen.ts @@ -1934,39 +1934,6 @@ export type SetPluginEnabledByIdResponse = (SuccessEnvelope); export type SetPluginEnabledByIdError = unknown; -export type ListPluginPagesByIdData = { - query: { - plugin_id: string; - }; -}; - -export type ListPluginPagesByIdResponse = (SuccessEnvelope); - -export type ListPluginPagesByIdError = unknown; - -export type GetPluginPageByIdData = { - query: { - page_name: string; - plugin_id: string; - }; -}; - -export type GetPluginPageByIdResponse = (string); - -export type GetPluginPageByIdError = unknown; - -export type GetPluginPageAssetByIdData = { - query: { - asset_path: string; - page_name: string; - plugin_id: string; - }; -}; - -export type GetPluginPageAssetByIdResponse = (unknown); - -export type GetPluginPageAssetByIdError = unknown; - export type GetPluginData = { body?: { delete_config?: boolean; @@ -2297,51 +2264,25 @@ export type DeletePluginSourceByIdResponse = (SuccessEnvelope); export type DeletePluginSourceByIdError = unknown; -export type ListPluginPagesData = { - path: { - plugin_id: string; - }; -}; - -export type ListPluginPagesResponse = (SuccessEnvelope); - -export type ListPluginPagesError = unknown; - -export type GetPluginPageData = { - path: { - page_name: string; - plugin_id: string; - }; -}; - -export type GetPluginPageResponse = (string); - -export type GetPluginPageError = unknown; - -export type GetPluginPageAssetData = { - path: { - /** - * URL-encoded relative asset path. - */ - asset_path: string; - page_name: string; +export type ListPluginViewsByIdData = { + query: { plugin_id: string; }; }; -export type GetPluginPageAssetResponse = (unknown); +export type ListPluginViewsByIdResponse = (SuccessEnvelope); -export type GetPluginPageAssetError = unknown; +export type ListPluginViewsByIdError = unknown; -export type ListPluginViewsByIdData = { +export type ListPluginPagesByIdData = { query: { plugin_id: string; }; }; -export type ListPluginViewsByIdResponse = (SuccessEnvelope); +export type ListPluginPagesByIdResponse = (SuccessEnvelope); -export type ListPluginViewsByIdError = unknown; +export type ListPluginPagesByIdError = unknown; export type GetPluginViewByIdData = { query: { @@ -2354,17 +2295,16 @@ export type GetPluginViewByIdResponse = (string); export type GetPluginViewByIdError = unknown; -export type GetPluginViewAssetByIdData = { +export type GetPluginPageByIdData = { query: { - asset_path: string; page_name: string; plugin_id: string; }; }; -export type GetPluginViewAssetByIdResponse = (unknown); +export type GetPluginPageByIdResponse = (string); -export type GetPluginViewAssetByIdError = unknown; +export type GetPluginPageByIdError = unknown; export type ListPluginViewsData = { path: { @@ -2376,10 +2316,20 @@ export type ListPluginViewsResponse = (SuccessEnvelope); export type ListPluginViewsError = unknown; +export type ListPluginPagesData = { + path: { + plugin_id: string; + }; +}; + +export type ListPluginPagesResponse = (SuccessEnvelope); + +export type ListPluginPagesError = unknown; + export type GetPluginViewData = { path: { - page_name: string; plugin_id: string; + view_name: string; }; }; @@ -2387,20 +2337,35 @@ export type GetPluginViewResponse = (string); export type GetPluginViewError = unknown; -export type GetPluginViewAssetData = { +export type GetPluginPageData = { + path: { + plugin_id: string; + view_name: string; + }; +}; + +export type GetPluginPageResponse = (string); + +export type GetPluginPageError = unknown; + +export type GetPluginViewTokenAssetData = { path: { /** * URL-encoded relative asset path. */ asset_path: string; - page_name: string; plugin_id: string; + /** + * Scoped plugin page asset token. + */ + token: string; + view_name: string; }; }; -export type GetPluginViewAssetResponse = (unknown); +export type GetPluginViewTokenAssetResponse = (unknown); -export type GetPluginViewAssetError = unknown; +export type GetPluginViewTokenAssetError = (unknown); export type GetPluginPageBridgeSdkResponse = (string); diff --git a/dashboard/src/api/v1.ts b/dashboard/src/api/v1.ts index 9c6e11324c..685e9b61d4 100644 --- a/dashboard/src/api/v1.ts +++ b/dashboard/src/api/v1.ts @@ -1425,7 +1425,7 @@ export const pluginApi = { }, page(pluginId: string, pageName: string) { return typed( - openApiV1.getPluginPageById({ + openApiV1.getPluginViewById({ query: { plugin_id: pluginId, page_name: pageName }, }) as any, ); diff --git a/dashboard/src/components/shared/ExtensionCard.vue b/dashboard/src/components/shared/ExtensionCard.vue index e5e487de48..d7a83112e6 100644 --- a/dashboard/src/components/shared/ExtensionCard.vue +++ b/dashboard/src/components/shared/ExtensionCard.vue @@ -38,7 +38,7 @@ const emit = defineEmits([ "view-readme", "view-changelog", "toggle-pin", - "open-webui", + "open-view", "change-source", ]); @@ -179,8 +179,8 @@ const togglePin = () => { emit("toggle-pin", props.extension); }; -const openWebui = () => { - emit("open-webui", props.extension); +const openView = () => { + emit("open-view", props.extension); }; @@ -403,7 +403,7 @@ const openWebui = () => { diff --git a/dashboard/src/composables/usePluginSidebarItems.ts b/dashboard/src/composables/usePluginSidebarItems.ts index 2ad2789722..3a4f257dc0 100644 --- a/dashboard/src/composables/usePluginSidebarItems.ts +++ b/dashboard/src/composables/usePluginSidebarItems.ts @@ -3,7 +3,7 @@ import { pluginApi } from "@/api/v1"; import type { menu } from "@/layouts/full/vertical-sidebar/sidebarItem"; const DEFAULT_ICON = "mdi-puzzle"; -const GROUP_I18N_KEY = "core.navigation.pluginWebui"; +const GROUP_I18N_KEY = "core.navigation.pluginView"; const GROUP_ICON = "mdi-puzzle-outline"; interface PluginEntry { diff --git a/dashboard/src/i18n/locales/en-US/core/navigation.json b/dashboard/src/i18n/locales/en-US/core/navigation.json index 3ab84921fc..43a442aa4b 100644 --- a/dashboard/src/i18n/locales/en-US/core/navigation.json +++ b/dashboard/src/i18n/locales/en-US/core/navigation.json @@ -63,6 +63,6 @@ "normal": "Normal Config", "system": "System Config" }, - "pluginWebui": "Plugin Views", - "pluginPageType": "Plugin View" + "pluginView": "Plugin Views", + "pluginViewType": "Plugin View" } diff --git a/dashboard/src/i18n/locales/en-US/features/extension.json b/dashboard/src/i18n/locales/en-US/features/extension.json index 45e2901dd3..bddea57813 100644 --- a/dashboard/src/i18n/locales/en-US/features/extension.json +++ b/dashboard/src/i18n/locales/en-US/features/extension.json @@ -47,7 +47,7 @@ "viewRepo": "Repository", "openPages": "Pages", "openPage": "Open", - "openWebui": "Open Plugin UI", + "openView": "Open View", "close": "Close", "save": "Save", "saveAndClose": "Save and Close", @@ -305,9 +305,9 @@ "invalidRepositoryUrl": "Please enter a valid Git repository URL", "enterJsonUrl": "Please enter a URL that returns plugin list JSON data", "pluginNotFound": "Plugin not found", - "pluginDisabled": "This plugin is closed. Open it before accessing its page.", - "pluginPageNotFound": "Plugin view not found", - "pluginPageLoadFailed": "Failed to load the plugin view", + "pluginDisabled": "This plugin is closed. Open it before accessing its view.", + "pluginViewNotFound": "Plugin view not found", + "pluginViewLoadFailed": "Failed to load the plugin view", "missingMarketPluginId": "This source record is missing legal plugin identifiers, so it cannot be installed from the market", "sourceBindSuccess": "Plugin source updated", "validatingPlugin": "Validating plugin...", diff --git a/dashboard/src/i18n/locales/ja-JP/core/navigation.json b/dashboard/src/i18n/locales/ja-JP/core/navigation.json index 9693d69cae..75cd4e4df4 100644 --- a/dashboard/src/i18n/locales/ja-JP/core/navigation.json +++ b/dashboard/src/i18n/locales/ja-JP/core/navigation.json @@ -63,6 +63,6 @@ "normal": "一般設定", "system": "システム設定" }, - "pluginWebui": "プラグインビュー", - "pluginPageType": "プラグインビュー" + "pluginView": "プラグインビュー", + "pluginViewType": "プラグインビュー" } diff --git a/dashboard/src/i18n/locales/ja-JP/features/extension.json b/dashboard/src/i18n/locales/ja-JP/features/extension.json index 205a266a8a..a8d0b991a3 100644 --- a/dashboard/src/i18n/locales/ja-JP/features/extension.json +++ b/dashboard/src/i18n/locales/ja-JP/features/extension.json @@ -47,7 +47,7 @@ "viewRepo": "リポジトリ", "openPages": "Pages", "openPage": "開く", - "openWebui": "プラグイン UI を開く", + "openView": "ビューを開く", "close": "閉じる", "save": "保存", "saveAndClose": "保存して閉じる", @@ -306,8 +306,8 @@ "enterJsonUrl": "プラグイン一覧の JSON データを返す URL を入力してください", "pluginNotFound": "プラグインが見つかりません", "pluginDisabled": "このプラグインは無効です。ページにアクセスする前に有効化してください。", - "pluginPageNotFound": "プラグインビューが見つかりません", - "pluginPageLoadFailed": "プラグインビューの読み込みに失敗しました", + "pluginViewNotFound": "プラグインビューが見つかりません", + "pluginViewLoadFailed": "プラグインビューの読み込みに失敗しました", "missingMarketPluginId": "有効なプラグイン識別子がないため、このプラグインマーケットのソースからインストールできません", "sourceBindSuccess": "プラグインソースを更新しました", "validatingPlugin": "プラグインを検証中…", diff --git a/dashboard/src/i18n/locales/ru-RU/core/navigation.json b/dashboard/src/i18n/locales/ru-RU/core/navigation.json index c11d098c18..e4bd5e89d6 100644 --- a/dashboard/src/i18n/locales/ru-RU/core/navigation.json +++ b/dashboard/src/i18n/locales/ru-RU/core/navigation.json @@ -63,6 +63,6 @@ "normal": "Обычная конфигурация", "system": "Системная конфигурация" }, - "pluginWebui": "Представления плагинов", - "pluginPageType": "Представление плагина" + "pluginView": "Представления плагинов", + "pluginViewType": "Представление плагина" } diff --git a/dashboard/src/i18n/locales/ru-RU/features/extension.json b/dashboard/src/i18n/locales/ru-RU/features/extension.json index 5552873beb..f7d0ad1195 100644 --- a/dashboard/src/i18n/locales/ru-RU/features/extension.json +++ b/dashboard/src/i18n/locales/ru-RU/features/extension.json @@ -47,7 +47,7 @@ "viewRepo": "Репозиторий", "openPages": "Pages", "openPage": "Открыть", - "openWebui": "Открыть UI плагина", + "openView": "Открыть представление", "close": "Закрыть", "save": "Сохранить", "saveAndClose": "Сохранить и закрыть", @@ -306,8 +306,8 @@ "enterJsonUrl": "Введите URL, возвращающий список плагинов в формате JSON", "pluginNotFound": "Плагин не найден", "pluginDisabled": "Этот плагин сейчас отключён. Включите его, чтобы открыть страницу.", - "pluginPageNotFound": "Представление плагина не найдено", - "pluginPageLoadFailed": "Не удалось загрузить представление плагина", + "pluginViewNotFound": "Представление плагина не найдено", + "pluginViewLoadFailed": "Не удалось загрузить представление плагина", "missingMarketPluginId": "Эта запись источника не содержит идентификаторов плагина, поэтому его нельзя установить из магазина", "sourceBindSuccess": "Источник плагина обновлен", "validatingPlugin": "Проверка плагина...", diff --git a/dashboard/src/i18n/locales/zh-CN/core/navigation.json b/dashboard/src/i18n/locales/zh-CN/core/navigation.json index 93a08ecd7a..523ed864d9 100644 --- a/dashboard/src/i18n/locales/zh-CN/core/navigation.json +++ b/dashboard/src/i18n/locales/zh-CN/core/navigation.json @@ -63,6 +63,6 @@ "normal": "普通配置", "system": "系统配置" }, - "pluginWebui": "插件可视化视图", - "pluginPageType": "插件可视化视图" + "pluginView": "插件可视化视图", + "pluginViewType": "插件可视化视图" } diff --git a/dashboard/src/i18n/locales/zh-CN/features/extension.json b/dashboard/src/i18n/locales/zh-CN/features/extension.json index 0c80993ce2..c6d4c55e80 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/extension.json +++ b/dashboard/src/i18n/locales/zh-CN/features/extension.json @@ -47,7 +47,7 @@ "viewRepo": "仓库", "openPages": "Pages", "openPage": "打开", - "openWebui": "打开插件UI界面", + "openView": "打开视图", "close": "关闭", "save": "保存", "saveAndClose": "保存并关闭", @@ -305,9 +305,9 @@ "invalidRepositoryUrl": "请输入有效的 Git 仓库链接", "enterJsonUrl": "请输入返回插件列表JSON数据的URL地址", "pluginNotFound": "未找到该插件", - "pluginDisabled": "该插件当前已关闭,请先打开后再访问页面", - "pluginPageNotFound": "未找到该插件可视化视图", - "pluginPageLoadFailed": "加载插件可视化视图失败", + "pluginDisabled": "该插件当前已关闭,请先打开后再访问视图", + "pluginViewNotFound": "未找到该插件可视化视图", + "pluginViewLoadFailed": "加载插件可视化视图失败", "missingMarketPluginId": "缺少合法的插件标识,无法从该插件市场源安装", "sourceBindSuccess": "插件源已更新", "validatingPlugin": "正在校验插件...", diff --git a/dashboard/src/layouts/full/FullLayout.vue b/dashboard/src/layouts/full/FullLayout.vue index 1e8b6ec699..8143c4b5c4 100644 --- a/dashboard/src/layouts/full/FullLayout.vue +++ b/dashboard/src/layouts/full/FullLayout.vue @@ -23,7 +23,7 @@ const routerLoadingStore = useRouterLoadingStore(); const isCurrentChatRoute = computed( () => route.path === "/chat" || route.path.startsWith("/chat/"), ); -const isPluginPageRoute = computed( +const isPluginViewRoute = computed( () => route.path.startsWith("/plugin-view/") || route.path.startsWith("/plugin-page/"), ); const isProviderPageRoute = computed(() => route.path === "/providers"); @@ -35,7 +35,7 @@ const isViewportLockedRoute = computed( isPlatformPageRoute.value, ); const isFullScreenRoute = computed( - () => isCurrentChatRoute.value || isPluginPageRoute.value, + () => isCurrentChatRoute.value || isPluginViewRoute.value, ); const shouldMountChat = ref(isCurrentChatRoute.value); @@ -160,7 +160,7 @@ onMounted(() => { height: '100%', width: '100%', overflow: isViewportLockedRoute ? 'hidden' : undefined, - position: isPluginPageRoute ? 'relative' : undefined, + position: isPluginViewRoute ? 'relative' : undefined, }" >
typeof props.item?.icon === 'string');
- {{ t('core.navigation.pluginPageType') }} + {{ t('core.navigation.pluginViewType') }}
diff --git a/dashboard/src/router/MainRoutes.ts b/dashboard/src/router/MainRoutes.ts index eaf4aa4cf9..aa40411a64 100644 --- a/dashboard/src/router/MainRoutes.ts +++ b/dashboard/src/router/MainRoutes.ts @@ -99,7 +99,7 @@ const MainRoutes = { { name: 'PluginView', path: '/plugin-view/:pluginName/:pageName', - component: () => import('@/views/PluginPagePage.vue') + component: () => import('@/views/PluginViewPage.vue') }, { // Legacy alias of the plugin view route. diff --git a/dashboard/src/utils/pluginI18n.js b/dashboard/src/utils/pluginI18n.js index 3a8b503338..ecf46d6c14 100644 --- a/dashboard/src/utils/pluginI18n.js +++ b/dashboard/src/utils/pluginI18n.js @@ -79,7 +79,7 @@ export function usePluginI18n() { return resolve(plugin?.i18n, `${base}.${attr}`, fallback); }; - const pluginPageTitle = (plugin, page, fallback = "") => { + const pluginViewTitle = (plugin, page, fallback = "") => { const pageFallback = fallback || (page && typeof page === "object" @@ -89,7 +89,7 @@ export function usePluginI18n() { return pluginPageText(plugin, page, "title", pageFallback); }; - const pluginPageDescription = (plugin, page, fallback = "") => { + const pluginViewDescription = (plugin, page, fallback = "") => { const pageFallback = fallback || (page && typeof page === "object" ? page.description || page.desc : "") || @@ -109,8 +109,8 @@ export function usePluginI18n() { pluginDesc, pluginShortDesc, pluginPageText, - pluginPageTitle, - pluginPageDescription, + pluginViewTitle, + pluginViewDescription, configText, }; } diff --git a/dashboard/src/views/PluginPagePage.vue b/dashboard/src/views/PluginViewPage.vue similarity index 96% rename from dashboard/src/views/PluginPagePage.vue rename to dashboard/src/views/PluginViewPage.vue index 2621d7acf2..471d3451f5 100644 --- a/dashboard/src/views/PluginPagePage.vue +++ b/dashboard/src/views/PluginViewPage.vue @@ -15,7 +15,7 @@ const { tm } = useModuleI18n("features/extension"); const { locale, pluginName: pluginDisplayName, - pluginPageTitle, + pluginViewTitle, } = usePluginI18n(); const customizer = useCustomizerStore(); @@ -32,7 +32,7 @@ let iframeMessageOrigin = null; const pluginName = computed(() => String(route.params.pluginName || "")); const pageName = computed(() => String(route.params.pageName || "")); const localizedPageTitle = computed(() => - pluginPageTitle( + pluginViewTitle( plugin.value, page.value || pageName.value, page.value?.title || pageName.value || tm("buttons.openPages"), @@ -551,7 +551,7 @@ const handleIframeLoad = () => { sendIframeContext(); }; -const loadPluginPage = async () => { +const loadPluginView = async () => { loading.value = true; errorMessage.value = ""; plugin.value = null; @@ -564,7 +564,7 @@ const loadPluginPage = async () => { const detailResponse = await pluginApi.get(pluginName.value); if (detailResponse.data?.status === "error") { throw new Error( - detailResponse.data.message || tm("messages.pluginPageLoadFailed"), + detailResponse.data.message || tm("messages.pluginViewLoadFailed"), ); } @@ -582,7 +582,7 @@ const loadPluginPage = async () => { const entryResponse = await pluginApi.page(pluginName.value, pageName.value); if (entryResponse.data?.status === "error") { throw new Error( - entryResponse.data.message || tm("messages.pluginPageLoadFailed"), + entryResponse.data.message || tm("messages.pluginViewLoadFailed"), ); } @@ -592,7 +592,7 @@ const loadPluginPage = async () => { typeof pageEntry.content_path !== "string" || !pageEntry.content_path.length ) { - errorMessage.value = tm("messages.pluginPageNotFound"); + errorMessage.value = tm("messages.pluginViewNotFound"); return; } @@ -605,7 +605,7 @@ const loadPluginPage = async () => { errorMessage.value = error?.response?.data?.message || error?.message || - tm("messages.pluginPageLoadFailed"); + tm("messages.pluginViewLoadFailed"); } finally { loading.value = false; } @@ -620,7 +620,7 @@ onBeforeUnmount(() => { cleanupSSEConnections(); }); -watch([pluginName, pageName], loadPluginPage, { immediate: true }); +watch([pluginName, pageName], loadPluginView, { immediate: true }); watch(locale, () => { sendIframeContext(); }); @@ -630,13 +630,13 @@ watch(() => customizer.uiTheme, () => {