Enhance upload functionality with genre selection and validation; refactor session cookie handling
CI/CD / WebPlayer (push) Successful in 39s
CI/CD / Deploy (push) Canceled after 0s
CI/CD / BackEnd (push) Canceled after 39s

This commit is contained in:
2026-09-23 18:33:21 +02:00
parent 5efd59826b
commit a7929c0ac9
11 changed files with 200 additions and 23 deletions
+20 -2
View File
@@ -52,9 +52,27 @@ export function unwrapOrError<T>(
return result.data;
}
export function apiErrorDetail(error: unknown): string | undefined {
if (typeof error !== 'object' || error === null) return undefined;
const { errors, detail, title } = error as {
errors?: Record<string, unknown>;
detail?: unknown;
title?: unknown;
};
if (errors && typeof errors === 'object') {
const messages = Object.values(errors)
.flat()
.filter((entry): entry is string => typeof entry === 'string');
if (messages.length > 0) return messages.join(' ');
}
if (typeof detail === 'string' && detail !== '') return detail;
if (typeof title === 'string' && title !== '') return title;
return undefined;
}
export function unwrapOrFail(
result: { error?: unknown },
message: string
): ActionFailure<{ message: string }> | undefined {
return result.error ? fail(502, { message }) : undefined;
): ActionFailure<{ message: string; detail?: string }> | undefined {
return result.error ? fail(502, { message, detail: apiErrorDetail(result.error) }) : undefined;
}
+39
View File
@@ -1,3 +1,4 @@
import type { Cookies } from '@sveltejs/kit';
import * as client from 'openid-client';
import { EncryptJWT, jwtDecrypt } from 'jose';
import { dev } from '$app/environment';
@@ -53,6 +54,44 @@ export function sessionCookieOptions(url: URL) {
};
}
const SESSION_CHUNK_SIZE = 3600;
function sessionChunkName(index: number): string {
return index === 0 ? SESSION_COOKIE : `${SESSION_COOKIE}.${index}`;
}
export function readSessionCookie(cookies: Cookies): string | undefined {
const parts: string[] = [];
for (let index = 0; ; index++) {
const part = cookies.get(sessionChunkName(index));
if (part === undefined) break;
parts.push(part);
}
return parts.length > 0 ? parts.join('') : undefined;
}
export function clearSessionCookie(cookies: Cookies, keep = 0): void {
for (const { name } of cookies.getAll()) {
const match =
name === SESSION_COOKIE
? 0
: name.startsWith(`${SESSION_COOKIE}.`)
? Number(name.slice(SESSION_COOKIE.length + 1))
: -1;
if (Number.isInteger(match) && match >= keep) cookies.delete(name, { path: '/' });
}
}
export function writeSessionCookie(cookies: Cookies, token: string, url: URL): void {
const options = sessionCookieOptions(url);
const count = Math.ceil(token.length / SESSION_CHUNK_SIZE);
for (let index = 0; index < count; index++) {
const chunk = token.slice(index * SESSION_CHUNK_SIZE, (index + 1) * SESSION_CHUNK_SIZE);
cookies.set(sessionChunkName(index), chunk, options);
}
clearSessionCookie(cookies, count);
}
export async function encodeSession(session: Session): Promise<string> {
const now = Math.floor(Date.now() / 1000);
return new EncryptJWT({ ...session })