@catbee/utils 2.0.0-next.0 → 2.0.0-next.1

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.
Files changed (97) hide show
  1. package/README.md +52 -16
  2. package/array/index.cjs +180 -71
  3. package/array/index.d.ts +293 -1
  4. package/array/index.mjs +171 -72
  5. package/async/index.cjs +92 -36
  6. package/async/index.d.ts +275 -1
  7. package/async/index.mjs +92 -36
  8. package/cache/index.cjs +1 -1
  9. package/cache/index.d.ts +155 -1
  10. package/cache/index.mjs +2 -2
  11. package/config/index.cjs +78 -64
  12. package/config/index.d.ts +64 -2
  13. package/config/index.mjs +76 -64
  14. package/context-store/index.d.ts +192 -1
  15. package/crypto/index.d.ts +163 -1
  16. package/date/index.cjs +46 -1
  17. package/date/index.d.ts +190 -1
  18. package/date/index.mjs +45 -2
  19. package/decorators/index.cjs +1156 -18
  20. package/decorators/index.d.ts +684 -1
  21. package/decorators/index.mjs +1156 -18
  22. package/dir/index.cjs +4 -3
  23. package/dir/index.d.ts +195 -1
  24. package/dir/index.mjs +4 -3
  25. package/env/index.cjs +10 -26
  26. package/env/index.d.ts +379 -1
  27. package/env/index.mjs +10 -26
  28. package/exception/index.d.ts +232 -1
  29. package/fs/index.cjs +70 -36
  30. package/fs/index.d.ts +205 -1
  31. package/fs/index.mjs +64 -34
  32. package/http-status-codes/index.d.ts +267 -1
  33. package/id/index.d.ts +37 -1
  34. package/index.cjs +3 -3
  35. package/index.d.ts +1 -1
  36. package/index.mjs +1 -1
  37. package/logger/index.cjs +11 -11
  38. package/logger/index.d.ts +189 -1
  39. package/logger/index.mjs +12 -12
  40. package/middleware/index.d.ts +103 -1
  41. package/obj/index.cjs +150 -162
  42. package/obj/index.d.ts +136 -1
  43. package/obj/index.mjs +150 -162
  44. package/package.json +11 -11
  45. package/performance/index.cjs +2 -2
  46. package/performance/index.d.ts +138 -1
  47. package/performance/index.mjs +2 -2
  48. package/request/index.cjs +1 -1
  49. package/request/index.d.ts +241 -2
  50. package/request/index.mjs +1 -1
  51. package/response/index.d.ts +318 -2
  52. package/server/index.cjs +27 -23
  53. package/server/index.d.ts +785 -4
  54. package/server/index.mjs +28 -23
  55. package/stream/index.d.ts +90 -1
  56. package/string/index.d.ts +102 -1
  57. package/type/index.cjs +1 -1
  58. package/type/index.d.ts +107 -1
  59. package/type/index.mjs +1 -1
  60. package/types/index.d.ts +774 -4
  61. package/url/index.cjs +2 -4
  62. package/url/index.d.ts +142 -1
  63. package/url/index.mjs +2 -4
  64. package/{validate → validation}/index.cjs +89 -42
  65. package/{validate/validate.utils.d.ts → validation/index.d.ts} +32 -23
  66. package/{validate → validation}/index.mjs +85 -42
  67. package/array/array.utils.d.ts +0 -191
  68. package/async/async.utils.d.ts +0 -296
  69. package/cache/cache.utils.d.ts +0 -176
  70. package/config/config.d.ts +0 -57
  71. package/context-store/context-store.utils.d.ts +0 -212
  72. package/crypto/crypto.utils.d.ts +0 -183
  73. package/date/date.utils.d.ts +0 -190
  74. package/decorators/decorators.utils.d.ts +0 -705
  75. package/dir/dir.utils.d.ts +0 -216
  76. package/env/env.utils.d.ts +0 -400
  77. package/exception/exception.utils.d.ts +0 -253
  78. package/fs/fs.utils.d.ts +0 -196
  79. package/http-status-codes/http-status-codes.d.ts +0 -289
  80. package/id/id.utils.d.ts +0 -59
  81. package/logger/logger.utils.d.ts +0 -210
  82. package/middleware/middleware.utils.d.ts +0 -123
  83. package/obj/obj.utils.d.ts +0 -156
  84. package/performance/performance.utils.d.ts +0 -159
  85. package/request/request.utils.d.ts +0 -109
  86. package/response/response.utils.d.ts +0 -186
  87. package/server/server.builder.d.ts +0 -531
  88. package/server/server.d.ts +0 -303
  89. package/stream/stream.utils.d.ts +0 -111
  90. package/string/string.utils.d.ts +0 -124
  91. package/type/type.utils.d.ts +0 -129
  92. package/types/api-response.d.ts +0 -175
  93. package/types/common.d.ts +0 -148
  94. package/types/config.d.ts +0 -88
  95. package/types/server.d.ts +0 -291
  96. package/url/url.utils.d.ts +0 -164
  97. package/validate/index.d.ts +0 -25
package/logger/index.d.ts CHANGED
@@ -22,4 +22,192 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- export * from './logger.utils';
25
+ import pino, { Logger as Logger$1 } from 'pino';
26
+
27
+ /**
28
+ * Logger type for application-wide logging.
29
+ */
30
+ type Logger = Logger$1;
31
+ /**
32
+ * Logger levels for application-wide logging.
33
+ */
34
+ type LoggerLevels = pino.Level;
35
+ declare const defaultSensitiveFields: string[];
36
+ /**
37
+ * Sets the global redaction censor function used throughout the application for log redaction.
38
+ *
39
+ * Use this function to customize how sensitive data is redacted in logs. The provided function
40
+ * will replace the default censor implementation.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Custom censor that redacts only specific values
45
+ * setRedactCensor((value, path, sensitiveFields) => {
46
+ * if (path.includes('password')) return '***';
47
+ * return value;
48
+ * });
49
+ * ```
50
+ *
51
+ * @param fn - The redaction censor function to use globally. This function receives:
52
+ * - value: The data value to potentially redact
53
+ * - path: Array of strings representing the path to the value in the object
54
+ * - sensitiveFields: Optional array of field names to consider sensitive
55
+ * @returns void
56
+ */
57
+ declare function setRedactCensor(fn: (value: unknown, path: string[], sensitiveFields?: string[]) => string): void;
58
+ /**
59
+ * Gets the current global redaction censor function used for log redaction.
60
+ *
61
+ * This function is called internally by the logger when determining how to redact
62
+ * sensitive information. It can also be used to access the current censor implementation
63
+ * for composition or extension.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const currentCensor = getRedactCensor();
68
+ * // Create an enhanced censor that extends the current one
69
+ * setRedactCensor((value, path, fields) => {
70
+ * // Add custom logic before delegating to current censor
71
+ * if (someCondition) return customHandling();
72
+ * return currentCensor(value, path, fields);
73
+ * });
74
+ * ```
75
+ *
76
+ * @returns The current redaction censor function
77
+ */
78
+ declare function getRedactCensor(): (value: unknown, path: string[], sensitiveFields?: string[]) => string;
79
+ /**
80
+ * Convenience function to redact sensitive data using the current global redact censor.
81
+ *
82
+ * This is a direct wrapper around the global censor function that simplifies usage
83
+ * in application code without needing to access the censor function directly.
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * // Redact a potential sensitive value
88
+ * const safeValue = redact(value, ['user', 'apiKey']);
89
+ * ```
90
+ *
91
+ * @param value - The value to potentially redact
92
+ * @param path - Array of strings representing the path to the value in the object
93
+ * @param sensitiveFields - Optional array of field names to consider sensitive
94
+ * @returns The redacted string value or "***" for redacted content
95
+ */
96
+ declare function redact(value: unknown, path: string[], sensitiveFields?: string[]): string;
97
+ /**
98
+ * @deprecated Use addSensitiveFields instead.
99
+ *
100
+ * Extends the current redaction function with additional fields to redact.
101
+ *
102
+ * This function wraps the existing censor while adding more fields to be considered
103
+ * sensitive without replacing the entire redaction logic.
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * // Add custom fields to be redacted in all future redaction operations
108
+ * addRedactFields(['customerId', 'accountNumber']);
109
+ * ```
110
+ *
111
+ * @param fields - Array of additional field names to redact
112
+ */
113
+ declare function addRedactFields(fields: string[]): void;
114
+ /**
115
+ * Retrieves the expanded list of sensitive fields.
116
+ *
117
+ * This function expands the default sensitive fields into their various naming
118
+ * conventions (e.g., camelCase, snake_case) and caches the result for efficiency.
119
+ *
120
+ * @returns Array of expanded sensitive field names
121
+ */
122
+ declare function getExpandedSensitiveFields(): string[];
123
+ /**
124
+ * Replaces the default list of sensitive fields with a new list.
125
+ *
126
+ * This is useful when you want complete control over what fields are considered
127
+ * sensitive by default, rather than using the library's built-in list.
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * // Replace default sensitive fields with a custom list
132
+ * setSensitiveFields(['password', 'ssn', 'creditCard']);
133
+ * ```
134
+ *
135
+ * @param fields - Array of field names to set as the new default sensitive fields
136
+ */
137
+ declare function setSensitiveFields(fields: string[]): void;
138
+ /**
139
+ * Adds additional field names to the default sensitive fields list.
140
+ *
141
+ * This preserves the existing sensitive fields while adding new ones for
142
+ * application-specific sensitive data.
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * // Add domain-specific sensitive fields to the default list
147
+ * addSensitiveFields(['socialSecurityNumber', 'medicalRecordNumber']);
148
+ * ```
149
+ *
150
+ * @param fields - Array of additional field names to add to the sensitive fields list
151
+ */
152
+ declare function addSensitiveFields(fields: string[]): void;
153
+ /**
154
+ * Use an object compatible with either modern or legacy global scopes.
155
+ */
156
+ declare const _globalThis: typeof globalThis;
157
+ /**
158
+ * Retrieves the current logger instance:
159
+ * - Returns a request-scoped logger from AsyncLocalStorage if available
160
+ * - Falls back to the global (singleton) logger
161
+ * - Initializes the global logger if not created yet
162
+ * - If newInstance is true, returns a fresh logger without any context
163
+ *
164
+ * @param {boolean} newInstance - If true, returns a fresh logger without any context
165
+ * @returns {Logger} The logger instance (request-bound or global root logger or fresh instance)
166
+ */
167
+ declare function getLogger(newInstance?: boolean): Logger$1;
168
+ /**
169
+ * Creates a child logger with additional context.
170
+ *
171
+ * @param {Record<string, any>} bindings - Properties to attach to all log records
172
+ * @param {Logger} [parentLogger] - Parent logger (defaults to current context logger or global)
173
+ * @returns {Logger} Child logger with merged context
174
+ */
175
+ declare function createChildLogger(bindings: Record<string, any>, parentLogger?: Logger$1): Logger$1;
176
+ /**
177
+ * Creates a request-scoped logger with request ID and stores it in context
178
+ *
179
+ * @param {string} requestId - Unique request identifier
180
+ * @param {object} [additionalContext] - Additional context to include in logs
181
+ * @returns {Logger} Request-scoped logger instance
182
+ */
183
+ declare function createRequestLogger(requestId: string, additionalContext?: Record<string, any>): Logger$1;
184
+ /**
185
+ * Utility to safely log errors with proper stack trace extraction
186
+ *
187
+ * @param {Error|unknown} error - Error object to log
188
+ * @param {string} [message] - Optional message to include
189
+ * @param {Record<string, any>} [context] - Additional context properties
190
+ */
191
+ declare function logError(error: Error | unknown, message?: string, context?: Record<string, any>): void;
192
+ /**
193
+ * Expands multiple sensitive field names into their variants.
194
+ * Useful to match fields like `api_key`, `apiKey`, `apikey`, `APIKEY`, etc.
195
+ */
196
+ declare function expandSensitiveFields(fields: string[]): string[];
197
+ /**
198
+ * Generates multiple variants of a sensitive field name.
199
+ * Useful to match fields like `api_key`, `apiKey`, `apikey`, `APIKEY`, etc.
200
+ */
201
+ declare function expandSensitiveField(field: string): string[];
202
+ /**
203
+ * Generates wildcard paths up to the given depth.
204
+ *
205
+ * depth = 2 ->
206
+ * password
207
+ * *.password
208
+ * *.*.password
209
+ */
210
+ declare function generateDeepPaths(field: string, depth: number): string[];
211
+
212
+ export { _globalThis, addRedactFields, addSensitiveFields, createChildLogger, createRequestLogger, defaultSensitiveFields, expandSensitiveField, expandSensitiveFields, generateDeepPaths, getExpandedSensitiveFields, getLogger, getRedactCensor, logError, redact, setRedactCensor, setSensitiveFields };
213
+ export type { Logger, LoggerLevels };
package/logger/index.mjs CHANGED
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  import pino, { stdTimeFunctions } from 'pino';
26
- import { defaultCatbeeConfig } from '@catbee/utils/config';
26
+ import { getCatbeeGlobalConfig } from '@catbee/utils/config';
27
27
  import { ContextStore, StoreKeys } from '@catbee/utils/context-store';
28
28
 
29
29
  var __defProp = Object.defineProperty;
@@ -152,8 +152,8 @@ function setupLogger(isGlobal = true) {
152
152
  ...sensitiveFields.flatMap((field) => generateDeepPaths(field, 2))
153
153
  ]);
154
154
  const logParams = {
155
- name: defaultCatbeeConfig.logger?.name || "@catbee/utils",
156
- level: defaultCatbeeConfig.logger?.level || "info",
155
+ name: getCatbeeGlobalConfig().logger?.name || "@catbee/utils",
156
+ level: getCatbeeGlobalConfig().logger?.level || "info",
157
157
  redact: {
158
158
  paths: Array.from(paths),
159
159
  censor: /* @__PURE__ */ __name((value, path) => redact(value, path), "censor")
@@ -169,25 +169,25 @@ function setupLogger(isGlobal = true) {
169
169
  timestamp: stdTimeFunctions.isoTime
170
170
  };
171
171
  let logger;
172
- const logDir = defaultCatbeeConfig.logger?.dir?.trim();
172
+ const logDir = getCatbeeGlobalConfig().logger?.dir?.trim();
173
173
  const hasFileLogging = Boolean(logDir);
174
- if (hasFileLogging && defaultCatbeeConfig.logger?.pretty) {
174
+ if (hasFileLogging && getCatbeeGlobalConfig().logger?.pretty) {
175
175
  logger = pino(logParams, pino.transport({
176
176
  targets: [
177
177
  {
178
178
  target: "pino-pretty",
179
- level: defaultCatbeeConfig.logger?.level ?? "info",
179
+ level: getCatbeeGlobalConfig().logger?.level ?? "info",
180
180
  options: {
181
- colorize: defaultCatbeeConfig.logger?.colorize,
181
+ colorize: getCatbeeGlobalConfig().logger?.colorize,
182
182
  translateTime: "SYS:standard",
183
183
  ignore: "pid,hostname",
184
- singleLine: defaultCatbeeConfig.logger?.singleLine,
184
+ singleLine: getCatbeeGlobalConfig().logger?.singleLine,
185
185
  levelFirst: true
186
186
  }
187
187
  },
188
188
  {
189
189
  target: "pino/file",
190
- level: defaultCatbeeConfig.logger?.level ?? "info",
190
+ level: getCatbeeGlobalConfig().logger?.level ?? "info",
191
191
  options: {
192
192
  destination: `${logDir}/app.log`,
193
193
  mkdir: true
@@ -203,14 +203,14 @@ function setupLogger(isGlobal = true) {
203
203
  mkdir: true
204
204
  }
205
205
  }));
206
- } else if (defaultCatbeeConfig.logger?.pretty) {
206
+ } else if (getCatbeeGlobalConfig().logger?.pretty) {
207
207
  logger = pino(logParams, pino.transport({
208
208
  target: "pino-pretty",
209
209
  options: {
210
- colorize: defaultCatbeeConfig.logger?.colorize,
210
+ colorize: getCatbeeGlobalConfig().logger?.colorize,
211
211
  translateTime: "SYS:standard",
212
212
  ignore: "pid,hostname",
213
- singleLine: defaultCatbeeConfig.logger?.singleLine,
213
+ singleLine: getCatbeeGlobalConfig().logger?.singleLine,
214
214
  levelFirst: true
215
215
  }
216
216
  }));
@@ -22,4 +22,106 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- export * from './middleware.utils';
25
+ import { Request, Response, NextFunction } from 'express';
26
+
27
+ type Middleware = (req: Request, res: Response, next: NextFunction) => void | Promise<void>;
28
+ /**
29
+ * Attaches a unique request ID to each request.
30
+ * Useful for request tracing and correlation between logs.
31
+ *
32
+ * @param {object} [options] - Configuration options
33
+ * @param {string} [options.headerName='X-Request-ID'] - Header name for request ID
34
+ * @param {boolean} [options.exposeHeader=true] - Whether to expose the header in response
35
+ * @param {() => string} [options.generator] - Custom ID generator function
36
+ * @returns {Middleware} Express-compatible middleware
37
+ */
38
+ declare function requestId(options?: {
39
+ headerName?: string;
40
+ exposeHeader?: boolean;
41
+ generator?: () => string;
42
+ }): Middleware;
43
+ /**
44
+ * Measures request processing time and logs or adds it to response headers.
45
+ *
46
+ * @param {object} [options] - Configuration options
47
+ * @param {boolean} [options.addHeader=true] - Whether to add X-Response-Time header
48
+ * @param {boolean} [options.logOnComplete=false] - Whether to log timing info
49
+ * @returns {Middleware} Express-compatible middleware
50
+ */
51
+ declare function responseTime(options?: {
52
+ addHeader?: boolean;
53
+ logOnComplete?: boolean;
54
+ }): (req: Request, res: Response, next: NextFunction) => void;
55
+ /**
56
+ * Request timeout middleware.
57
+ * Aborts requests that take too long to process.
58
+ *
59
+ * @param {number} [timeoutMs=30000] - Timeout in milliseconds
60
+ * @returns {Middleware} Express-compatible middleware
61
+ */
62
+ declare function timeout(timeoutMs?: number): Middleware;
63
+ /**
64
+ * Creates an Express middleware that initializes a per-request context.
65
+ *
66
+ * @param {object} [options] - Optional configuration
67
+ * @param {string} [options.headerName='x-request-id'] - Header to look for request ID
68
+ * @param {boolean} [options.autoLog=true] - Whether to log automatically when context is initialized
69
+ * @returns {(req: Request, res: Response, next: NextFunction) => void} Express middleware function
70
+ */
71
+ declare function setupRequestContext(options?: {
72
+ headerName?: string;
73
+ autoLog?: boolean;
74
+ }): Middleware;
75
+ interface ErrorHandlerOptions {
76
+ /** Whether to log errors (default: true) */
77
+ logErrors?: boolean;
78
+ /** Whether to include error details in non-production (default: false) */
79
+ includeDetails?: boolean;
80
+ }
81
+ /**
82
+ * Global error handling middleware with enhanced features.
83
+ *
84
+ * @param {ErrorHandlerOptions} options - Error handler options
85
+ * @param {boolean} [options.logErrors=true] - Whether to log errors
86
+ * @param {boolean} [options.includeDetails=false] - Whether to include error details in non-production
87
+ * @returns Error middleware
88
+ *
89
+ * @example
90
+ * import express from 'express';
91
+ * import { errorHandler } from '@catbee/utils';
92
+ *
93
+ * const app = express();
94
+ *
95
+ * // Your routes
96
+ * app.get('/ping', (req, res) => {
97
+ * throw new Error('Something went wrong');
98
+ * });
99
+ *
100
+ * // Error handler (must be last middleware)
101
+ * app.use(errorHandler({ includeDetails: true }));
102
+ *
103
+ * app.listen(3000, () => {
104
+ * console.log('Server running on port 3000');
105
+ * });
106
+ */
107
+ declare function errorHandler(options?: ErrorHandlerOptions): (err: any, req: Request, res: Response, _next: NextFunction) => Response<any, Record<string, any>>;
108
+ /**
109
+ * Health check middleware for service status and custom checks.
110
+ *
111
+ * @param {object} [options] - Health check options
112
+ * @param {string} [options.path='/healthz'] - Health check endpoint path
113
+ * @param {Array<{name: string; check: () => Promise<boolean> | boolean}>} [options.checks] - Custom health checks
114
+ * @param {boolean} [options.detailed=true] - Show detailed check results
115
+ * @returns {Middleware} Express-compatible middleware
116
+ */
117
+ declare function healthCheck(options?: {
118
+ path?: string;
119
+ checks?: Array<{
120
+ name: string;
121
+ check: () => Promise<boolean> | boolean;
122
+ }>;
123
+ detailed?: boolean;
124
+ }): Middleware;
125
+
126
+ export { errorHandler, healthCheck, requestId, responseTime, setupRequestContext, timeout };
127
+ export type { ErrorHandlerOptions, Middleware };