UNPKG

@net-vert/core

Version:

Dependency Inversion Network Library with Type-Safe Injection.

367 lines (300 loc) 12.5 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, false, 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, false, 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<false>; /** * 创建带并发控制和重试的请求器 * 适用场景:批量请求场景,需要控制并发数量,失败后自动重试 * @param config 组合配置对象 */ export declare function createConcurrentRetryRequestor<D = any>(config: ConcurrentRetryConfig<D>): Requestor<false>; 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; }; export declare function createRequestor<const Extensions extends readonly Middleware[]>(config: CreateRequestorConfig<Extensions> & { extensions: Extensions; }): Requestor<HasSyncMiddleware<Extensions>>; export declare function createRequestor(config?: CreateRequestorConfig): Requestor<false>; 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]>; export declare type HasSyncMiddleware<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? First extends TypedMiddleware<MIDDLEWARE_TYPE.SYNC, true, any, any> ? true : HasSyncMiddleware<Rest> : false; 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, false, D, R> & { promiseCache: PromiseCache; }; export declare const inject: (requestor: BaseRequestor, instanceKey?: string) => void; export declare type Key = string | symbol | number; export declare type MaybePromise<IsSync, R> = IsSync extends true ? R : IsSync extends false ? Promise<R> : R | Promise<R>; export declare type Middleware<IsSync extends boolean = false, D = any, R = any> = (context: { config: RequestConfig<D>; next: () => MaybePromise<IsSync, R>; ctx: MiddlewareContext; }) => MaybePromise<IsSync, R>; declare enum MIDDLEWARE_TYPE { CACHE = "cache", RETRY = "retry", IDEMPOTENT = "idempotent", CONCURRENT = "concurrent", SYNC = "sync" } 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<IsSync extends boolean = false> { request: <R = any, D = any>(config: RequestConfig<D>) => MaybePromise<IsSync, R>; get: <R = any, D = any>(url: string, config?: WithoutMethod<D>) => MaybePromise<IsSync, R>; post: <R = any, D = any>(url: string, data?: D, config?: WithoutMethod<D>) => MaybePromise<IsSync, R>; put: <R = any, D = any>(url: string, data?: D, config?: WithoutMethod<D>) => MaybePromise<IsSync, R>; delete: <R = any, D = any>(url: string, config?: WithoutMethod<D>) => MaybePromise<IsSync, R>; } export declare const retry: <D = any, R = any>(options?: Partial<RetryOptions<D>>) => TypedMiddleware<MIDDLEWARE_TYPE.RETRY, false, 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[]>; }; /** * 缓存中有数据则直接返回。 * suspense 为 true 时,会抛出一个 Promise(而不是普通错误),Promise resolve 后得到数据。 * suspense 为 false 时,会返回一个 Promise,Promise resolve 后得到数据,调用者需要用 await 或 .then 捕获。 */ export declare function sync<D = any, R = any>(options: Partial<SyncOptions<D>> & { suspense: true; }): TypedMiddleware<MIDDLEWARE_TYPE.SYNC, true, D, R>; export declare function sync<D = any, R = any>(options: Partial<SyncOptions<D>> & { suspense: false; }): TypedMiddleware<MIDDLEWARE_TYPE.SYNC, any, D, R>; export declare function sync<D = any, R = any>(options?: Partial<SyncOptions<D>>): TypedMiddleware<MIDDLEWARE_TYPE.SYNC, true, D, R>; declare interface SyncOptions<D = any, R = any> extends CacheOptions<D, R> { isValid: (ctx: CacheCheckContext<D, R>) => boolean; suspense: boolean; wrapSuspense?: (params: WrapSuspense<D, R>) => 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>>; export declare type TypedMiddleware<Type extends MiddlewareType, IsSync extends boolean = false, D = any, R = any> = Middleware<IsSync, 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'>; declare type WrapSuspense<D = any, R = any> = { key: CacheKey; config: RequestConfig<D>; p: Promise<R>; }; export { }