convex
Version:
Client for the Convex Cloud
143 lines (136 loc) • 4.84 kB
text/typescript
import { convexToJson, jsonToConvex } from "../../values/index.js";
import { GenericAPI } from "../../api/index.js";
import { GenericDataModel } from "../data_model.js";
import {
ActionCtx,
MutationCtx,
PublicMutation,
PublicAction,
PublicQuery,
QueryCtx,
} from "../registration.js";
import { setupAuth, setupActionAuth } from "./authentication_impl.js";
import { setupReader, setupWriter } from "./database_impl.js";
import { setupActionDatabaseClient } from "./actions_impl.js";
async function invokeMutation<
F extends (ctx: MutationCtx<GenericDataModel>, ...args: any) => any
>(func: F, argsStr: string) {
const args = jsonToConvex(JSON.parse(argsStr));
const mutationCtx = {
db: setupWriter(),
auth: setupAuth(),
};
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,
Args extends any[],
Output
>(
func: (ctx: MutationCtx<DataModel>, ...args: Args) => Output
): PublicMutation<DataModel, Args, Output> => {
const m = func as unknown as PublicMutation<DataModel, 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(),
};
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 = {
query: databaseClient.query,
mutation: databaseClient.mutation,
auth: setupActionAuth(requestId),
};
const result = await Promise.resolve(func(ctx, ...(args as any)));
return JSON.stringify(convexToJson(result === undefined ? null : result));
}
/**
* Define function 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;
};