@catbee/utils
Version:
A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.
217 lines (213 loc) • 8.23 kB
TypeScript
/*
* The MIT License
*
* Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { AsyncLocalStorage } from 'node:async_hooks';
/**
* Type representing the store object used in AsyncLocalStorage.
* Keys must be unique symbols to ensure isolation and prevent collisions.
*/
interface Store {
[key: symbol]: unknown;
}
/**
* Predefined symbols used as keys in AsyncLocalStorage.
* Add new symbols here to avoid duplication.
*/
declare const StoreKeys: {
LOGGER: symbol;
REQUEST_ID: symbol;
USER: symbol;
SESSION: symbol;
TRANSACTION_ID: symbol;
USER_ID: symbol;
TENANT_ID: symbol;
TRACE_ID: symbol;
CORRELATION_ID: symbol;
};
/**
* Retrieves the current request ID from the async context, if available.
*
* @returns {string | undefined} The request ID string or undefined if not present in the current context.
*/
declare function getRequestId(): string | undefined;
/**
* Type-safe getter for common context values.
*
* @param key The store key symbol
* @returns The typed value from the store
*/
declare function getFromContext<T>(key: symbol): T | undefined;
/**
* ContextStore manages per-request scoped context using AsyncLocalStorage.
* It allows storing and retrieving data across async calls (e.g., request ID, logger).
*
* Example (Express middleware):
* ```
* // Middleware to initialize context and logger
* app.use((req, res, next) => {
* const requestId = req.headers["x-request-id"]?.toString() || crypto.randomUUID();
* ContextStore.run({ [StoreKeys.REQUEST_ID]: requestId }, () => {
* ContextStore.set(StoreKeys.LOGGER, getLogger().child({ requestId }));
* next();
* });
* });
* ```
*/
declare class ContextStore {
/**
* The underlying AsyncLocalStorage instance for context.
* @private
*/
private static readonly storage;
/**
* Returns the raw AsyncLocalStorage instance for advanced access.
*
* @returns {AsyncLocalStorage<Store>} The AsyncLocalStorage instance.
*/
static getInstance(): AsyncLocalStorage<Store>;
/**
* Retrieves a value from the async context store by symbol key.
*
* @typeParam T - The expected return type of the value.
* @param {symbol} key - Unique symbol used as the store key.
* @returns {T | undefined} The value found (typed) or undefined if not present.
*/
static get<T>(key: symbol): T | undefined;
/**
* Sets a value in the current context store by symbol key.
*
* @typeParam T - The value type to set.
* @param {symbol} key - Unique symbol key.
* @param {T} value - Value to set in context.
* @throws {Error} If called outside an active context (not within a .run call or in the wrong async boundaries).
*/
static set<T>(key: symbol, value: T): void;
/**
* Retrieves the entire context store object for the current async context.
*
* @returns {Store | undefined} The current store object or undefined if called outside a context.
*/
static getAll(): Store | undefined;
/**
* Initializes a new async context and executes a callback within it.
* This must be called at the beginning of a request or logical async flow.
*
* @typeParam T - The callback's return type.
* @param {Store} store - The initial key-value store object.
* @param {() => T} callback - The function to run within the new context.
* @returns {T} The result of the callback function.
*/
static run<T>(store: Store, callback: () => T): T;
/**
* Checks if a key exists in the current context store.
*
* @param {symbol} key - The symbol key to check.
* @returns {boolean} True if the key exists, false otherwise.
*/
static has(key: symbol): boolean;
/**
* Removes a value from the current context store by symbol key.
*
* @param {symbol} key - The symbol key to delete.
* @returns {boolean} True if the key was deleted, false if the key wasn't found or no active context.
* @throws {Error} If called outside an active context.
*/
static delete(key: symbol): boolean;
/**
* Updates multiple values in the current context store at once.
*
* @param {Partial<Record<symbol, unknown>>} values - Object containing symbol keys and values to update.
* @throws {Error} If called outside an active context.
*/
static patch(values: Partial<Record<symbol, unknown>>): void;
/**
* Executes a callback with a temporary store value that only exists during execution.
* Original store is restored after callback completes.
*
* @typeParam T - The callback's return type.
* @param {symbol} key - The symbol key to temporarily set.
* @param {unknown} value - The temporary value.
* @param {() => T} callback - The function to execute with the temporary value.
* @returns {T} The result of the callback function.
* @throws {Error} If called outside an active context.
*/
static withValue<T>(key: symbol, value: unknown, callback: () => T): T;
/**
* Creates a new context that inherits values from the current context.
*
* @typeParam T - The callback's return type.
* @param {Partial<Record<symbol, unknown>>} newValues - New values to add to or override in the context.
* @param {() => T} callback - The function to execute in the new context.
* @returns {T} The result of the callback function.
*/
static extend<T>(newValues: Partial<Record<symbol, unknown>>, callback: () => T): T;
/**
* Creates Express middleware that initializes a context for each request.
*
* @param {(req: any) => Partial<Record<symbol, unknown>>} initialValuesFactory - Function that returns initial context values.
* @returns Express middleware function.
*/
static createExpressMiddleware(initialValuesFactory?: (req: any) => Partial<Record<symbol, unknown>>): (req: any, _res: any, next: any) => void;
}
/**
* Type-safe wrapper for accessing and modifying context values with specific types.
*
* @typeParam T - The value type.
*/
declare class TypedContextKey<T> {
private readonly symbol;
private readonly defaultValue?;
/**
* Creates a new typed context key.
*
* @param symbol - The unique symbol for this key
* @param defaultValue - Optional default value if key is not found
*/
constructor(symbol: symbol, defaultValue?: T | undefined);
/**
* Gets the current value for this key.
*
* @returns The value or defaultValue if not found
*/
get(): T | undefined;
/**
* Sets the value for this key.
*
* @param value The value to set
*/
set(value: T): void;
/**
* Checks if this key exists in the context.
*
* @returns True if the key exists
*/
exists(): boolean;
/**
* Deletes this key from the context.
*
* @returns True if the key was deleted
*/
delete(): boolean;
}
export { ContextStore, StoreKeys, TypedContextKey, getFromContext, getRequestId };
export type { Store };