UNPKG

convex

Version:

Client for the Convex Cloud

201 lines (192 loc) 6.71 kB
import { GenericAPI } from "../../api/index.js"; import { convexToJson, jsonToConvex } from "../../values/index.js"; import { GenericDataModel } from "../data_model.js"; import { ActionCtx, HttpEndpointCtx, MutationCtx, PublicAction, PublicHttpEndpoint, PublicMutation, PublicQuery, QueryCtx, } from "../registration.js"; import { setupActionDatabaseClient } from "./actions_impl.js"; import { setupActionAuth, setupAuth } from "./authentication_impl.js"; import { setupReader, setupWriter } from "./database_impl.js"; import { setupHttpCalls } from "./http_impl.js"; import { setupActionScheduler, setupMutationScheduler, } from "./scheduler_impl.js"; import { setupStorageReader, setupStorageWriter } from "./storage_impl.js"; import { performJsSyscall } from "./syscall.js"; async function invokeMutation< F extends ( ctx: MutationCtx<GenericDataModel, GenericAPI>, ...args: any ) => any >(func: F, argsStr: string) { const args = jsonToConvex(JSON.parse(argsStr)); const mutationCtx = { db: setupWriter(), auth: setupAuth(), storage: setupStorageWriter(), scheduler: setupMutationScheduler(), }; const result = await Promise.resolve(func(mutationCtx, ...(args as any))); return JSON.stringify(convexToJson(result === undefined ? null : result)); } /** * Define a mutation in this Convex app's public API. * * This function will be allowed to modify your Convex database and will be accessible from the client. * * If you're using code generation, use the `mutation` function in * `convex/_generated/server.d.ts` which is typed for your data model. * * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. * * @public */ export const mutationGeneric = < DataModel extends GenericDataModel, API extends GenericAPI, Args extends any[], Output >( func: (ctx: MutationCtx<DataModel, API>, ...args: Args) => Output ): PublicMutation<DataModel, API, Args, Output> => { const m = func as unknown as PublicMutation<DataModel, API, Args, Output>; // Helpful runtime check that functions are only be registered once if (m.isRegistered) { throw new Error("Function registered twice " + func); } m.isRegistered = true; m.isMutation = true; m.invokeMutation = argsStr => invokeMutation(func as any, argsStr); return m; }; async function invokeQuery< F extends (ctx: QueryCtx<GenericDataModel>, ...args: any) => any >(func: F, argsStr: string) { const args = jsonToConvex(JSON.parse(argsStr)); const queryCtx = { db: setupReader(), auth: setupAuth(), storage: setupStorageReader(), }; const result = await Promise.resolve(func(queryCtx, ...(args as any))); return JSON.stringify(convexToJson(result === undefined ? null : result)); } /** * Define a query in this Convex app's public API. * * This function will be allowed to read your Convex database and will be accessible from the client. * * If you're using code generation, use the `query` function in * `convex/_generated/server.d.ts` which is typed for your data model. * * @param func - The query function. It receives a {@link QueryCtx} as its first argument. * @returns The wrapped query. Include this as an `export` to name it and make it accessible. * * @public */ export const queryGeneric = < DataModel extends GenericDataModel, Args extends any[], Output >( func: (ctx: QueryCtx<DataModel>, ...args: Args) => Output ): PublicQuery<DataModel, Args, Output> => { const q = func as unknown as PublicQuery<DataModel, Args, Output>; // Helpful runtime check that functions are only be registered once if (q.isRegistered) { throw new Error("Function registered twice " + func); } q.isRegistered = true; q.isQuery = true; q.invokeQuery = argsStr => invokeQuery(func as any, argsStr); return q; }; async function invokeAction< API extends GenericAPI, F extends (ctx: ActionCtx<API>, ...args: any) => any >(func: F, requestId: string, argsStr: string) { const args = jsonToConvex(JSON.parse(argsStr)); const databaseClient = setupActionDatabaseClient(requestId); const ctx = { runQuery: databaseClient.runQuery, runMutation: databaseClient.runMutation, auth: setupActionAuth(requestId), scheduler: setupActionScheduler(requestId), }; const result = await Promise.resolve(func(ctx, ...(args as any))); return JSON.stringify(convexToJson(result === undefined ? null : result)); } /** * Define an action in this Convex app's public API. * * @param func - The function. It receives a {@link ActionCtx} as its first argument. * @returns The wrapped function. Include this as an `export` to name it and make it accessible. * * @public */ export const actionGeneric = < API extends GenericAPI, Args extends any[], Output >( func: (ctx: ActionCtx<API>, ...args: Args) => Output ): PublicAction<API, Args, Output> => { const q = func as unknown as PublicAction<API, Args, Output>; // Helpful runtime check that functions are only be registered once if (q.isRegistered) { throw new Error("Function registered twice " + func); } q.isRegistered = true; q.isAction = true; q.invokeAction = (requestId, argsStr) => invokeAction(func as any, requestId, argsStr); return q; }; async function invokeHttpEndpoint< API extends GenericAPI, F extends (ctx: HttpEndpointCtx<API>, request: Request) => any >(func: F, argsStr: string) { const calls = setupHttpCalls(); const ctx = { ...calls, auth: setupAuth(), }; const request = performJsSyscall("requestFromConvexJson", { convexJson: JSON.parse(argsStr), }); const response: any = await Promise.resolve(func(ctx, request)); return JSON.stringify( performJsSyscall("convexJsonFromResponse", { response }) ); } /** * Define a Convex HTTP endpoint. * * @param func - The function. It receives an {@link HttpEndpointCtx} as its first argument, and a `Request` object * as its second. * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. * * @public */ export const httpEndpointGeneric = <API extends GenericAPI>( func: (ctx: HttpEndpointCtx<API>, request: Request) => Promise<Response> ): PublicHttpEndpoint<API> => { const q = func as unknown as PublicHttpEndpoint<API>; // Helpful runtime check that functions are only be registered once if (q.isRegistered) { throw new Error("Function registered twice " + func); } q.isRegistered = true; q.isHttp = true; q.invokeHttpEndpoint = argsStr => invokeHttpEndpoint(func as any, argsStr); return q; };