@net-vert/core
Version:
Dependency Inversion Network Library with Type-Safe Injection.
367 lines (300 loc) • 12.5 kB
TypeScript
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 { }