{"record":{"id":"2e0152c192f05a60","repo":"yikart/AiToEarn","slug":"aitoearn","errorCode":null,"errorMessage":"请先安装 Aitoearn 浏览器插件","messagePattern":"请先安装 Aitoearn 浏览器插件","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"project/aitoearn-web/src/store/plugin/store.ts","lineNumber":732,"sourceCode":"            return result.data || null\n          }\n          else {\n            console.error('同步账号失败:', result?.message)\n            return null\n          }\n        }\n        catch (error) {\n          console.error('同步账号到数据库失败:', error)\n          return null\n        }\n      },\n\n      /** 登录到指定平台 */\n      async login(platform: PluginPlatformType) {\n        const { status, platformAccounts } = get()\n\n        if (status === Status.NOT_INSTALLED)\n          throw new Error(ERROR_MESSAGES.PLUGIN_NOT_INSTALLED)\n\n        if (status !== Status.READY)\n          throw new Error(ERROR_MESSAGES.PLUGIN_NOT_READY)\n\n        try {\n          const result = await window.AIToEarnPlugin!.login(platform)\n          set({\n            platformAccounts: { ...platformAccounts, [platform]: result },\n          })\n          await methods.syncAccountToDatabase(platform)\n          return result\n        }\n        catch (error) {\n          console.error('登录失败:', error)\n          throw error\n        }\n      },\n","sourceCodeStart":714,"sourceCodeEnd":750,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-web/src/store/plugin/store.ts#L714-L750","documentation":"The plugin store's login(platform) throws ERROR_MESSAGES.PLUGIN_NOT_INSTALLED ('请先安装 Aitoearn 浏览器插件') when the tracked status is Status.NOT_INSTALLED. The store detects extension presence at startup; login is refused up front because window.AIToEarnPlugin cannot be invoked without the extension.","triggerScenarios":"Calling the store's login() action while usePluginStore status === Status.NOT_INSTALLED — the extension is not detected in the browser (absent window.AIToEarnPlugin at detection time).","commonSituations":"Fresh browser without the extension; user disabled the extension; page not reloaded after installing the extension so the store never re-detected it; browser profile where the extension isn't installed.","solutions":["Install the Aitoearn browser extension from the official download page, then reload the page so the store re-detects it.","Trigger a status re-check (store's detection/init method) after installation before calling login().","Gate the login button on status === Status.READY and render an install guide when NOT_INSTALLED.","Catch this error by message and route the user to the plugin install flow instead of a generic error toast."],"exampleFix":"// before\nawait usePluginStore.getState().login('douyin')\n\n// after\nconst { status } = usePluginStore.getState()\nif (status === Status.NOT_INSTALLED) {\n  openPluginInstallGuide()\n  return\n}\nawait usePluginStore.getState().login('douyin')","handlingStrategy":"validation","validationCode":"const { status } = usePluginStore.getState()\nif (status === Status.NOT_INSTALLED) {\n  openPluginInstallGuide()\n  return\n}\nif (status !== Status.READY) await waitForPluginReady()\nawait login(platform)","typeGuard":"function isPluginReady(status: Status): status is Status.READY {\n  return status === Status.READY\n}","tryCatchPattern":"try {\n  await login(platform)\n}\ncatch (e) {\n  if (e.message === ERROR_MESSAGES.PLUGIN_NOT_INSTALLED)\n    return showInstallDialog()\n  throw e\n}","preventionTips":["Read plugin store status before login and disable the button when NOT_INSTALLED","Trigger re-detection after the user installs the extension instead of requiring a full reload","Map this error message to an install-guide dialog, not a generic toast","Show the extension download link wherever plugin-dependent actions are offered"],"tags":["browser-extension","plugin","login","state-guard"],"backgroundTag":"browser-extension-not-installed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}