UNPKG

sveltekit-flash-message

Version:

Send temporary data to the next request after redirect. Works with both SSR and client.

116 lines (115 loc) 4.04 kB
import { redirect as redir } from '@sveltejs/kit'; //const d = console.debug; // Cannot change. const cookieName = 'flash'; export const flashCookieOptions = { path: '/', maxAge: 120, httpOnly: false, sameSite: 'strict' }; ///////////////////////////////////////////////////////////////////// /** * @deprecated Renamed to loadFlash. */ export function loadFlashMessage(cb) { return loadFlash(cb); } /** * Retrieves the flash message from the previous request. * Use as a wrapper around a top-level load function, usually in a +layout.server.ts file. */ export function loadFlash(cb) { return async (event) => { const flash = _loadFlash(event).flash; const loadFunction = await cb(event); return { flash, ...loadFunction }; }; } export function _loadFlash(event) { const dataString = event.cookies.get(cookieName); if (!dataString) { //d('No flash cookie found.'); return { [cookieName]: undefined }; } let data = undefined; if (dataString) { // Detect if event is XMLHttpRequest, basically by checking if the browser // is honoring the sec-fetch-dest header, or accepting json. // event.isDataRequest is also used. const setFetchDest = event.request.headers.get('sec-fetch-dest'); const accept = event.request.headers.get('accept'); if (event.isDataRequest || setFetchDest == 'empty' || accept == '*/*' || accept?.includes('application/json')) { //d('Possible fetch request, keeping cookie for client.'); } else { //d('Flash cookie found, clearing'); event.cookies.delete(cookieName, { path: flashCookieOptions.path ?? '/' }); } try { data = JSON.parse(dataString); } catch (e) { // Ignore data if parsing error } } return { [cookieName]: data }; } export const load = _loadFlash; export function redirect(status, location, message, event) { switch (arguments.length) { case 2: if (typeof status === 'number') { return realRedirect(status, `${location}`); } else { const message = status; const event = location; // Remove the named action, if it exists const redirectUrl = new URL(event.url); for (const [key] of redirectUrl.searchParams) { if (key.startsWith('/')) { redirectUrl.searchParams.delete(key); } break; } return realRedirect(303, redirectUrl, message, event); } case 3: return realRedirect(303, status, location, message); case 4: return realRedirect(status, location, message, event); default: throw new Error('Invalid redirect arguments'); } } function realRedirect(status, location, message, event) { if (!message) return redir(status, location.toString()); if (!event) throw new Error('RequestEvent is required for redirecting with flash message'); const cookies = 'cookies' in event ? event.cookies : event; cookies.set(cookieName, JSON.stringify(message), { ...flashCookieOptions, path: flashCookieOptions.path ?? '/' }); return redir(status, location.toString()); } //////////////////////////////////////////////////////// /** * Set the flash message without redirecting, for example when validation fails in a form action. * @param {App.PageData['flash']} message The flash message. * @param {RequestEvent} event The event for the form action or load function. */ export function setFlash(message, event) { const cookies = 'cookies' in event ? event.cookies : event; cookies.set(cookieName, JSON.stringify(message), { ...flashCookieOptions, path: flashCookieOptions.path ?? '/' }); }