feat: add admin accounts and image templates

This commit is contained in:
inman
2026-07-03 11:25:25 +08:00
parent d98e58adfa
commit c3ea9f0eb1
61 changed files with 7016 additions and 199 deletions

View File

@@ -14,10 +14,14 @@ export type AuthSession = {
user: AuthUser;
issuedAt: number;
expiresAt: number;
accessToken?: string;
tokenType?: string;
};
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
const DEFAULT_COOKIE_CHUNK_SIZE = 3000;
const DEFAULT_COOKIE_MAX_CHUNKS = 20;
export async function createSignedJsonValue(value: unknown, secret: string): Promise<string> {
const payload = bytesToBase64Url(textEncoder.encode(JSON.stringify(value)));
@@ -42,6 +46,39 @@ export async function createSessionCookieValue(session: AuthSession, secret: str
return createSignedJsonValue(session, secret);
}
export function chunkCookieValue(value: string, chunkSize = DEFAULT_COOKIE_CHUNK_SIZE): string[] {
if (value.length <= chunkSize) return [value];
const chunks: string[] = [];
for (let index = 0; index < value.length; index += chunkSize) {
chunks.push(value.slice(index, index + chunkSize));
}
return chunks;
}
export function chunkedCookieName(baseName: string, index: number): string {
return index === 0 ? baseName : `${baseName}.${index}`;
}
export function chunkedCookieNames(baseName: string, maxChunks = DEFAULT_COOKIE_MAX_CHUNKS): string[] {
return Array.from({ length: maxChunks }, (_, index) => chunkedCookieName(baseName, index));
}
export function readChunkedCookieValue(
baseName: string,
getValue: (name: string) => string | undefined,
maxChunks = DEFAULT_COOKIE_MAX_CHUNKS
): string | undefined {
const first = getValue(baseName);
if (!first) return undefined;
let value = first;
for (let index = 1; index < maxChunks; index += 1) {
const chunk = getValue(chunkedCookieName(baseName, index));
if (!chunk) break;
value += chunk;
}
return value;
}
export async function parseSessionCookieValue(
value: string | undefined,
secret: string,
@@ -53,6 +90,8 @@ export async function parseSessionCookieValue(
if (session.expiresAt <= nowSeconds) return null;
return {
...session,
accessToken: typeof session.accessToken === "string" ? session.accessToken : undefined,
tokenType: typeof session.tokenType === "string" ? session.tokenType : undefined,
user: {
...session.user,
authorities: Array.isArray(session.user.authorities) ? session.user.authorities : [],