export const runtime = 'nodejs' export function toCamelCaseKey(key: string): string { return key.replace(/_([a-zA-Z])/g, (_, c: string) => c.toUpperCase()); } export function toSnakeCaseKey(key: string): string { return key.replace(/[A-Z]/g, (m) => `_${m.toLowerCase()}`); } /** * 创建一个代理对象,使得读取属性时同时兼容 snake_case 与 camelCase 键名。 * 访问顺序:原名 -> camelCase -> snake_case */ export function createCamelCompatibleProxy(root: T): T { const seen = new WeakMap(); const wrap = (value: any): any => { if (value === null || typeof value !== 'object') return value; if (seen.has(value)) return seen.get(value); const proxied = new Proxy(value, handler); seen.set(value, proxied); return proxied; }; const handler: ProxyHandler = { get(target, prop, receiver) { // 非字符串属性(如 Symbol、数字索引)直接透传 if (typeof prop !== 'string') { return wrap(Reflect.get(target, prop, receiver)); } const primary = prop; if (primary in target) return wrap(Reflect.get(target, primary, receiver)); const camel = toCamelCaseKey(primary); if (camel in target) return wrap(Reflect.get(target, camel, receiver)); const snake = toSnakeCaseKey(primary); if (snake in target) return wrap(Reflect.get(target, snake, receiver)); return wrap(Reflect.get(target, prop, receiver)); }, has(target, prop) { if (typeof prop !== 'string') return prop in target; const primary = prop === 'auther' ? 'autherInfo' : prop; return ( primary in target || toCamelCaseKey(primary) in target || toSnakeCaseKey(primary) in target ); } }; return wrap(root); } /** 选择首个可用 URL */ export function pickFirstUrl(list?: string[]) { return Array.isArray(list) && list.length ? list[0] : undefined; } // 别名,兼容旧命名 export const firstUrl = pickFirstUrl;