diff --git a/src/authorized.ts b/src/authorized.ts index 84cc4b2..f5cc5f5 100644 --- a/src/authorized.ts +++ b/src/authorized.ts @@ -23,6 +23,7 @@ import { getMutationUserResolver, getQueryUserResolver, } from './runtime'; +import { toAuthContext } from './types'; import type { AuthContext, ConvexLibConfig, @@ -219,14 +220,6 @@ const missingPermissionCheckerMessage = ( : '`runtime.action.permissionChecker`, `permissionCheckerAction`, or `permissionChecker`' }.`; -const toAuthContext = ( - user: User, -): AuthContext => ({ - user, - userId: user._id, - role: user.role, -}); - const getPermissionCheckerForQuery = < User extends ConvexLibUser, DataModel extends GenericDataModel, @@ -241,23 +234,22 @@ const getPermissionCheckerForQuery = < MutationVisibility, ActionVisibility >, -) => - (() => { - const checker = - config.runtime?.query?.permissionChecker ?? - config.permissionCheckerQuery ?? - config.permissionChecker; - - if (!checker) { - throw new Error(missingPermissionCheckerMessage('query')); - } +) => { + const checker = + config.runtime?.query?.permissionChecker ?? + config.permissionCheckerQuery ?? + config.permissionChecker; + + if (!checker) { + throw new Error(missingPermissionCheckerMessage('query')); + } - return checker as PermissionChecker< - GenericQueryCtx, - DataModel, - User['role'] - >; - })(); + return checker as PermissionChecker< + GenericQueryCtx, + DataModel, + User['role'] + >; +}; const getPermissionCheckerForMutation = < User extends ConvexLibUser, @@ -273,23 +265,22 @@ const getPermissionCheckerForMutation = < MutationVisibility, ActionVisibility >, -) => - (() => { - const checker = - config.runtime?.mutation?.permissionChecker ?? - config.permissionCheckerMutation ?? - config.permissionChecker; - - if (!checker) { - throw new Error(missingPermissionCheckerMessage('mutation')); - } +) => { + const checker = + config.runtime?.mutation?.permissionChecker ?? + config.permissionCheckerMutation ?? + config.permissionChecker; + + if (!checker) { + throw new Error(missingPermissionCheckerMessage('mutation')); + } - return checker as PermissionChecker< - GenericMutationCtx, - DataModel, - User['role'] - >; - })(); + return checker as PermissionChecker< + GenericMutationCtx, + DataModel, + User['role'] + >; +}; const getPermissionCheckerForAction = < User extends ConvexLibUser, @@ -305,23 +296,22 @@ const getPermissionCheckerForAction = < MutationVisibility, ActionVisibility >, -) => - (() => { - const checker = - config.runtime?.action?.permissionChecker ?? - config.permissionCheckerAction ?? - config.permissionChecker; - - if (!checker) { - throw new Error(missingPermissionCheckerMessage('action')); - } +) => { + const checker = + config.runtime?.action?.permissionChecker ?? + config.permissionCheckerAction ?? + config.permissionChecker; + + if (!checker) { + throw new Error(missingPermissionCheckerMessage('action')); + } - return checker as PermissionChecker< - GenericActionCtx, - GenericDataModel, - User['role'] - >; - })(); + return checker as PermissionChecker< + GenericActionCtx, + GenericDataModel, + User['role'] + >; +}; const resolveAuthorizedQueryContext = async < User extends ConvexLibUser, diff --git a/src/capabilities.ts b/src/capabilities.ts index 8a6e690..2285990 100644 --- a/src/capabilities.ts +++ b/src/capabilities.ts @@ -164,13 +164,10 @@ export const createCapabilityChecker = < role: Role, ): Promise> => { const keys = Object.keys(config.registry) as Key[]; - const results = {} as Record; - - for (const key of keys) { - results[key] = await has(ctx, role, key); - } - - return results; + const entries = await Promise.all( + keys.map(async key => [key, await has(ctx, role, key)] as const), + ); + return Object.fromEntries(entries) as Record; }; const keys = Object.keys(config.registry) as readonly Key[]; diff --git a/src/primitives.ts b/src/primitives.ts index e9bcfb7..ddb55e5 100644 --- a/src/primitives.ts +++ b/src/primitives.ts @@ -24,6 +24,7 @@ import { getMutationUserResolver, getQueryUserResolver, } from './runtime'; +import { toAuthContext } from './types'; import type { AuthContext, ConvexLibConfig, ConvexLibUser } from './types'; export type { ConvexLibConfig, ConvexLibUser } from './types'; @@ -197,14 +198,6 @@ export interface CapabilityPrimitivesConfig< >; } -const toAuthContext = ( - user: User, -): AuthContext => ({ - user, - userId: user._id, - role: user.role, -}); - const resolveQueryAuthContext = async < User extends ConvexLibUser, DataModel extends GenericDataModel, @@ -294,23 +287,22 @@ const getCapabilityCheckerForQuery = < ActionVisibility, TRegistry >, -) => - (() => { - const checker = - config.runtime?.query?.capabilityChecker ?? - config.capabilityCheckerQuery ?? - config.capabilityChecker; - - if (!checker) { - throw new Error(missingCapabilityCheckerMessage('query')); - } - - return checker as CapabilityChecker< - GenericQueryCtx, - TRegistry, - User['role'] - >; - })(); +) => { + const checker = + config.runtime?.query?.capabilityChecker ?? + config.capabilityCheckerQuery ?? + config.capabilityChecker; + + if (!checker) { + throw new Error(missingCapabilityCheckerMessage('query')); + } + + return checker as CapabilityChecker< + GenericQueryCtx, + TRegistry, + User['role'] + >; +}; const getCapabilityCheckerForMutation = < User extends ConvexLibUser, @@ -328,23 +320,22 @@ const getCapabilityCheckerForMutation = < ActionVisibility, TRegistry >, -) => - (() => { - const checker = - config.runtime?.mutation?.capabilityChecker ?? - config.capabilityCheckerMutation ?? - config.capabilityChecker; - - if (!checker) { - throw new Error(missingCapabilityCheckerMessage('mutation')); - } - - return checker as CapabilityChecker< - GenericMutationCtx, - TRegistry, - User['role'] - >; - })(); +) => { + const checker = + config.runtime?.mutation?.capabilityChecker ?? + config.capabilityCheckerMutation ?? + config.capabilityChecker; + + if (!checker) { + throw new Error(missingCapabilityCheckerMessage('mutation')); + } + + return checker as CapabilityChecker< + GenericMutationCtx, + TRegistry, + User['role'] + >; +}; const getCapabilityCheckerForAction = < User extends ConvexLibUser, @@ -362,23 +353,22 @@ const getCapabilityCheckerForAction = < ActionVisibility, TRegistry >, -) => - (() => { - const checker = - config.runtime?.action?.capabilityChecker ?? - config.capabilityCheckerAction ?? - config.capabilityChecker; - - if (!checker) { - throw new Error(missingCapabilityCheckerMessage('action')); - } - - return checker as CapabilityChecker< - GenericActionCtx, - TRegistry, - User['role'] - >; - })(); +) => { + const checker = + config.runtime?.action?.capabilityChecker ?? + config.capabilityCheckerAction ?? + config.capabilityChecker; + + if (!checker) { + throw new Error(missingCapabilityCheckerMessage('action')); + } + + return checker as CapabilityChecker< + GenericActionCtx, + TRegistry, + User['role'] + >; +}; const hasCapabilityChecker = < User extends ConvexLibUser, diff --git a/src/types.ts b/src/types.ts index 0b15985..5c7a131 100644 --- a/src/types.ts +++ b/src/types.ts @@ -35,6 +35,14 @@ export type AuthContext = { role: User['role']; }; +export const toAuthContext = ( + user: User, +): AuthContext => ({ + user, + userId: user._id, + role: user.role, +}); + export type OwnedQuery = < TableName extends TableNamesInDataModel, >( diff --git a/src/zod-helpers.ts b/src/zod-helpers.ts index 9a19e3d..2bf4e41 100644 --- a/src/zod-helpers.ts +++ b/src/zod-helpers.ts @@ -2,7 +2,9 @@ import { z } from 'zod'; /** * Create a Zod validator for a Convex document ID. - * The table name parameter is for documentation / type hinting only. + * Validation only checks that the value is a string; it does not verify the + * actual Convex ID format. The table name parameter is for documentation / + * type hinting only. */ export const zid = (_tableName: string) => z.custom(value => typeof value === 'string');