Skip to content

AppConfig

createApp()에 전달하는 설정 객체의 필드별 상세 설명.

ts
interface AppConfig {
  modules: Constructor[]
  guards?: IpcGuard[]
  pipes?: IpcPipe[]
  exceptionHandlers?: IpcExceptionHandler[]
  logger?: AppLogger
  onError?: (name: string, error: unknown) => void
}

필수 필드

modules

ts
modules: Constructor[]

@Module() 데코레이터가 적용된 모듈 클래스 배열. 배열 순서가 provider 등록 순서를 결정한다.

모듈 중 하나는 반드시 OnMainWindowCreate를 구현한 provider를 포함해야 한다. 메인 윈도우는 이 provider가 생성한다 (Lifecycle 참고).

모듈 A의 provider가 모듈 B의 provider를 inject()하려면 모듈 B가 먼저 나열되어야 한다:

ts
modules: [
  CoreModule,      // 먼저 등록
  FeatureModule,   // CoreModule의 provider를 inject 가능
]

선택 필드

guards

ts
guards?: IpcGuard[]

기본값: []

IPC 요청을 검증하는 Guard 인스턴스 배열. 배열 순서대로 canActivate()를 실행하며, 하나라도 false를 반환하면 요청을 거부한다.

ts
guards: [new SenderGuard(), new RateLimitGuard()]

pipes

ts
pipes?: IpcPipe[]

기본값: []

IPC 인자를 변환하거나 검증하는 Pipe 인스턴스 배열. Guard 통과 후, 핸들러 실행 전에 배열 순서대로 transform()을 실행한다. 각 Pipe의 반환값이 다음 Pipe의 입력이 된다.

글로벌 Pipe는 모든 IPC 요청에 적용된다. 특정 핸들러에만 적용하려면 @UsePipes() 데코레이터를 사용한다.

ts
pipes: [new ZodPipe()]

Pipe에서 throw하면 ExceptionHandler가 처리한다. Zod의 parse() 실패 등이 자연스럽게 에러 응답이 된다.

exceptionHandlers

ts
exceptionHandlers?: IpcExceptionHandler[]

기본값: []

Guard 실패 또는 핸들러 에러를 처리하는 ExceptionHandler 인스턴스 배열. Guard가 실패하거나 핸들러에서 에러가 발생하면 첫 번째 handler의 catch()가 호출된다. catch()IpcError ({ code, message })를 반환하고, 프레임워크가 { ok: false, error } 형태의 IpcResponse로 래핑하여 렌더러에 전달한다.

handler가 없으면 프레임워크가 기본 IpcError를 생성한다 (Guard 실패 시 UNAUTHORIZED, 핸들러 에러 시 INTERNAL_ERROR).

ts
exceptionHandlers: [new ErrorHandler()]

logger

ts
logger?: AppLogger

기본값: undefined (로깅 없음)

부트스트랩 과정의 로그를 출력하는 로거. info() 메서드만 요구한다.

ts
interface AppLogger {
  info(message: string): void
}
ts
logger: {
  info: (msg) => console.log(`[ipc] ${msg}`),
}

로깅 내용:

  • 모듈별 provider/controller 등록
  • IPC 채널 핸들러 등록
  • Lifecycle 단계 진행

onError

ts
onError?: (name: string, error: unknown) => void

기본값: undefined

Lifecycle 메서드(onInit, onWindowAttach, onDispose) 실행 중 에러가 발생했을 때 호출되는 콜백. 에러가 발생해도 나머지 provider의 lifecycle은 계속 실행된다. onMainWindowCreate는 예외로, 구현체 수가 1개가 아니면 부트스트랩 자체가 실패한다.

ts
onError: (name, error) => {
  logger.error(`Lifecycle error in ${name}:`, error);
}

name은 에러가 발생한 provider 클래스의 이름이다.