@qlover/fe-corekit 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { LoggerInterface } from '@qlover/logger';
1
2
  import { AxiosRequestConfig, AxiosStatic } from 'axios';
2
3
 
3
4
  /**
@@ -1909,6 +1910,781 @@ declare class SyncExecutor<ExecutorConfig extends ExecutorConfigInterface = Exec
1909
1910
  protected run<Result, Params = unknown>(data: Params, actualTask: SyncTask<Result, Params>): Result;
1910
1911
  }
1911
1912
 
1913
+ /**
1914
+ * Configuration interface for AbortPlugin
1915
+ *
1916
+ * Defines the parameters needed to control request cancellation behavior,
1917
+ * including identifiers, abort signals, timeout settings, and callback functions
1918
+ */
1919
+ interface AbortPluginConfig {
1920
+ /**
1921
+ * Unique identifier for the abort operation
1922
+ *
1923
+ * Used to identify and manage specific abort controller instances
1924
+ * If not provided, will use `requestId` or auto-generated value
1925
+ *
1926
+ * @optional
1927
+ * @example `"user-profile-fetch"`
1928
+ */
1929
+ id?: string;
1930
+ /**
1931
+ * Request unique identifier
1932
+ *
1933
+ * Alternative to `id`, used for identifying specific requests
1934
+ * Useful when tracking requests across different systems
1935
+ *
1936
+ * @optional
1937
+ * @example `"req_123456789"`
1938
+ */
1939
+ requestId?: string;
1940
+ /**
1941
+ * Callback function triggered when operation is aborted
1942
+ *
1943
+ * Receives the abort configuration (excluding the callback itself to prevent recursion)
1944
+ * Useful for cleanup operations or user notifications
1945
+ *
1946
+ * @optional
1947
+ * @example
1948
+ * ```typescript
1949
+ * onAborted: (config) => {
1950
+ * console.log(`Request ${config.id} was cancelled`);
1951
+ * // Perform cleanup operations
1952
+ * }
1953
+ * ```
1954
+ */
1955
+ onAborted?<T extends AbortPluginConfig>(config: T): void;
1956
+ /**
1957
+ * AbortSignal instance for request cancellation
1958
+ *
1959
+ * If not provided, the plugin will create and manage one automatically
1960
+ * Can be provided externally to integrate with existing abort mechanisms
1961
+ *
1962
+ * @optional
1963
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | AbortSignal MDN}
1964
+ */
1965
+ signal?: AbortSignal;
1966
+ /**
1967
+ * Timeout duration in milliseconds
1968
+ *
1969
+ * When set, the operation will be automatically aborted after this duration
1970
+ * Helps prevent hanging requests and manages resource cleanup
1971
+ *
1972
+ * @optional
1973
+ * @default `undefined` (no timeout)
1974
+ * @example `5000` // 5 seconds timeout
1975
+ * @example `30000` // 30 seconds timeout
1976
+ */
1977
+ abortTimeout?: number;
1978
+ }
1979
+ /**
1980
+ * Error identifier constant for abort-related errors
1981
+ *
1982
+ * Used to identify abort errors in error handling logic
1983
+ */
1984
+ declare const ABORT_ERROR_ID = "ABORT_ERROR";
1985
+ /**
1986
+ * Configuration extractor function type
1987
+ *
1988
+ * Extracts `AbortPluginConfig` from executor context parameters
1989
+ * Enables flexible configuration passing in different execution contexts
1990
+ *
1991
+ * @template T - Type of the parameters object
1992
+ * @param parameters - Executor context parameters
1993
+ * @returns Extracted abort configuration
1994
+ *
1995
+ * @example
1996
+ * ```typescript
1997
+ * const extractor: AbortConfigExtractor<MyParams> = (params) => ({
1998
+ * id: params.requestId,
1999
+ * abortTimeout: params.timeout,
2000
+ * signal: params.customSignal
2001
+ * });
2002
+ * ```
2003
+ */
2004
+ type AbortConfigExtractor<T> = (parameters: T) => AbortPluginConfig;
2005
+ /**
2006
+ * Configuration options for initializing AbortPlugin
2007
+ *
2008
+ * Defines optional settings for logger integration, default timeout,
2009
+ * and custom configuration extraction logic
2010
+ *
2011
+ * @template T - Type of the executor parameters
2012
+ */
2013
+ interface AbortPluginOptions<T> {
2014
+ /**
2015
+ * Logger instance for debugging and monitoring
2016
+ *
2017
+ * When provided, the plugin will log abort events, timeouts,
2018
+ * and cleanup operations for debugging purposes
2019
+ *
2020
+ * @optional
2021
+ * @example
2022
+ * ```typescript
2023
+ * import { Logger } from '@qlover/logger';
2024
+ * const logger = new Logger({ level: 'debug' });
2025
+ * ```
2026
+ */
2027
+ logger?: LoggerInterface;
2028
+ /**
2029
+ * Default timeout duration in milliseconds
2030
+ *
2031
+ * Applied to all requests unless overridden by individual request config
2032
+ * Helps establish consistent timeout behavior across the application
2033
+ *
2034
+ * @optional
2035
+ * @default `undefined` (no default timeout)
2036
+ * @example `10000` // 10 seconds default timeout
2037
+ */
2038
+ timeout?: number;
2039
+ /**
2040
+ * Custom configuration extractor function
2041
+ *
2042
+ * Extracts `AbortPluginConfig` from executor context parameters
2043
+ * Allows customization of how abort configuration is retrieved
2044
+ *
2045
+ * @default Direct cast of parameters to `AbortPluginConfig`
2046
+ * @optional
2047
+ * @example
2048
+ * ```typescript
2049
+ * getConfig: (params) => ({
2050
+ * id: params.requestId,
2051
+ * abortTimeout: params.customTimeout,
2052
+ * signal: params.abortSignal
2053
+ * })
2054
+ * ```
2055
+ */
2056
+ getConfig?: AbortConfigExtractor<T>;
2057
+ }
2058
+ /**
2059
+ * Custom error class for abort operations
2060
+ *
2061
+ * Extends `ExecutorError` to provide rich abort-specific error information,
2062
+ * including abort identifiers, timeout details, and user-friendly descriptions
2063
+ *
2064
+ * Core features:
2065
+ * - Abort identification: Tracks which operation was aborted via `abortId`
2066
+ * - Timeout tracking: Records timeout duration when abort is timeout-triggered
2067
+ * - Timeout detection: Provides `isTimeout()` method to distinguish timeout aborts
2068
+ * - Friendly descriptions: Generates human-readable error messages with context
2069
+ *
2070
+ * @example Basic abort error
2071
+ * ```typescript
2072
+ * const error = new AbortError(
2073
+ * 'Operation cancelled by user',
2074
+ * 'fetch-user-123'
2075
+ * );
2076
+ * console.log(error.getDescription());
2077
+ * // Output: "Operation cancelled by user (Request: fetch-user-123)"
2078
+ * ```
2079
+ *
2080
+ * @example Timeout abort error
2081
+ * ```typescript
2082
+ * const error = new AbortError(
2083
+ * 'Request timed out',
2084
+ * 'api-call-456',
2085
+ * 5000
2086
+ * );
2087
+ * if (error.isTimeout()) {
2088
+ * console.log(`Request ${error.abortId} timed out after ${error.timeout}ms`);
2089
+ * }
2090
+ * ```
2091
+ */
2092
+ declare class AbortError extends ExecutorError {
2093
+ /**
2094
+ * Unique identifier for the aborted operation
2095
+ *
2096
+ * Helps track and identify which specific operation was aborted
2097
+ * Corresponds to `id` or `requestId` from `AbortPluginConfig`
2098
+ *
2099
+ * @optional
2100
+ * @example `"fetch-user-profile-123"`
2101
+ * @example `"upload-file-456"`
2102
+ */
2103
+ readonly abortId?: string;
2104
+ /**
2105
+ * Timeout duration in milliseconds
2106
+ *
2107
+ * Only populated when abort was triggered by a timeout
2108
+ * Used to distinguish between manual aborts and timeout-based aborts
2109
+ *
2110
+ * @optional
2111
+ * @example `5000` // 5 seconds timeout
2112
+ */
2113
+ readonly timeout?: number;
2114
+ /**
2115
+ * Creates a new AbortError instance
2116
+ *
2117
+ * @param message - Human-readable error message describing why the operation was aborted
2118
+ * @param abortId - Optional identifier for the aborted operation
2119
+ * @param timeout - Optional timeout duration in milliseconds (indicates timeout-based abort)
2120
+ *
2121
+ * @example Manual abort
2122
+ * ```typescript
2123
+ * new AbortError('User cancelled the upload', 'upload-123')
2124
+ * ```
2125
+ *
2126
+ * @example Timeout abort
2127
+ * ```typescript
2128
+ * new AbortError('Request exceeded time limit', 'api-call-456', 5000)
2129
+ * ```
2130
+ */
2131
+ constructor(message: string, abortId?: string, timeout?: number);
2132
+ /**
2133
+ * Checks if the abort was triggered by a timeout
2134
+ *
2135
+ * Useful for distinguishing between manual cancellations and timeout-based aborts,
2136
+ * enabling different error handling strategies
2137
+ *
2138
+ * @returns `true` if abort was caused by timeout, `false` otherwise
2139
+ *
2140
+ * @example
2141
+ * ```typescript
2142
+ * try {
2143
+ * await fetchData();
2144
+ * } catch (error) {
2145
+ * if (error instanceof AbortError && error.isTimeout()) {
2146
+ * console.log('Request timed out, please try again');
2147
+ * } else {
2148
+ * console.log('Request was cancelled');
2149
+ * }
2150
+ * }
2151
+ * ```
2152
+ */
2153
+ isTimeout(): boolean;
2154
+ /**
2155
+ * Generates a user-friendly error description with context
2156
+ *
2157
+ * Combines the error message with additional context like request ID and timeout duration
2158
+ * Provides more informative error messages for debugging and user feedback
2159
+ *
2160
+ * @returns Formatted error description string
2161
+ *
2162
+ * @example Without context
2163
+ * ```typescript
2164
+ * const error = new AbortError('Operation aborted');
2165
+ * error.getDescription(); // "Operation aborted"
2166
+ * ```
2167
+ *
2168
+ * @example With request ID
2169
+ * ```typescript
2170
+ * const error = new AbortError('Operation aborted', 'req-123');
2171
+ * error.getDescription(); // "Operation aborted (Request: req-123)"
2172
+ * ```
2173
+ *
2174
+ * @example With timeout context
2175
+ * ```typescript
2176
+ * const error = new AbortError('Timeout', 'req-456', 5000);
2177
+ * error.getDescription(); // "Timeout (Request: req-456, Timeout: 5000ms)"
2178
+ * ```
2179
+ */
2180
+ getDescription(): string;
2181
+ }
2182
+ /**
2183
+ * Executor plugin for managing request cancellation and timeout handling
2184
+ *
2185
+ * Core concept:
2186
+ * Provides comprehensive abort control for asynchronous operations by managing
2187
+ * `AbortController` instances, timeout mechanisms, and cleanup operations.
2188
+ * Integrates seamlessly with the executor plugin system to handle operation
2189
+ * lifecycle and error management.
2190
+ *
2191
+ * Main features:
2192
+ * - Request cancellation: Manual and automatic abort control with per-request tracking
2193
+ * - Generates unique identifiers for each request
2194
+ * - Manages `AbortController` instances lifecycle
2195
+ * - Supports both programmatic and user-triggered cancellation
2196
+ * - Prevents duplicate requests by aborting previous ones with same ID
2197
+ *
2198
+ * - Timeout management: Automatic operation timeout with configurable duration
2199
+ * - Sets up timeout timers for each operation
2200
+ * - Automatically aborts operations exceeding timeout
2201
+ * - Provides timeout-specific error information
2202
+ * - Cleans up timers to prevent memory leaks
2203
+ *
2204
+ * - Signal integration: Seamless integration with AbortSignal API
2205
+ * - Creates and manages `AbortSignal` instances
2206
+ * - Supports external signal injection
2207
+ * - Provides `raceWithAbort` for signal-unaware operations
2208
+ * - Handles signal events and state changes
2209
+ *
2210
+ * - Resource cleanup: Automatic cleanup of controllers and timers
2211
+ * - Removes completed operation resources
2212
+ * - Clears timeout timers on success or error
2213
+ * - Prevents memory leaks from abandoned operations
2214
+ * - Supports batch cleanup with `abortAll()`
2215
+ *
2216
+ * - Error handling: Rich abort error information with context
2217
+ * - Distinguishes between manual and timeout aborts
2218
+ * - Provides detailed error descriptions
2219
+ * - Maintains error context across plugin lifecycle
2220
+ * - Supports custom error callbacks via `onAborted`
2221
+ *
2222
+ * @template TParameters - Type of executor context parameters, defaults to `AbortPluginConfig`
2223
+ *
2224
+ * @example Basic usage with executor
2225
+ * ```typescript
2226
+ * import { Executor } from '@/executor';
2227
+ * import { AbortPlugin } from '@/executor/plugins';
2228
+ *
2229
+ * const executor = new Executor();
2230
+ * const abortPlugin = new AbortPlugin();
2231
+ * executor.use(abortPlugin);
2232
+ *
2233
+ * // Execute with abort support
2234
+ * const result = await executor.execute({
2235
+ * id: 'fetch-users',
2236
+ * abortTimeout: 5000
2237
+ * });
2238
+ * ```
2239
+ *
2240
+ * @example Manual abort
2241
+ * ```typescript
2242
+ * const abortPlugin = new AbortPlugin();
2243
+ * executor.use(abortPlugin);
2244
+ *
2245
+ * // Start operation
2246
+ * const promise = executor.execute({ id: 'long-running-task' });
2247
+ *
2248
+ * // Cancel after 2 seconds
2249
+ * setTimeout(() => {
2250
+ * abortPlugin.abort('long-running-task');
2251
+ * }, 2000);
2252
+ * ```
2253
+ *
2254
+ * @example With custom configuration extractor
2255
+ * ```typescript
2256
+ * interface MyParams {
2257
+ * requestId: string;
2258
+ * timeout: number;
2259
+ * customSignal?: AbortSignal;
2260
+ * }
2261
+ *
2262
+ * const abortPlugin = new AbortPlugin<MyParams>({
2263
+ * logger: myLogger,
2264
+ * getConfig: (params) => ({
2265
+ * id: params.requestId,
2266
+ * abortTimeout: params.timeout,
2267
+ * signal: params.customSignal
2268
+ * })
2269
+ * });
2270
+ * ```
2271
+ *
2272
+ * @example With abort callback
2273
+ * ```typescript
2274
+ * await executor.execute({
2275
+ * id: 'upload-file',
2276
+ * abortTimeout: 30000,
2277
+ * onAborted: (config) => {
2278
+ * console.log(`Upload ${config.id} was cancelled`);
2279
+ * // Clean up temporary files
2280
+ * cleanupTempFiles();
2281
+ * }
2282
+ * });
2283
+ * ```
2284
+ *
2285
+ * @example Abort all pending operations
2286
+ * ```typescript
2287
+ * // Start multiple operations
2288
+ * executor.execute({ id: 'task-1' });
2289
+ * executor.execute({ id: 'task-2' });
2290
+ * executor.execute({ id: 'task-3' });
2291
+ *
2292
+ * // Cancel all at once
2293
+ * abortPlugin.abortAll();
2294
+ * ```
2295
+ */
2296
+ declare class AbortPlugin<TParameters> implements ExecutorPlugin {
2297
+ /**
2298
+ * Plugin identifier name
2299
+ *
2300
+ * Used by the executor system to identify this plugin
2301
+ */
2302
+ readonly pluginName = "AbortPlugin";
2303
+ /**
2304
+ * Ensures only one instance of this plugin can be registered
2305
+ *
2306
+ * Prevents conflicts from multiple abort plugin instances
2307
+ */
2308
+ readonly onlyOne = true;
2309
+ /**
2310
+ * Counter for auto-generating request identifiers
2311
+ *
2312
+ * Incremented each time a new request without ID is processed
2313
+ *
2314
+ * @private
2315
+ */
2316
+ private requestCounter;
2317
+ /**
2318
+ * Map of active abort controllers indexed by request key
2319
+ *
2320
+ * Stores `AbortController` instances for ongoing operations
2321
+ * Enables abort operations by request identifier
2322
+ *
2323
+ * @protected
2324
+ */
2325
+ protected readonly controllers: Map<string, AbortController>;
2326
+ /**
2327
+ * Map of active timeout timers indexed by request key
2328
+ *
2329
+ * Stores timeout IDs for cleanup when operations complete
2330
+ * Prevents memory leaks from abandoned timers
2331
+ *
2332
+ * @protected
2333
+ */
2334
+ protected readonly timeouts: Map<string, NodeJS.Timeout>;
2335
+ /**
2336
+ * Configuration extractor function
2337
+ *
2338
+ * Extracts `AbortPluginConfig` from executor parameters
2339
+ * Enables flexible configuration in different contexts
2340
+ *
2341
+ * @protected
2342
+ */
2343
+ protected readonly getConfig: AbortConfigExtractor<TParameters>;
2344
+ /**
2345
+ * Optional logger instance for debugging
2346
+ *
2347
+ * When provided, logs abort events, timeouts, and cleanup operations
2348
+ *
2349
+ * @protected
2350
+ * @optional
2351
+ */
2352
+ protected readonly logger?: LoggerInterface;
2353
+ /**
2354
+ * Creates a new AbortPlugin instance
2355
+ *
2356
+ * @param options - Plugin configuration options
2357
+ * @param options.logger - Logger instance for debugging and monitoring
2358
+ * @param options.timeout - Default timeout duration for all requests
2359
+ * @param options.getConfig - Custom configuration extractor function
2360
+ *
2361
+ * @example With logger
2362
+ * ```typescript
2363
+ * import { Logger } from '@qlover/logger';
2364
+ *
2365
+ * const abortPlugin = new AbortPlugin({
2366
+ * logger: new Logger({ level: 'debug' })
2367
+ * });
2368
+ * ```
2369
+ *
2370
+ * @example With custom extractor
2371
+ * ```typescript
2372
+ * const abortPlugin = new AbortPlugin({
2373
+ * getConfig: (params) => ({
2374
+ * id: params.customId,
2375
+ * abortTimeout: params.maxWaitTime
2376
+ * })
2377
+ * });
2378
+ * ```
2379
+ */
2380
+ constructor(options?: AbortPluginOptions<TParameters>);
2381
+ /**
2382
+ * Checks if an error is abort-related (static utility method)
2383
+ *
2384
+ * Comprehensive check for various abort error types including custom `AbortError`,
2385
+ * native browser `AbortError`, `ExecutorError` with abort ID, `DOMException`,
2386
+ * and abort events. Can be used independently without plugin instance.
2387
+ *
2388
+ * Detection logic:
2389
+ * 1. Custom `AbortError` instance
2390
+ * 2. Native `Error` with name 'AbortError'
2391
+ * 3. `ExecutorError` with `ABORT_ERROR_ID`
2392
+ * 4. `DOMException` with name 'AbortError'
2393
+ * 5. `Event` with type 'abort'
2394
+ *
2395
+ * @param error - Error object to check
2396
+ * @returns `true` if error is abort-related, `false` otherwise
2397
+ *
2398
+ * @example Basic usage
2399
+ * ```typescript
2400
+ * try {
2401
+ * await fetch(url, { signal });
2402
+ * } catch (error) {
2403
+ * if (AbortPlugin.isAbortError(error)) {
2404
+ * console.log('Request was cancelled');
2405
+ * } else {
2406
+ * console.error('Request failed:', error);
2407
+ * }
2408
+ * }
2409
+ * ```
2410
+ *
2411
+ * @example In error handler
2412
+ * ```typescript
2413
+ * function handleError(error: unknown) {
2414
+ * if (AbortPlugin.isAbortError(error)) {
2415
+ * // User cancelled - don't show error message
2416
+ * return;
2417
+ * }
2418
+ * showErrorNotification(error);
2419
+ * }
2420
+ * ```
2421
+ */
2422
+ static isAbortError(error?: unknown): error is AbortError;
2423
+ /**
2424
+ * Generates unique request identifier from configuration
2425
+ *
2426
+ * Priority order:
2427
+ * 1. `requestId` from config
2428
+ * 2. `id` from config
2429
+ * 3. Auto-generated identifier: `{pluginName}-{counter}`
2430
+ *
2431
+ * @param config - Abort plugin configuration
2432
+ * @returns Unique request identifier string
2433
+ *
2434
+ * @protected
2435
+ * @example
2436
+ * ```typescript
2437
+ * // With requestId
2438
+ * generateRequestKey({ requestId: 'fetch-user' }) // "fetch-user"
2439
+ *
2440
+ * // With id
2441
+ * generateRequestKey({ id: 'upload-file' }) // "upload-file"
2442
+ *
2443
+ * // Auto-generated
2444
+ * generateRequestKey({}) // "AbortPlugin-1"
2445
+ * ```
2446
+ */
2447
+ protected generateRequestKey(config: AbortPluginConfig): string;
2448
+ /**
2449
+ * Cleans up resources associated with a request
2450
+ *
2451
+ * Removes abort controller and clears timeout timer for the specified request
2452
+ * Prevents memory leaks by releasing references and stopping timers
2453
+ * Only logs when resources actually exist to avoid noise
2454
+ *
2455
+ * @param config - Configuration object or request identifier string
2456
+ *
2457
+ * @example With config object
2458
+ * ```typescript
2459
+ * cleanup({ id: 'fetch-users' });
2460
+ * ```
2461
+ *
2462
+ * @example With identifier string
2463
+ * ```typescript
2464
+ * cleanup('fetch-users');
2465
+ * ```
2466
+ */
2467
+ cleanup(config: AbortPluginConfig | string): void;
2468
+ /**
2469
+ * Executor lifecycle hook: called before operation execution
2470
+ *
2471
+ * Performs the following setup operations:
2472
+ * 1. Extracts abort configuration from context parameters
2473
+ * 2. Generates unique request key
2474
+ * 3. Aborts any existing request with same key (prevents duplicates)
2475
+ * 4. Creates new `AbortController` if signal not provided
2476
+ * 5. Sets up timeout timer if `abortTimeout` configured
2477
+ * 6. Injects abort signal into configuration
2478
+ *
2479
+ * @param context - Executor context containing parameters and metadata
2480
+ *
2481
+ * @example Configuration in context
2482
+ * ```typescript
2483
+ * executor.execute({
2484
+ * id: 'fetch-data',
2485
+ * abortTimeout: 5000,
2486
+ * onAborted: (config) => console.log('Aborted:', config.id)
2487
+ * });
2488
+ * ```
2489
+ */
2490
+ onBefore(context: ExecutorContext<TParameters>): void;
2491
+ /**
2492
+ * Executor lifecycle hook: called after successful execution
2493
+ *
2494
+ * Cleans up resources (controller and timeout) for completed operation
2495
+ * Ensures no memory leaks from successful operations
2496
+ *
2497
+ * @param context - Executor context containing parameters and metadata
2498
+ *
2499
+ * @example
2500
+ * ```typescript
2501
+ * // After successful execution, resources are automatically cleaned
2502
+ * await executor.execute({ id: 'task-1' });
2503
+ * // AbortController and timeout for 'task-1' are now removed
2504
+ * ```
2505
+ */
2506
+ onSuccess({ parameters }: ExecutorContext<TParameters>): void;
2507
+ /**
2508
+ * Executor lifecycle hook: called when execution fails
2509
+ *
2510
+ * Handles abort-related errors and cleans up resources
2511
+ *
2512
+ * Error handling logic:
2513
+ * 1. Check if error is abort-related using `isAbortError()`
2514
+ * 2. If abort error: Extract reason from signal, cleanup resources, return `AbortError`
2515
+ * 3. If other error: Still cleanup resources to prevent leaks
2516
+ *
2517
+ * @param context - Executor context containing error, parameters, and metadata
2518
+ * @returns `AbortError` if error is abort-related, `void` otherwise
2519
+ *
2520
+ * @example Abort error handling
2521
+ * ```typescript
2522
+ * try {
2523
+ * await executor.execute({ id: 'task-1', abortTimeout: 100 });
2524
+ * } catch (error) {
2525
+ * if (error instanceof AbortError) {
2526
+ * console.log(error.getDescription());
2527
+ * // "The operation was aborted due to timeout (Request: task-1, Timeout: 100ms)"
2528
+ * }
2529
+ * }
2530
+ * ```
2531
+ */
2532
+ onError({ error, parameters }: ExecutorContext<TParameters>): ExecutorError | void;
2533
+ /**
2534
+ * Manually aborts a specific operation
2535
+ *
2536
+ * Triggers abort for the specified request, calls `onAborted` callback if provided,
2537
+ * and cleans up all associated resources
2538
+ *
2539
+ * @param config - Configuration object with request identifier or identifier string
2540
+ * @returns `true` if operation was aborted, `false` if no matching operation found
2541
+ *
2542
+ * @example Abort by ID
2543
+ * ```typescript
2544
+ * abortPlugin.abort('fetch-users');
2545
+ * ```
2546
+ *
2547
+ * @example Abort with config
2548
+ * ```typescript
2549
+ * abortPlugin.abort({ id: 'upload-file' });
2550
+ * ```
2551
+ *
2552
+ * @example Conditional abort
2553
+ * ```typescript
2554
+ * if (userClickedCancel) {
2555
+ * const aborted = abortPlugin.abort('long-task');
2556
+ * if (aborted) {
2557
+ * console.log('Task cancelled successfully');
2558
+ * }
2559
+ * }
2560
+ * ```
2561
+ */
2562
+ abort(config: AbortPluginConfig | string): boolean;
2563
+ /**
2564
+ * Aborts all pending operations
2565
+ *
2566
+ * Iterates through all active controllers, aborts each operation,
2567
+ * and clears all controllers and timeout timers
2568
+ *
2569
+ * Use cases:
2570
+ * - User logs out
2571
+ * - Component unmounts
2572
+ * - Application shutdown
2573
+ * - Navigation away from page
2574
+ *
2575
+ * @example Component cleanup
2576
+ * ```typescript
2577
+ * class MyComponent {
2578
+ * private abortPlugin = new AbortPlugin();
2579
+ *
2580
+ * onDestroy() {
2581
+ * // Cancel all pending requests
2582
+ * this.abortPlugin.abortAll();
2583
+ * }
2584
+ * }
2585
+ * ```
2586
+ *
2587
+ * @example User logout
2588
+ * ```typescript
2589
+ * function logout() {
2590
+ * abortPlugin.abortAll(); // Cancel all API calls
2591
+ * clearUserData();
2592
+ * redirectToLogin();
2593
+ * }
2594
+ * ```
2595
+ */
2596
+ abortAll(): void;
2597
+ /**
2598
+ * Creates a Promise that rejects when signal is aborted
2599
+ *
2600
+ * Returns both the promise and a cleanup function to remove event listener
2601
+ * Prevents memory leaks by allowing proper cleanup of abort event handlers
2602
+ *
2603
+ * Implementation details:
2604
+ * 1. Immediately rejects if signal is already aborted
2605
+ * 2. Attaches event listener for future abort events
2606
+ * 3. Returns cleanup function to remove listener
2607
+ * 4. Uses signal reason if available, otherwise creates new `AbortError`
2608
+ *
2609
+ * @param signal - AbortSignal to monitor
2610
+ * @returns Object containing promise and cleanup function
2611
+ * @returns promise - Promise that rejects on abort
2612
+ * @returns cleanup - Function to remove event listener
2613
+ *
2614
+ * @private Internal use only
2615
+ *
2616
+ * @example Internal usage
2617
+ * ```typescript
2618
+ * const { promise, cleanup } = this.createAbortPromise(signal);
2619
+ * try {
2620
+ * await Promise.race([someOperation(), promise]);
2621
+ * } finally {
2622
+ * cleanup(); // Always cleanup to prevent memory leak
2623
+ * }
2624
+ * ```
2625
+ */
2626
+ private createAbortPromise;
2627
+ /**
2628
+ * Wraps an async operation with `Promise.race` to ensure abort signal responsiveness
2629
+ *
2630
+ * Defensive mechanism for operations that don't natively check abort signals
2631
+ * Uses promise racing to interrupt operations when signal is aborted,
2632
+ * even if the underlying operation ignores the signal
2633
+ *
2634
+ * Use cases:
2635
+ * - Third-party APIs that don't support `AbortSignal`
2636
+ * - Legacy code without abort handling
2637
+ * - Gateway operations that don't check signal
2638
+ * - Any async operation needing guaranteed cancellation
2639
+ *
2640
+ * @template T - Type of the promise result
2641
+ * @param promise - Promise to wrap with abort capability
2642
+ * @param signal - AbortSignal to monitor, if not provided returns original promise
2643
+ * @returns Wrapped promise that rejects immediately when signal is aborted
2644
+ *
2645
+ * @example Basic usage
2646
+ * ```typescript
2647
+ * const controller = new AbortController();
2648
+ * const result = await abortPlugin.raceWithAbort(
2649
+ * fetch('/api/data'), // Even if fetch doesn't check signal
2650
+ * controller.signal
2651
+ * );
2652
+ * ```
2653
+ *
2654
+ * @example With third-party library
2655
+ * ```typescript
2656
+ * const result = await abortPlugin.raceWithAbort(
2657
+ * legacyApiCall(), // Library doesn't support abort
2658
+ * signal
2659
+ * );
2660
+ * ```
2661
+ *
2662
+ * @example Without signal (pass-through)
2663
+ * ```typescript
2664
+ * // When signal is not provided, returns original promise
2665
+ * const result = await abortPlugin.raceWithAbort(somePromise());
2666
+ * ```
2667
+ *
2668
+ * @example Timeout with abort
2669
+ * ```typescript
2670
+ * const controller = new AbortController();
2671
+ * setTimeout(() => controller.abort(), 5000);
2672
+ *
2673
+ * try {
2674
+ * const result = await abortPlugin.raceWithAbort(
2675
+ * longRunningOperation(),
2676
+ * controller.signal
2677
+ * );
2678
+ * } catch (error) {
2679
+ * if (AbortPlugin.isAbortError(error)) {
2680
+ * console.log('Operation timed out');
2681
+ * }
2682
+ * }
2683
+ * ```
2684
+ */
2685
+ raceWithAbort<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T>;
2686
+ }
2687
+
1912
2688
  /**
1913
2689
  * Configuration options for the RetryPlugin
1914
2690
  *
@@ -3470,6 +4246,296 @@ interface ExpireOptions {
3470
4246
  expires?: unknown;
3471
4247
  }
3472
4248
 
4249
+ /**
4250
+ * Key-value storage interface for managing a single value with persistence support
4251
+ *
4252
+ * Core concept:
4253
+ * Provides a unified interface for storing and retrieving a single value associated
4254
+ * with a specific key. Supports both in-memory and persistent storage backends,
4255
+ * enabling flexible storage strategies for different use cases.
4256
+ *
4257
+ * **v2.3.0 before this was an abstract class, now it is an interface**
4258
+ *
4259
+ * Main features:
4260
+ * - Single value storage: Store one value per key instance
4261
+ * - Key management: Retrieve the storage key associated with this instance
4262
+ * - Value retrieval: Get stored value from memory or persistent storage
4263
+ * - Value persistence: Save value to underlying storage backend
4264
+ * - Value removal: Clear value from both memory and persistent storage
4265
+ * - Options support: Flexible options parameter for storage-specific configurations
4266
+ *
4267
+ * Typical usage scenarios:
4268
+ * - Token storage: Store authentication tokens with persistence
4269
+ * - User info storage: Persist user information across sessions
4270
+ * - Configuration storage: Store application settings (theme, language, etc.)
4271
+ * - Session data: Manage temporary session-specific data
4272
+ *
4273
+ * Design decisions:
4274
+ * - Returns `null` when value is not found (explicit null handling)
4275
+ * - Options parameter is optional to support simple use cases
4276
+ * - Generic types allow type-safe storage of any value type
4277
+ * - Supports both synchronous and asynchronous storage backends through options
4278
+ *
4279
+ * @template Key - The type of the storage key (e.g., `string`, `number`, `symbol`)
4280
+ * @template Value - The type of value to store
4281
+ * @template Opt - The type of options for storage operations (defaults to `unknown`)
4282
+ *
4283
+ * @example Basic usage with localStorage
4284
+ * ```typescript
4285
+ * const tokenStorage: KeyStorageInterface<string, string> = new KeyStorage('token', {
4286
+ * storage: localStorage
4287
+ * });
4288
+ *
4289
+ * // Store token
4290
+ * tokenStorage.set('abc123token');
4291
+ *
4292
+ * // Retrieve token
4293
+ * const token = tokenStorage.get(); // Returns 'abc123token'
4294
+ *
4295
+ * // Get storage key
4296
+ * const key = tokenStorage.getKey(); // Returns 'token'
4297
+ *
4298
+ * // Remove token
4299
+ * tokenStorage.remove();
4300
+ * ```
4301
+ *
4302
+ * @example User information storage
4303
+ * ```typescript
4304
+ * interface User {
4305
+ * id: string;
4306
+ * name: string;
4307
+ * email: string;
4308
+ * }
4309
+ *
4310
+ * const userStorage: KeyStorageInterface<string, User> = new KeyStorage('user', {
4311
+ * storage: localStorage
4312
+ * });
4313
+ *
4314
+ * const user: User = {
4315
+ * id: '123',
4316
+ * name: 'John Doe',
4317
+ * email: 'john@example.com'
4318
+ * };
4319
+ *
4320
+ * userStorage.set(user);
4321
+ * const storedUser = userStorage.get(); // Returns User object
4322
+ * ```
4323
+ *
4324
+ * @example With custom options
4325
+ * ```typescript
4326
+ * interface StorageOptions {
4327
+ * encrypt?: boolean;
4328
+ * expires?: number;
4329
+ * }
4330
+ *
4331
+ * const secureStorage: KeyStorageInterface<string, string, StorageOptions> =
4332
+ * new KeyStorage('secret', {
4333
+ * storage: localStorage,
4334
+ * encrypt: true
4335
+ * });
4336
+ *
4337
+ * secureStorage.set('sensitive-data', { encrypt: true, expires: 3600 });
4338
+ * ```
4339
+ */
4340
+ interface KeyStorageInterface<Key, Value, Opt = unknown> {
4341
+ /**
4342
+ * Get the storage key associated with this instance
4343
+ *
4344
+ * Returns the key that was used to initialize this storage instance.
4345
+ * This key is used to identify the storage location in the underlying
4346
+ * storage backend.
4347
+ *
4348
+ * @returns The storage key of type `Key`
4349
+ *
4350
+ * @example
4351
+ * ```typescript
4352
+ * const storage = new KeyStorage('my-key', { storage: localStorage });
4353
+ * const key = storage.getKey(); // Returns 'my-key'
4354
+ * ```
4355
+ */
4356
+ getKey(): Key;
4357
+ /**
4358
+ * Get the current in-memory value without accessing persistent storage
4359
+ *
4360
+ * Returns the value currently stored in memory. This method does not
4361
+ * attempt to load from persistent storage. Use `get()` if you want
4362
+ * to retrieve from persistent storage when memory value is null.
4363
+ *
4364
+ * Returns `null` if:
4365
+ * - No value has been set yet
4366
+ * - Value was removed via `remove()`
4367
+ * - Value was never loaded from storage
4368
+ *
4369
+ * @returns The current in-memory value, or `null` if not available
4370
+ *
4371
+ * @example
4372
+ * ```typescript
4373
+ * const storage = new KeyStorage('token', { storage: localStorage });
4374
+ *
4375
+ * // Initially null (not loaded from storage yet)
4376
+ * const memValue = storage.getValue(); // Returns null
4377
+ *
4378
+ * // After setting
4379
+ * storage.set('abc123');
4380
+ * const memValue2 = storage.getValue(); // Returns 'abc123'
4381
+ *
4382
+ * // After removal
4383
+ * storage.remove();
4384
+ * const memValue3 = storage.getValue(); // Returns null
4385
+ * ```
4386
+ */
4387
+ getValue(): Value | null;
4388
+ /**
4389
+ * Retrieve value from storage with optional configuration
4390
+ *
4391
+ * Retrieval strategy:
4392
+ * 1. First checks in-memory value (fast path)
4393
+ * 2. If memory value is null and persistent storage is available,
4394
+ * loads from persistent storage and updates memory cache
4395
+ * 3. Returns null if value doesn't exist in either location
4396
+ *
4397
+ * The `options` parameter allows passing storage-specific configuration
4398
+ * that may override default behavior (e.g., encryption settings, expiration checks).
4399
+ *
4400
+ * @param options - Optional storage operation configuration
4401
+ * @returns The stored value, or `null` if not found
4402
+ *
4403
+ * @example Basic retrieval
4404
+ * ```typescript
4405
+ * const storage = new KeyStorage('token', { storage: localStorage });
4406
+ * storage.set('abc123');
4407
+ * const token = storage.get(); // Returns 'abc123'
4408
+ * ```
4409
+ *
4410
+ * @example With options
4411
+ * ```typescript
4412
+ * interface Options {
4413
+ * decrypt?: boolean;
4414
+ * }
4415
+ *
4416
+ * const storage = new KeyStorage<string, string, Options>('secret', {
4417
+ * storage: localStorage
4418
+ * });
4419
+ *
4420
+ * // Retrieve with decryption
4421
+ * const value = storage.get({ decrypt: true });
4422
+ * ```
4423
+ *
4424
+ * @example Handling null values
4425
+ * ```typescript
4426
+ * const storage = new KeyStorage('data', { storage: localStorage });
4427
+ * const value = storage.get();
4428
+ *
4429
+ * if (value === null) {
4430
+ * console.log('No value stored');
4431
+ * } else {
4432
+ * console.log('Value:', value);
4433
+ * }
4434
+ * ```
4435
+ */
4436
+ get(options?: Opt): Value | null;
4437
+ /**
4438
+ * Store a value with optional configuration
4439
+ *
4440
+ * Storage behavior:
4441
+ * - Updates in-memory value immediately
4442
+ * - Persists to underlying storage backend if available
4443
+ * - Merges provided options with default options
4444
+ * - Overwrites any existing value for this key
4445
+ *
4446
+ * The `options` parameter can be used to pass storage-specific settings
4447
+ * such as encryption, expiration, or other backend-specific configurations.
4448
+ *
4449
+ * @param value - The value to store (can be any type matching `Value`)
4450
+ * @param options - Optional storage operation configuration
4451
+ *
4452
+ * @example Basic storage
4453
+ * ```typescript
4454
+ * const storage = new KeyStorage('token', { storage: localStorage });
4455
+ * storage.set('abc123token');
4456
+ * ```
4457
+ *
4458
+ * @example Storing complex objects
4459
+ * ```typescript
4460
+ * interface User {
4461
+ * id: string;
4462
+ * name: string;
4463
+ * }
4464
+ *
4465
+ * const storage = new KeyStorage<string, User>('user', {
4466
+ * storage: localStorage
4467
+ * });
4468
+ *
4469
+ * storage.set({
4470
+ * id: '123',
4471
+ * name: 'John Doe'
4472
+ * });
4473
+ * ```
4474
+ *
4475
+ * @example With encryption options
4476
+ * ```typescript
4477
+ * interface Options {
4478
+ * encrypt?: boolean;
4479
+ * expires?: number;
4480
+ * }
4481
+ *
4482
+ * const storage = new KeyStorage<string, string, Options>('secret', {
4483
+ * storage: localStorage
4484
+ * });
4485
+ *
4486
+ * storage.set('sensitive-data', {
4487
+ * encrypt: true,
4488
+ * expires: Date.now() + 3600000 // 1 hour
4489
+ * });
4490
+ * ```
4491
+ */
4492
+ set(value: Value, options?: Opt): void;
4493
+ /**
4494
+ * Remove the stored value from both memory and persistent storage
4495
+ *
4496
+ * Removal behavior:
4497
+ * - Clears in-memory value (sets to `null`)
4498
+ * - Removes value from persistent storage backend if available
4499
+ * - Applies any options-specific removal behavior
4500
+ *
4501
+ * After calling `remove()`, subsequent calls to `get()` will return `null`
4502
+ * until a new value is set via `set()`.
4503
+ *
4504
+ * @param options - Optional storage operation configuration
4505
+ *
4506
+ * @example Basic removal
4507
+ * ```typescript
4508
+ * const storage = new KeyStorage('token', { storage: localStorage });
4509
+ * storage.set('abc123');
4510
+ * storage.remove(); // Removes from both memory and localStorage
4511
+ * const token = storage.get(); // Returns null
4512
+ * ```
4513
+ *
4514
+ * @example With options
4515
+ * ```typescript
4516
+ * interface Options {
4517
+ * softDelete?: boolean;
4518
+ * }
4519
+ *
4520
+ * const storage = new KeyStorage<string, string, Options>('data', {
4521
+ * storage: localStorage
4522
+ * });
4523
+ *
4524
+ * // Remove with soft delete option
4525
+ * storage.remove({ softDelete: true });
4526
+ * ```
4527
+ *
4528
+ * @example Clearing user session
4529
+ * ```typescript
4530
+ * const userStorage = new KeyStorage('user', { storage: localStorage });
4531
+ *
4532
+ * // User logs out
4533
+ * userStorage.remove();
4534
+ * ```
4535
+ */
4536
+ remove(options?: Opt): void;
4537
+ }
4538
+
3473
4539
  /**
3474
4540
  * Interface representing a synchronous storage mechanism.
3475
4541
  *
@@ -3533,18 +4599,6 @@ interface KeyStorageOptions<Key, Sopt = unknown> extends ExpireOptions {
3533
4599
  */
3534
4600
  storage?: SyncStorageInterface<Key, Sopt>;
3535
4601
  }
3536
- declare abstract class KeyStorageInterface<Key, Value, Opt extends KeyStorageOptions<Key> = KeyStorageOptions<Key>> {
3537
- readonly key: Key;
3538
- protected options: Opt;
3539
- protected value: Value | null;
3540
- constructor(key: Key, options?: Opt);
3541
- getKey(): Key;
3542
- getValue(): Value | null;
3543
- abstract get(options?: Opt): Value | null;
3544
- abstract set(value: Value, options?: Opt): void;
3545
- abstract remove(options?: Opt): void;
3546
- }
3547
-
3548
4602
  /**
3549
4603
  * KeyStorage is a storage that can be used to store a single value.
3550
4604
  *
@@ -3582,9 +4636,14 @@ declare abstract class KeyStorageInterface<Key, Value, Opt extends KeyStorageOpt
3582
4636
  * tokenStorage.remove(); // remove from localStorage
3583
4637
  * ```
3584
4638
  */
3585
- declare class KeyStorage<Key, Value, Opt extends KeyStorageOptions<Key> = KeyStorageOptions<Key>> extends KeyStorageInterface<Key, Value, Opt> {
4639
+ declare class KeyStorage<Key, Value, Opt extends KeyStorageOptions<Key> = KeyStorageOptions<Key>> implements KeyStorageInterface<Key, Value, Opt> {
4640
+ readonly key: Key;
4641
+ protected options: Opt;
3586
4642
  protected value: Value | null;
4643
+ constructor(key: Key, options?: Opt);
3587
4644
  protected mergeOptions(options?: Opt): Opt;
4645
+ getKey(): Key;
4646
+ getValue(): Value | null;
3588
4647
  get(options?: Opt): Value | null;
3589
4648
  set(token: Value, options?: Opt): void;
3590
4649
  remove(options?: Opt): void;
@@ -3947,4 +5006,4 @@ type Intersection<T1, T2> = {
3947
5006
  [P in keyof T1 & keyof T2]: T1[P] | T2[P];
3948
5007
  };
3949
5008
 
3950
- export { AsyncExecutor, type AsyncStorageInterface, Base64Serializer, type Encryptor, Executor, type ExecutorConfigInterface, type ExecutorContext, ExecutorError, type ExecutorPlugin, type ExpireOptions, FetchAbortPlugin, FetchURLPlugin, type HookRuntimes, type HookType, type Intersection, JSONSerializer, type JSONSerializerOptions, KeyStorage, KeyStorageInterface, type KeyStorageOptions, ObjectStorage, type ObjectStorageOptions, type PipeArg, type PromiseTask, RequestAdapterAxios, type RequestAdapterConfig, RequestAdapterFetch, type RequestAdapterFetchConfig, type RequestAdapterInterface, type RequestAdapterResponse, RequestError, RequestErrorID, RequestManager, RequestScheduler, RequestTransaction, type RequestTransactionInterface, type RetryOptions, RetryPlugin, type SerializerIneterface, type StorageValue, SyncExecutor, SyncStorage, type SyncStorageInterface, type SyncTask, type Task, type ValueOf };
5009
+ export { ABORT_ERROR_ID, type AbortConfigExtractor, AbortError, AbortPlugin, type AbortPluginConfig, type AbortPluginOptions, AsyncExecutor, type AsyncStorageInterface, Base64Serializer, type Encryptor, Executor, type ExecutorConfigInterface, type ExecutorContext, ExecutorError, type ExecutorPlugin, type ExpireOptions, FetchAbortPlugin, FetchURLPlugin, type HookRuntimes, type HookType, type Intersection, JSONSerializer, type JSONSerializerOptions, KeyStorage, type KeyStorageInterface, type KeyStorageOptions, ObjectStorage, type ObjectStorageOptions, type PipeArg, type PromiseTask, RequestAdapterAxios, type RequestAdapterConfig, RequestAdapterFetch, type RequestAdapterFetchConfig, type RequestAdapterInterface, type RequestAdapterResponse, RequestError, RequestErrorID, RequestManager, RequestScheduler, RequestTransaction, type RequestTransactionInterface, type RetryOptions, RetryPlugin, type SerializerIneterface, type StorageValue, SyncExecutor, SyncStorage, type SyncStorageInterface, type SyncTask, type Task, type ValueOf };