Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 46 additions & 56 deletions src/authorized.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
getMutationUserResolver,
getQueryUserResolver,
} from './runtime';
import { toAuthContext } from './types';
import type {
AuthContext,
ConvexLibConfig,
Expand Down Expand Up @@ -219,14 +220,6 @@ const missingPermissionCheckerMessage = (
: '`runtime.action.permissionChecker`, `permissionCheckerAction`, or `permissionChecker`'
}.`;

const toAuthContext = <User extends ConvexLibUser>(
user: User,
): AuthContext<User> => ({
user,
userId: user._id,
role: user.role,
});

const getPermissionCheckerForQuery = <
User extends ConvexLibUser,
DataModel extends GenericDataModel,
Expand All @@ -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>,
DataModel,
User['role']
>;
})();
return checker as PermissionChecker<
GenericQueryCtx<DataModel>,
DataModel,
User['role']
>;
};

const getPermissionCheckerForMutation = <
User extends ConvexLibUser,
Expand All @@ -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>,
DataModel,
User['role']
>;
})();
return checker as PermissionChecker<
GenericMutationCtx<DataModel>,
DataModel,
User['role']
>;
};

const getPermissionCheckerForAction = <
User extends ConvexLibUser,
Expand All @@ -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<DataModel>,
GenericDataModel,
User['role']
>;
})();
return checker as PermissionChecker<
GenericActionCtx<DataModel>,
GenericDataModel,
User['role']
>;
};

const resolveAuthorizedQueryContext = async <
User extends ConvexLibUser,
Expand Down
11 changes: 4 additions & 7 deletions src/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,10 @@ export const createCapabilityChecker = <
role: Role,
): Promise<Record<Key, boolean>> => {
const keys = Object.keys(config.registry) as Key[];
const results = {} as Record<Key, boolean>;

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<Key, boolean>;
};

const keys = Object.keys(config.registry) as readonly Key[];
Expand Down
108 changes: 49 additions & 59 deletions src/primitives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -197,14 +198,6 @@ export interface CapabilityPrimitivesConfig<
>;
}

const toAuthContext = <User extends ConvexLibUser>(
user: User,
): AuthContext<User> => ({
user,
userId: user._id,
role: user.role,
});

const resolveQueryAuthContext = async <
User extends ConvexLibUser,
DataModel extends GenericDataModel,
Expand Down Expand Up @@ -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<DataModel>,
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<DataModel>,
TRegistry,
User['role']
>;
};

const getCapabilityCheckerForMutation = <
User extends ConvexLibUser,
Expand All @@ -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<DataModel>,
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<DataModel>,
TRegistry,
User['role']
>;
};

const getCapabilityCheckerForAction = <
User extends ConvexLibUser,
Expand All @@ -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<DataModel>,
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<DataModel>,
TRegistry,
User['role']
>;
};

const hasCapabilityChecker = <
User extends ConvexLibUser,
Expand Down
8 changes: 8 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ export type AuthContext<User extends ConvexLibUser> = {
role: User['role'];
};

export const toAuthContext = <User extends ConvexLibUser>(
user: User,
): AuthContext<User> => ({
user,
userId: user._id,
role: user.role,
});

export type OwnedQuery<DataModel extends GenericDataModel> = <
TableName extends TableNamesInDataModel<DataModel>,
>(
Expand Down
4 changes: 3 additions & 1 deletion src/zod-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>(value => typeof value === 'string');
Expand Down
Loading