From f7a6bc2d2192ee178917761ea1612213a3777590 Mon Sep 17 00:00:00 2001 From: yang1 <1242769896@qq.com> Date: Fri, 31 Jul 2026 14:58:16 +0800 Subject: [PATCH] fix(webui): globally register correct MIME types for static assets (#5190) On Windows, mimetypes.guess_type() reads the Content Type value from HKEY_CLASSES_ROOT\.js (and other extensions) in the registry, which is commonly set to text/plain because .js is associated with Windows Script Host rather than web JavaScript. The registry value overrides Python's built-in mapping and causes browsers to reject ES module scripts. Fix by explicitly registering correct MIME types via mimetypes.add_type() at module import time for common web static extensions (.js, .mjs, .css, .html, .json, .svg, .wasm). Using strict=True ensures the values replace the registry-backed standard mappings used by mimetypes.guess_type(). This benefits all callers of mimetypes.guess_type() in the gateway process, not just _serve_static. Closes #5190 Co-authored-by: amkile <44280409+amkile@users.noreply.github.com> --- nanobot/webui/ws_http.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/nanobot/webui/ws_http.py b/nanobot/webui/ws_http.py index 1f895b17a..1fa17e575 100644 --- a/nanobot/webui/ws_http.py +++ b/nanobot/webui/ws_http.py @@ -116,6 +116,30 @@ from nanobot.webui.workspaces import WebUIWorkspaceController _SLOW_WEBUI_HTTP_LOG_MS = 1_000 _AUTOMATION_VALUES_HEADER = "X-Nanobot-Automation-Values" +# Fix for #5190: On Windows, mimetypes.guess_type() reads the registry key +# HKEY_CLASSES_ROOT\.js\Content Type, which is commonly set to 'text/plain' +# because .js is associated with Windows Script Host rather than web JavaScript. +# That registry value overrides Python's built-in mapping and causes browsers to +# reject ES module scripts with: +# Failed to load module script: Expected a JavaScript-or-Wasm module script +# but the server responded with a MIME type of "text/plain". +# We explicitly register correct MIME types for common web static assets here +# (module-import time) so all callers of mimetypes.guess_type() in this process +# benefit, regardless of host registry configuration. +_MIME_FIXES: dict[str, str] = { + ".js": "application/javascript", + ".mjs": "application/javascript", + ".css": "text/css", + ".html": "text/html", + ".json": "application/json", + ".svg": "image/svg+xml", + ".wasm": "application/wasm", +} + +for _ext, _ctype in _MIME_FIXES.items(): + mimetypes.add_type(_ctype, _ext, strict=True) + + if TYPE_CHECKING: from nanobot.bus.queue import MessageBus from nanobot.channels.websocket.runtime import WebSocketConfig @@ -123,7 +147,6 @@ if TYPE_CHECKING: from nanobot.session.manager import SessionManager from nanobot.triggers.local_store import LocalTriggerStore - def _decode_api_key(raw_key: str) -> str | None: key = unquote(raw_key) _api_key_re = re.compile(r"^[A-Za-z0-9_:.-]{1,128}$")