any typescript genius can help with writing a wrapper function for a SvelteKit loader ?

the way that the auth library i'm working with works, is that it recommends reading in the auth from the request (after being processed by hooks), and redirecting in the pager loader. so for a bunch of my pages, i'm gonna want almost the same structure, with computation specific to the page:
export const load = (async (req) => {
const auth = await req.locals.auth.validateUser();
if (!auth?.user) redirect(302, '/');

// do stuff here custom to each page
const customProps = 'customPropsThatIGetFromDoingStuff';

return {
customProps,
...auth?.user
};
}) satisfies PageServerLoad;
export const load = (async (req) => {
const auth = await req.locals.auth.validateUser();
if (!auth?.user) redirect(302, '/');

// do stuff here custom to each page
const customProps = 'customPropsThatIGetFromDoingStuff';

return {
customProps,
...auth?.user
};
}) satisfies PageServerLoad;
naturally, i'd like to extract the repetitive logic so i don't have to write it every time i make a page that's protected. i was thinking something such that it works like
export const load = protect((async (request) => {
// custom callback (the 'do stuff here custom to each page' from the prior snippet)
return stuff
}) satisfies PageServerLoad, { customRedirect: "/login" })
export const load = protect((async (request) => {
// custom callback (the 'do stuff here custom to each page' from the prior snippet)
return stuff
}) satisfies PageServerLoad, { customRedirect: "/login" })
any thoughts? essentially all implementations i'm able to come up with just entirely break Svelte's type system when loading the data in
1 Reply
jack
jack12mo ago
my best attempt at the implementation
export const protect = (loader?: ServerLoad, opts?: ProtectOptions) => {
return (async (req) => {
const { user } = await req.locals.auth.validateUser();
if (!user) redirect(302, opts?.custom_redict ?? '/login');

const loaderData = loader ? await loader(req) : {};

return {
...user,
...loaderData
};
}) satisfies PageServerLoad;
};
export const protect = (loader?: ServerLoad, opts?: ProtectOptions) => {
return (async (req) => {
const { user } = await req.locals.auth.validateUser();
if (!user) redirect(302, opts?.custom_redict ?? '/login');

const loaderData = loader ? await loader(req) : {};

return {
...user,
...loaderData
};
}) satisfies PageServerLoad;
};
honestly, even something such as
export const load = (async (req) => {
const { returnWithUser } = await protect(req);

return returnWithUser({
athletes: await prisma.athlete.findMany({})
});
}) satisfies PageServerLoad;
export const load = (async (req) => {
const { returnWithUser } = await protect(req);

return returnWithUser({
athletes: await prisma.athlete.findMany({})
});
}) satisfies PageServerLoad;
where protect is defined as such:
export const protect = async (req: ServerLoadEvent, opts?: ProtectOptions) => {
const auth = await req.locals.auth.validateUser();

if (!auth?.user) {
throw redirect(302, opts?.redirect ?? '/');
}

return {
user: auth.user,
returnWithUser: (data?: Record<string, unknown>) => ({
...data,
...auth.user
})
};
};
export const protect = async (req: ServerLoadEvent, opts?: ProtectOptions) => {
const auth = await req.locals.auth.validateUser();

if (!auth?.user) {
throw redirect(302, opts?.redirect ?? '/');
}

return {
user: auth.user,
returnWithUser: (data?: Record<string, unknown>) => ({
...data,
...auth.user
})
};
};
i think the type of data in returnWithUser is my issue? or just something surrounding Svelte's loader type implementation