44
55A 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.
66
7- ---
7+ ![ CI ] ( https://github.com/catbee-technologies/catbee-utils/actions/workflows/node-build.yml/badge.svg ) ![ Coverage ] ( https://codecov.io/gh/catbee-technologies/catbee-utils/branch/main/graph/badge.svg ) ![ Audit ] ( https://github.com/catbee-technologies/catbee-utils/actions/workflows/audit.yml/badge.svg ) ![ Publish ] ( https://github.com/catbee-technologies/catbee-utils/actions/workflows/npm-publish.yml/badge.svg )
88
99## 📦 Installation
1010
@@ -15,7 +15,7 @@ npm i @catbee/utils
1515## ⚡ Quick Start
1616
1717``` ts
18- import { chunk , sleep , getLogger } from " @catbee/utils" ;
18+ import { chunk , sleep , getLogger , uuid , isEmail } from " @catbee/utils" ;
1919
2020// Chunk an array
2121const result = chunk ([1 , 2 , 3 , 4 , 5 ], 2 ); // [[1, 2], [3, 4], [5]]
@@ -24,29 +24,35 @@ const result = chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
2424await sleep (1000 );
2525
2626// Log with context
27- const logger = getLogger ();
28- logger .info (" App started" );
27+ getLogger ().info (" App started" );
28+
29+ // Generate a secure UUID
30+ console .log (uuid ()); // e.g. 2a563ec1-caf6-4fe2-b60c-9cf7fb1bdb7f
31+
32+ // Basic validation
33+ console .log (isEmail (" user@example.com" )); // true
34+
2935```
3036
3137## 📦 Modules Overview
3238
33- - ** Array Utilities** ( ` array.utils.ts ` )
34- - ** Async Utilities** ( ` async.utils.ts ` )
35- - ** Cache Utilities** ( ` cache.utils.ts ` )
36- - ** Context Store** ( ` context-store.utils.ts ` )
37- - ** Crypto Utilities** ( ` crypto.utils.ts ` )
38- - ** Directory Utilities** ( ` dir.utils.ts ` )
39- - ** Environment Utilities** ( ` env.utils.ts ` )
40- - ** Exception Utilities** ( ` exception.utils.ts ` )
41- - ** File System Utilities** ( ` fs.utils.ts ` )
42- - ** HTTP Status Codes** ( ` http-status-codes.ts ` )
43- - ** Logger ** ( ` logger.utils.ts ` )
44- - ** Object Utilities** ( ` obj.utils.ts ` )
45- - ** Response Utilities** ( ` response.utils.ts ` )
46- - ** String Utilities** ( ` string.utils.ts ` )
47- - ** URL Utilities** ( ` url.utils.ts ` )
48-
49- ---
39+ - [ ** Array Utilities** ] ( #- array-utilities )
40+ - [ ** Async Utilities** ] ( #- async-utilities )
41+ - [ ** Cache Utilities** ] ( #- cache-utilities )
42+ - [ ** Context Store** ] ( #- context-store)
43+ - [ ** Crypto Utilities** ] ( #- crypto-utilities )
44+ - [ ** Directory Utilities** ] ( #-directory-utilities )
45+ - [ ** Environment Utilities** ] ( #-environment-utilities )
46+ - [ ** Exception Utilities** ] ( #- exception-utilities )
47+ - [ ** File System Utilities** ] ( #-file-system-utilities )
48+ - [ ** HTTP Status Codes** ] ( #- http-status-codes)
49+ - [ ** ID Utilities ** ] ( #-id-utilities )
50+ - [ ** Logger Utilities** ] ( #-logger-utility )
51+ - [ ** Object Utilities** ] ( #-object-utilities )
52+ - [ ** Response Utilities** ] ( #-response-utilities )
53+ - [ ** String Utilities** ] ( #-string-utilities )
54+ - [ ** URL Utilities ** ] ( #-url-utilities )
55+ - [ ** Validate Utilities ** ] ( #-validate-utilities )
5056
5157## 📦 Array Utilities
5258
@@ -60,40 +66,32 @@ logger.info("App started");
6066- ` intersect<T>(a: T[], b: T[]): T[] ` – Intersection.
6167- ` mergeSort<T extends object>(array: T[], key: string, direction = 'asc'): T[] ` – Merge sort by nested key.
6268
63- ---
64-
6569## ⏳ Async Utilities
6670
6771- ` sleep(ms: number): Promise<void> `
68- - ` debounce<T>(fn, wait): T `
69- - ` throttle<T>(fn, wait): T `
70- - ` retry<T>(fn: () => Promise<T>, retries: number): Promise<T> `
72+ - ` debounce<T>(fn: T , wait: number ): T & { cancel(): void; flush(): void } `
73+ - ` throttle<T>(fn: T , wait: number, options? ): T `
74+ - ` retry<T>(fn: () => Promise<T>, retries? : number): Promise<T> `
7175- ` withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> `
72- - ` runInBatches<T>(items: T[], batchSize: number, fn: (item: T ) => Promise<void>): Promise<void > `
76+ - ` runInBatches<T>(tasks: (( ) => Promise<T>)[], batchSize: number): Promise<T[] > `
7377- ` singletonAsync<TArgs, TResult>(fn: (...args: TArgs) => Promise<TResult>): (...args: TArgs) => Promise<TResult> `
74- - ` settleAll<T>(promises: Promise<T>[]): Promise<SettledResult<T>[]> `
78+ - ` settleAll<T>(tasks: (() => Promise<T>) []): Promise<SettledResult<T>[]> `
7579- ` createTaskQueue(limit: number) `
76- - ` runInSeries<T>(items: T[], fn: (item: T) => Promise<void>): Promise<void> `
77-
78- ---
80+ - ` runInSeries<T>(tasks: (() => Promise<T>)[]): Promise<T[]> `
7981
8082## 🗃️ Cache Utilities
8183
8284- ` TTLCache<K, V>(ttl: number) ` – In-memory TTL cache with ` .set ` , ` .get ` , ` .has ` , ` .delete ` , ` .clear ` .
8385
84- ---
85-
86- ## 🔐 Crypto Utilities
87-
88- - ` hmac(input: string, secret: string): string `
89- - ` hash(input: string): string `
90- - ` sha256Hmac(input: string, secret: string): string `
91- - ` sha1(input: string): string `
92- - ` sha256(input: string): string `
93- - ` md5(input: string): string `
94- - ` randomString(): string `
86+ You can use it like:
9587
96- ---
88+ ``` ts
89+ const cache = new TTLCache <string , number >(3600_000 );
90+ cache .set (" foo" , 42 );
91+ cache .get (" foo" ); // 42
92+ cache .has (" foo" ); // true
93+ cache .cleanup (); // cleans expired
94+ ```
9795
9896## 🧩 Context Store
9997
@@ -109,7 +107,56 @@ logger.info("App started");
109107- ` StoreKeys ` – Common context keys.
110108- ` getRequestId(): string | undefined ` – Get the current request ID from context.
111109
112- ---
110+ ### Example (Express middleware usage):
111+
112+ ``` ts
113+ // ✅ Recommended: Unified middleware to initialize context and logger
114+ import { ContextStore , StoreKeys , getLogger } from " @catbee/utils" ;
115+ import crypto from " crypto" ;
116+
117+ export function setupRequestContext(req : Request , res : Response , next : NextFunction ): void {
118+ const requestId = req .headers [" x-request-id" ]?.toString () || crypto .randomUUID ();
119+
120+ ContextStore .run ({ [StoreKeys .REQUEST_ID ]: requestId }, () => {
121+ const logger = getLogger ().child ({ reqId: requestId });
122+ ContextStore .set (StoreKeys .LOGGER , logger );
123+ logger .info (" Request context initialized" );
124+ next ();
125+ });
126+ }
127+
128+ // In your app entry point
129+ app .use (setupRequestContext );
130+ ```
131+
132+ 👇 Alternatively, split it into two separate middlewares:
133+
134+ ``` ts
135+ // First: Initialize context with request ID
136+ app .use ((req , res , next ) => {
137+ const requestId = req .headers [" x-request-id" ] || crypto .randomUUID ();
138+ ContextStore .run ({ [StoreKeys .REQUEST_ID ]: requestId }, () => next ());
139+ });
140+
141+ // Second: Inject logger into the context
142+ app .use ((req , res , next ) => {
143+ const logger = getLogger ().child ({ reqId: req .headers [" x-request-id" ] });
144+ ContextStore .set (StoreKeys .LOGGER , logger );
145+ logger .info (" Request started" );
146+ next ();
147+ });
148+ ```
149+
150+ ## 🔐 Crypto Utilities
151+
152+ - ` hmac(algorithm: string, input: string, secret: string): string `
153+ - ` hash(algorithm: string, input: string): string `
154+ - ` sha256Hmac(input: string, secret: string): string `
155+ - ` sha1(input: string): string `
156+ - ` sha256(input: string): string `
157+ - ` md5(input: string): string `
158+ - ` randomString(): string `
159+
113160
114161## 📂 Directory Utilities
115162
@@ -123,7 +170,6 @@ logger.info("App started");
123170- ` getDirSize(dirPath: string): Promise<number> `
124171- ` watchDir(dirPath: string, cb: (event, filename) => void) `
125172
126- ---
127173
128174## 🌱 Environment Utilities
129175
@@ -145,14 +191,12 @@ logger.info("App started");
145191 - ` getEnum<T extends string>(key: string, allowedValues: T[], defaultValue?: T): T ` – Get and validate an enum-like environment variable.
146192 - ` has(key: string): boolean ` – Check if an environment variable exists.
147193 - ` delete(key: string): void ` – Delete an environment variable (useful in tests).
148-
149- ---
194+
150195
151196## 🚨 Exception Utilities
152197
153198- ` HttpError ` , ` InternalServerErrorException ` , ` UnauthorizedException ` , ` BadRequestException ` , ` NotFoundException ` , ` ForbiddenException ` , ` ConflictException ` , ` BadGatewayException ` , ` TooManyRequestsException ` , ` ServiceUnavailableException ` , ` GatewayTimeoutException ` – All extend ` ErrorResponse ` .
154199
155- ---
156200
157201## 📁 File System Utilities
158202
@@ -161,7 +205,6 @@ logger.info("App started");
161205- ` writeJsonFile(path: string, data: any): Promise<void> `
162206- ` deleteFileIfExists(path: string): Promise<boolean> `
163207
164- ---
165208
166209## 📊 HTTP Status Codes
167210
@@ -179,13 +222,21 @@ import { HttpStatusCodes } from "@catbee/utils";
179222res .status (HttpStatusCodes .BAD_REQUEST ).send (" Invalid payload" );
180223```
181224
182- ## 📝 Response Utilities
225+ ## 🆔 ID Utilities
226+
227+ Helpers for generating unique and random identifiers, covering popular formats for distributed systems and secure tokens.
228+
229+ - ` uuid(): string ` — Generate a UUID v4 string (RFC 4122).
230+ - ` ulidString(): string ` — Generate a ULID (Universally Unique Lexicographically Sortable Identifier).
231+ - ` nanoId(size?: number): string ` — Generate a nanoid string.
232+ - ` randomHex(byteLength?: number): string ` — Generate a cryptographically strong random hex string of given length in bytes.
233+ - ` randomInt(min: number, max: number): number ` — Generate a secure random integer between min and max, inclusive.
183234
184- - ` SuccessResponse<T> ` – Standard API success wrapper.
185- - ` ErrorResponse ` – Standard API error wrapper.
186- - Types: ` ApiResponse<T> ` , ` Pagination<T> ` , ` PaginationResponse<T> `
187235
188- ---
236+ ## 📄 Logger Utilities
237+
238+ - ` getLogger(): Logger ` – Context-aware logger (uses ` pino ` ).
239+
189240
190241## 🧩 Object Utilities
191242
@@ -196,7 +247,13 @@ res.status(HttpStatusCodes.BAD_REQUEST).send("Invalid payload");
196247- ` flattenObject<T>(obj: T): Record<string, any> `
197248- ` getValueByPath<T>(obj: T, path: string) `
198249
199- ---
250+
251+ ## 📝 Response Utilities
252+
253+ - ` SuccessResponse<T> ` – Standard API success wrapper.
254+ - ` ErrorResponse ` – Standard API error wrapper.
255+ - Types: ` ApiResponse<T> ` , ` Pagination<T> ` , ` PaginationResponse<T> `
256+
200257
201258## 🧵 String Utilities
202259
@@ -206,20 +263,24 @@ res.status(HttpStatusCodes.BAD_REQUEST).send("Invalid payload");
206263- ` slugify(str: string): string `
207264- ` truncate(str: string, len: number): string `
208265
209- ---
210266
211267## 🌐 URL Utilities
212268
213269- ` appendQueryParams(url: string, params: object): string `
214270- ` parseQueryString(query: string): Record<string, string> `
215271
216- ---
217272
218- ## 📄 Logger Utility
273+ ## ✅ Validate Utilities
274+ A comprehensive suite of string/format validators for safe input and API checks.
219275
220- - ` getLogger(): Logger ` – Context-aware logger (uses ` pino ` ).
221-
222- ---
276+ - ` isEmail(str: string): boolean ` — Validate basic email address.
277+ - ` isUUID(str: string): boolean ` — Validate string as UUID (v1–v5).
278+ - ` isURL(str: string): boolean ` — Check if string is a valid URL.
279+ - ` isPhone(str: string): boolean ` — Validate (international/E164/local) phone number.
280+ - ` isAlphanumeric(str: string): boolean ` — Check for letters/numbers only.
281+ - ` isNumeric(strOrNum: string | number) ` : boolean — Check safely parsable numeric value.
282+ - ` isHexColor(str: string): boolean ` — Validate hex color (#RGB or #RRGGBB).
283+ - ` isISODate(str: string): boolean ` — Validate ISO 8601 date string.
223284
224285## 🏁 Usage
225286
@@ -229,8 +290,6 @@ Import only what you need:
229290import { chunk , sleep , TTLCache , getLogger } from " @catbee/utils" ;
230291```
231292
232- ---
233-
234293## 📜 License
235294
236295MIT © catbee-technologies
0 commit comments