Files
geo/apps/desktop-client/src/main/platform-auth-adapters.ts
T

103 lines
2.8 KiB
TypeScript
Raw Normal View History

import { aiPlatformCatalog } from "@geo/shared-types";
import {
probePublishAccountSession,
silentRefreshPublishAccountSession,
type PublishAccountIdentity,
} from "./account-binder";
import type {
AuthProbeResult,
PlatformFailureClassification,
} from "./auth-types";
export interface PlatformFailureInput {
summary?: string | null;
error?: Record<string, unknown> | null;
message?: string | null;
}
export interface PlatformAdapter {
probe(account: PublishAccountIdentity, partition: string): Promise<AuthProbeResult>;
silentRefresh(account: PublishAccountIdentity, partition: string): Promise<boolean>;
classifyFailure(input: PlatformFailureInput): PlatformFailureClassification;
}
function normalizeFailureText(input: PlatformFailureInput): string {
const values = [
input.summary,
input.message,
typeof input.error?.code === "string" ? input.error.code : null,
typeof input.error?.message === "string" ? input.error.message : null,
typeof input.error?.detail === "string" ? input.error.detail : null,
typeof input.error?.verify_scene === "string" ? input.error.verify_scene : null,
];
return values
.filter((value): value is string => typeof value === "string" && Boolean(value.trim()))
.join(" | ")
.toLowerCase();
}
function classifyFailure(input: PlatformFailureInput): PlatformFailureClassification {
const text = normalizeFailureText(input);
if (!text) {
return "ok";
}
if (
/(verify_scene|verification required|captcha|challenge|验证码|滑块|人机验证|安全验证|请完成验证|短信验证|扫码验证)/i.test(text)
) {
return "challenge";
}
if (
/(not_logged_in|unauthorized|unauthenticated|login redirect|login required|signin|sign in|expired|401|登录态失效|请先登录|未登录)/i
.test(text)
) {
return "auth_failure";
}
if (
/(network|timeout|timed out|failed to fetch|econnreset|econnrefused|enotfound|dns|socket hang up|502|503|504)/i
.test(text)
) {
return "network";
}
return "ok";
}
const genericAdapter: PlatformAdapter = {
async probe(account, partition) {
return await probePublishAccountSession(account, partition);
},
async silentRefresh(account, partition) {
return await silentRefreshPublishAccountSession(account, partition);
},
classifyFailure,
};
const adapterRegistry = new Map<string, PlatformAdapter>(
[
...aiPlatformCatalog.map((platform) => platform.id),
"toutiaohao",
"baijiahao",
"sohu",
"qiehao",
"zhihu",
"wangyihao",
"jianshu",
"bilibili",
"juejin",
"smzdm",
"weixin_gzh",
"zol",
"dongchedi",
].map((platform) => [platform, genericAdapter]),
);
export function getPlatformAdapter(platformId: string): PlatformAdapter {
return adapterRegistry.get(platformId) ?? genericAdapter;
}