File size: 2,864 Bytes
494c9e4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | /** 三页 Cached history 共用的 `?content=` 参数名 */
export const DEFAULT_CONTENT_URL_PARAM = 'content';
/** LLM Causal Flow(gen_attribute)打包 demo:`?demo=` 为文件名(不含 .json) */
export const DEFAULT_DEMO_URL_PARAM = 'demo';
export function readContentUrlParam(paramName: string = DEFAULT_CONTENT_URL_PARAM): string | null {
try {
const u = new URL(window.location.href);
const v = u.searchParams.get(paramName);
return v != null && v.length > 0 ? v : null;
} catch {
return null;
}
}
export function replaceContentUrlParam(
value: string | null,
paramName: string = DEFAULT_CONTENT_URL_PARAM,
logLabel?: string
): void {
replaceUrlParam(value, paramName, logLabel ?? 'contentUrl');
}
export function readDemoUrlParam(paramName: string = DEFAULT_DEMO_URL_PARAM): string | null {
try {
const u = new URL(window.location.href);
const v = u.searchParams.get(paramName);
return v != null && v.length > 0 ? v : null;
} catch {
return null;
}
}
function replaceUrlParam(value: string | null, paramName: string, logLabel: string): void {
try {
const u = new URL(window.location.href);
if (value) {
u.searchParams.set(paramName, value);
} else {
u.searchParams.delete(paramName);
}
window.history.replaceState(null, '', u.toString());
} catch (e: unknown) {
console.warn(`[${logLabel}] URL sync failed:`, e);
}
}
export function replaceDemoUrlParam(
value: string | null,
paramName: string = DEFAULT_DEMO_URL_PARAM,
logLabel?: string
): void {
replaceUrlParam(value, paramName, logLabel ?? 'contentUrl:demo');
}
export type RunContentUrlHydrateOptions<T> = {
readRaw: () => string | null;
fetchEntry: (raw: string) => Promise<T | undefined>;
/** 缺省:仅判断 entry 非 undefined/null */
isValid?: (entry: T) => boolean;
/** 第二参为 URL 中的原始 `content` 值(IndexedDB 条目的短哈希键) */
apply: (entry: T, rawContentKey: string) => void | Promise<void>;
onMissing: () => void | Promise<void>;
onApplyError?: (error: unknown) => void | Promise<void>;
};
export async function runContentUrlHydrate<T>(options: RunContentUrlHydrateOptions<T>): Promise<void> {
const raw = options.readRaw();
if (!raw) return;
const entry = await options.fetchEntry(raw);
const ok =
entry != null && (options.isValid ? options.isValid(entry) : true);
if (!ok) {
await Promise.resolve(options.onMissing());
return;
}
try {
await options.apply(entry, raw);
} catch (e: unknown) {
if (options.onApplyError) {
await Promise.resolve(options.onApplyError(e));
} else {
throw e;
}
}
}
|