import type { RequestEventType, RequestProgressEventType, RequestResponseEventType } from "managers"; import type { RequestInstance } from "./request.types"; type HookName = | "onBeforeSent" | "onRequestStart" | "onResponseStart" | "onUploadProgress" | "onDownloadProgress" | "onResponse" | "onRemove"; export interface RequestHooks { onBeforeSent: (cb: (eventData: RequestEventType) => void) => () => void; onRequestStart: (cb: (eventData: RequestEventType) => void) => () => void; onResponseStart: (cb: (eventData: RequestEventType) => void) => () => void; onUploadProgress: (cb: (eventData: RequestProgressEventType) => void) => () => void; onDownloadProgress: (cb: (eventData: RequestProgressEventType) => void) => () => void; onResponse: (cb: (eventData: RequestResponseEventType) => void) => () => void; onRemove: (cb: (eventData: RequestEventType) => void) => () => void; /** @internal Invoke all registered listeners for a given hook */ __emit: (name: HookName, data: any) => void; /** @internal Get a snapshot of all registered listeners (used by clone) */ __snapshot: () => Record void>>; } const HOOK_NAMES: HookName[] = [ "onBeforeSent", "onRequestStart", "onResponseStart", "onUploadProgress", "onDownloadProgress", "onResponse", "onRemove", ]; export function createRequestHooks( initial?: Record void>>, ): RequestHooks { const listeners: Record void>> = { onBeforeSent: [], onRequestStart: [], onResponseStart: [], onUploadProgress: [], onDownloadProgress: [], onResponse: [], onRemove: [], }; if (initial) { HOOK_NAMES.forEach((name) => { listeners[name] = [...initial[name]]; }); } const subscribe = (name: HookName) => { return (cb: (...args: any[]) => void) => { listeners[name].push(cb); return () => { const idx = listeners[name].indexOf(cb); if (idx !== -1) listeners[name].splice(idx, 1); }; }; }; return { onBeforeSent: subscribe("onBeforeSent"), onRequestStart: subscribe("onRequestStart"), onResponseStart: subscribe("onResponseStart"), onUploadProgress: subscribe("onUploadProgress"), onDownloadProgress: subscribe("onDownloadProgress"), onResponse: subscribe("onResponse"), onRemove: subscribe("onRemove"), __emit(name: HookName, data: any) { listeners[name].forEach((cb) => { cb(data); }); }, __snapshot() { const snap = {} as Record void>>; HOOK_NAMES.forEach((name) => { snap[name] = [...listeners[name]]; }); return snap; }, }; }