import { getKeys, type AnyObject, type ClientSchema, type SQLHandler, type SQLOptions, type TableHandler, } from "prostgles-types"; import type { AuthClientRequest } from "../Auth/AuthTypes"; import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder"; import type { Prostgles } from "../Prostgles"; import type { ServerFunctionDefinition } from "../PublishParser/defineServerFunction"; import type { PermissionScope } from "../PublishParser/publishTypesAndUtils"; import { runClientMethod, runClientRequest, runClientSqlRequest } from "../runClientRequest"; import { getClientSchema } from "./getClientSchema"; export type ClientHandlers = { clientSql: SQLHandler; clientDb: DBOFullyTyped; clientMethods: Record; clientSchema: ClientSchema; }; export const getClientHandlers = async ( prostgles: Prostgles, clientReq: AuthClientRequest, scope: PermissionScope | undefined, ): Promise => { const clientSchema = clientReq.socket?.prostgles?.get(prostgles.appId) ?? (await getClientSchema.bind(prostgles)(clientReq, scope)); const sqlHandler: SQLHandler | undefined = (( query: string, params?: unknown, options?: SQLOptions, ) => runClientSqlRequest.bind(prostgles)({ query, params, options }, clientReq)) as SQLHandler; const tableHandlers = Object.fromEntries( prostgles.dboBuilder.tablesOrViews!.map((table) => { const methods = [...tableMethods]; const handlers = Object.fromEntries( methods.map((command) => { const method = (param1: unknown, param2: unknown, param3: unknown) => runClientRequest.bind(prostgles)( { command, tableName: table.name, param1, param2, param3 }, clientReq, scope, ); return [command, method]; }), ); return [table.name, handlers]; }), ); const txNotAllowed: {} = { tx: () => { throw new Error("Transactions are not allowed in client handlers"); }, }; const clientSql = ((query: string, params?: AnyObject, options?: SQLOptions) => { if (scope && !scope.allowSql) { throw new Error("SQL is dissallowed by PermissionScope"); } return sqlHandler(query, params, options); }) as SQLHandler; const clientDb = { ...tableHandlers, ...txNotAllowed, } as DBOFullyTyped; const clientMethods: Record = Object.fromEntries( clientSchema.methods.map(({ name, input, description, output }) => { const methodHandler = (input?: unknown) => { if (scope && !scope.methods?.[name]) { throw new Error(`Method ${name} is not allowed by PermissionScope`); } return runClientMethod.bind(prostgles)({ name, input }, clientReq); }; return [name, { name, input, description, output, run: methodHandler }]; }), ); return { clientDb, clientSql, clientMethods, clientSchema }; }; const tableMethods = getKeys({ count: 1, find: 1, findOne: 1, getColumns: 1, getInfo: 1, size: 1, subscribe: 1, subscribeOne: 1, delete: 1, insert: 1, update: 1, upsert: 1, updateBatch: 1, insertMany: 1, } satisfies Record);