export type TChallengeJsonPrimitive = string | number | boolean | null; export type TChallengeJsonValue = | TChallengeJsonPrimitive | TChallengeJsonValue[] | { [key: string]: TChallengeJsonValue }; export type TChallengeSettings = Record; export type TChallengeDecisionAction = 'allow' | 'bypass' | 'challenge' | 'deny'; export type TChallengeResponseFormat = 'html' | 'json'; export interface IChallengeApplyTo { methods?: string[]; browserNavigationsOnly?: boolean; includePaths?: string[]; excludePaths?: string[]; } export interface IChallengeClearanceConfig { ttlSeconds?: number; bindToHost?: boolean; bindToRoute?: boolean; bindToIp?: boolean; } /** * Serializable route intent. This shape must not contain deployment wiring or secrets. */ export interface IRouteChallengeConfig { providerId: string; challengeType: string; policyRef?: string; settings?: TChallengeSettings; applyTo?: IChallengeApplyTo; clearance?: IChallengeClearanceConfig; } export interface IChallengeTypeManifest { challengeType: string; label: string; description?: string; settingsSchema?: TChallengeSettings; } export interface IChallengeProviderManifest { providerId: string; label: string; description?: string; challengeTypes: IChallengeTypeManifest[]; } export interface IChallengeRequestContext { requestId?: string; method: string; url: string; path: string; host?: string; headers?: Record; clientIp?: string; routeId?: string; routeName?: string; isTls?: boolean; timestamp?: number; } export interface IChallengeClearanceContext { valid: boolean; expiresAt?: number; reason?: string; } export interface IChallengeAssessRequest { challenge: IRouteChallengeConfig; context: IChallengeRequestContext; clearance?: IChallengeClearanceContext; } export interface IChallengeDecisionBase { action: TChallengeDecisionAction; reason?: string; } export interface IChallengeAllowDecision extends IChallengeDecisionBase { action: 'allow' | 'bypass'; } export interface IChallengeChallengeDecision extends IChallengeDecisionBase { action: 'challenge'; challengeId: string; statusCode?: number; format?: TChallengeResponseFormat; data?: TChallengeSettings; } export interface IChallengeDenyDecision extends IChallengeDecisionBase { action: 'deny'; statusCode: number; body?: string; headers?: Record; } export type IChallengeDecision = | IChallengeAllowDecision | IChallengeChallengeDecision | IChallengeDenyDecision; export interface IChallengeRenderRequest { challenge: IRouteChallengeConfig; context: IChallengeRequestContext; challengeId: string; data?: TChallengeSettings; } export interface IChallengeRenderResponse { statusCode: number; headers?: Record; body: string; format: TChallengeResponseFormat; } export interface IChallengeVerifyRequest { challenge: IRouteChallengeConfig; context: IChallengeRequestContext; challengeId: string; payload?: TChallengeSettings; } export interface IChallengeVerifyResult { success: boolean; reason?: string; clearanceTtlSeconds?: number; data?: TChallengeSettings; } export interface IChallengeType { challengeType: string; getManifest(): IChallengeTypeManifest; assess(requestArg: IChallengeAssessRequest): Promise; render(requestArg: IChallengeRenderRequest): Promise; verify(requestArg: IChallengeVerifyRequest): Promise; } export interface IChallengeProvider { providerId: string; getManifest(): Promise; assess(requestArg: IChallengeAssessRequest): Promise; render(requestArg: IChallengeRenderRequest): Promise; verify(requestArg: IChallengeVerifyRequest): Promise; }