Source

types.ts

import { Adapter, ConfigOf, ContextOf } from "@decaf-ts/core";
import { Constructor } from "@decaf-ts/decoration";
import { ExecutionContext, Type } from "@nestjs/common";
import {
  RequestToContextTransformer,
  type ModelControllerFactoryConfig,
  type AuthHandler as AuthHandlerBase,
} from "@decaf-ts/for-http/server";
import { DecafRequestContext } from "./request/index";

export interface DecafRequestHandler<
  C extends DecafRequestContext = DecafRequestContext,
> {
  handle(context: C, req: Request, res: Response): Promise<void>;
}

export interface ObserverEventsOptions {
  /**
   * Enables or disables SSE stream events globally
   */
  enableObserverEvents?: boolean;

  /**
   * Enables explicit subscription registration and per-subscriber filtering.
   * Broadcast remains the default when omitted or false.
   */
  subscriptionMode?: boolean;

  /**
   * List of adapter flavours that will emit stream events
   * If omitted, all registered flavours may be used
   */
  observerFlavours?: any[];

  /**
   * SSE endpoint path
   * @default "/events"
   */
  observerApiPath?: string;
}

/**
 * @publicApi
 */
export type DecafModuleOptions<
  CONF = any,
  A extends Adapter<CONF, any, any, any> = Adapter<CONF, any, any, any>,
> = {
  conf: [
    Constructor<A>,
    ConfigOf<A>,
    ...args:
      | any[]
      | [
          ...any[],
          (
            | RequestToContextTransformer<ContextOf<A>>
            | Constructor<RequestToContextTransformer<ContextOf<A>>>
          ),
        ],
  ][];
  alias?: string;
  autoControllers: boolean;
  autoServices?: boolean;
  controllerExposure?: Record<string, boolean | string[]>;
  controllerConfig?: Record<string, ModelControllerFactoryConfig>;
  observerOptions?: ObserverEventsOptions;
  aggregations?: boolean;
  handlers?: Type<DecafRequestHandler>[];
  initialization?: () => Promise<void>;
};

/**
 * NestJS-narrowed alias for the base {@link AuthHandlerBase} class from
 * `@decaf-ts/for-http/server`, specializing the execution context to
 * `ExecutionContext` and the request context to {@link DecafRequestContext}.
 *
 * Concrete handlers extend this class and override `extractFromRequest`.
 *
 * @example
 * export class CustomAuthHandler extends AuthHandler {
 *   protected extractFromRequest(request: any) {
 *     const req = ctx.switchToHttp().getRequest();
 *     const userRole = req.headers.authorization?.split(" ")[1] as string;
 *     if (!userRole) throw new AuthorizationError("Unauthenticated");
 *     return { user: userRole, roles: [userRole] };
 *   }
 * }
 *
 * // auth.module.ts
 * @Global()
 * @Module({
 *  providers: [
 *    AuthInterceptor,
 *    CustomAuthHandler,
 *    { provide: AUTH_HANDLER, useClass: CustomAuthHandler },
 *  ],
 *  exports: [AUTH_HANDLER, AuthInterceptor],
 * })
 * export class AuthModule {}
 */
export type AuthHandler<
  EC = ExecutionContext,
  C extends DecafRequestContext = DecafRequestContext,
> = AuthHandlerBase<EC, C>;