Last active
October 30, 2025 21:27
-
-
Save sillvva/1cd1c04347fa66ecc402eb1764e6852b to your computer and use it in GitHub Desktop.
Guarded Remote Functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { command, form, getRequestEvent, query } from "$app/server"; | |
| import type { StandardSchemaV1 } from "@standard-schema/spec"; | |
| import { | |
| redirect, | |
| type Invalid, | |
| type RemoteCommand, | |
| type RemoteFormFactory, | |
| type RemoteFormInput, | |
| type RemoteQueryFunction, | |
| type RequestEvent | |
| } from "@sveltejs/kit"; | |
| const LOGINPAGE = "/"; | |
| function isStandardSchema(schema: object): schema is StandardSchemaV1 { | |
| return "~standard" in schema; | |
| } | |
| // ------------------------------------------------------------------------------------------------- | |
| // guardedQuery: Remote Query with auth guard | |
| // ------------------------------------------------------------------------------------------------- | |
| export function guardedQuery<Schema extends StandardSchemaV1, Output>( | |
| schema: Schema, | |
| fn: ( | |
| output: StandardSchemaV1.InferOutput<Schema>, | |
| auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent } | |
| ) => Promise<Output> | |
| ): RemoteQueryFunction<StandardSchemaV1.InferInput<Schema>, Promise<Output>>; | |
| export function guardedQuery<Output>( | |
| fn: (auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent }) => Promise<Output> | |
| ): RemoteQueryFunction<void, Promise<Output>>; | |
| export function guardedQuery<Schema extends StandardSchemaV1, Output>( | |
| schemaOrFn: Schema | ((auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent }) => Promise<Output>), | |
| maybeFn?: ( | |
| output: StandardSchemaV1.InferOutput<Schema>, | |
| auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent } | |
| ) => Promise<Output> | |
| ) { | |
| // Handle the case with schema parameter (first overload) | |
| if (isStandardSchema(schemaOrFn) && typeof maybeFn === "function") { | |
| return query(schemaOrFn, (output) => { | |
| const event = getRequestEvent(); | |
| if (!event.locals.user) redirect(302, LOGINPAGE); | |
| return maybeFn(output, { user: event.locals.user, event }); | |
| }); | |
| } | |
| // Handle the case where there's no schema parameter (second overload) | |
| if (isFunction(schemaOrFn) && !maybeFn) { | |
| return query(() => { | |
| const event = getRequestEvent(); | |
| if (!event.locals.user) redirect(302, LOGINPAGE); | |
| return schemaOrFn({ user: event.locals.user, event }); | |
| }); | |
| } | |
| throw new Error("Invalid arguments"); | |
| } | |
| // ------------------------------------------------------------------------------------------------- | |
| // guardedCommand: Remote Command with auth guard (async/await) | |
| // ------------------------------------------------------------------------------------------------- | |
| export function guardedCommand<Schema extends StandardSchemaV1, Output>( | |
| schema: Schema, | |
| fn: ( | |
| output: StandardSchemaV1.InferOutput<Schema>, | |
| auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent } | |
| ) => Promise<Output> | |
| ): RemoteCommand<StandardSchemaV1.InferInput<Schema>, Promise<Output | { redirect: string }>>; | |
| export function guardedCommand<Input, Output>( | |
| fn: (input: Input, auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent }) => Promise<Output> | |
| ): RemoteCommand<Input, Promise<Output | { redirect: string }>>; | |
| export function guardedCommand<Schema extends StandardSchemaV1, Input, Output>( | |
| schemaOrFn: Schema | ((input: Input, auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent }) => Promise<Output>), | |
| maybeFn?: ( | |
| output: StandardSchemaV1.InferOutput<Schema>, | |
| auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent } | |
| ) => Promise<Output> | |
| ) { | |
| // Handle the case with schema parameter (first overload) | |
| if (isStandardSchema(schemaOrFn) && typeof maybeFn === "function") { | |
| return command(schemaOrFn, async (output) => { | |
| const event = getRequestEvent(); | |
| if (!event.locals.user) return { redirect: LOGINPAGE }; | |
| return await maybeFn(output, { user: event.locals.user, event }); | |
| }); | |
| } | |
| // Handle the case where there's no schema parameter (second overload) | |
| if (isFunction(schemaOrFn) && !maybeFn) { | |
| return command("unchecked", async (input: Input) => { | |
| const event = getRequestEvent(); | |
| if (!event.locals.user) return { redirect: LOGINPAGE }; | |
| return await schemaOrFn(input, { user: event.locals.user, event }); | |
| }); | |
| } | |
| throw new Error("Invalid arguments"); | |
| } | |
| // ------------------------------------------------------------------------------------------------- | |
| // guardedForm: Remote Form with auth guard (async/await) | |
| // ------------------------------------------------------------------------------------------------- | |
| export function guardedForm<Schema extends StandardSchemaV1<RemoteFormInput, Record<string, unknown>>, Output>( | |
| schema: Schema, | |
| fn: ( | |
| output: StandardSchemaV1.InferOutput<Schema>, | |
| auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent; invalid: Invalid<StandardSchemaV1.InferInput<Schema>> } | |
| ) => Promise<Output> | |
| ): RemoteFormFactory<StandardSchemaV1.InferInput<Schema>, Output>; | |
| export function guardedForm<Input extends RemoteFormInput, Output>( | |
| fn: ( | |
| output: Input, | |
| auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent; invalid: Invalid<Input> } | |
| ) => Promise<Output> | |
| ): RemoteFormFactory<Input, Output>; | |
| export function guardedForm< | |
| Schema extends StandardSchemaV1<RemoteFormInput, Record<string, unknown>>, | |
| Input extends RemoteFormInput, | |
| Output | |
| >( | |
| schemaOrFn: | |
| | Schema | |
| | (( | |
| output: Input, | |
| auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent; invalid: Invalid<Input> } | |
| ) => Promise<Output>), | |
| maybeFn?: ( | |
| output: StandardSchemaV1.InferOutput<Schema>, | |
| auth: { user: NonNullable<App.Locals["user"]>; event: RequestEvent; invalid: Invalid<StandardSchemaV1.InferInput<Schema>> } | |
| ) => Promise<Output> | |
| ) { | |
| // Handle the case with schema parameter (first overload) | |
| if (isStandardSchema(schemaOrFn) && typeof maybeFn === "function") { | |
| return form(schemaOrFn, async (output, invalid) => { | |
| const event = getRequestEvent(); | |
| if (!event.locals.user) redirect(302, LOGINPAGE); | |
| return await maybeFn(output, { invalid, user: event.locals.user, event }); | |
| }); | |
| } | |
| // Handle the case where there's no schema parameter (second overload) | |
| if (isFunction(schemaOrFn) && !maybeFn) { | |
| return form("unchecked", async (input: Input, invalid) => { | |
| const event = getRequestEvent(); | |
| if (!event.locals.user) redirect(302, LOGINPAGE); | |
| return await schemaOrFn(input, { invalid, user: event.locals.user, event }); | |
| }); | |
| } | |
| throw new Error("Invalid arguments"); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment