{"record":{"id":"68ae1430f679c39b","repo":"lbjlaq/Antigravity-Manager","slug":"command-cmd-not-supported-in-web-mode","errorCode":null,"errorMessage":"Command [${cmd}] not supported in Web mode.","messagePattern":"Command \\[(.+?)\\] not supported in Web mode\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/utils/request.ts","lineNumber":184,"sourceCode":"};\n\nexport async function request<T>(cmd: string, args?: any): Promise<T> {\n  // 1. Tauri 环境：直接使用 invoke ...\n  if (isTauri) {\n    try {\n      const { invoke } = await import('@tauri-apps/api/core');\n      return await invoke<T>(cmd, args);\n    } catch (error) {\n      console.error(`Tauri Invoke Error [${cmd}]:`, error);\n      throw error;\n    }\n  }\n\n  // 2. Web 环境：映射到 HTTP API\n  const mapping = COMMAND_MAPPING[cmd];\n  if (!mapping) {\n    console.error(`Command [${cmd}] is not yet mapped for Web mode. Failing.`);\n    throw new Error(`Command [${cmd}] not supported in Web mode.`);\n  }\n\n  let url = mapping.url;\n  // [FIX] 创建 args 副本，用于移除已使用的路径参数\n  let bodyArgs = args ? { ...args } : undefined;\n\n  // 通用路径参数处理：替换 :key 为 args[key]\n  if (args) {\n    Object.keys(args).forEach(key => {\n      const placeholder = `:${key}`;\n      if (url.includes(placeholder)) {\n        url = url.replace(placeholder, encodeURIComponent(String(args[key])));\n        // [FIX] 从 body 参数中移除已用于路径的参数\n        if (bodyArgs) {\n          delete bodyArgs[key];\n        }\n      }\n    });","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/lbjlaq/Antigravity-Manager/blob/a2e3c454237d6d6ef423dfe20505b1ac62803c7c/src/utils/request.ts#L166-L202","documentation":"request() in src/utils/request.ts:184 throws this when running in a browser (no window.__TAURI_INTERNALS__/__TAURI__, detected at request.ts:2) and the command name is not a key of COMMAND_MAPPING. In Web mode every Tauri `invoke(cmd)` is translated to an HTTP call against a mapping entry (request.ts:5-166); an unmapped command has no HTTP route, so the adapter deliberately fails fast instead of guessing. It is a development/deployment-gap error: the backend Tauri command exists but nobody added its web-mode HTTP equivalent.","triggerScenarios":"Calling invoke('query_transit_info', ...) (used by src/pages/ApiKeyFun.tsx:129/151/180/188 — not present in COMMAND_MAPPING), or any newly added backend command, while the app is served as a plain website. Also triggered by typos in command names, e.g. invoke('get_proxy_stat') vs 'get_proxy_stats'.","commonSituations":"A feature is developed and tested in the Tauri desktop shell (where invoke works natively) and later deployed to the web build; a new Tauri command is wired into the frontend without a matching REST endpoint/mapping entry in the same change; renaming a Rust command without updating COMMAND_MAPPING keys.","solutions":["Add an entry to COMMAND_MAPPING in src/utils/request.ts pointing at the backend HTTP route, e.g. 'query_transit_info': { url: '/api/transit/query', method: 'POST' }, and implement that route in the web server.","If the command genuinely cannot work in a browser (needs OS access), gate the UI: hide the feature in web mode instead of letting request() throw.","Check for a command-name typo by diffing the invoke() call site against the COMMAND_MAPPING keys.","As a last resort for the specific page, run the app in the Tauri desktop shell where the native invoke path (request.ts:170-178) is used."],"exampleFix":"// before\nconst rawText = await request<string>('query_transit_info', { url, key });\n// → Error: Command [query_transit_info] not supported in Web mode.\n\n// after: src/utils/request.ts — add the mapping\nconst COMMAND_MAPPING = {\n  // ...\n  'query_transit_info': { url: '/api/transit/query', method: 'POST' },\n};","handlingStrategy":"validation","validationCode":"// request.ts — expose a support check\nexport const isTauriRuntime = () => !!(window as any).__TAURI_INTERNALS__ || !!(window as any).__TAURI__;\nexport function isCommandSupportedInWeb(cmd: string): boolean {\n  return Object.prototype.hasOwnProperty.call(COMMAND_MAPPING, cmd);\n}\n\n// caller — gate before invoking\nif (!isTauriRuntime() && !isCommandSupportedInWeb('query_transit_info')) {\n  throw new Error('This feature requires the desktop app');\n}","typeGuard":"// request.ts\nexport type WebCommand = keyof typeof COMMAND_MAPPING;\nexport const isWebCommand = (cmd: string): cmd is WebCommand => cmd in COMMAND_MAPPING;","tryCatchPattern":"try {\n  return await request('query_transit_info', { url, key });\n} catch (e) {\n  if (e instanceof Error && e.message.endsWith('not supported in Web mode.')) {\n    // deployment gap, not transient: disable the feature, do not retry\n    setFeatureUnavailable(true);\n    return null;\n  }\n  throw e;\n}","preventionTips":["Treat COMMAND_MAPPING as the contract: any PR that adds an invoke('<new_cmd>') call must add the mapping entry (and HTTP route) in the same change.","Type command names as a union of known commands (keyof typeof COMMAND_MAPPING in web-capable code) so unmapped names fail at compile time.","Add a startup check comparing invoked command names against COMMAND_MAPPING keys in web builds to catch gaps before users do.","Never rely on the browser build for OS-level commands; gate such UI behind isTauriRuntime()."],"tags":["tauri","web-mode","command-mapping","http-api","environment"],"backgroundTag":"tauri-command-missing-web-mapping","analyzedSha":"a2e3c454237d6d6ef423dfe20505b1ac62803c7c","analyzedAt":"2026-08-16T19:44:46.389Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}