@catbee/utils 0.0.8-rc.1 → 0.0.8-rc.3

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 (280) hide show
  1. package/build/{esnext → cjs}/config.d.ts +0 -1
  2. package/build/{src → cjs}/config.js +0 -1
  3. package/build/{esnext → cjs}/index.d.ts +0 -1
  4. package/build/{src → cjs}/index.js +0 -1
  5. package/build/{esnext → cjs}/servers/server.builder.d.ts +0 -1
  6. package/build/{src → cjs}/servers/server.builder.js +10 -13
  7. package/build/{src → cjs}/servers/server.d.ts +0 -1
  8. package/build/{src → cjs}/servers/server.js +83 -75
  9. package/build/{src → cjs}/types/api-response.d.ts +0 -1
  10. package/build/{src → cjs}/types/api-response.js +0 -1
  11. package/build/{src → cjs}/types/index.d.ts +0 -1
  12. package/build/{src → cjs}/types/index.js +0 -1
  13. package/build/{src → cjs}/types/server.d.ts +0 -1
  14. package/build/{src → cjs}/types/server.js +0 -1
  15. package/build/{src → cjs}/utils/array.utils.d.ts +0 -1
  16. package/build/{src → cjs}/utils/array.utils.js +0 -1
  17. package/build/{src → cjs}/utils/async.utils.d.ts +0 -1
  18. package/build/{src → cjs}/utils/async.utils.js +2 -3
  19. package/build/{esnext → cjs}/utils/cache.utils.d.ts +0 -1
  20. package/build/{src → cjs}/utils/cache.utils.js +7 -6
  21. package/build/{esnext → cjs}/utils/context-store.utils.d.ts +1 -2
  22. package/build/{src → cjs}/utils/context-store.utils.js +10 -9
  23. package/build/{esnext → cjs}/utils/crypto.utils.d.ts +0 -1
  24. package/build/{src → cjs}/utils/crypto.utils.js +5 -3
  25. package/build/{src → cjs}/utils/date.utils.d.ts +0 -1
  26. package/build/{src → cjs}/utils/date.utils.js +1 -2
  27. package/build/{src → cjs}/utils/decorators.utils.d.ts +30 -27
  28. package/build/{src → cjs}/utils/decorators.utils.js +169 -30
  29. package/build/{esnext → cjs}/utils/dir.utils.d.ts +0 -1
  30. package/build/{src → cjs}/utils/dir.utils.js +6 -7
  31. package/build/{esnext → cjs}/utils/env.utils.d.ts +0 -1
  32. package/build/{src → cjs}/utils/env.utils.js +5 -8
  33. package/build/{src → cjs}/utils/exception.utils.d.ts +0 -1
  34. package/build/{src → cjs}/utils/exception.utils.js +2 -1
  35. package/build/{src → cjs}/utils/fs.utils.d.ts +0 -1
  36. package/build/{src → cjs}/utils/fs.utils.js +12 -13
  37. package/build/{esnext → cjs}/utils/http-status-codes.d.ts +0 -1
  38. package/build/{src → cjs}/utils/http-status-codes.js +0 -1
  39. package/build/{esnext → cjs}/utils/id.utils.d.ts +0 -1
  40. package/build/{src → cjs}/utils/id.utils.js +0 -1
  41. package/build/{src → cjs}/utils/logger.utils.d.ts +0 -1
  42. package/build/{src → cjs}/utils/logger.utils.js +10 -6
  43. package/build/{esnext → cjs}/utils/middleware.utils.d.ts +0 -1
  44. package/build/{src → cjs}/utils/middleware.utils.js +16 -17
  45. package/build/{esnext → cjs}/utils/obj.utils.d.ts +0 -1
  46. package/build/{src → cjs}/utils/obj.utils.js +1 -2
  47. package/build/{src → cjs}/utils/performance.utils.d.ts +0 -1
  48. package/build/{src → cjs}/utils/performance.utils.js +6 -4
  49. package/build/{esnext → cjs}/utils/request.utils.d.ts +0 -1
  50. package/build/{src → cjs}/utils/request.utils.js +7 -3
  51. package/build/{esnext → cjs}/utils/response.utils.d.ts +0 -1
  52. package/build/{src → cjs}/utils/response.utils.js +42 -28
  53. package/build/{esnext → cjs}/utils/stream.utils.d.ts +0 -1
  54. package/build/{src → cjs}/utils/stream.utils.js +0 -1
  55. package/build/{esnext → cjs}/utils/string.utils.d.ts +0 -1
  56. package/build/{src → cjs}/utils/string.utils.js +0 -1
  57. package/build/{src → cjs}/utils/type.utils.d.ts +0 -1
  58. package/build/{src → cjs}/utils/type.utils.js +2 -3
  59. package/build/{src → cjs}/utils/url.utils.d.ts +0 -1
  60. package/build/{src → cjs}/utils/url.utils.js +8 -9
  61. package/build/{src → cjs}/utils/validate.utils.d.ts +0 -1
  62. package/build/{src → cjs}/utils/validate.utils.js +2 -3
  63. package/build/esm/config.d.ts +0 -1
  64. package/build/esm/config.js +6 -7
  65. package/build/esm/index.d.ts +0 -1
  66. package/build/esm/index.js +0 -1
  67. package/build/esm/servers/server.builder.d.ts +0 -1
  68. package/build/esm/servers/server.builder.js +99 -147
  69. package/build/esm/servers/server.d.ts +0 -1
  70. package/build/esm/servers/server.js +591 -876
  71. package/build/esm/types/api-response.d.ts +0 -1
  72. package/build/esm/types/api-response.js +0 -1
  73. package/build/esm/types/index.d.ts +0 -1
  74. package/build/esm/types/index.js +0 -1
  75. package/build/esm/types/server.d.ts +0 -1
  76. package/build/esm/types/server.js +0 -1
  77. package/build/esm/utils/array.utils.d.ts +0 -1
  78. package/build/esm/utils/array.utils.js +48 -86
  79. package/build/esm/utils/async.utils.d.ts +0 -1
  80. package/build/esm/utils/async.utils.js +247 -524
  81. package/build/esm/utils/cache.utils.d.ts +0 -1
  82. package/build/esm/utils/cache.utils.js +96 -301
  83. package/build/esm/utils/context-store.utils.d.ts +1 -2
  84. package/build/esm/utils/context-store.utils.js +62 -79
  85. package/build/esm/utils/crypto.utils.d.ts +0 -1
  86. package/build/esm/utils/crypto.utils.js +78 -175
  87. package/build/esm/utils/date.utils.d.ts +0 -1
  88. package/build/esm/utils/date.utils.js +47 -53
  89. package/build/esm/utils/decorators.utils.d.ts +30 -27
  90. package/build/esm/utils/decorators.utils.js +417 -461
  91. package/build/esm/utils/dir.utils.d.ts +0 -1
  92. package/build/esm/utils/dir.utils.js +264 -786
  93. package/build/esm/utils/env.utils.d.ts +0 -1
  94. package/build/esm/utils/env.utils.js +180 -271
  95. package/build/esm/utils/exception.utils.d.ts +0 -1
  96. package/build/esm/utils/exception.utils.js +112 -289
  97. package/build/esm/utils/fs.utils.d.ts +0 -1
  98. package/build/esm/utils/fs.utils.js +169 -401
  99. package/build/esm/utils/http-status-codes.d.ts +0 -1
  100. package/build/esm/utils/http-status-codes.js +0 -1
  101. package/build/esm/utils/id.utils.d.ts +0 -1
  102. package/build/esm/utils/id.utils.js +5 -9
  103. package/build/esm/utils/logger.utils.d.ts +0 -1
  104. package/build/esm/utils/logger.utils.js +34 -71
  105. package/build/esm/utils/middleware.utils.d.ts +0 -1
  106. package/build/esm/utils/middleware.utils.js +65 -155
  107. package/build/esm/utils/obj.utils.d.ts +0 -1
  108. package/build/esm/utils/obj.utils.js +69 -176
  109. package/build/esm/utils/performance.utils.d.ts +0 -1
  110. package/build/esm/utils/performance.utils.js +92 -195
  111. package/build/esm/utils/request.utils.d.ts +0 -1
  112. package/build/esm/utils/request.utils.js +41 -74
  113. package/build/esm/utils/response.utils.d.ts +0 -1
  114. package/build/esm/utils/response.utils.js +84 -107
  115. package/build/esm/utils/stream.utils.d.ts +0 -1
  116. package/build/esm/utils/stream.utils.js +38 -113
  117. package/build/esm/utils/string.utils.d.ts +0 -1
  118. package/build/esm/utils/string.utils.js +6 -11
  119. package/build/esm/utils/type.utils.d.ts +0 -1
  120. package/build/esm/utils/type.utils.js +8 -12
  121. package/build/esm/utils/url.utils.d.ts +0 -1
  122. package/build/esm/utils/url.utils.js +49 -127
  123. package/build/esm/utils/validate.utils.d.ts +0 -1
  124. package/build/esm/utils/validate.utils.js +23 -40
  125. package/package.json +288 -63
  126. package/build/esm/config.js.map +0 -1
  127. package/build/esm/index.js.map +0 -1
  128. package/build/esm/servers/server.builder.js.map +0 -1
  129. package/build/esm/servers/server.js.map +0 -1
  130. package/build/esm/types/api-response.js.map +0 -1
  131. package/build/esm/types/index.js.map +0 -1
  132. package/build/esm/types/server.js.map +0 -1
  133. package/build/esm/utils/array.utils.js.map +0 -1
  134. package/build/esm/utils/async.utils.js.map +0 -1
  135. package/build/esm/utils/cache.utils.js.map +0 -1
  136. package/build/esm/utils/context-store.utils.js.map +0 -1
  137. package/build/esm/utils/crypto.utils.js.map +0 -1
  138. package/build/esm/utils/date.utils.js.map +0 -1
  139. package/build/esm/utils/decorators.utils.js.map +0 -1
  140. package/build/esm/utils/dir.utils.js.map +0 -1
  141. package/build/esm/utils/env.utils.js.map +0 -1
  142. package/build/esm/utils/exception.utils.js.map +0 -1
  143. package/build/esm/utils/fs.utils.js.map +0 -1
  144. package/build/esm/utils/http-status-codes.js.map +0 -1
  145. package/build/esm/utils/id.utils.js.map +0 -1
  146. package/build/esm/utils/logger.utils.js.map +0 -1
  147. package/build/esm/utils/middleware.utils.js.map +0 -1
  148. package/build/esm/utils/obj.utils.js.map +0 -1
  149. package/build/esm/utils/performance.utils.js.map +0 -1
  150. package/build/esm/utils/request.utils.js.map +0 -1
  151. package/build/esm/utils/response.utils.js.map +0 -1
  152. package/build/esm/utils/stream.utils.js.map +0 -1
  153. package/build/esm/utils/string.utils.js.map +0 -1
  154. package/build/esm/utils/type.utils.js.map +0 -1
  155. package/build/esm/utils/url.utils.js.map +0 -1
  156. package/build/esm/utils/validate.utils.js.map +0 -1
  157. package/build/esnext/config.js +0 -133
  158. package/build/esnext/config.js.map +0 -1
  159. package/build/esnext/index.js +0 -50
  160. package/build/esnext/index.js.map +0 -1
  161. package/build/esnext/servers/server.builder.js +0 -657
  162. package/build/esnext/servers/server.builder.js.map +0 -1
  163. package/build/esnext/servers/server.d.ts +0 -256
  164. package/build/esnext/servers/server.js +0 -955
  165. package/build/esnext/servers/server.js.map +0 -1
  166. package/build/esnext/types/api-response.d.ts +0 -152
  167. package/build/esnext/types/api-response.js +0 -34
  168. package/build/esnext/types/api-response.js.map +0 -1
  169. package/build/esnext/types/index.d.ts +0 -125
  170. package/build/esnext/types/index.js +0 -25
  171. package/build/esnext/types/index.js.map +0 -1
  172. package/build/esnext/types/server.d.ts +0 -268
  173. package/build/esnext/types/server.js +0 -25
  174. package/build/esnext/types/server.js.map +0 -1
  175. package/build/esnext/utils/array.utils.d.ts +0 -168
  176. package/build/esnext/utils/array.utils.js +0 -345
  177. package/build/esnext/utils/array.utils.js.map +0 -1
  178. package/build/esnext/utils/async.utils.d.ts +0 -265
  179. package/build/esnext/utils/async.utils.js +0 -620
  180. package/build/esnext/utils/async.utils.js.map +0 -1
  181. package/build/esnext/utils/cache.utils.js +0 -293
  182. package/build/esnext/utils/cache.utils.js.map +0 -1
  183. package/build/esnext/utils/context-store.utils.js +0 -289
  184. package/build/esnext/utils/context-store.utils.js.map +0 -1
  185. package/build/esnext/utils/crypto.utils.js +0 -276
  186. package/build/esnext/utils/crypto.utils.js.map +0 -1
  187. package/build/esnext/utils/date.utils.d.ts +0 -159
  188. package/build/esnext/utils/date.utils.js +0 -384
  189. package/build/esnext/utils/date.utils.js.map +0 -1
  190. package/build/esnext/utils/decorators.utils.d.ts +0 -508
  191. package/build/esnext/utils/decorators.utils.js +0 -877
  192. package/build/esnext/utils/decorators.utils.js.map +0 -1
  193. package/build/esnext/utils/dir.utils.js +0 -477
  194. package/build/esnext/utils/dir.utils.js.map +0 -1
  195. package/build/esnext/utils/env.utils.js +0 -785
  196. package/build/esnext/utils/env.utils.js.map +0 -1
  197. package/build/esnext/utils/exception.utils.d.ts +0 -230
  198. package/build/esnext/utils/exception.utils.js +0 -381
  199. package/build/esnext/utils/exception.utils.js.map +0 -1
  200. package/build/esnext/utils/fs.utils.d.ts +0 -164
  201. package/build/esnext/utils/fs.utils.js +0 -349
  202. package/build/esnext/utils/fs.utils.js.map +0 -1
  203. package/build/esnext/utils/http-status-codes.js +0 -295
  204. package/build/esnext/utils/http-status-codes.js.map +0 -1
  205. package/build/esnext/utils/id.utils.js +0 -84
  206. package/build/esnext/utils/id.utils.js.map +0 -1
  207. package/build/esnext/utils/logger.utils.d.ts +0 -160
  208. package/build/esnext/utils/logger.utils.js +0 -300
  209. package/build/esnext/utils/logger.utils.js.map +0 -1
  210. package/build/esnext/utils/middleware.utils.js +0 -236
  211. package/build/esnext/utils/middleware.utils.js.map +0 -1
  212. package/build/esnext/utils/obj.utils.js +0 -413
  213. package/build/esnext/utils/obj.utils.js.map +0 -1
  214. package/build/esnext/utils/performance.utils.d.ts +0 -136
  215. package/build/esnext/utils/performance.utils.js +0 -271
  216. package/build/esnext/utils/performance.utils.js.map +0 -1
  217. package/build/esnext/utils/request.utils.js +0 -186
  218. package/build/esnext/utils/request.utils.js.map +0 -1
  219. package/build/esnext/utils/response.utils.js +0 -247
  220. package/build/esnext/utils/response.utils.js.map +0 -1
  221. package/build/esnext/utils/stream.utils.js +0 -210
  222. package/build/esnext/utils/stream.utils.js.map +0 -1
  223. package/build/esnext/utils/string.utils.js +0 -165
  224. package/build/esnext/utils/string.utils.js.map +0 -1
  225. package/build/esnext/utils/type.utils.d.ts +0 -90
  226. package/build/esnext/utils/type.utils.js +0 -187
  227. package/build/esnext/utils/type.utils.js.map +0 -1
  228. package/build/esnext/utils/url.utils.d.ts +0 -141
  229. package/build/esnext/utils/url.utils.js +0 -304
  230. package/build/esnext/utils/url.utils.js.map +0 -1
  231. package/build/esnext/utils/validate.utils.d.ts +0 -177
  232. package/build/esnext/utils/validate.utils.js +0 -320
  233. package/build/esnext/utils/validate.utils.js.map +0 -1
  234. package/build/src/config.d.ts +0 -122
  235. package/build/src/config.js.map +0 -1
  236. package/build/src/index.d.ts +0 -27
  237. package/build/src/index.js.map +0 -1
  238. package/build/src/servers/server.builder.d.ts +0 -508
  239. package/build/src/servers/server.builder.js.map +0 -1
  240. package/build/src/servers/server.js.map +0 -1
  241. package/build/src/types/api-response.js.map +0 -1
  242. package/build/src/types/index.js.map +0 -1
  243. package/build/src/types/server.js.map +0 -1
  244. package/build/src/utils/array.utils.js.map +0 -1
  245. package/build/src/utils/async.utils.js.map +0 -1
  246. package/build/src/utils/cache.utils.d.ts +0 -153
  247. package/build/src/utils/cache.utils.js.map +0 -1
  248. package/build/src/utils/context-store.utils.d.ts +0 -189
  249. package/build/src/utils/context-store.utils.js.map +0 -1
  250. package/build/src/utils/crypto.utils.d.ts +0 -160
  251. package/build/src/utils/crypto.utils.js.map +0 -1
  252. package/build/src/utils/date.utils.js.map +0 -1
  253. package/build/src/utils/decorators.utils.js.map +0 -1
  254. package/build/src/utils/dir.utils.d.ts +0 -196
  255. package/build/src/utils/dir.utils.js.map +0 -1
  256. package/build/src/utils/env.utils.d.ts +0 -377
  257. package/build/src/utils/env.utils.js.map +0 -1
  258. package/build/src/utils/exception.utils.js.map +0 -1
  259. package/build/src/utils/fs.utils.js.map +0 -1
  260. package/build/src/utils/http-status-codes.d.ts +0 -266
  261. package/build/src/utils/http-status-codes.js.map +0 -1
  262. package/build/src/utils/id.utils.d.ts +0 -36
  263. package/build/src/utils/id.utils.js.map +0 -1
  264. package/build/src/utils/logger.utils.js.map +0 -1
  265. package/build/src/utils/middleware.utils.d.ts +0 -100
  266. package/build/src/utils/middleware.utils.js.map +0 -1
  267. package/build/src/utils/obj.utils.d.ts +0 -124
  268. package/build/src/utils/obj.utils.js.map +0 -1
  269. package/build/src/utils/performance.utils.js.map +0 -1
  270. package/build/src/utils/request.utils.d.ts +0 -86
  271. package/build/src/utils/request.utils.js.map +0 -1
  272. package/build/src/utils/response.utils.d.ts +0 -163
  273. package/build/src/utils/response.utils.js.map +0 -1
  274. package/build/src/utils/stream.utils.d.ts +0 -88
  275. package/build/src/utils/stream.utils.js.map +0 -1
  276. package/build/src/utils/string.utils.d.ts +0 -93
  277. package/build/src/utils/string.utils.js.map +0 -1
  278. package/build/src/utils/type.utils.js.map +0 -1
  279. package/build/src/utils/url.utils.js.map +0 -1
  280. package/build/src/utils/validate.utils.js.map +0 -1
@@ -1,236 +0,0 @@
1
- /*
2
- * The MIT License
3
- *
4
- * Copyright (c) 2025 Catbee Technologies. https://catbee-utils.npm.hprasath.com/license
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a copy
7
- * of this software and associated documentation files (the "Software"), to deal
8
- * in the Software without restriction, including without limitation the rights
9
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- * copies of the Software, and to permit persons to whom the Software is
11
- * furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice shall be included in all
14
- * copies or substantial portions of the Software.
15
- *
16
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- * SOFTWARE.
23
- */
24
- import { uuid } from './id.utils';
25
- import { HttpStatusCodes } from './http-status-codes';
26
- import { createFinalErrorResponse, ErrorResponse } from './response.utils';
27
- import { getLogger } from './logger.utils';
28
- import { ContextStore, StoreKeys } from './context-store.utils';
29
- import { RequestTimeoutException } from './exception.utils';
30
- /**
31
- * Attaches a unique request ID to each request.
32
- * Useful for request tracing and correlation between logs.
33
- *
34
- * @param {object} [options] - Configuration options
35
- * @param {string} [options.headerName='X-Request-ID'] - Header name for request ID
36
- * @param {boolean} [options.exposeHeader=true] - Whether to expose the header in response
37
- * @param {() => string} [options.generator] - Custom ID generator function
38
- * @returns {Middleware} Express-compatible middleware
39
- */
40
- export function requestId(options) {
41
- const headerName = (options === null || options === void 0 ? void 0 : options.headerName) || 'X-Request-ID';
42
- const exposeHeader = (options === null || options === void 0 ? void 0 : options.exposeHeader) !== false;
43
- const generateId = (options === null || options === void 0 ? void 0 : options.generator) || uuid;
44
- return (req, res, next) => {
45
- // Use existing request ID from header or generate a new one
46
- const existingId = req.headers[headerName.toLowerCase()];
47
- const id = existingId || generateId();
48
- // Attach ID to request object
49
- req.id = id;
50
- // Add ID to response headers
51
- if (exposeHeader) {
52
- res.setHeader(headerName, id);
53
- }
54
- next();
55
- };
56
- }
57
- /**
58
- * Measures request processing time and logs or adds it to response headers.
59
- *
60
- * @param {object} [options] - Configuration options
61
- * @param {boolean} [options.addHeader=true] - Whether to add X-Response-Time header
62
- * @param {boolean} [options.logOnComplete=false] - Whether to log timing info
63
- * @returns {Middleware} Express-compatible middleware
64
- */
65
- export function responseTime(options) {
66
- const addHeader = (options === null || options === void 0 ? void 0 : options.addHeader) !== false;
67
- const logOnComplete = (options === null || options === void 0 ? void 0 : options.logOnComplete) === true;
68
- return (req, res, next) => {
69
- const start = process.hrtime();
70
- // Function to calculate duration
71
- const getDuration = () => {
72
- const diff = process.hrtime(start);
73
- return (diff[0] * 1e3 + diff[1] * 1e-6).toFixed(2);
74
- };
75
- if (addHeader) {
76
- // Ensure header is set before response is sent
77
- const originalWriteHead = res.writeHead;
78
- res.writeHead = function (...args) {
79
- res.setHeader('X-Response-Time', `${getDuration()}ms`);
80
- return originalWriteHead.apply(this, args);
81
- };
82
- }
83
- if (logOnComplete) {
84
- res.on('finish', () => {
85
- getLogger().info(`${req.method} ${req.url} - ${getDuration()}ms`);
86
- });
87
- }
88
- next();
89
- };
90
- }
91
- /**
92
- * Request timeout middleware.
93
- * Aborts requests that take too long to process.
94
- *
95
- * @param {number} [timeoutMs=30000] - Timeout in milliseconds
96
- * @returns {Middleware} Express-compatible middleware
97
- */
98
- export function timeout(timeoutMs = 30000) {
99
- return (_req, res, next) => {
100
- // Set timeout for the request
101
- const timer = setTimeout(() => {
102
- const response = new RequestTimeoutException('Request timed out');
103
- res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(response);
104
- }, timeoutMs);
105
- // Clear timeout when response is sent
106
- res.on('finish', () => {
107
- clearTimeout(timer);
108
- });
109
- next();
110
- };
111
- }
112
- /**
113
- * Creates an Express middleware that initializes a per-request context.
114
- *
115
- * @param {object} [options] - Optional configuration
116
- * @param {string} [options.headerName='x-request-id'] - Header to look for request ID
117
- * @param {boolean} [options.autoLog=true] - Whether to log automatically when context is initialized
118
- * @returns {(req: Request, res: Response, next: NextFunction) => void} Express middleware function
119
- */
120
- export function setupRequestContext(options = {}) {
121
- const { headerName = 'x-request-id', autoLog = true } = options;
122
- return (req, _res, next) => {
123
- // Generate or use existing request ID
124
- const requestId = req.headers[headerName] || (req === null || req === void 0 ? void 0 : req['id']) || uuid();
125
- ContextStore.run({ [StoreKeys.REQUEST_ID]: requestId }, () => {
126
- // Create a child logger for this request
127
- const childLogger = getLogger().child({
128
- requestId,
129
- method: req.method,
130
- url: req.originalUrl || req.url
131
- });
132
- req.logger = childLogger;
133
- // Store logger in context
134
- ContextStore.set(StoreKeys.LOGGER, childLogger);
135
- if (autoLog) {
136
- req.logger.info('Request context initialized');
137
- }
138
- next();
139
- });
140
- };
141
- }
142
- /**
143
- * Global error handling middleware with enhanced features.
144
- *
145
- * @param {ErrorHandlerOptions} options - Error handler options
146
- * @param {boolean} [options.logErrors=true] - Whether to log errors
147
- * @param {boolean} [options.includeDetails=false] - Whether to include error details in non-production
148
- * @returns Error middleware
149
- *
150
- * @example
151
- * import express from 'express';
152
- * import { errorHandler } from '@catbee/utils';
153
- *
154
- * const app = express();
155
- *
156
- * // Your routes
157
- * app.get('/ping', (req, res) => {
158
- * throw new Error('Something went wrong');
159
- * });
160
- *
161
- * // Error handler (must be last middleware)
162
- * app.use(errorHandler({ includeDetails: true }));
163
- *
164
- * app.listen(3000, () => {
165
- * console.log('Server running on port 3000');
166
- * });
167
- */
168
- export function errorHandler(options) {
169
- const logErrors = (options === null || options === void 0 ? void 0 : options.logErrors) !== false;
170
- const includeDetails = (options === null || options === void 0 ? void 0 : options.includeDetails) === true;
171
- return (err, req, res, _next) => {
172
- // Determine status code
173
- const status = (err === null || err === void 0 ? void 0 : err.status) || (err === null || err === void 0 ? void 0 : err.statusCode) || HttpStatusCodes.INTERNAL_SERVER_ERROR;
174
- // Log error if enabled
175
- if (logErrors) {
176
- getLogger().error({ err }, `${err.message || 'Unknown error'}`);
177
- }
178
- // Handle ErrorResponse instances (our custom error class)
179
- if (err instanceof ErrorResponse) {
180
- const result = {
181
- error: true,
182
- message: err.message,
183
- timestamp: err.timestamp,
184
- requestId: (err === null || err === void 0 ? void 0 : err.requestId) || (req === null || req === void 0 ? void 0 : req.id) || uuid(),
185
- status,
186
- path: req.originalUrl || req.url
187
- };
188
- if (includeDetails && (err === null || err === void 0 ? void 0 : err.stack)) {
189
- result.stack = err.stack.split('\n').map((line) => line.trim());
190
- }
191
- return res.status(status).json(result);
192
- }
193
- // Handle any other errors
194
- return res
195
- .status(status)
196
- .json(createFinalErrorResponse(req, status, (err === null || err === void 0 ? void 0 : err.message) || 'Internal Server Error', err, { includeDetails }));
197
- };
198
- }
199
- /**
200
- * Health check middleware for service status and custom checks.
201
- *
202
- * @param {object} [options] - Health check options
203
- * @param {string} [options.path='/healthz'] - Health check endpoint path
204
- * @param {Array<{name: string; check: () => Promise<boolean> | boolean}>} [options.checks] - Custom health checks
205
- * @param {boolean} [options.detailed=true] - Show detailed check results
206
- * @returns {Middleware} Express-compatible middleware
207
- */
208
- export function healthCheck(options) {
209
- const path = (options === null || options === void 0 ? void 0 : options.path) || '/healthz';
210
- const checks = (options === null || options === void 0 ? void 0 : options.checks) || [];
211
- const detailed = (options === null || options === void 0 ? void 0 : options.detailed) !== false;
212
- return async (req, res, next) => {
213
- if (req.path !== path)
214
- return next();
215
- const results = {};
216
- let allHealthy = true;
217
- for (const check of checks) {
218
- try {
219
- const result = await Promise.resolve(check.check());
220
- results[check.name] = !!result;
221
- if (!result)
222
- allHealthy = false;
223
- }
224
- catch (_a) {
225
- results[check.name] = false;
226
- allHealthy = false;
227
- }
228
- }
229
- const status = allHealthy ? HttpStatusCodes.OK : HttpStatusCodes.SERVICE_UNAVAILABLE;
230
- const response = detailed
231
- ? { status: allHealthy ? 'ok' : 'unhealthy', checks: results, timestamp: new Date().toISOString() }
232
- : { status: allHealthy ? 'ok' : 'unhealthy' };
233
- res.status(status).json(response);
234
- };
235
- }
236
- //# sourceMappingURL=middleware.utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"middleware.utils.js","sourceRoot":"","sources":["../../../src/utils/middleware.utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The MIT License\n *\n * Copyright (c) 2025 Catbee Technologies. https://catbee-utils.npm.hprasath.com/license\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport { uuid } from './id.utils';\nimport { HttpStatusCodes } from './http-status-codes';\nimport { createFinalErrorResponse, ErrorResponse } from './response.utils';\nimport { getLogger } from './logger.utils';\nimport type { Request, Response, NextFunction } from 'express';\nimport { ContextStore, StoreKeys } from './context-store.utils';\nimport { RequestTimeoutException } from './exception.utils';\nimport { ApiErrorResponse } from '../types/api-response';\n\nexport type Middleware = (req: Request, res: Response, next: NextFunction) => void | Promise<void>;\n\n/**\n * Attaches a unique request ID to each request.\n * Useful for request tracing and correlation between logs.\n *\n * @param {object} [options] - Configuration options\n * @param {string} [options.headerName='X-Request-ID'] - Header name for request ID\n * @param {boolean} [options.exposeHeader=true] - Whether to expose the header in response\n * @param {() => string} [options.generator] - Custom ID generator function\n * @returns {Middleware} Express-compatible middleware\n */\nexport function requestId(options?: {\n headerName?: string;\n exposeHeader?: boolean;\n generator?: () => string;\n}): Middleware {\n const headerName = options?.headerName || 'X-Request-ID';\n const exposeHeader = options?.exposeHeader !== false;\n const generateId = options?.generator || uuid;\n\n return (req, res, next) => {\n // Use existing request ID from header or generate a new one\n const existingId = req.headers[headerName.toLowerCase()];\n const id = (existingId as string) || generateId();\n\n // Attach ID to request object\n req.id = id;\n\n // Add ID to response headers\n if (exposeHeader) {\n res.setHeader(headerName, id);\n }\n\n next();\n };\n}\n\n/**\n * Measures request processing time and logs or adds it to response headers.\n *\n * @param {object} [options] - Configuration options\n * @param {boolean} [options.addHeader=true] - Whether to add X-Response-Time header\n * @param {boolean} [options.logOnComplete=false] - Whether to log timing info\n * @returns {Middleware} Express-compatible middleware\n */\nexport function responseTime(options?: { addHeader?: boolean; logOnComplete?: boolean }) {\n const addHeader = options?.addHeader !== false;\n const logOnComplete = options?.logOnComplete === true;\n\n return (req: Request, res: Response, next: NextFunction) => {\n const start = process.hrtime();\n\n // Function to calculate duration\n const getDuration = () => {\n const diff = process.hrtime(start);\n return (diff[0] * 1e3 + diff[1] * 1e-6).toFixed(2);\n };\n\n if (addHeader) {\n // Ensure header is set before response is sent\n const originalWriteHead = res.writeHead;\n res.writeHead = function (...args: any[]) {\n res.setHeader('X-Response-Time', `${getDuration()}ms`);\n return originalWriteHead.apply(this, args as any);\n };\n }\n\n if (logOnComplete) {\n res.on('finish', () => {\n getLogger().info(`${req.method} ${req.url} - ${getDuration()}ms`);\n });\n }\n\n next();\n };\n}\n\n/**\n * Request timeout middleware.\n * Aborts requests that take too long to process.\n *\n * @param {number} [timeoutMs=30000] - Timeout in milliseconds\n * @returns {Middleware} Express-compatible middleware\n */\nexport function timeout(timeoutMs: number = 30000): Middleware {\n return (_req, res, next) => {\n // Set timeout for the request\n const timer = setTimeout(() => {\n const response = new RequestTimeoutException('Request timed out');\n res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(response);\n }, timeoutMs);\n\n // Clear timeout when response is sent\n res.on('finish', () => {\n clearTimeout(timer);\n });\n\n next();\n };\n}\n\n/**\n * Creates an Express middleware that initializes a per-request context.\n *\n * @param {object} [options] - Optional configuration\n * @param {string} [options.headerName='x-request-id'] - Header to look for request ID\n * @param {boolean} [options.autoLog=true] - Whether to log automatically when context is initialized\n * @returns {(req: Request, res: Response, next: NextFunction) => void} Express middleware function\n */\nexport function setupRequestContext(options: { headerName?: string; autoLog?: boolean } = {}): Middleware {\n const { headerName = 'x-request-id', autoLog = true } = options;\n return (req, _res, next) => {\n // Generate or use existing request ID\n const requestId = (req.headers[headerName] as string) || req?.['id'] || uuid();\n\n ContextStore.run({ [StoreKeys.REQUEST_ID]: requestId }, () => {\n // Create a child logger for this request\n const childLogger = getLogger().child({\n requestId,\n method: req.method,\n url: req.originalUrl || req.url\n });\n\n req.logger = childLogger;\n\n // Store logger in context\n ContextStore.set(StoreKeys.LOGGER, childLogger);\n\n if (autoLog) {\n req.logger.info('Request context initialized');\n }\n\n next();\n });\n };\n}\n\nexport interface ErrorHandlerOptions {\n /** Whether to log errors (default: true) */\n logErrors?: boolean;\n /** Whether to include error details in non-production (default: false) */\n includeDetails?: boolean;\n}\n\n/**\n * Global error handling middleware with enhanced features.\n *\n * @param {ErrorHandlerOptions} options - Error handler options\n * @param {boolean} [options.logErrors=true] - Whether to log errors\n * @param {boolean} [options.includeDetails=false] - Whether to include error details in non-production\n * @returns Error middleware\n *\n * @example\n * import express from 'express';\n * import { errorHandler } from '@catbee/utils';\n *\n * const app = express();\n *\n * // Your routes\n * app.get('/ping', (req, res) => {\n * throw new Error('Something went wrong');\n * });\n *\n * // Error handler (must be last middleware)\n * app.use(errorHandler({ includeDetails: true }));\n *\n * app.listen(3000, () => {\n * console.log('Server running on port 3000');\n * });\n */\nexport function errorHandler(options?: ErrorHandlerOptions) {\n const logErrors = options?.logErrors !== false;\n const includeDetails = options?.includeDetails === true;\n\n return (err: any, req: Request, res: Response, _next: NextFunction) => {\n // Determine status code\n const status = err?.status || err?.statusCode || HttpStatusCodes.INTERNAL_SERVER_ERROR;\n\n // Log error if enabled\n if (logErrors) {\n getLogger().error({ err }, `${err.message || 'Unknown error'}`);\n }\n\n // Handle ErrorResponse instances (our custom error class)\n if (err instanceof ErrorResponse) {\n const result: ApiErrorResponse = {\n error: true,\n message: err.message,\n timestamp: err.timestamp,\n requestId: err?.requestId || req?.id || uuid(),\n status,\n path: req.originalUrl || req.url\n };\n\n if (includeDetails && err?.stack) {\n result.stack = err.stack.split('\\n').map((line: string) => line.trim());\n }\n return res.status(status).json(result);\n }\n\n // Handle any other errors\n return res\n .status(status)\n .json(createFinalErrorResponse(req, status, err?.message || 'Internal Server Error', err, { includeDetails }));\n };\n}\n\n/**\n * Health check middleware for service status and custom checks.\n *\n * @param {object} [options] - Health check options\n * @param {string} [options.path='/healthz'] - Health check endpoint path\n * @param {Array<{name: string; check: () => Promise<boolean> | boolean}>} [options.checks] - Custom health checks\n * @param {boolean} [options.detailed=true] - Show detailed check results\n * @returns {Middleware} Express-compatible middleware\n */\nexport function healthCheck(options?: {\n path?: string;\n checks?: Array<{ name: string; check: () => Promise<boolean> | boolean }>;\n detailed?: boolean;\n}): Middleware {\n const path = options?.path || '/healthz';\n const checks = options?.checks || [];\n const detailed = options?.detailed !== false;\n\n return async (req, res, next) => {\n if (req.path !== path) return next();\n const results: Record<string, boolean> = {};\n let allHealthy = true;\n for (const check of checks) {\n try {\n const result = await Promise.resolve(check.check());\n results[check.name] = !!result;\n if (!result) allHealthy = false;\n } catch {\n results[check.name] = false;\n allHealthy = false;\n }\n }\n const status = allHealthy ? HttpStatusCodes.OK : HttpStatusCodes.SERVICE_UNAVAILABLE;\n const response = detailed\n ? { status: allHealthy ? 'ok' : 'unhealthy', checks: results, timestamp: new Date().toISOString() }\n : { status: allHealthy ? 'ok' : 'unhealthy' };\n res.status(status).json(response);\n };\n}\n"]}
@@ -1,413 +0,0 @@
1
- /*
2
- * The MIT License
3
- *
4
- * Copyright (c) 2025 Catbee Technologies. https://catbee-utils.npm.hprasath.com/license
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a copy
7
- * of this software and associated documentation files (the "Software"), to deal
8
- * in the Software without restriction, including without limitation the rights
9
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- * copies of the Software, and to permit persons to whom the Software is
11
- * furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice shall be included in all
14
- * copies or substantial portions of the Software.
15
- *
16
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- * SOFTWARE.
23
- */
24
- /**
25
- * Checks whether the object has no own enumerable properties.
26
- *
27
- * @param {Record<any, any>} obj - The object to check.
28
- * @returns {boolean} True if the object is empty, false otherwise.
29
- */
30
- export function isObjEmpty(obj) {
31
- return !!obj && typeof obj === 'object' && Object.keys(obj).length === 0;
32
- }
33
- /**
34
- * Returns a new object with only the specified keys picked.
35
- *
36
- * @template T
37
- * @template K
38
- * @param {T} obj - The source object.
39
- * @param {K[]} keys - Keys to pick from the object.
40
- * @returns {Pick<T, K>} New object with picked keys.
41
- */
42
- export function pick(obj, keys) {
43
- return Object.fromEntries(keys.map(key => [key, obj[key]]));
44
- }
45
- /**
46
- * Returns a new object with the specified keys omitted.
47
- *
48
- * @template T
49
- * @template K
50
- * @param {T} obj - The source object.
51
- * @param {K[]} keys - Keys to omit from the object.
52
- * @returns {Omit<T, K>} New object without omitted keys.
53
- */
54
- export function omit(obj, keys) {
55
- return Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key)));
56
- }
57
- /**
58
- * Deeply merges multiple objects into the target object (mutates and returns the target object, not pure).
59
- *
60
- * @template T
61
- * @param {T} target - The object to merge into (will be mutated).
62
- * @param {...any[]} sources - The objects to merge from.
63
- * @returns {T} The merged object (same as target).
64
- */
65
- export function deepObjMerge(target, ...sources) {
66
- if (!sources.length)
67
- return target;
68
- const seen = new WeakMap();
69
- seen.set(target, target);
70
- for (const s of sources) {
71
- if (s && typeof s === 'object') {
72
- seen.set(s, target);
73
- }
74
- }
75
- function deepClone(value) {
76
- if (value === null || typeof value !== 'object')
77
- return value;
78
- if (seen.has(value))
79
- return seen.get(value);
80
- // Date
81
- if (value instanceof Date) {
82
- return new Date(value.getTime());
83
- }
84
- // Array
85
- if (Array.isArray(value)) {
86
- const clone = [];
87
- seen.set(value, clone);
88
- value.forEach((item, i) => (clone[i] = deepClone(item)));
89
- return clone;
90
- }
91
- // Set
92
- if (value instanceof Set) {
93
- const clone = new Set();
94
- seen.set(value, clone);
95
- value.forEach(item => clone.add(deepClone(item)));
96
- return clone;
97
- }
98
- // Map
99
- if (value instanceof Map) {
100
- const clone = new Map();
101
- seen.set(value, clone);
102
- value.forEach((val, key) => clone.set(key, deepClone(val)));
103
- return clone;
104
- }
105
- // RegExp
106
- if (value instanceof RegExp) {
107
- return new RegExp(value.source, value.flags);
108
- }
109
- // ArrayBuffer
110
- if (value instanceof ArrayBuffer) {
111
- return value.slice(0);
112
- }
113
- // TypedArrays
114
- if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
115
- const typed = value; // cast for TS
116
- const ctor = typed.constructor;
117
- // List of standard TypedArray constructors
118
- const typedArrayCtors = [
119
- Int8Array,
120
- Uint8Array,
121
- Uint8ClampedArray,
122
- Int16Array,
123
- Uint16Array,
124
- Int32Array,
125
- Uint32Array,
126
- Float32Array,
127
- Float64Array,
128
- BigInt64Array,
129
- BigUint64Array
130
- ].filter(Boolean); // filter out undefined (for environments without BigInt)
131
- const typedArrayCtorSet = new Set(typedArrayCtors);
132
- if (typeof ctor === 'function' && typedArrayCtorSet.has(ctor)) {
133
- // Defensive: ensure buffer is an ArrayBuffer and slice is available
134
- const buffer = typed.buffer && typeof typed.buffer.slice === 'function' ? typed.buffer.slice(0) : typed.buffer;
135
- const clone = new ctor(buffer, typed.byteOffset, typed.length);
136
- seen.set(value, clone);
137
- return clone;
138
- }
139
- else if (typeof typed.slice === 'function') {
140
- // Fallback: try using slice if available (e.g., Node.js Buffer)
141
- const clone = typed.slice();
142
- seen.set(value, clone);
143
- return clone;
144
- }
145
- else {
146
- // Could not safely clone, throw an error for better debugging
147
- throw new Error('Cannot deep clone unknown TypedArray type: ' + (typed && typed.constructor && typed.constructor.name));
148
- }
149
- }
150
- const clone = Object.create(Object.getPrototypeOf(value));
151
- seen.set(value, clone);
152
- Reflect.ownKeys(value).forEach(key => {
153
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
154
- if (descriptor.get || descriptor.set) {
155
- Object.defineProperty(clone, key, descriptor);
156
- }
157
- else {
158
- clone[key] = deepClone(value[key]);
159
- }
160
- });
161
- return clone;
162
- }
163
- function mergeProp(target, source, key) {
164
- const targetValue = target[key];
165
- const sourceValue = source[key];
166
- // Ignore undefined in source
167
- if (sourceValue === undefined)
168
- return;
169
- // Primitives → overwrite directly
170
- if (sourceValue === null || typeof sourceValue !== 'object') {
171
- target[key] = sourceValue;
172
- return;
173
- }
174
- // Arrays → replace (lodash behavior)
175
- if (Array.isArray(sourceValue)) {
176
- target[key] = deepClone(sourceValue);
177
- return;
178
- }
179
- // Special cloneable objects
180
- if (sourceValue instanceof Date ||
181
- sourceValue instanceof RegExp ||
182
- sourceValue instanceof Set ||
183
- sourceValue instanceof Map ||
184
- sourceValue instanceof ArrayBuffer ||
185
- (ArrayBuffer.isView(sourceValue) && !(sourceValue instanceof DataView))) {
186
- target[key] = deepClone(sourceValue);
187
- return;
188
- }
189
- // Plain objects → recursive merge
190
- if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
191
- for (const k of Reflect.ownKeys(sourceValue)) {
192
- mergeProp(targetValue, sourceValue, k);
193
- }
194
- return;
195
- }
196
- // Default → overwrite with clone
197
- target[key] = deepClone(sourceValue);
198
- }
199
- for (const source of sources) {
200
- if (source == null)
201
- continue;
202
- for (const key of Reflect.ownKeys(source)) {
203
- mergeProp(target, source, key);
204
- }
205
- }
206
- return target;
207
- }
208
- /**
209
- * Checks if a value is a plain object (i.e., not an array, null, or a built-in object).
210
- *
211
- * @param value - The value to check.
212
- * @returns True if the value is a plain object, false otherwise.
213
- */
214
- export function isPlainObject(value) {
215
- if (typeof value !== 'object' || value === null)
216
- return false;
217
- if (Array.isArray(value))
218
- return false;
219
- const proto = Object.getPrototypeOf(value);
220
- return proto === Object.prototype || proto === null;
221
- }
222
- /**
223
- * Flattens a nested object using dot notation for keys (e.g., `{a: {b: 1}}` → `{ "a.b": 1 }`).
224
- *
225
- * @template T
226
- * @param {T} obj - The object to flatten.
227
- * @param {string} [prefix=""] - Optional prefix for nested keys (used internally).
228
- * @returns {Record<string, any>} A new object with flattened keys.
229
- */
230
- export function flattenObject(obj, prefix = '') {
231
- return Object.entries(obj).reduce((acc, [key, value]) => {
232
- const newKey = prefix ? `${prefix}.${key}` : key;
233
- if (value && typeof value === 'object' && !Array.isArray(value)) {
234
- Object.assign(acc, flattenObject(value, newKey));
235
- }
236
- else {
237
- acc[newKey] = value;
238
- }
239
- return acc;
240
- }, {});
241
- }
242
- /**
243
- * Safely gets the value of a deeply nested key in an object using dot/bracket notation path.
244
- *
245
- * @template T
246
- * @param {T} obj - The object to extract from.
247
- * @param {string} path - String path using dot and/or bracket notation (e.g., 'user.friends[0].name').
248
- * @returns {any} The value at the given path, or undefined if not found.
249
- */
250
- export function getValueByPath(obj, path) {
251
- if (!obj || typeof obj !== 'object')
252
- return undefined;
253
- // Convert path like "a.b[0].c" into ["a", "b", "0", "c"]
254
- const parts = path
255
- .replace(/\[(\d+)\]/g, '.$1') // convert [0] to .0
256
- .split('.')
257
- .filter(Boolean); // remove empty strings
258
- return parts.reduce((acc, key) => acc === null || acc === void 0 ? void 0 : acc[key], obj);
259
- }
260
- /**
261
- * Sets a value at a deeply nested key in an object using dot/bracket notation path.
262
- * Creates intermediate objects and arrays as needed.
263
- *
264
- * @template T
265
- * @param {T} obj - The object to modify.
266
- * @param {string} path - String path using dot and/or bracket notation (e.g., 'user.friends[0].name').
267
- * @param {any} value - The value to set at the path.
268
- * @returns {T} The modified object.
269
- */
270
- export function setValueByPath(obj, path, value) {
271
- if (!obj || typeof obj !== 'object')
272
- return obj;
273
- // Convert path like "a.b[0].c" into ["a", "b", "0", "c"]
274
- const parts = path
275
- .replace(/\[(\d+)\]/g, '.$1') // convert [0] to .0
276
- .split('.')
277
- .filter(Boolean); // remove empty strings
278
- // Handle empty path
279
- if (parts.length === 0)
280
- return obj;
281
- let current = obj;
282
- // Navigate to the parent of the target property
283
- for (let i = 0; i < parts.length - 1; i++) {
284
- const key = parts[i];
285
- const isArrayIndex = !isNaN(Number(parts[i + 1]));
286
- if (current[key] === undefined) {
287
- // Create intermediate object or array based on next key type
288
- current[key] = isArrayIndex ? [] : {};
289
- }
290
- current = current[key];
291
- }
292
- // Set the value at the final key
293
- const finalKey = parts[parts.length - 1];
294
- current[finalKey] = value;
295
- return obj;
296
- }
297
- /**
298
- * Performs a deep equality check between two objects.
299
- *
300
- * @param {any} a - First value to compare.
301
- * @param {any} b - Second value to compare.
302
- * @returns {boolean} True if values are deeply equal.
303
- */
304
- export function isEqual(a, b) {
305
- // Check if primitives or references to the same object
306
- if (a === b)
307
- return true;
308
- // Check if either is null/undefined or not an object
309
- if (a == null || b == null || typeof a !== 'object' || typeof b !== 'object') {
310
- return false;
311
- }
312
- // Handle Date objects
313
- if (a instanceof Date && b instanceof Date) {
314
- return a.getTime() === b.getTime();
315
- }
316
- // If one is Date but the other isn't
317
- if (a instanceof Date || b instanceof Date) {
318
- return false;
319
- }
320
- // Handle arrays
321
- if (Array.isArray(a) && Array.isArray(b)) {
322
- if (a.length !== b.length)
323
- return false;
324
- // Check each element
325
- for (let i = 0; i < a.length; i++) {
326
- if (!isEqual(a[i], b[i]))
327
- return false;
328
- }
329
- return true;
330
- }
331
- // If one is Array but the other isn't
332
- if (Array.isArray(a) || Array.isArray(b)) {
333
- return false;
334
- }
335
- // Compare object keys
336
- const keysA = Object.keys(a);
337
- const keysB = Object.keys(b);
338
- if (keysA.length !== keysB.length)
339
- return false;
340
- // Check if every key in A exists in B and has the same value
341
- return keysA.every(key => Object.prototype.hasOwnProperty.call(b, key) && isEqual(a[key], b[key]));
342
- }
343
- /**
344
- * Filters object properties based on a predicate function.
345
- *
346
- * @template T
347
- * @param {T} obj - The source object.
348
- * @param {(value: any, key: string, obj: T) => boolean} predicate - Filter function.
349
- * @returns {Partial<T>} New object with filtered properties.
350
- */
351
- export function filterObject(obj, predicate) {
352
- return Object.fromEntries(Object.entries(obj).filter(([key, value]) => predicate(value, key, obj)));
353
- }
354
- /**
355
- * Maps object values to new values using a mapping function.
356
- *
357
- * @template T
358
- * @template U
359
- * @param {T} obj - The source object.
360
- * @param {(value: any, key: string, obj: T) => U} mapFn - Mapping function.
361
- * @returns {Record<keyof T, U>} New object with mapped values.
362
- */
363
- export function mapObject(obj, mapFn) {
364
- return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, mapFn(value, key, obj)]));
365
- }
366
- /**
367
- * Recursively freezes an object and all its properties.
368
- * Makes an object immutable.
369
- *
370
- * @template T
371
- * @param {T} obj - The object to freeze.
372
- * @returns {Readonly<T>} The frozen object.
373
- */
374
- export function deepFreeze(obj) {
375
- // Freeze primitive properties
376
- Object.freeze(obj);
377
- // Recursively freeze nested objects
378
- for (const prop of Object.getOwnPropertyNames(obj)) {
379
- const value = obj[prop];
380
- if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
381
- deepFreeze(value);
382
- }
383
- }
384
- return obj;
385
- }
386
- /**
387
- * Safely checks if a value is an object (not null, not array).
388
- *
389
- * @param {unknown} value - Value to check.
390
- * @returns {boolean} True if value is a non-null, non-array object.
391
- */
392
- export function isObject(value) {
393
- return value !== null && typeof value === 'object' && !Array.isArray(value);
394
- }
395
- /**
396
- * Gets all paths in an object using dot notation.
397
- *
398
- * @param {Record<string, any>} obj - Object to analyze.
399
- * @param {string} [parentPath=""] - Internal param for recursion.
400
- * @returns {string[]} Array of all paths in dot notation.
401
- */
402
- export function getAllPaths(obj, parentPath = '') {
403
- if (!isObject(obj))
404
- return [];
405
- return Object.entries(obj).flatMap(([key, value]) => {
406
- const currentPath = parentPath ? `${parentPath}.${key}` : key;
407
- if (isObject(value)) {
408
- return [currentPath, ...getAllPaths(value, currentPath)];
409
- }
410
- return [currentPath];
411
- });
412
- }
413
- //# sourceMappingURL=obj.utils.js.map