import { IOptions, IRules, ShieldRule } from './types'; /** * * @param ruleTree * @param options * * Generates middleware from given rules. * */ export function generateMiddlewareFromRuleTree>( ruleTree: IRules, options: IOptions, ) { return (opts: { next: Function; ctx: TContext; type: string; path: string; input: { [name: string]: any }; getRawInput: () => unknown; }) => { const { next, ctx, type, path, input, getRawInput } = opts; const rawInput = getRawInput(); const opWithPath: Array = path.split('.'); const opName: string = opWithPath[opWithPath.length - 1]; const keys = Object.keys(ruleTree); let rule: ShieldRule | undefined; if (keys.includes('query') || keys.includes('mutation')) { //@ts-ignore rule = ruleTree?.[type]?.[opName]; } else { const namespace = opWithPath[0]; const tree = (ruleTree as Record)[namespace]; if (tree?.[type]?.[opName]) { rule = tree?.[type]?.[opName]; } } rule = rule || options.fallbackRule; if (rule) { return rule?.resolve(ctx, type, path, input, rawInput, options).then((result) => { if (result instanceof Error) throw result; // Handle context extension if (typeof result === 'object' && result !== null && 'ctx' in result) { // Merge context extension and call next with updated context const extendedCtx = { ...ctx, ...result.ctx }; return next({ ctx: extendedCtx }); } if (!result) throw options.fallbackError; return next(); }); } return next(); }; }