import { isThenable, type MaybePromise, type PothosOutputFieldConfig, type SchemaTypes, } from '@pothos/core'; import type { GraphQLResolveInfo } from 'graphql'; import type { PothosScopeAuthPlugin, UnauthorizedErrorFn } from '.'; import { ForbiddenError } from './errors'; import RequestCache from './request-cache'; import { AuthScopeFailureType, type ResolveStep, type UnauthorizedResolver } from './types'; const defaultUnauthorizedResolver: UnauthorizedResolver = ( _root, _args, _context, _info, error, ) => { throw error; }; export function resolveHelper( steps: ResolveStep[], plugin: PothosScopeAuthPlugin, fieldConfig: PothosOutputFieldConfig, ) { const unauthorizedResolver = fieldConfig.pothosOptions.unauthorizedResolver ?? defaultUnauthorizedResolver; const globalUnauthorizedError = plugin.builder.options.scopeAuth?.unauthorizedError; const defaultUnauthorizedError: UnauthorizedErrorFn = ( parent, _args, context, info, result, ) => { if (globalUnauthorizedError) { return globalUnauthorizedError(parent, context, info, result); } if ( (result.failure.kind === AuthScopeFailureType.AuthScope || result.failure.kind === AuthScopeFailureType.AuthScopeFunction) && result.failure.error ) { return result.failure.error; } return result.message; }; const createError: UnauthorizedErrorFn = fieldConfig.pothosOptions.unauthorizedError ?? defaultUnauthorizedError; return (parent: unknown, args: {}, context: Types['Context'], info: GraphQLResolveInfo) => { let resolvedValue: unknown; const cache = RequestCache.fromContext(context, plugin.builder); function runSteps(index: number): MaybePromise { for (let i = index; i < steps.length; i += 1) { const { run, errorMessage } = steps[i]; const stepResult = run(cache, parent, args, context, info, (val) => { resolvedValue = val; }); if (isThenable(stepResult)) { return stepResult.then((result) => { if (result) { const error = createError(parent as object, args, context, info, { message: typeof errorMessage === 'function' ? errorMessage(parent, args, context, info) : errorMessage, failure: result, }); return unauthorizedResolver( parent as never, args, context as never, info, typeof error === 'string' ? new ForbiddenError(error, result) : error, ); } return runSteps(i + 1); }); } if (stepResult) { const error = createError(parent as object, args, context, info, { message: typeof errorMessage === 'function' ? errorMessage(parent, args, context, info) : errorMessage, failure: stepResult, }); return unauthorizedResolver( parent as never, args, context as never, info, typeof error === 'string' ? new ForbiddenError(error, stepResult) : error, ); } } return resolvedValue; } return runSteps(0); }; }