import type { JSONB, JSONBObjectTypeIfDefined, MaybePromise } from "prostgles-types"; import type { SessionUser } from "../Auth/AuthTypes"; import type { PublishParams } from "./publishTypesAndUtils"; export type ServerFunctionDefinition = { input?: Record | undefined; description?: string; /** * undefined if not allowed */ run: undefined | ((args: Record | undefined) => MaybePromise); }; export const defineServerFunction = < TInput extends Record | undefined = undefined, >(args: { input?: TInput; description?: string; /** * undefined if not allowed */ run: undefined | ((args: JSONBObjectTypeIfDefined) => MaybePromise); }) => args as unknown as ServerFunctionDefinition; export type ServerFunctionDefinitions = ( /** * params will be undefined on first run to generate the definitions */ params: undefined | PublishParams, ) => MaybePromise>; export const createServerFunctionWithContext = ( /** * undefined if not allowed */ context: Context | undefined, ) => { return < Input extends Record | undefined, Run extends (args: JSONBObjectTypeIfDefined, context: Context) => MaybePromise, >(args: { input?: Input; description?: string; run: Run; }) => ({ ...args, run: context === undefined ? undefined : ( (validatedArgs: any) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument return args.run(validatedArgs, context) as Run; } ), }) satisfies ServerFunctionDefinition; }; type InputOf = T extends { input?: infer I } ? I : undefined; // if inference fails or is invalid → fall back to undefined type SafeInput = I extends Record ? I : undefined; type ServerFunctionArgsFrom = { input?: InputOf; description?: string; run: ( args: JSONBObjectTypeIfDefined>>, context: Context, ) => MaybePromise; }; type ServerFunctionBlock = { [K in keyof Defs]: ServerFunctionArgsFrom; }; type WrappedDef = Def extends ( { input?: infer I; description?: infer D; run: (a: any, c: Context) => infer R; } ) ? { input?: SafeInput; description?: D extends string ? D : string | undefined; run: undefined | ((a: any) => R); // keep return type, widen args } : never; type WrappedBlock = { [K in keyof Defs]: WrappedDef; }; export const createServerFunctionBlockWithContext = (context: Context | undefined) => { return >( defs: Defs & ServerFunctionBlock, ): WrappedBlock => { const wrapped = {} as WrappedBlock; for (const key in defs) { const def = defs[key]; wrapped[key] = { ...def, run: context === undefined ? undefined : (args: any) => def.run(args, context), }; } return wrapped satisfies Record; }; };