2026-04-13 19:21:42 +08:00
|
|
|
"use server";
|
|
|
|
|
|
|
|
|
|
import { cookies } from "next/headers";
|
|
|
|
|
|
|
|
|
|
type RequestCookies = Awaited<ReturnType<typeof cookies>>;
|
|
|
|
|
|
2025-11-23 10:55:04 +08:00
|
|
|
const decodeValue = (value?: string) => {
|
|
|
|
|
if (!value) return value;
|
2026-01-15 20:54:21 +08:00
|
|
|
let v = value;
|
|
|
|
|
// 说明:部分环境下 cookies() 读取到的值仍是 URL 编码(例如 %5B%22...%22%5D),
|
|
|
|
|
// Supabase Auth Helpers 期望拿到可直接 JSON.parse 的字符串,因此这里做一次解码。
|
|
|
|
|
// 若不是合法的 URL 编码字符串,decodeURIComponent 会抛错,我们直接兜底返回原值。
|
|
|
|
|
if (v.includes("%")) {
|
|
|
|
|
try {
|
|
|
|
|
v = decodeURIComponent(v);
|
|
|
|
|
} catch {
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return v.startsWith("base64-") ? Buffer.from(v.slice(7), "base64").toString("utf8") : v;
|
2025-11-23 10:55:04 +08:00
|
|
|
};
|
2026-04-13 19:21:42 +08:00
|
|
|
|
|
|
|
|
const encodeValue = (value: string) => {
|
|
|
|
|
if (!value) return value;
|
|
|
|
|
// Next.js 会自动 base64 编码,我们只需处理已有 base64 前缀的情况
|
|
|
|
|
if (value.startsWith("base64-")) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const wrapCookies = (store: RequestCookies) => {
|
|
|
|
|
return {
|
|
|
|
|
get: (name: string) => {
|
|
|
|
|
const cookie = store.get(name);
|
|
|
|
|
if (!cookie) return cookie;
|
|
|
|
|
return { ...cookie, value: decodeValue(cookie.value) };
|
|
|
|
|
},
|
|
|
|
|
getAll: (...args: Parameters<RequestCookies["getAll"]>) =>
|
|
|
|
|
store.getAll(...args).map((cookie) => ({ ...cookie, value: decodeValue(cookie.value) })),
|
2025-11-23 10:55:04 +08:00
|
|
|
set: (...args: Parameters<RequestCookies["set"]>) => {
|
2026-01-08 06:28:14 +08:00
|
|
|
const [name, value, options] = args as unknown as [
|
|
|
|
|
unknown,
|
|
|
|
|
unknown,
|
|
|
|
|
unknown,
|
|
|
|
|
];
|
|
|
|
|
if (typeof name === "string" && typeof value === "string") {
|
|
|
|
|
(store as any).set(name, encodeValue(value), options as any);
|
|
|
|
|
return;
|
2025-11-23 10:55:04 +08:00
|
|
|
}
|
2026-01-08 06:28:14 +08:00
|
|
|
(store as any).set(...(args as any));
|
2025-11-23 10:55:04 +08:00
|
|
|
},
|
2026-04-13 19:21:42 +08:00
|
|
|
delete: (...args: Parameters<RequestCookies["delete"]>) => store.delete(...args),
|
|
|
|
|
has: (...args: Parameters<RequestCookies["has"]>) => store.has(...args),
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getDecodedCookies = async () => {
|
|
|
|
|
const store = await cookies();
|
|
|
|
|
return wrapCookies(store) as RequestCookies;
|
|
|
|
|
};
|