notFound, redirect, unauthorized
Throw helpers for route loaders: stop and show the not-found page, send the visitor to another address, or refuse a guest.
import { notFound, redirect, unauthorized } from '@salla.sa/twilight-theme-engine/providers';In plain words
A loader is the function that fetches a page's data before the page renders. Sometimes it has to stop: the product does not exist, the page moved, or the visitor must be signed in. Throw one of these and the router takes over: throw notFound(), throw redirect('/ar/cart'), throw unauthorized().
They are written without naming a router, so loader code reads the same whichever framework runs it.
Signature
let notFound: (message?: string) => never
let redirect: (path: string, opts?: { replace?: boolean }) => never
let unauthorized: (message?: string) => neverTry it live
TanStack adapter active: true
throw notFound(…): {…} 2 keys
value: {…} 2 keys
import { notFound } from '@salla.sa/twilight-theme-engine/providers';
import { product } from '@salla.sa/twilight-theme-engine/api/product';
export async function loader({ params }: { params: { id: string } }) {
const found = await product.find(params.id).catch(() => null);
if (!found) throw notFound('Product not found');
return { product: found };
}
Example
import { notFound, redirect } from '@salla.sa/twilight-theme-engine/providers';
import { product } from '@salla.sa/twilight-theme-engine/api/product';
export async function loader({ params }: { params: { id: string; locale?: string } }) {
const found = await product.find(params.id).catch(() => null);
if (!found) throw notFound('Gift card not found');
// redirect() adds no locale: carry the current one (a single-language store has none).
const prefix = params.locale ? `/${params.locale}` : '';
if (found.type !== 'codes') throw redirect(`${prefix}/offers`);
return { product: found };
}
How it behaves
They are
letbindings thatconfigureNavigation()replaces. Importing/tanstack, as every theme'sapp/router.tsxdoes, swaps in:notFoundthrows TanStack'snotFound({ data: message }),redirectthrows TanStack'sredirect({ to: path, replace }), andunauthorizedkeeps throwing the engine'sUnauthorizedError.What the visitor sees: TanStack's not-found component for
notFound, and forunauthorizedthe router's default error component, which renders a 401ErrorPagewithout the home button (DefaultErrorComponentin src/tanstack/router.tsx). The engine's profile and settings loaders throwunauthorized()when there is no token.Their return type is
never, and they throw themselves. Writingthrow notFound()makes the stop visible to readers and to TypeScript.
Gotchas
redirectuses the path exactly as given; unlikeuseNavigate(), no locale is added. On a multilingual storeredirect('/cart')lands on a locale-less URL, and the locale wrapper sends it on to/ar/cart(the fallback locale), whatever language the visitor had. Build the path with the current locale.Without the TanStack adapter (a unit test, or code that never imports
/tanstack),redirectsetswindow.locationin the browser before it throwsRedirectError: a real navigation.
Related
Wrap an API call in a loader: orThrow turns any failure into a not-found error, orUnauthorized turns a 401 or 403 into the unauthorized flow.
NotFoundError, RedirectError, UnauthorizedErrorThe error classes behind the loader helpers, so an error screen can tell a missing page, a redirect and a refused guest apart.
configureNavigationReplaces what notFound, redirect and unauthorized throw. A framework adapter calls it once; theme code never needs to.