Files
Genarrative/src/hooks/useResolvedAssetReadUrl.ts
T
2026-04-27 14:23:19 +08:00

73 lines
1.7 KiB
TypeScript

import { useEffect, useState } from 'react';
import {
isGeneratedLegacyPath,
resolveAssetReadUrl,
} from '../services/assetReadUrlService';
type UseResolvedAssetReadUrlOptions = {
enabled?: boolean;
expireSeconds?: number;
refreshKey?: string | number | null;
};
export function useResolvedAssetReadUrl(
source: string | null | undefined,
options: UseResolvedAssetReadUrlOptions = {},
) {
const enabled = options.enabled !== false;
const normalizedSource = source?.trim() ?? '';
const shouldResolve =
enabled && Boolean(normalizedSource) && isGeneratedLegacyPath(normalizedSource);
const [resolvedUrl, setResolvedUrl] = useState(
shouldResolve ? '' : normalizedSource,
);
useEffect(() => {
if (!normalizedSource) {
setResolvedUrl('');
return;
}
if (!shouldResolve) {
setResolvedUrl(normalizedSource);
return;
}
let cancelled = false;
// 生成资源通常是 OSS 私有对象;签名 URL 未就绪前不能把裸 generated 路径交给 img 触发无鉴权 GET。
setResolvedUrl('');
void resolveAssetReadUrl(normalizedSource, {
expireSeconds: options.expireSeconds,
refreshKey: options.refreshKey,
})
.then((nextUrl) => {
if (!cancelled) {
setResolvedUrl(nextUrl);
}
})
.catch(() => {
if (!cancelled) {
// 签名失败时保持空 src,避免继续请求无签名的私有对象兼容路径。
setResolvedUrl('');
}
});
return () => {
cancelled = true;
};
}, [
normalizedSource,
options.expireSeconds,
options.refreshKey,
shouldResolve,
]);
return {
resolvedUrl,
isResolving: shouldResolve && !resolvedUrl,
shouldResolve,
};
}