重构为Monorepo:拆分xhs/xhh应用与core包并完成双服务部署改造
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
interface FeedTargetInput {
|
||||
feed_id?: string;
|
||||
xsec_token?: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
interface UserTargetInput {
|
||||
user_id?: string;
|
||||
xsec_token?: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
interface FeedTargetResolved {
|
||||
feedId: string;
|
||||
xsecToken: string;
|
||||
}
|
||||
|
||||
interface UserTargetResolved {
|
||||
userId: string;
|
||||
xsecToken: string;
|
||||
}
|
||||
|
||||
function parseXhsUrl(rawUrl: string): URL {
|
||||
const trimmed = rawUrl.trim();
|
||||
if (!trimmed) {
|
||||
throw new Error('url cannot be empty');
|
||||
}
|
||||
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
return new URL(trimmed);
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('/')) {
|
||||
return new URL(`https://www.xiaohongshu.com${trimmed}`);
|
||||
}
|
||||
|
||||
return new URL(`https://${trimmed}`);
|
||||
}
|
||||
|
||||
function extractFeedIdFromPath(pathname: string): string | undefined {
|
||||
const patterns = [
|
||||
/\/explore\/([a-zA-Z0-9_-]+)/,
|
||||
/\/discovery\/item\/([a-zA-Z0-9_-]+)/,
|
||||
/\/note\/([a-zA-Z0-9_-]+)/,
|
||||
];
|
||||
|
||||
for (const pattern of patterns) {
|
||||
const match = pathname.match(pattern);
|
||||
if (match?.[1]) return match[1];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function extractUserIdFromPath(pathname: string): string | undefined {
|
||||
const match = pathname.match(/\/user\/profile\/([a-zA-Z0-9_-]+)/);
|
||||
return match?.[1];
|
||||
}
|
||||
|
||||
function extractXsecToken(url: URL): string | undefined {
|
||||
return url.searchParams.get('xsec_token') ?? url.searchParams.get('xsecToken') ?? undefined;
|
||||
}
|
||||
|
||||
export function resolveFeedTarget(input: FeedTargetInput): FeedTargetResolved {
|
||||
let feedId = input.feed_id?.trim();
|
||||
let xsecToken = input.xsec_token?.trim();
|
||||
|
||||
if (input.url) {
|
||||
const parsed = parseXhsUrl(input.url);
|
||||
feedId = feedId || extractFeedIdFromPath(parsed.pathname);
|
||||
xsecToken = xsecToken || extractXsecToken(parsed);
|
||||
}
|
||||
|
||||
if (!feedId || !xsecToken) {
|
||||
throw new Error('xhs_get_feed_detail requires either url with feed_id/xsec_token, or both feed_id and xsec_token');
|
||||
}
|
||||
|
||||
return { feedId, xsecToken };
|
||||
}
|
||||
|
||||
export function resolveUserTarget(input: UserTargetInput): UserTargetResolved {
|
||||
let userId = input.user_id?.trim();
|
||||
let xsecToken = input.xsec_token?.trim();
|
||||
|
||||
if (input.url) {
|
||||
const parsed = parseXhsUrl(input.url);
|
||||
userId = userId || extractUserIdFromPath(parsed.pathname);
|
||||
xsecToken = xsecToken || extractXsecToken(parsed);
|
||||
}
|
||||
|
||||
if (!userId || !xsecToken) {
|
||||
throw new Error('xhs_get_user_profile requires either url with user_id/xsec_token, or both user_id and xsec_token');
|
||||
}
|
||||
|
||||
return { userId, xsecToken };
|
||||
}
|
||||
Reference in New Issue
Block a user