feat(desktop-client/wangyihao): harden token capture and draft submit flow

Inject the YiDun guardian client to obtain ursToken without relying on
window.neg, fetch the publish detail (wemediaId/onlineState/...) before
saving drafts so 100002 "参数错误" stops blocking submit, downgrade
markdown tables to paragraph rows like Baijiahao, and surface friendlier
errors for token, draft and publish-click failures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-30 18:15:20 +08:00
parent 9525c1144d
commit bf25fa1a80
6 changed files with 701 additions and 87 deletions
@@ -2,9 +2,13 @@ import { describe, expect, it } from "vitest";
import {
QIEHAO_REAL_NAME_AUTH_MESSAGE,
WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE,
WANGYIHAO_PUBLISH_CLICK_MESSAGE,
WANGYIHAO_TOKEN_MISSING_MESSAGE,
isQiehaoRealNameAuthError,
normalizePublisherErrorMessage,
normalizeQiehaoPublishErrorMessage,
normalizeWangyihaoPublishErrorMessage,
} from "./publisher-errors";
describe("publisher error normalization", () => {
@@ -19,6 +23,31 @@ describe("publisher error normalization", () => {
expect(normalizeQiehaoPublishErrorMessage("publish rejected", -5022)).toBe(QIEHAO_REAL_NAME_AUTH_MESSAGE);
});
it("normalizes Wangyihao token missing failures", () => {
expect(normalizePublisherErrorMessage("wangyihao_token_missing")).toBe(WANGYIHAO_TOKEN_MISSING_MESSAGE);
expect(normalizeWangyihaoPublishErrorMessage("Error: wangyihao_token_missing")).toBe(
WANGYIHAO_TOKEN_MISSING_MESSAGE,
);
});
it("normalizes Wangyihao draft parameter failures", () => {
expect(normalizePublisherErrorMessage("wangyihao_draft_save_failed:wangyihao_error_100002")).toBe(
WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE,
);
expect(normalizeWangyihaoPublishErrorMessage("wangyihao_draft_save_failed:参数错误")).toBe(
WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE,
);
});
it("normalizes Wangyihao publish click failures", () => {
expect(normalizePublisherErrorMessage("wangyihao_publish_click_failed")).toBe(
WANGYIHAO_PUBLISH_CLICK_MESSAGE,
);
expect(normalizeWangyihaoPublishErrorMessage("wangyihao_publish_click_failed:未找到发布按钮")).toBe(
WANGYIHAO_PUBLISH_CLICK_MESSAGE,
);
});
it("leaves unknown publisher errors unchanged", () => {
expect(normalizePublisherErrorMessage("qiehao_publish_failed")).toBe("qiehao_publish_failed");
});
@@ -1,4 +1,9 @@
export const QIEHAO_REAL_NAME_AUTH_MESSAGE = "企鹅号账号未完成实名认证,请先到企鹅号后台完成实名认证后再重试。";
export const WANGYIHAO_TOKEN_MISSING_MESSAGE = "网易号发布凭证获取失败,请重新打开网易号后台确认登录状态。";
export const WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE =
"网易号草稿保存失败:参数错误。请检查标题、正文、封面或账号状态后重试。";
export const WANGYIHAO_PUBLISH_CLICK_MESSAGE =
"网易号草稿已保存,但自动发布未完成。请打开网易号后台确认草稿状态后重试。";
function normalizeErrorText(value: string | null | undefined): string | null {
const trimmed = value?.trim();
@@ -37,6 +42,28 @@ export function normalizeQiehaoPublishErrorMessage(
return isQiehaoRealNameAuthError(normalized, code) ? QIEHAO_REAL_NAME_AUTH_MESSAGE : normalized;
}
export function normalizePublisherErrorMessage(message: string | null | undefined): string | null {
return normalizeQiehaoPublishErrorMessage(message);
export function normalizeWangyihaoPublishErrorMessage(message: string | null | undefined): string | null {
const normalized = normalizeErrorText(message);
if (!normalized) {
return null;
}
if (/\bwangyihao_token_missing\b/i.test(normalized)) {
return WANGYIHAO_TOKEN_MISSING_MESSAGE;
}
if (
/\bwangyihao_error_100002\b/i.test(normalized)
|| /\bwangyihao_draft_save_failed:.*参数错误/i.test(normalized)
) {
return WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE;
}
if (/\bwangyihao_publish_click_failed\b/i.test(normalized)) {
return WANGYIHAO_PUBLISH_CLICK_MESSAGE;
}
return normalized;
}
export function normalizePublisherErrorMessage(message: string | null | undefined): string | null {
const qiehaoMessage = normalizeQiehaoPublishErrorMessage(message);
return normalizeWangyihaoPublishErrorMessage(qiehaoMessage);
}