export class ProfileValidationError extends Error { constructor( message: string, public readonly fields: Record, public readonly reauthenticate = false, public readonly status: number | null = null, ) { super(message); } } export async function profileJson( url: string, data: object = {}, method: 'GET' | 'POST' = 'POST', ) { let token = ''; if (method !== 'GET') { const cookie = typeof document === 'undefined' ? undefined : document.cookie .split(';') .map((value) => value.trim()) .find((value) => value.startsWith('XSRF-TOKEN=')); try { token = cookie ? decodeURIComponent(cookie.slice(11)) : ''; } catch { throw new ProfileValidationError( 'A sessão não pôde ser validada. Actualize a página e tente novamente.', {}, ); } } const response = await fetch(url, { method, credentials: 'same-origin', headers: { Accept: 'application/json', ...(typeof FormData !== 'undefined' && data instanceof FormData ? {} : { 'Content-Type': 'application/json' }), ...(method === 'GET' ? {} : { 'X-XSRF-TOKEN': token }), }, ...(method === 'GET' ? {} : { body: typeof FormData !== 'undefined' && data instanceof FormData ? data : JSON.stringify(data), }), }); const result = await response.json().catch(() => null); const reauthenticate = response.headers.get('X-Portal-Reauthentication') === 'required'; if (!response.ok || (result === null && response.status !== 204)) throw new ProfileValidationError( typeof result?.message === 'string' ? result.message : response.status === 419 ? 'A sessão expirou. Actualize a página e tente novamente.' : 'A ação não foi concluída. Tente novamente.', Object.fromEntries( Object.entries(result?.errors ?? {}).map(([key, value]) => [ key, Array.isArray(value) ? value.join(' ') : String(value), ]), ), reauthenticate, response.status, ); return result; }