Last active
January 13, 2026 01:14
-
-
Save STBoyden/fd55dfe4eeea8a3bb5d0af177d0da6b1 to your computer and use it in GitHub Desktop.
Effect.ts + SvelteKit 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 type { RemoteFormInput } from "@sveltejs/kit"; | |
| import { command, form, query } from "$app/server"; | |
| import { Effect, Schema } from "effect"; | |
| /** | |
| * Creates a remote query defined with `Effect`. Shares the same behaviour as | |
| * SvelteKit's `query`. | |
| * | |
| * @param schema The `Schema` to validate arguments against. | |
| * @param handler The `Effect` to run when this function is ran. | |
| * @template A success value for the given `Effect`. | |
| * @template E possible error for the given `Effect`. | |
| * @see query | |
| */ | |
| export const effectfulQuery = <A, E, ASchema, ISchema>( | |
| schema: Schema.Schema<ASchema, ISchema, never>, | |
| handler: (args: ASchema) => Effect.Effect<A, E, never> | |
| ) => query(Schema.standardSchemaV1(schema), async args => Effect.runPromiseExit(handler(args))); | |
| /** | |
| * Creates a remote batch query defined with `Effect`. Shares the same | |
| * behaviour as SvelteKit's `query.batch`. | |
| * | |
| * @param schema The `Schema` to validate arguments against. | |
| * @param handler The `Effect` to run when this function is ran. | |
| * @template A success value for the given `Effect`. | |
| * @template E possible error for the given `Effect`. | |
| * @see query.batch | |
| */ | |
| export const effectfulBatchQuery = <A, E, ASchema, ISchema>( | |
| schema: Schema.Schema<ASchema, ISchema, never>, | |
| handler: ( | |
| args: ASchema[] | |
| ) => Effect.Effect<(args: ASchema, index?: number) => Effect.Effect<A, E, never>> | |
| ) => | |
| query.batch(Schema.standardSchemaV1(schema), async args => { | |
| return (arg, index) => | |
| Effect.runSyncExit(handler(args).pipe(Effect.andThen(fn => fn(arg, index)))); | |
| }); | |
| /* eslint-disable @typescript-eslint/no-explicit-any */ | |
| /** | |
| * Creates a remote form function defined with `Effect`. Shares the same | |
| * behaviour as SvelteKit's `form`. | |
| * | |
| * @param schema The `Schema` to validate arguments and fields against. | |
| * @param handler The `Effect` to run when this function is ran. | |
| * @template A success value for the given `Effect`. | |
| * @template E possible error for the given `Effect`. | |
| * @see form | |
| */ | |
| export const effectfulForm = < | |
| A, | |
| E, | |
| ASchema extends Record<string, any>, | |
| ISchema extends RemoteFormInput | |
| >( | |
| schema: Schema.Schema<ASchema, ISchema, never>, | |
| handler: (args: ASchema) => Effect.Effect<A, E, never> | |
| ) => form(Schema.standardSchemaV1(schema), async args => Effect.runPromiseExit(handler(args))); | |
| /* eslint-enable @typescript-eslint/no-explicit-any */ | |
| /** | |
| * Creates a remote command function defined with `Effect`. Shares the same | |
| * behaviour as SvelteKit's `command`. | |
| * | |
| * @param schema The `Schema` to validate arguments and fields against. | |
| * @param handler The `Effect` to run when this function is ran. | |
| * @template A success value for the given `Effect`. | |
| * @template E possible error for the given `Effect`. | |
| * @see command | |
| */ | |
| export const effectfulCommand = <A, E, ASchema, ISchema>( | |
| schema: Schema.Schema<ASchema, ISchema, never>, | |
| handler: (args: ASchema) => Effect.Effect<A, E, never> | |
| ) => command(Schema.standardSchemaV1(schema), async args => Effect.runPromiseExit(handler(args))); |
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 type { | |
| RemoteCommand, | |
| RemoteForm, | |
| RemoteFormInput, | |
| RemoteQueryFunction | |
| } from "@sveltejs/kit"; | |
| import { command, form, query } from "$app/server"; | |
| import { Effect, Schema } from "effect"; | |
| /** | |
| * Creates a remote query defined with `Effect`. Shares the same behaviour as | |
| * SvelteKit's `query`. | |
| * | |
| * @param schema The `Schema` to validate arguments against. | |
| * @param handler The `Effect` to run when this function is ran. When `E` is `never`, then the return value will be non-nullish, otherwise the result can be `undefined`. | |
| * @template A success value for the given `Effect`. | |
| * @template E possible error for the given `Effect`. | |
| * @template QueryReturn `A` when `E == never`, otherwise `A | undefined`. | |
| * @see query | |
| */ | |
| export const effectfulQuery = < | |
| A, | |
| E, | |
| ASchema, | |
| ISchema, | |
| QueryReturn = E extends never ? A : A | undefined | |
| >( | |
| schema: Schema.Schema<ASchema, ISchema, never>, | |
| handler: (args: ASchema) => Effect.Effect<A, E, never> | |
| ): RemoteQueryFunction<ISchema, QueryReturn> => | |
| query(Schema.standardSchemaV1(schema), async args => | |
| Effect.runPromise( | |
| Effect.gen(function* () { | |
| const result = handler(args); | |
| if (yield* Effect.isSuccess(result)) { | |
| return yield* result; | |
| } else { | |
| yield* Effect.tapError(result, error => | |
| Effect.logError(`An error occurred in remote query function: ${error}`) | |
| ); | |
| return undefined; | |
| } | |
| }) | |
| ) | |
| ) as RemoteQueryFunction<ISchema, QueryReturn>; | |
| /** | |
| * Creates a remote batch query defined with `Effect`. Shares the same | |
| * behaviour as SvelteKit's `query.batch`. | |
| * | |
| * @param schema The `Schema` to validate arguments against. | |
| * @param handler The `Effect` to run when this function is ran. When `E` is `never`, then the return value will be non-nullish, otherwise the result can be `undefined`. | |
| * @template A success value for the given `Effect`. | |
| * @template E possible error for the given `Effect`. | |
| * @template BatchQueryReturn `A` when `E == never`, otherwise `A | undefined`. | |
| * @see query.batch | |
| */ | |
| export const effectfulBatchQuery = < | |
| A, | |
| E, | |
| ASchema, | |
| ISchema, | |
| BatchQueryReturn = E extends never ? A : A | undefined | |
| >( | |
| schema: Schema.Schema<ASchema, ISchema, never>, | |
| handler: ( | |
| args: ASchema[] | |
| ) => Effect.Effect<(args: ASchema, index?: number) => Effect.Effect<BatchQueryReturn, E, never>> | |
| ): RemoteQueryFunction<ISchema, BatchQueryReturn> => | |
| query.batch(Schema.standardSchemaV1(schema), async args => { | |
| const lookup = handler(args); | |
| return (arg, index) => | |
| Effect.runSync( | |
| Effect.gen(function* () { | |
| const fn = yield* lookup; | |
| const result = fn(arg, index); | |
| if (yield* Effect.isSuccess(result)) { | |
| return yield* result; | |
| } else { | |
| yield* Effect.tapError(result, error => | |
| Effect.logError( | |
| `An error occurred in remote query batch function [index: ${index}, arg: ${arg}]: ${error}` | |
| ) | |
| ); | |
| return undefined; | |
| } | |
| }) | |
| ); | |
| }) as RemoteQueryFunction<ISchema, BatchQueryReturn>; | |
| /* eslint-disable @typescript-eslint/no-explicit-any */ | |
| /** | |
| * Creates a remote form function defined with `Effect`. Shares the same | |
| * behaviour as SvelteKit's `form`. | |
| * | |
| * @param schema The `Schema` to validate arguments and fields against. | |
| * @param handler The `Effect` to run when this function is ran. When `E` is `never`, then the return value will be non-nullish, otherwise the result can be `undefined`. | |
| * @template A success value for the given `Effect`. | |
| * @template E possible error for the given `Effect`. | |
| * @template FormReturn `A` when `E == never`, otherwise `A | undefined`. | |
| * @see form | |
| */ | |
| export const effectfulForm = < | |
| A, | |
| E, | |
| ASchema extends Record<string, any>, | |
| ISchema extends RemoteFormInput, | |
| FormReturn = E extends never ? A : A | undefined | |
| >( | |
| schema: Schema.Schema<ASchema, ISchema, never>, | |
| handler: (args: ASchema) => Effect.Effect<A, E, never> | |
| ): RemoteForm<ISchema, FormReturn> => | |
| form(Schema.standardSchemaV1(schema), async args => | |
| Effect.runPromise( | |
| Effect.gen(function* () { | |
| const result = handler(args); | |
| if (yield* Effect.isSuccess(result)) { | |
| return yield* result; | |
| } else { | |
| yield* Effect.tapError(result, error => | |
| Effect.logError(`An error occurred in remote form function: ${error}`) | |
| ); | |
| return undefined; | |
| } | |
| }) | |
| ) | |
| ) as RemoteForm<ISchema, FormReturn>; | |
| /* eslint-enable @typescript-eslint/no-explicit-any */ | |
| /** | |
| * Creates a remote command function defined with `Effect`. Shares the same | |
| * behaviour as SvelteKit's `command`. | |
| * | |
| * @param schema The `Schema` to validate arguments and fields against. | |
| * @param handler The `Effect` to run when this function is ran. When `E` is `never`, then the return value will be non-nullish, otherwise the result can be `undefined`. | |
| * @template A success value for the given `Effect`. | |
| * @template E possible error for the given `Effect`. | |
| * @template CommandReturn `A` when `E == never`, otherwise `A | undefined`. | |
| * @see command | |
| */ | |
| export const effectfulCommand = < | |
| A, | |
| E, | |
| ASchema, | |
| ISchema, | |
| CommandReturn = E extends never ? A : A | undefined | |
| >( | |
| schema: Schema.Schema<ASchema, ISchema, never>, | |
| handler: (args: ASchema) => Effect.Effect<A, E, never> | |
| ): RemoteCommand<ISchema, CommandReturn> => | |
| command(Schema.standardSchemaV1(schema), async args => | |
| Effect.runPromise( | |
| Effect.gen(function* () { | |
| const result = handler(args); | |
| if (yield* Effect.isSuccess(result)) { | |
| return yield* result; | |
| } else { | |
| yield* Effect.tapError(result, error => | |
| Effect.logError(`An error occurred in remote command function: ${error}`) | |
| ); | |
| return undefined; | |
| } | |
| }) | |
| ) | |
| ) as RemoteCommand<ISchema, CommandReturn>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks