124 lines
3.7 KiB
TypeScript
124 lines
3.7 KiB
TypeScript
/** Shared auth cookies so storefront + customer.{domain} share one login. */
|
|
|
|
export const SHARED_ACCESS_TOKEN_KEY = "meshkee_customer_access_token";
|
|
export const SHARED_REFRESH_TOKEN_KEY = "meshkee_customer_refresh_token";
|
|
|
|
const CHUNK_SIZE = 2800;
|
|
const MAX_CHUNKS = 24;
|
|
|
|
function cookieDomain(): string | undefined {
|
|
if (typeof window === "undefined") return undefined;
|
|
const host = window.location.hostname.toLowerCase();
|
|
if (host === "localhost" || host === "127.0.0.1") return undefined;
|
|
const parts = host.split(".").filter(Boolean);
|
|
if (parts.length < 2) return undefined;
|
|
return `.${parts.slice(-2).join(".")}`;
|
|
}
|
|
|
|
function readRawCookie(name: string): string | null {
|
|
if (typeof document === "undefined") return null;
|
|
const prefix = `${name}=`;
|
|
const match = document.cookie.split("; ").find((row) => row.startsWith(prefix));
|
|
if (!match) return null;
|
|
return match.slice(prefix.length);
|
|
}
|
|
|
|
function writeRawCookie(name: string, value: string | null) {
|
|
if (typeof document === "undefined") return;
|
|
const domain = cookieDomain();
|
|
if (value == null) {
|
|
let cookie = `${name}=; path=/; max-age=0; SameSite=Lax`;
|
|
if (domain) cookie += `; domain=${domain}`;
|
|
document.cookie = cookie;
|
|
return;
|
|
}
|
|
const maxAge = 60 * 60 * 24 * 30;
|
|
let cookie = `${name}=${value}; path=/; max-age=${maxAge}; SameSite=Lax`;
|
|
if (domain) cookie += `; domain=${domain}`;
|
|
document.cookie = cookie;
|
|
}
|
|
|
|
function clearChunkedCookie(name: string) {
|
|
writeRawCookie(name, null);
|
|
const n = Number(readRawCookie(`${name}_n`) || "0");
|
|
writeRawCookie(`${name}_n`, null);
|
|
for (let i = 0; i < Math.max(n, MAX_CHUNKS); i++) {
|
|
writeRawCookie(`${name}_${i}`, null);
|
|
}
|
|
}
|
|
|
|
function writeCookie(name: string, value: string | null) {
|
|
clearChunkedCookie(name);
|
|
if (value == null || value === "") return;
|
|
|
|
const encoded = encodeURIComponent(value);
|
|
if (encoded.length <= 3500) {
|
|
writeRawCookie(name, encoded);
|
|
return;
|
|
}
|
|
|
|
const chunks: string[] = [];
|
|
for (let i = 0; i < encoded.length; i += CHUNK_SIZE) {
|
|
chunks.push(encoded.slice(i, i + CHUNK_SIZE));
|
|
}
|
|
writeRawCookie(`${name}_n`, String(chunks.length));
|
|
chunks.forEach((chunk, i) => writeRawCookie(`${name}_${i}`, chunk));
|
|
}
|
|
|
|
function readCookie(name: string): string | null {
|
|
const n = Number(readRawCookie(`${name}_n`) || "0");
|
|
if (n > 0) {
|
|
let encoded = "";
|
|
for (let i = 0; i < n; i++) {
|
|
const part = readRawCookie(`${name}_${i}`);
|
|
if (part == null) return null;
|
|
encoded += part;
|
|
}
|
|
try {
|
|
return decodeURIComponent(encoded);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
const raw = readRawCookie(name);
|
|
if (raw == null) return null;
|
|
try {
|
|
return decodeURIComponent(raw);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function writeSharedAuthCookies(accessToken: string, refreshToken?: string) {
|
|
writeCookie(SHARED_ACCESS_TOKEN_KEY, accessToken);
|
|
if (refreshToken) writeCookie(SHARED_REFRESH_TOKEN_KEY, refreshToken);
|
|
}
|
|
|
|
export function clearSharedAuthCookies() {
|
|
writeCookie(SHARED_ACCESS_TOKEN_KEY, null);
|
|
writeCookie(SHARED_REFRESH_TOKEN_KEY, null);
|
|
}
|
|
|
|
export function readSharedAccessToken(): string | null {
|
|
return readCookie(SHARED_ACCESS_TOKEN_KEY);
|
|
}
|
|
|
|
export function readSharedRefreshToken(): string | null {
|
|
return readCookie(SHARED_REFRESH_TOKEN_KEY);
|
|
}
|
|
|
|
export function hydrateLocalTokensFromSharedCookies(
|
|
accessKey = SHARED_ACCESS_TOKEN_KEY,
|
|
refreshKey = SHARED_REFRESH_TOKEN_KEY,
|
|
): boolean {
|
|
if (typeof window === "undefined") return false;
|
|
if (localStorage.getItem(accessKey)) return false;
|
|
const access = readSharedAccessToken();
|
|
if (!access) return false;
|
|
localStorage.setItem(accessKey, access);
|
|
const refresh = readSharedRefreshToken();
|
|
if (refresh) localStorage.setItem(refreshKey, refresh);
|
|
return true;
|
|
}
|