UNPKG

@net-vert/core

Version:

Dependency Inversion Network Library with Type-Safe Injection.

425 lines (361 loc) 13.3 kB
import { AnyRecord } from 'store-vert'; import { EnhancedStore } from 'store-vert'; import { Key as Key_2 } from 'store-vert'; import { Store } from 'store-vert'; import { StoreFactory } from 'store-vert'; import { StoreKey } from 'store-vert'; import { TaskQueue } from 'id-queue'; export declare type BaseRequestor = (config: RequestConfig<any>) => any; /** * 缓存中间件 * 支持: * - 自定义缓存 key 生成 * - 自定义缓存有效期(固定时长或动态计算) * - 自定义缓存有效性校验 * - 自定义存储介质 */ export declare const cache: <D = any, R = any>(options?: Partial<CacheOptions<D, R>>) => CacheMiddleware<D, R>; /** 请求前上下文:检查缓存是否有效 */ declare interface CacheCheckContext<D = any, R = any> { key: CacheKey; config: RequestConfig<D>; cachedData?: R; } /** * 缓存 + 幂等组合配置(扁平化) */ export declare type CachedIdempotentConfig<D = any, R = any> = FlattenWithInstanceKey<[ CacheOptions<D, R>, IdempotencyOptions<D> ]>; /** 缓存 key 类型 */ export declare type CacheKey = string | number | symbol; /** 请求前上下文:生成缓存 key */ declare interface CacheKeyContext<D = any> { config: RequestConfig<D>; } /** 缓存中间件类型(带 storage 实例)*/ declare type CacheMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.CACHE, D, R> & { storage: CacheStorageInstance<R>; }; /** 缓存模块配置 */ declare interface CacheOptions<D = any, R = any> { /** * 缓存 key 生成函数 * 默认使用 method + url 哈希 */ key: (ctx: CacheKeyContext<D>) => CacheKey; /** * 缓存有效期 * - number: 固定毫秒数 * - function: 可根据请求或响应动态计算 */ duration: number | ((ctx: CacheUpdateContext<D, R>) => number); /** * 判断缓存是否有效(请求前) * - 可以根据现有缓存数据或其他条件动态判断 * - 返回 boolean 或 Promise<boolean> */ isValid: (ctx: CacheCheckContext<D, R>) => boolean | Promise<boolean>; /** 缓存介质 */ store: StoreDescriptor; } declare type CacheSchema<R> = Record<CacheKey, R>; declare type CacheStorageInstance<R = any> = ExpirableCacheStorage<R> & EnhancedStore<ExpirableSchema<CacheSchema<R>>>; /** 请求后上下文:更新缓存 */ declare interface CacheUpdateContext<D = any, R = any> { key: CacheKey; config: RequestConfig<D>; cachedData?: R; response: R; } export declare const concurrent: <D = any, R = any>(options?: Partial<ConcurrentOptions<D>>) => ConcurrentMiddleware<D, R>; declare type ConcurrentContext<D = any> = { config: RequestConfig<D>; }; declare type ConcurrentMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.CONCURRENT, D, R> & { pool: ConcurrentPool; }; declare type ConcurrentOptions<D = any> = { parallelCount: number; createId: (params: ConcurrentContext<D>) => Id; }; declare class ConcurrentPool<T extends any = any> { parallelCount: number; tasks: TaskItemList<T>; runningCount: number; constructor(parallelCount?: number); add(id: Id, task: Task<T>): Promise<T>; remove(id: Id): void; execute(currentTask: TaskItem<T>): Promise<void>; _run(): void; } /** * 并发 + 重试组合配置(扁平化) */ export declare type ConcurrentRetryConfig<D = any> = FlattenWithInstanceKey<[ ConcurrentOptions<D>, RetryOptions<D> ]>; /** * 创建带缓存和幂等的请求器 * 适用场景:数据查询接口,既需要缓存提升性能,又要避免重复请求 * @param config 组合配置对象 */ export declare function createCachedIdempotentRequestor<D = any, R = any>(config: CachedIdempotentConfig<D, R>): Requestor; /** * 创建带并发控制和重试的请求器 * 适用场景:批量请求场景,需要控制并发数量,失败后自动重试 * @param config 组合配置对象 */ export declare function createConcurrentRetryRequestor<D = any>(config: ConcurrentRetryConfig<D>): Requestor; declare const createPromiseCache: () => { getPromise: <T = unknown>(key: SafeKey) => Promise<T> | undefined; setPromise: <T = unknown>(key: SafeKey, promise: Promise<T>) => void; delPromise: (key: SafeKey) => boolean; clearCache: () => void; }; /** * 创建请求器 * @param config 配置对象(可选) * @returns 返回 Requestor 实例(所有方法都返回 Promise) */ export declare function createRequestor<const Extensions extends readonly Middleware[] = []>(config?: CreateRequestorConfig<Extensions>): Requestor; export declare interface CreateRequestorConfig<Extensions extends readonly Middleware[] = readonly Middleware[]> { extensions?: Extensions; instanceKey?: Key; } declare class ExpirableCacheStorage<R = any> { store: EnhancedStore<ExpirableSchema<CacheSchema<R>>>; constructor(store: StoreDescriptor); /** * 设置缓存(自动包装成 ExpirableValue) * @param key 缓存 key * @param value 要缓存的值 * @param duration 过期时长(毫秒),默认 24 小时 */ setCache(key: CacheKey, value: R, duration?: number): void; /** * 获取缓存值(检查过期,如果过期返回 undefined) * @param key 缓存 key * @returns 未过期返回值,已过期返回 undefined */ getCache(key: CacheKey): Promise<R | undefined>; /** * 检查是否有有效的缓存(未过期) * @param key 缓存 key * @returns true 表示有有效缓存,false 表示无缓存或已过期 */ hasValidCache(key: CacheKey): Promise<boolean>; } /** * 将 Schema 的所有值类型映射为 ExpirableValue 包装的版本 * 用于缓存存储的类型转换 */ export declare type ExpirableSchema<Schema extends AnyRecord> = { [K in keyof Schema]: ExpirableValue<Schema[K]>; }; /** * 带过期时间的值类型(通用型) * 可用于缓存、幂等、同步等需要时间控制的场景 */ export declare type ExpirableValue<T = any> = { value: T; expireAt: number; }; /** * 扁平化多个对象类型 * @template Types - 需要扁平化的对象类型元组 * @example * ```ts * type Result = Flatten<[{ a: string }, { b: number }, { c: boolean }]> * // Result = { a: string } & { b: number } & { c: boolean } * ``` */ export declare type Flatten<Types extends readonly any[]> = UnionToIntersection<Types[number]>; /** * 组合工具:扁平化多个对象类型并添加 instanceKey * @template Types - 需要扁平化的对象类型元组 * @example * ```ts * type Result = FlattenWithInstanceKey<[TypeA, TypeB, TypeC]> * // Result = TypeA & TypeB & TypeC & { instanceKey?: Key } * ``` */ export declare type FlattenWithInstanceKey<Types extends readonly any[]> = WithInstanceKey<Flatten<Types>>; export declare type HandlerParams<T extends keyof Requestor> = Parameters<Requestor[T]>; declare type Id = string | number; declare type IdempotencyContext<D = any> = { config: RequestConfig<D>; }; declare type IdempotencyOptions<D = any> = { key: (params: IdempotencyContext<D>) => string; }; export declare const idempotent: <D = any, R = any>(options?: Partial<IdempotencyOptions<D>>) => IdempotentMiddleware<D, R>; declare type IdempotentMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.IDEMPOTENT, D, R> & { promiseCache: PromiseCache; }; export declare const inject: (requestor: BaseRequestor, instanceKey?: string) => void; export declare type Key = string | symbol | number; export declare type Middleware<D = any, R = any> = (context: { config: RequestConfig<D>; next: () => Promise<R>; ctx: MiddlewareContext; }) => Promise<R>; declare enum MIDDLEWARE_TYPE { CACHE = "cache", RETRY = "retry", IDEMPOTENT = "idempotent", CONCURRENT = "concurrent", THROTTLE = "throttle" } export declare interface MiddlewareContext extends Record<string, any> { } declare type MiddlewareType = MIDDLEWARE_TYPE; declare type PromiseCache = ReturnType<typeof createPromiseCache>; declare enum REQUEST_METHOD { GET = "get", POST = "post", PUT = "put", DELETE = "delete" } export declare interface RequestConfig<D = any> extends Record<string, any> { url: string; method: RequestMethod; data?: D; } declare type RequestMethod = REQUEST_METHOD; export declare interface Requestor { request: <R = any, D = any>(config: RequestConfig<D>) => Promise<R>; get: <R = any, D = any>(url: string, config?: WithoutMethod<D>) => Promise<R>; post: <R = any, D = any>(url: string, data?: D, config?: WithoutMethod<D>) => Promise<R>; put: <R = any, D = any>(url: string, data?: D, config?: WithoutMethod<D>) => Promise<R>; delete: <R = any, D = any>(url: string, config?: WithoutMethod<D>) => Promise<R>; } export declare const retry: <D = any, R = any>(options?: Partial<RetryOptions<D>>) => TypedMiddleware<MIDDLEWARE_TYPE.RETRY, D, R>; declare type RetryContext<D = any> = { config: RequestConfig<D>; lastResponse: any; attempt: number; }; declare type RetryOptions<D = any> = { retries: number; delay: number | ((params: RetryContext<D>) => number); retryCondition: (params: RetryContext<D>) => boolean; }; declare type SafeKey = string | number | symbol; export declare type StoreDescriptor = StoreKey | { key: Key_2; factory: StoreFactory<Store<AnyRecord>, any[]>; }; declare type Task<T> = () => Promise<T>; declare type TaskItem<T> = { task: Task<T>; resolve: (value: T) => void; reject: (reason: any) => void; }; declare type TaskItemList<T> = TaskQueue<TaskItem<T>>; /** * 节流中间件 * * 确保所有请求按照最小间隔时间排队执行 * * @example * ```typescript * // 创建节流中间件,每次请求最少间隔 1 秒 * const throttleMiddleware = throttle({ interval: 1000 }) * * // 带超时控制,超过 5 秒丢弃请求 * const throttleMiddleware = throttle({ * interval: 1000, * timeout: 5000 * }) * * // 所有使用该中间件的请求共享同一个节流器 * const api1 = createRequest(config1, [throttleMiddleware]) * const api2 = createRequest(config2, [throttleMiddleware]) * * // 组合使用 * const api3 = createRequest(config3, [ * cache({ duration: 5000 }), // 优先走缓存 * idempotent(), // 去重相同请求 * throttle({ interval: 1000 }), // 限制请求速率 * retry({ retries: 3 }) // 失败重试 * ]) * * // 查看节流器状态 * throttleMiddleware.throttler.getStatus() * ``` */ export declare const throttle: <D = any, R = any>(options?: Partial<ThrottleOptions>) => ThrottleMiddleware<D, R>; /** * 节流中间件类型 */ declare type ThrottleMiddleware<D = any, R = any> = Middleware<D, R> & { __middlewareType: MIDDLEWARE_TYPE.THROTTLE; throttler: Throttler; }; /** * 节流中间件配置 */ declare interface ThrottleOptions { /** * 最小请求间隔(毫秒) * @default 1000 */ interval: number; /** * 队列超时时间(毫秒) * 如果请求在队列中等待超过此时间,将被拒绝并抛出 ThrottleTimeoutError * - 不设置(undefined):永不超时,所有请求都会执行 * - 设为 0:立即超时,直接拒绝排队的请求 * - 设为正数:等待指定时间后超时 * @default undefined */ timeout?: number; } /** * 节流器接口 */ declare interface Throttler { /** 添加任务到队列 */ add: <T>(task: () => Promise<T>) => Promise<T>; /** 获取节流器状态 */ getStatus: () => ThrottlerStatus; /** 清空队列(慎用) */ clear: () => void; } /** * 节流器状态 */ declare interface ThrottlerStatus { /** 当前队列长度 */ queueLength: number; /** 上次执行时间戳 */ lastExecutionTime: number; /** 是否正在处理队列 */ isProcessing: boolean; /** 预计下次执行时间 */ nextExecutionTime: number | null; } export declare type TypedMiddleware<Type extends MiddlewareType, D = any, R = any> = Middleware<D, R> & { __middlewareType: Type; }; /* Excluded from this release type: UnionToIntersection */ export declare const useRequestor: (instanceKey?: Key) => BaseRequestor; /** * 给类型添加可选的 instanceKey 字段 * @template T - 源对象类型 * @example * ```ts * type Config = { timeout: number } * type Result = WithInstanceKey<Config> * // Result = { timeout: number; instanceKey?: Key } * ``` */ export declare type WithInstanceKey<T> = T & { /** 请求器实例 key(可选) */ instanceKey?: Key; }; export declare type WithoutMethod<D = any> = Omit<RequestConfig<D>, 'method' | 'url'>; export { }