Files
wehub-resource-sync 9b395f5cc3
E2E Headed Chrome / e2e-headed (macos-15) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (ubuntu-latest) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (windows-latest) (push) Has been cancelled
CI / build (macos-latest) (push) Has been cancelled
CI / build (ubuntu-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
CI / unit-test (push) Has been cancelled
CI / bun-test (push) Has been cancelled
CI / adapter-test (push) Has been cancelled
CI / smoke-test (macos-latest) (push) Has been cancelled
CI / smoke-test (ubuntu-latest) (push) Has been cancelled
Security Audit / audit (push) Has been cancelled
Build Chrome Extension / build (push) Has been cancelled
Trigger Website Rebuild (Docs Updated) / dispatch (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:48 +08:00

49 lines
1.8 KiB
JavaScript

import { AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors';
const CHINA_DATE_FORMATTER = new Intl.DateTimeFormat('en-US', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
});
/** Format a Unix ms timestamp as the matching `YYYY-MM-DD` in Asia/Shanghai (xueqiu's canonical user timezone for all markets). */
export function formatChinaDate(ts) {
if (ts == null) return null;
const parts = Object.fromEntries(
CHINA_DATE_FORMATTER.formatToParts(new Date(ts))
.filter((part) => part.type !== 'literal')
.map((part) => [part.type, part.value]),
);
return `${parts.year}-${parts.month}-${parts.day}`;
}
/**
* Fetch a xueqiu JSON API from inside the browser context (credentials included).
* Page must already be navigated to xueqiu.com before calling this function.
* Throws CliError on HTTP errors; otherwise returns the parsed JSON.
*/
export async function fetchXueqiuJson(page, url) {
const result = await page.evaluate(`(async () => {
const res = await fetch(${JSON.stringify(url)}, { credentials: 'include' });
if (!res.ok) return { __xqErr: res.status };
try {
return await res.json();
} catch {
return { __xqErr: 'parse' };
}
})()`);
const r = result;
if (r?.__xqErr !== undefined) {
const code = r.__xqErr;
if (code === 401 || code === 403) {
throw new AuthRequiredError('xueqiu.com', '未登录或登录已过期');
}
if (code === 'parse') {
throw new CommandExecutionError('响应不是有效 JSON', '可能触发了风控,请检查登录状态或稍后重试');
}
throw new CommandExecutionError(`HTTP ${code}`, '请检查网络连接或登录状态');
}
return result;
}