import { hasEffectiveMothershipLogin } from "@/lib/rpa/mothership-login-context"; import type { RpaErrorCode } from "@/modules/rpa/errors"; type PageTextRule = { patterns: RegExp[]; code: RpaErrorCode; }; const PAGE_TEXT_RULES: PageTextRule[] = [ { patterns: [ /no carriers available/i, /no capacity/i, /unable to find a carrier/i, /无可用承运商/, /暂无运力/, ], code: "CARRIER_NO_CAPACITY", }, { patterns: [ /address not supported/i, /zip code is not supported/i, /we don't service this area/i, /不支持该邮编/, /地址不在服务范围/, ], code: "ADDRESS_NOT_SUPPORTED", }, ]; export function hasMothershipCredentials(): boolean { return hasEffectiveMothershipLogin(); } /** Mothership 页面文案 → 业务 error_code(task-110 / task-128) */ export function mapPageTextToErrorCode(pageText: string): RpaErrorCode | null { const normalized = pageText.trim(); if (!normalized) { return null; } for (const rule of PAGE_TEXT_RULES) { if (rule.patterns.some((pattern) => pattern.test(normalized))) { return rule.code; } } return null; } /** * URL → 错误分类(v0.6) * login 无凭据由 QuotePageAdapter.isLoginWithoutCredentials 处理为 STRUCT_CHANGE */ export function mapUrlToErrorCode(url: string): RpaErrorCode | null { const lower = url.toLowerCase(); if (lower.includes("captcha") || lower.includes("challenge")) { return "RPA_CAPTCHA"; } if ( lower.includes("/login") || lower.includes("/sign-in") || lower.includes("/signin") ) { if (hasMothershipCredentials()) { // 有账密仍落登录页:优先按账密错误处理,而非笼统会话过期 return "PROVIDER_LOGIN_FAILED"; } return null; } return null; } /** 入口类错误:不重试、不消耗 job 重试配额(task-128/129) */ export function isEntryErrorCode(code: RpaErrorCode): boolean { return ( code === "QUOTE_ENTRY_UNAVAILABLE" || code === "ADDRESS_SUGGESTION_NOT_FOUND" ); }