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
JavaScript
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 ?? '/'
});
}