ce76980fe5
- 新增 JWT httpOnly cookie 认证链路 (jose),登录/注册签发 token, 所有用户和盲盒 API 改为从 cookie 提取 userId,不再信任客户端传值 - 新增 /api/auth/logout 端点清除认证 cookie - GET /api/user 区分 owner/非 owner,非 owner 不暴露 email - atomicUpdateRoom 新增 per-room 应用层互斥锁,防止 SQLite 下并发 lost update - 修复 getRoomData 中 fire-and-forget delete 改为 await - 37 个静默 catch 块跨 17 个文件添加 console.error 日志 - 新增 REFACTOR_PLAN.md 全景分析文档
54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
import { toPng } from "html-to-image";
|
|
|
|
export async function loadImageAsDataUrl(src: string): Promise<string | null> {
|
|
try {
|
|
const img = new Image();
|
|
img.crossOrigin = "anonymous";
|
|
img.src = src;
|
|
await new Promise<void>((resolve, reject) => {
|
|
img.onload = () => resolve();
|
|
img.onerror = () => reject();
|
|
});
|
|
const canvas = document.createElement("canvas");
|
|
canvas.width = img.naturalWidth;
|
|
canvas.height = img.naturalHeight;
|
|
const ctx = canvas.getContext("2d")!;
|
|
ctx.drawImage(img, 0, 0);
|
|
return canvas.toDataURL("image/jpeg", 0.85);
|
|
} catch (e) {
|
|
console.error("proxyToDataUrl failed:", e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function generateImage(el: HTMLElement): Promise<string> {
|
|
return toPng(el, {
|
|
pixelRatio: 2,
|
|
quality: 0.95,
|
|
cacheBust: true,
|
|
skipAutoScale: true,
|
|
filter: (node) => {
|
|
if (node instanceof HTMLElement && node.dataset.shareExclude === "true") {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
});
|
|
}
|
|
|
|
export function downloadDataUrl(dataUrl: string, filename: string) {
|
|
const link = document.createElement("a");
|
|
link.download = filename;
|
|
link.href = dataUrl;
|
|
link.click();
|
|
}
|
|
|
|
export function dataUrlToFile(dataUrl: string, filename: string): File {
|
|
const arr = dataUrl.split(",");
|
|
const mime = arr[0].match(/:(.*?);/)?.[1] || "image/png";
|
|
const bstr = atob(arr[1]);
|
|
const u8 = new Uint8Array(bstr.length);
|
|
for (let i = 0; i < bstr.length; i++) u8[i] = bstr.charCodeAt(i);
|
|
return new File([u8], filename, { type: mime });
|
|
}
|