Files
nest/packages/core/guards/guards-context-creator.ts
2026-02-15 13:07:08 +01:00

126 lines
3.4 KiB
TypeScript

import type { CanActivate } from '@nestjs/common';
import { iterate } from 'iterare';
import { ApplicationConfig } from '../application-config.js';
import { ContextCreator } from '../helpers/context-creator.js';
import { STATIC_CONTEXT } from '../injector/constants.js';
import { NestContainer } from '../injector/container.js';
import { InstanceWrapper } from '../injector/instance-wrapper.js';
import {
GUARDS_METADATA,
type Controller,
isEmpty,
isFunction,
} from '@nestjs/common/internal';
import type { Type } from '@nestjs/common';
export class GuardsContextCreator extends ContextCreator {
private moduleContext: string;
constructor(
private readonly container: NestContainer,
private readonly config?: ApplicationConfig,
) {
super();
}
public create(
instance: Controller,
callback: (...args: unknown[]) => unknown,
module: string,
contextId = STATIC_CONTEXT,
inquirerId?: string,
): CanActivate[] {
this.moduleContext = module;
return this.createContext(
instance,
callback,
GUARDS_METADATA,
contextId,
inquirerId,
);
}
public createConcreteContext<T extends unknown[], R extends unknown[]>(
metadata: T,
contextId = STATIC_CONTEXT,
inquirerId?: string,
): R {
if (isEmpty(metadata)) {
return [] as unknown[] as R;
}
return iterate(metadata)
.filter((guard: any) => guard && (guard.name || guard.canActivate))
.map(guard =>
this.getGuardInstance(guard as Function, contextId, inquirerId),
)
.filter(
(guard: CanActivate | null) => !!guard && isFunction(guard.canActivate),
)
.toArray() as R;
}
public getGuardInstance(
metatype: Function | CanActivate,
contextId = STATIC_CONTEXT,
inquirerId?: string,
): CanActivate | null {
const isObject = !!(metatype as CanActivate).canActivate;
if (isObject) {
return metatype as CanActivate;
}
const instanceWrapper = this.getInstanceByMetatype(
metatype as Type<unknown>,
);
if (!instanceWrapper) {
return null;
}
const instanceHost = instanceWrapper.getInstanceByContextId(
this.getContextId(contextId, instanceWrapper),
inquirerId,
);
return instanceHost && instanceHost.instance;
}
public getInstanceByMetatype(
metatype: Type<unknown>,
): InstanceWrapper | undefined {
if (!this.moduleContext) {
return;
}
const collection = this.container.getModules();
const moduleRef = collection.get(this.moduleContext);
if (!moduleRef) {
return;
}
const injectables = moduleRef.injectables;
return injectables.get(metatype);
}
public getGlobalMetadata<T extends unknown[]>(
contextId = STATIC_CONTEXT,
inquirerId?: string,
): T {
if (!this.config) {
return [] as unknown[] as T;
}
const globalGuards = this.config.getGlobalGuards() as T;
if (contextId === STATIC_CONTEXT && !inquirerId) {
return globalGuards;
}
const scopedGuardWrappers =
this.config.getGlobalRequestGuards() as InstanceWrapper[];
const scopedGuards = iterate(scopedGuardWrappers)
.map(wrapper =>
wrapper.getInstanceByContextId(
this.getContextId(contextId, wrapper),
inquirerId,
),
)
.filter(host => !!host)
.map(host => host.instance)
.toArray();
return globalGuards.concat(scopedGuards) as T;
}
}