@catbee/utils 0.0.1 → 0.0.2

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 (197) hide show
  1. package/README.md +303 -107
  2. package/build/esm/config.d.ts +12 -0
  3. package/build/esm/config.js +12 -0
  4. package/build/esm/config.js.map +1 -1
  5. package/build/esm/index.d.ts +1 -0
  6. package/build/esm/index.js +1 -0
  7. package/build/esm/index.js.map +1 -1
  8. package/build/esm/types/api-response.d.ts +82 -0
  9. package/build/esm/types/api-response.js.map +1 -1
  10. package/build/esm/utils/array.utils.d.ts +64 -1
  11. package/build/esm/utils/array.utils.js +139 -2
  12. package/build/esm/utils/array.utils.js.map +1 -1
  13. package/build/esm/utils/async.utils.d.ts +60 -1
  14. package/build/esm/utils/async.utils.js +160 -2
  15. package/build/esm/utils/async.utils.js.map +1 -1
  16. package/build/esm/utils/cache.utils.d.ts +67 -4
  17. package/build/esm/utils/cache.utils.js +210 -28
  18. package/build/esm/utils/cache.utils.js.map +1 -1
  19. package/build/esm/utils/context-store.utils.d.ts +101 -0
  20. package/build/esm/utils/context-store.utils.js +182 -0
  21. package/build/esm/utils/context-store.utils.js.map +1 -1
  22. package/build/esm/utils/crypto.utils.d.ts +110 -8
  23. package/build/esm/utils/crypto.utils.js +298 -15
  24. package/build/esm/utils/crypto.utils.js.map +1 -1
  25. package/build/esm/utils/decorators.utils.d.ts +40 -0
  26. package/build/esm/utils/decorators.utils.js +312 -0
  27. package/build/esm/utils/decorators.utils.js.map +1 -0
  28. package/build/esm/utils/dir.utils.d.ts +121 -0
  29. package/build/esm/utils/dir.utils.js +577 -0
  30. package/build/esm/utils/dir.utils.js.map +1 -1
  31. package/build/esm/utils/env.utils.d.ts +83 -0
  32. package/build/esm/utils/env.utils.js +233 -0
  33. package/build/esm/utils/env.utils.js.map +1 -1
  34. package/build/esm/utils/exception.utils.d.ts +116 -0
  35. package/build/esm/utils/exception.utils.js +322 -0
  36. package/build/esm/utils/exception.utils.js.map +1 -1
  37. package/build/esm/utils/fs.utils.d.ts +132 -0
  38. package/build/esm/utils/fs.utils.js +421 -0
  39. package/build/esm/utils/fs.utils.js.map +1 -1
  40. package/build/esm/utils/http-status-codes.d.ts +87 -178
  41. package/build/esm/utils/http-status-codes.js +92 -178
  42. package/build/esm/utils/http-status-codes.js.map +1 -1
  43. package/build/esm/utils/id.utils.d.ts +11 -10
  44. package/build/esm/utils/id.utils.js +29 -20
  45. package/build/esm/utils/id.utils.js.map +1 -1
  46. package/build/esm/utils/logger.utils.d.ts +24 -0
  47. package/build/esm/utils/logger.utils.js +54 -0
  48. package/build/esm/utils/logger.utils.js.map +1 -1
  49. package/build/esm/utils/middleware.utils.d.ts +72 -0
  50. package/build/esm/utils/middleware.utils.js +158 -0
  51. package/build/esm/utils/middleware.utils.js.map +1 -0
  52. package/build/esm/utils/obj.utils.d.ts +65 -3
  53. package/build/esm/utils/obj.utils.js +205 -6
  54. package/build/esm/utils/obj.utils.js.map +1 -1
  55. package/build/esm/utils/response.utils.d.ts +101 -0
  56. package/build/esm/utils/response.utils.js +153 -0
  57. package/build/esm/utils/response.utils.js.map +1 -1
  58. package/build/esm/utils/string.utils.d.ts +61 -5
  59. package/build/esm/utils/string.utils.js +101 -11
  60. package/build/esm/utils/string.utils.js.map +1 -1
  61. package/build/esm/utils/url.utils.d.ts +117 -0
  62. package/build/esm/utils/url.utils.js +287 -0
  63. package/build/esm/utils/url.utils.js.map +1 -1
  64. package/build/esm/utils/validate.utils.d.ts +110 -0
  65. package/build/esm/utils/validate.utils.js +186 -0
  66. package/build/esm/utils/validate.utils.js.map +1 -1
  67. package/build/esnext/config.d.ts +12 -0
  68. package/build/esnext/config.js +12 -0
  69. package/build/esnext/config.js.map +1 -1
  70. package/build/esnext/index.d.ts +1 -0
  71. package/build/esnext/index.js +1 -0
  72. package/build/esnext/index.js.map +1 -1
  73. package/build/esnext/types/api-response.d.ts +82 -0
  74. package/build/esnext/types/api-response.js.map +1 -1
  75. package/build/esnext/utils/array.utils.d.ts +64 -1
  76. package/build/esnext/utils/array.utils.js +129 -2
  77. package/build/esnext/utils/array.utils.js.map +1 -1
  78. package/build/esnext/utils/async.utils.d.ts +60 -1
  79. package/build/esnext/utils/async.utils.js +117 -1
  80. package/build/esnext/utils/async.utils.js.map +1 -1
  81. package/build/esnext/utils/cache.utils.d.ts +67 -4
  82. package/build/esnext/utils/cache.utils.js +137 -9
  83. package/build/esnext/utils/cache.utils.js.map +1 -1
  84. package/build/esnext/utils/context-store.utils.d.ts +101 -0
  85. package/build/esnext/utils/context-store.utils.js +168 -0
  86. package/build/esnext/utils/context-store.utils.js.map +1 -1
  87. package/build/esnext/utils/crypto.utils.d.ts +110 -8
  88. package/build/esnext/utils/crypto.utils.js +205 -15
  89. package/build/esnext/utils/crypto.utils.js.map +1 -1
  90. package/build/esnext/utils/decorators.utils.d.ts +40 -0
  91. package/build/esnext/utils/decorators.utils.js +155 -0
  92. package/build/esnext/utils/decorators.utils.js.map +1 -0
  93. package/build/esnext/utils/dir.utils.d.ts +121 -0
  94. package/build/esnext/utils/dir.utils.js +306 -0
  95. package/build/esnext/utils/dir.utils.js.map +1 -1
  96. package/build/esnext/utils/env.utils.d.ts +83 -0
  97. package/build/esnext/utils/env.utils.js +185 -0
  98. package/build/esnext/utils/env.utils.js.map +1 -1
  99. package/build/esnext/utils/exception.utils.d.ts +116 -0
  100. package/build/esnext/utils/exception.utils.js +213 -0
  101. package/build/esnext/utils/exception.utils.js.map +1 -1
  102. package/build/esnext/utils/fs.utils.d.ts +132 -0
  103. package/build/esnext/utils/fs.utils.js +268 -0
  104. package/build/esnext/utils/fs.utils.js.map +1 -1
  105. package/build/esnext/utils/http-status-codes.d.ts +87 -178
  106. package/build/esnext/utils/http-status-codes.js +92 -178
  107. package/build/esnext/utils/http-status-codes.js.map +1 -1
  108. package/build/esnext/utils/id.utils.d.ts +11 -10
  109. package/build/esnext/utils/id.utils.js +27 -19
  110. package/build/esnext/utils/id.utils.js.map +1 -1
  111. package/build/esnext/utils/logger.utils.d.ts +24 -0
  112. package/build/esnext/utils/logger.utils.js +42 -0
  113. package/build/esnext/utils/logger.utils.js.map +1 -1
  114. package/build/esnext/utils/middleware.utils.d.ts +72 -0
  115. package/build/esnext/utils/middleware.utils.js +157 -0
  116. package/build/esnext/utils/middleware.utils.js.map +1 -0
  117. package/build/esnext/utils/obj.utils.d.ts +65 -3
  118. package/build/esnext/utils/obj.utils.js +167 -3
  119. package/build/esnext/utils/obj.utils.js.map +1 -1
  120. package/build/esnext/utils/response.utils.d.ts +101 -0
  121. package/build/esnext/utils/response.utils.js +138 -0
  122. package/build/esnext/utils/response.utils.js.map +1 -1
  123. package/build/esnext/utils/string.utils.d.ts +61 -5
  124. package/build/esnext/utils/string.utils.js +110 -14
  125. package/build/esnext/utils/string.utils.js.map +1 -1
  126. package/build/esnext/utils/url.utils.d.ts +117 -0
  127. package/build/esnext/utils/url.utils.js +248 -0
  128. package/build/esnext/utils/url.utils.js.map +1 -1
  129. package/build/esnext/utils/validate.utils.d.ts +110 -0
  130. package/build/esnext/utils/validate.utils.js +184 -0
  131. package/build/esnext/utils/validate.utils.js.map +1 -1
  132. package/build/src/config.d.ts +12 -0
  133. package/build/src/config.js +12 -0
  134. package/build/src/config.js.map +1 -1
  135. package/build/src/index.d.ts +1 -0
  136. package/build/src/index.js +1 -0
  137. package/build/src/index.js.map +1 -1
  138. package/build/src/types/api-response.d.ts +82 -0
  139. package/build/src/types/api-response.js.map +1 -1
  140. package/build/src/utils/array.utils.d.ts +64 -1
  141. package/build/src/utils/array.utils.js +137 -4
  142. package/build/src/utils/array.utils.js.map +1 -1
  143. package/build/src/utils/async.utils.d.ts +60 -1
  144. package/build/src/utils/async.utils.js +124 -4
  145. package/build/src/utils/async.utils.js.map +1 -1
  146. package/build/src/utils/cache.utils.d.ts +67 -4
  147. package/build/src/utils/cache.utils.js +137 -9
  148. package/build/src/utils/cache.utils.js.map +1 -1
  149. package/build/src/utils/context-store.utils.d.ts +101 -0
  150. package/build/src/utils/context-store.utils.js +171 -1
  151. package/build/src/utils/context-store.utils.js.map +1 -1
  152. package/build/src/utils/crypto.utils.d.ts +110 -8
  153. package/build/src/utils/crypto.utils.js +224 -27
  154. package/build/src/utils/crypto.utils.js.map +1 -1
  155. package/build/src/utils/decorators.utils.d.ts +40 -0
  156. package/build/src/utils/decorators.utils.js +165 -0
  157. package/build/src/utils/decorators.utils.js.map +1 -0
  158. package/build/src/utils/dir.utils.d.ts +121 -0
  159. package/build/src/utils/dir.utils.js +316 -0
  160. package/build/src/utils/dir.utils.js.map +1 -1
  161. package/build/src/utils/env.utils.d.ts +83 -0
  162. package/build/src/utils/env.utils.js +186 -1
  163. package/build/src/utils/env.utils.js.map +1 -1
  164. package/build/src/utils/exception.utils.d.ts +116 -0
  165. package/build/src/utils/exception.utils.js +226 -1
  166. package/build/src/utils/exception.utils.js.map +1 -1
  167. package/build/src/utils/fs.utils.d.ts +132 -0
  168. package/build/src/utils/fs.utils.js +282 -0
  169. package/build/src/utils/fs.utils.js.map +1 -1
  170. package/build/src/utils/http-status-codes.d.ts +87 -178
  171. package/build/src/utils/http-status-codes.js +92 -178
  172. package/build/src/utils/http-status-codes.js.map +1 -1
  173. package/build/src/utils/id.utils.d.ts +11 -10
  174. package/build/src/utils/id.utils.js +27 -19
  175. package/build/src/utils/id.utils.js.map +1 -1
  176. package/build/src/utils/logger.utils.d.ts +24 -0
  177. package/build/src/utils/logger.utils.js +45 -0
  178. package/build/src/utils/logger.utils.js.map +1 -1
  179. package/build/src/utils/middleware.utils.d.ts +72 -0
  180. package/build/src/utils/middleware.utils.js +163 -0
  181. package/build/src/utils/middleware.utils.js.map +1 -0
  182. package/build/src/utils/obj.utils.d.ts +65 -3
  183. package/build/src/utils/obj.utils.js +177 -7
  184. package/build/src/utils/obj.utils.js.map +1 -1
  185. package/build/src/utils/response.utils.d.ts +101 -0
  186. package/build/src/utils/response.utils.js +146 -1
  187. package/build/src/utils/response.utils.js.map +1 -1
  188. package/build/src/utils/string.utils.d.ts +61 -5
  189. package/build/src/utils/string.utils.js +122 -20
  190. package/build/src/utils/string.utils.js.map +1 -1
  191. package/build/src/utils/url.utils.d.ts +117 -0
  192. package/build/src/utils/url.utils.js +257 -0
  193. package/build/src/utils/url.utils.js.map +1 -1
  194. package/build/src/utils/validate.utils.d.ts +110 -0
  195. package/build/src/utils/validate.utils.js +198 -0
  196. package/build/src/utils/validate.utils.js.map +1 -1
  197. package/package.json +20 -12
@@ -1,4 +1,5 @@
1
- import { createHmac, createHash, randomUUID, } from "crypto";
1
+ import { createHmac, createHash, randomUUID, randomBytes, createCipheriv, createDecipheriv, scrypt, timingSafeEqual, } from "crypto";
2
+ import { promisify } from "util";
2
3
  /**
3
4
  * Generates an HMAC digest using the specified algorithm and secret key.
4
5
  *
@@ -8,9 +9,9 @@ import { createHmac, createHash, randomUUID, } from "crypto";
8
9
  * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding ('hex', 'base64', etc).
9
10
  * @returns {string} HMAC digest as a string.
10
11
  */
11
- export const hmac = (algorithm, input, secret, encoding = "hex") => {
12
+ export function hmac(algorithm, input, secret, encoding = "hex") {
12
13
  return createHmac(algorithm, secret).update(input).digest(encoding);
13
- };
14
+ }
14
15
  /**
15
16
  * Generates a hash digest using the specified algorithm.
16
17
  *
@@ -19,9 +20,9 @@ export const hmac = (algorithm, input, secret, encoding = "hex") => {
19
20
  * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding ('hex', 'base64', etc).
20
21
  * @returns {string} Hash digest as a string.
21
22
  */
22
- export const hash = (algorithm, input, encoding = "hex") => {
23
+ export function hash(algorithm, input, encoding = "hex") {
23
24
  return createHash(algorithm).update(input).digest(encoding);
24
- };
25
+ }
25
26
  /**
26
27
  * Generates an HMAC-SHA256 digest.
27
28
  *
@@ -29,9 +30,9 @@ export const hash = (algorithm, input, encoding = "hex") => {
29
30
  * @param {string} secret - The secret key.
30
31
  * @returns {string} SHA-256 HMAC digest as a string.
31
32
  */
32
- export const sha256Hmac = (input, secret) => {
33
+ export function sha256Hmac(input, secret) {
33
34
  return hmac("sha256", input, secret);
34
- };
35
+ }
35
36
  /**
36
37
  * Generates a SHA1 hash digest.
37
38
  *
@@ -39,9 +40,9 @@ export const sha256Hmac = (input, secret) => {
39
40
  * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding.
40
41
  * @returns {string} SHA-1 hash as a string.
41
42
  */
42
- export const sha1 = (input, encoding = "hex") => {
43
+ export function sha1(input, encoding = "hex") {
43
44
  return hash("sha1", input, encoding);
44
- };
45
+ }
45
46
  /**
46
47
  * Generates a SHA256 hash digest.
47
48
  *
@@ -49,24 +50,213 @@ export const sha1 = (input, encoding = "hex") => {
49
50
  * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding.
50
51
  * @returns {string} SHA-256 hash as a string.
51
52
  */
52
- export const sha256 = (input, encoding = "hex") => {
53
+ export function sha256(input, encoding = "hex") {
53
54
  return hash("sha256", input, encoding);
54
- };
55
+ }
55
56
  /**
56
57
  * Generates an MD5 hash digest.
57
58
  *
58
59
  * @param {string} input - The string to hash.
59
60
  * @returns {string} MD5 hash as a string.
60
61
  */
61
- export const md5 = (input) => {
62
+ export function md5(input) {
62
63
  return hash("md5", input);
63
- };
64
+ }
64
65
  /**
65
66
  * Generates a cryptographically strong random string by hashing a random UUID with SHA-256.
66
67
  *
67
68
  * @returns {string} Random string hashed with SHA-256 (hex encoding).
68
69
  */
69
- export const randomString = () => {
70
+ export function randomString() {
70
71
  return sha256(randomUUID());
71
- };
72
+ }
73
+ /**
74
+ * Generates a secure random buffer of specified byte length.
75
+ *
76
+ * @param {number} [byteLength=32] - Number of random bytes to generate.
77
+ * @returns {Buffer} Buffer containing random bytes.
78
+ */
79
+ export function generateRandomBytes(byteLength = 32) {
80
+ return randomBytes(byteLength);
81
+ }
82
+ /**
83
+ * Generates a secure random string of specified byte length with specified encoding.
84
+ *
85
+ * @param {number} [byteLength=32] - Number of random bytes to generate.
86
+ * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding.
87
+ * @returns {string} Random string in specified encoding.
88
+ */
89
+ export function generateRandomBytesAsString(byteLength = 32, encoding = "hex") {
90
+ return randomBytes(byteLength).toString(encoding);
91
+ }
92
+ /**
93
+ * Generates a secure API key with a specified format.
94
+ *
95
+ * @param {string} [prefix=''] - Optional prefix for the key.
96
+ * @param {number} [byteLength=24] - Number of random bytes to generate.
97
+ * @returns {string} Formatted API key.
98
+ */
99
+ export function generateApiKey(prefix = "", byteLength = 24) {
100
+ const randomString = generateRandomBytesAsString(byteLength, "base64");
101
+ const key = randomString
102
+ .replace(/[+/=]/g, "") // Remove non-URL-safe characters
103
+ .substring(0, 32); // Limit length
104
+ return prefix ? `${prefix}_${key}` : key;
105
+ }
106
+ /**
107
+ * Compares two strings, arrays, or buffers in constant time to prevent timing attacks.
108
+ *
109
+ * @param {string | Buffer | Uint8Array} a - First value to compare
110
+ * @param {string | Buffer | Uint8Array} b - Second value to compare
111
+ * @returns {boolean} True if values are equal
112
+ */
113
+ export function safeCompare(a, b) {
114
+ if (typeof a === "string" && typeof b === "string") {
115
+ // Convert strings to buffers
116
+ const bufA = Buffer.from(a);
117
+ const bufB = Buffer.from(b);
118
+ // Compare lengths first (not constant time, but prevents timing attack on contents)
119
+ if (bufA.length !== bufB.length)
120
+ return false;
121
+ return timingSafeEqual(bufA, bufB);
122
+ }
123
+ else if ((a instanceof Buffer || a instanceof Uint8Array) &&
124
+ (b instanceof Buffer || b instanceof Uint8Array)) {
125
+ // Compare lengths first
126
+ if (a.length !== b.length)
127
+ return false;
128
+ return timingSafeEqual(a instanceof Buffer ? a : Buffer.from(a), b instanceof Buffer ? b : Buffer.from(b));
129
+ }
130
+ throw new Error("Cannot compare: inputs must be strings, Buffers, or Uint8Arrays");
131
+ }
132
+ // Promisified version of scrypt for key derivation
133
+ const scryptAsync = promisify(scrypt);
134
+ /**
135
+ * Encrypts data using a symmetric key with secure defaults (AES-256-GCM).
136
+ *
137
+ * @param {string | Buffer} data - Data to encrypt
138
+ * @param {string | Buffer} key - Encryption key or passphrase
139
+ * @param {EncryptionOptions} [options] - Encryption options
140
+ * @returns {Promise<EncryptionResult>} Encrypted data with metadata
141
+ */
142
+ export async function encrypt(data, key, options = {}) {
143
+ const algorithm = options.algorithm || "aes-256-gcm";
144
+ const inputEncoding = options.inputEncoding || "utf8";
145
+ const outputEncoding = options.outputEncoding || "hex";
146
+ // Generate a random IV
147
+ const iv = randomBytes(16);
148
+ // Derive key using scrypt if key is a string (passphrase)
149
+ const derivedKey = typeof key === "string" ? await scryptAsync(key, iv.slice(0, 8), 32) : key;
150
+ // Create cipher
151
+ const cipher = createCipheriv(algorithm, derivedKey, iv);
152
+ // Encrypt the data
153
+ let ciphertext;
154
+ if (typeof data === "string") {
155
+ ciphertext = cipher.update(data, inputEncoding, outputEncoding);
156
+ ciphertext += cipher.final(outputEncoding);
157
+ }
158
+ else {
159
+ const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
160
+ ciphertext = outputEncoding
161
+ ? encrypted.toString(outputEncoding)
162
+ : encrypted;
163
+ }
164
+ // Get authentication tag if using GCM mode
165
+ const authTag = algorithm.includes("gcm")
166
+ ? cipher.getAuthTag()
167
+ : undefined;
168
+ return {
169
+ ciphertext,
170
+ iv,
171
+ authTag,
172
+ algorithm,
173
+ };
174
+ }
175
+ /**
176
+ * Decrypts data that was encrypted with the encrypt function.
177
+ *
178
+ * @param {EncryptionResult} encryptedData - The encrypted data and metadata
179
+ * @param {string | Buffer} key - Decryption key or passphrase
180
+ * @param {DecryptionOptions} [options] - Decryption options
181
+ * @returns {Promise<string | Buffer>} Decrypted data
182
+ */
183
+ export async function decrypt(encryptedData, key, options = {}) {
184
+ const algorithm = options.algorithm || encryptedData.algorithm || "aes-256-gcm";
185
+ const inputEncoding = options.inputEncoding || "hex";
186
+ const outputEncoding = options.outputEncoding || "utf8";
187
+ // Derive key using scrypt if key is a string (passphrase)
188
+ const derivedKey = typeof key === "string"
189
+ ? await scryptAsync(key, encryptedData.iv.slice(0, 8), 32)
190
+ : key;
191
+ // Create decipher
192
+ const decipher = createDecipheriv(algorithm, derivedKey, encryptedData.iv);
193
+ // Set auth tag if using GCM mode
194
+ if (encryptedData.authTag && algorithm.includes("gcm")) {
195
+ decipher.setAuthTag(encryptedData.authTag);
196
+ }
197
+ // Decrypt the data
198
+ let decrypted;
199
+ if (typeof encryptedData.ciphertext === "string") {
200
+ decrypted = decipher.update(encryptedData.ciphertext, inputEncoding, outputEncoding);
201
+ decrypted += decipher.final(outputEncoding);
202
+ }
203
+ else {
204
+ const result = Buffer.concat([
205
+ decipher.update(encryptedData.ciphertext),
206
+ decipher.final(),
207
+ ]);
208
+ decrypted = outputEncoding ? result.toString(outputEncoding) : result;
209
+ }
210
+ return decrypted;
211
+ }
212
+ /**
213
+ * Creates a signed token with an expiration time and payload.
214
+ *
215
+ * @param {object} payload - Data to include in the token
216
+ * @param {string} secret - Secret key for signing
217
+ * @param {number} [expiresInSeconds=3600] - Token expiration in seconds
218
+ * @returns {string} Signed token string
219
+ */
220
+ export function createSignedToken(payload, secret, expiresInSeconds = 3600) {
221
+ // Create payload with expiration
222
+ const tokenPayload = Object.assign(Object.assign({}, payload), { exp: Math.floor(Date.now() / 1000) + expiresInSeconds });
223
+ // Convert to string
224
+ const payloadStr = JSON.stringify(tokenPayload);
225
+ // Base64 encode the payload
226
+ const base64Payload = Buffer.from(payloadStr).toString("base64url");
227
+ // Create signature
228
+ const signature = hmac("sha256", base64Payload, secret, "base64url");
229
+ // Combine payload and signature
230
+ return `${base64Payload}.${signature}`;
231
+ }
232
+ /**
233
+ * Verifies and decodes a signed token.
234
+ *
235
+ * @param {string} token - The token to verify
236
+ * @param {string} secret - Secret key for verification
237
+ * @returns {object | null} Decoded payload if valid, null if invalid
238
+ */
239
+ export function verifySignedToken(token, secret) {
240
+ try {
241
+ // Split token into parts
242
+ const [payloadB64, signature] = token.split(".");
243
+ if (!payloadB64 || !signature)
244
+ return null;
245
+ // Verify signature
246
+ const expectedSignature = hmac("sha256", payloadB64, secret, "base64url");
247
+ if (!safeCompare(signature, expectedSignature))
248
+ return null;
249
+ // Decode payload
250
+ const payloadStr = Buffer.from(payloadB64, "base64url").toString("utf8");
251
+ const payload = JSON.parse(payloadStr);
252
+ // Check expiration
253
+ if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) {
254
+ return null;
255
+ }
256
+ return payload;
257
+ }
258
+ catch (_a) {
259
+ return null;
260
+ }
261
+ }
72
262
  //# sourceMappingURL=crypto.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.utils.js","sourceRoot":"","sources":["../../../src/utils/crypto.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,EAEV,UAAU,GACX,MAAM,QAAQ,CAAC;AAEhB;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,SAAiB,EACjB,KAAa,EACb,MAAc,EACd,WAAiC,KAAK,EAC9B,EAAE;IACV,OAAO,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,SAAiB,EACjB,KAAa,EACb,WAAiC,KAAK,EAC9B,EAAE;IACV,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC9D,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,MAAc,EAAU,EAAE;IAClE,OAAO,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AACvC,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,KAAa,EACb,WAAiC,KAAK,EAC9B,EAAE;IACV,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AACvC,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,KAAa,EACb,WAAiC,KAAK,EAC9B,EAAE;IACV,OAAO,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE;IAC3C,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAW,EAAE;IACvC,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;AAC9B,CAAC,CAAC","sourcesContent":["import {\n createHmac,\n createHash,\n BinaryToTextEncoding,\n randomUUID,\n} from \"crypto\";\n\n/**\n * Generates an HMAC digest using the specified algorithm and secret key.\n *\n * @param {string} algorithm - The hashing algorithm (e.g., 'sha256', 'sha1').\n * @param {string} input - The string to hash.\n * @param {string} secret - The secret key for HMAC.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding ('hex', 'base64', etc).\n * @returns {string} HMAC digest as a string.\n */\nexport const hmac = (\n algorithm: string,\n input: string,\n secret: string,\n encoding: BinaryToTextEncoding = \"hex\",\n): string => {\n return createHmac(algorithm, secret).update(input).digest(encoding);\n};\n\n/**\n * Generates a hash digest using the specified algorithm.\n *\n * @param {string} algorithm - The hashing algorithm (e.g., 'sha256', 'md5').\n * @param {string} input - The string to hash.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding ('hex', 'base64', etc).\n * @returns {string} Hash digest as a string.\n */\nexport const hash = (\n algorithm: string,\n input: string,\n encoding: BinaryToTextEncoding = \"hex\",\n): string => {\n return createHash(algorithm).update(input).digest(encoding);\n};\n\n/**\n * Generates an HMAC-SHA256 digest.\n *\n * @param {string} input - The string to hash.\n * @param {string} secret - The secret key.\n * @returns {string} SHA-256 HMAC digest as a string.\n */\nexport const sha256Hmac = (input: string, secret: string): string => {\n return hmac(\"sha256\", input, secret);\n};\n\n/**\n * Generates a SHA1 hash digest.\n *\n * @param {string} input - The string to hash.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding.\n * @returns {string} SHA-1 hash as a string.\n */\nexport const sha1 = (\n input: string,\n encoding: BinaryToTextEncoding = \"hex\",\n): string => {\n return hash(\"sha1\", input, encoding);\n};\n\n/**\n * Generates a SHA256 hash digest.\n *\n * @param {string} input - The string to hash.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding.\n * @returns {string} SHA-256 hash as a string.\n */\nexport const sha256 = (\n input: string,\n encoding: BinaryToTextEncoding = \"hex\",\n): string => {\n return hash(\"sha256\", input, encoding);\n};\n\n/**\n * Generates an MD5 hash digest.\n *\n * @param {string} input - The string to hash.\n * @returns {string} MD5 hash as a string.\n */\nexport const md5 = (input: string): string => {\n return hash(\"md5\", input);\n};\n\n/**\n * Generates a cryptographically strong random string by hashing a random UUID with SHA-256.\n *\n * @returns {string} Random string hashed with SHA-256 (hex encoding).\n */\nexport const randomString = (): string => {\n return sha256(randomUUID());\n};\n"]}
1
+ {"version":3,"file":"crypto.utils.js","sourceRoot":"","sources":["../../../src/utils/crypto.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createHmac,\n createHash,\n BinaryToTextEncoding,\n randomUUID,\n randomBytes,\n createCipheriv,\n createDecipheriv,\n scrypt,\n timingSafeEqual,\n CipherGCMTypes,\n} from \"crypto\";\nimport { promisify } from \"util\";\n\nexport type BufferEncoding =\n | \"ascii\"\n | \"utf8\"\n | \"utf-8\"\n | \"utf16le\"\n | \"utf-16le\"\n | \"ucs2\"\n | \"ucs-2\"\n | \"base64\"\n | \"base64url\"\n | \"latin1\"\n | \"binary\"\n | \"hex\";\n\n/**\n * Generates an HMAC digest using the specified algorithm and secret key.\n *\n * @param {string} algorithm - The hashing algorithm (e.g., 'sha256', 'sha1').\n * @param {string} input - The string to hash.\n * @param {string} secret - The secret key for HMAC.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding ('hex', 'base64', etc).\n * @returns {string} HMAC digest as a string.\n */\nexport function hmac(\n algorithm: string,\n input: string,\n secret: string,\n encoding: BinaryToTextEncoding = \"hex\",\n): string {\n return createHmac(algorithm, secret).update(input).digest(encoding);\n}\n\n/**\n * Generates a hash digest using the specified algorithm.\n *\n * @param {string} algorithm - The hashing algorithm (e.g., 'sha256', 'md5').\n * @param {string} input - The string to hash.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding ('hex', 'base64', etc).\n * @returns {string} Hash digest as a string.\n */\nexport function hash(\n algorithm: string,\n input: string,\n encoding: BinaryToTextEncoding = \"hex\",\n): string {\n return createHash(algorithm).update(input).digest(encoding);\n}\n\n/**\n * Generates an HMAC-SHA256 digest.\n *\n * @param {string} input - The string to hash.\n * @param {string} secret - The secret key.\n * @returns {string} SHA-256 HMAC digest as a string.\n */\nexport function sha256Hmac(input: string, secret: string): string {\n return hmac(\"sha256\", input, secret);\n}\n\n/**\n * Generates a SHA1 hash digest.\n *\n * @param {string} input - The string to hash.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding.\n * @returns {string} SHA-1 hash as a string.\n */\nexport function sha1(\n input: string,\n encoding: BinaryToTextEncoding = \"hex\",\n): string {\n return hash(\"sha1\", input, encoding);\n}\n\n/**\n * Generates a SHA256 hash digest.\n *\n * @param {string} input - The string to hash.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding.\n * @returns {string} SHA-256 hash as a string.\n */\nexport function sha256(\n input: string,\n encoding: BinaryToTextEncoding = \"hex\",\n): string {\n return hash(\"sha256\", input, encoding);\n}\n\n/**\n * Generates an MD5 hash digest.\n *\n * @param {string} input - The string to hash.\n * @returns {string} MD5 hash as a string.\n */\nexport function md5(input: string): string {\n return hash(\"md5\", input);\n}\n\n/**\n * Generates a cryptographically strong random string by hashing a random UUID with SHA-256.\n *\n * @returns {string} Random string hashed with SHA-256 (hex encoding).\n */\nexport function randomString(): string {\n return sha256(randomUUID());\n}\n\n/**\n * Generates a secure random buffer of specified byte length.\n *\n * @param {number} [byteLength=32] - Number of random bytes to generate.\n * @returns {Buffer} Buffer containing random bytes.\n */\nexport function generateRandomBytes(byteLength: number = 32): Buffer {\n return randomBytes(byteLength);\n}\n\n/**\n * Generates a secure random string of specified byte length with specified encoding.\n *\n * @param {number} [byteLength=32] - Number of random bytes to generate.\n * @param {BinaryToTextEncoding} [encoding='hex'] - Output encoding.\n * @returns {string} Random string in specified encoding.\n */\nexport function generateRandomBytesAsString(\n byteLength: number = 32,\n encoding: BinaryToTextEncoding = \"hex\",\n): string {\n return randomBytes(byteLength).toString(encoding);\n}\n\n/**\n * Generates a secure API key with a specified format.\n *\n * @param {string} [prefix=''] - Optional prefix for the key.\n * @param {number} [byteLength=24] - Number of random bytes to generate.\n * @returns {string} Formatted API key.\n */\nexport function generateApiKey(\n prefix: string = \"\",\n byteLength: number = 24,\n): string {\n const randomString = generateRandomBytesAsString(byteLength, \"base64\");\n const key = randomString\n .replace(/[+/=]/g, \"\") // Remove non-URL-safe characters\n .substring(0, 32); // Limit length\n\n return prefix ? `${prefix}_${key}` : key;\n}\n\n/**\n * Compares two strings, arrays, or buffers in constant time to prevent timing attacks.\n *\n * @param {string | Buffer | Uint8Array} a - First value to compare\n * @param {string | Buffer | Uint8Array} b - Second value to compare\n * @returns {boolean} True if values are equal\n */\nexport function safeCompare(\n a: string | Buffer | Uint8Array,\n b: string | Buffer | Uint8Array,\n): boolean {\n if (typeof a === \"string\" && typeof b === \"string\") {\n // Convert strings to buffers\n const bufA = Buffer.from(a);\n const bufB = Buffer.from(b);\n\n // Compare lengths first (not constant time, but prevents timing attack on contents)\n if (bufA.length !== bufB.length) return false;\n\n return timingSafeEqual(bufA, bufB);\n } else if (\n (a instanceof Buffer || a instanceof Uint8Array) &&\n (b instanceof Buffer || b instanceof Uint8Array)\n ) {\n // Compare lengths first\n if (a.length !== b.length) return false;\n\n return timingSafeEqual(\n a instanceof Buffer ? a : Buffer.from(a),\n b instanceof Buffer ? b : Buffer.from(b),\n );\n }\n\n throw new Error(\n \"Cannot compare: inputs must be strings, Buffers, or Uint8Arrays\",\n );\n}\n\n/**\n * Interface for encryption options\n */\nexport interface EncryptionOptions {\n /** Algorithm to use (default: aes-256-gcm) */\n algorithm?: CipherGCMTypes;\n /** Input encoding for plaintext if string (default: utf8) */\n inputEncoding?: BufferEncoding;\n /** Output encoding for ciphertext (default: hex) */\n outputEncoding?: BinaryToTextEncoding;\n}\n\n/**\n * Interface for decryption options\n */\nexport interface DecryptionOptions {\n /** Algorithm to use (default: aes-256-gcm) */\n algorithm?: CipherGCMTypes;\n /** Input encoding for ciphertext if string (default: hex) */\n inputEncoding?: BinaryToTextEncoding;\n /** Output encoding for plaintext (default: utf8) */\n outputEncoding?: BufferEncoding;\n}\n\n/**\n * Result of encryption operation including all data needed for decryption\n */\nexport interface EncryptionResult {\n /** Encrypted data (string or Buffer based on options) */\n ciphertext: string | Buffer;\n /** Initialization vector */\n iv: Buffer;\n /** Authentication tag (for GCM mode) */\n authTag?: Buffer;\n /** Algorithm used */\n algorithm: string;\n}\n\n// Promisified version of scrypt for key derivation\nconst scryptAsync = promisify<string | Buffer, string | Buffer, number, Buffer>(\n scrypt,\n);\n\n/**\n * Encrypts data using a symmetric key with secure defaults (AES-256-GCM).\n *\n * @param {string | Buffer} data - Data to encrypt\n * @param {string | Buffer} key - Encryption key or passphrase\n * @param {EncryptionOptions} [options] - Encryption options\n * @returns {Promise<EncryptionResult>} Encrypted data with metadata\n */\nexport async function encrypt(\n data: string | Buffer,\n key: string | Buffer,\n options: EncryptionOptions = {},\n): Promise<EncryptionResult> {\n const algorithm = options.algorithm || \"aes-256-gcm\";\n const inputEncoding = options.inputEncoding || \"utf8\";\n const outputEncoding = options.outputEncoding || \"hex\";\n\n // Generate a random IV\n const iv = randomBytes(16);\n\n // Derive key using scrypt if key is a string (passphrase)\n const derivedKey =\n typeof key === \"string\" ? await scryptAsync(key, iv.slice(0, 8), 32) : key;\n\n // Create cipher\n const cipher = createCipheriv(algorithm, derivedKey, iv);\n\n // Encrypt the data\n let ciphertext: string | Buffer;\n\n if (typeof data === \"string\") {\n ciphertext = cipher.update(\n data,\n inputEncoding,\n outputEncoding as BufferEncoding,\n );\n ciphertext += cipher.final(outputEncoding as BufferEncoding);\n } else {\n const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);\n ciphertext = outputEncoding\n ? encrypted.toString(outputEncoding)\n : encrypted;\n }\n\n // Get authentication tag if using GCM mode\n const authTag = algorithm.includes(\"gcm\")\n ? (cipher as any).getAuthTag()\n : undefined;\n\n return {\n ciphertext,\n iv,\n authTag,\n algorithm,\n };\n}\n\n/**\n * Decrypts data that was encrypted with the encrypt function.\n *\n * @param {EncryptionResult} encryptedData - The encrypted data and metadata\n * @param {string | Buffer} key - Decryption key or passphrase\n * @param {DecryptionOptions} [options] - Decryption options\n * @returns {Promise<string | Buffer>} Decrypted data\n */\nexport async function decrypt(\n encryptedData: EncryptionResult,\n key: string | Buffer,\n options: DecryptionOptions = {},\n): Promise<string | Buffer> {\n const algorithm =\n options.algorithm || encryptedData.algorithm || \"aes-256-gcm\";\n const inputEncoding = options.inputEncoding || \"hex\";\n const outputEncoding = options.outputEncoding || \"utf8\";\n\n // Derive key using scrypt if key is a string (passphrase)\n const derivedKey =\n typeof key === \"string\"\n ? await scryptAsync(key, encryptedData.iv.slice(0, 8), 32)\n : key;\n\n // Create decipher\n const decipher = createDecipheriv(algorithm, derivedKey, encryptedData.iv);\n\n // Set auth tag if using GCM mode\n if (encryptedData.authTag && algorithm.includes(\"gcm\")) {\n (decipher as any).setAuthTag(encryptedData.authTag);\n }\n\n // Decrypt the data\n let decrypted: string | Buffer;\n\n if (typeof encryptedData.ciphertext === \"string\") {\n decrypted = decipher.update(\n encryptedData.ciphertext,\n inputEncoding as BufferEncoding,\n outputEncoding,\n );\n decrypted += decipher.final(outputEncoding);\n } else {\n const result = Buffer.concat([\n decipher.update(encryptedData.ciphertext),\n decipher.final(),\n ]);\n decrypted = outputEncoding ? result.toString(outputEncoding) : result;\n }\n\n return decrypted;\n}\n\n/**\n * Creates a signed token with an expiration time and payload.\n *\n * @param {object} payload - Data to include in the token\n * @param {string} secret - Secret key for signing\n * @param {number} [expiresInSeconds=3600] - Token expiration in seconds\n * @returns {string} Signed token string\n */\nexport function createSignedToken(\n payload: Record<string, any>,\n secret: string,\n expiresInSeconds: number = 3600,\n): string {\n // Create payload with expiration\n const tokenPayload = {\n ...payload,\n exp: Math.floor(Date.now() / 1000) + expiresInSeconds,\n };\n\n // Convert to string\n const payloadStr = JSON.stringify(tokenPayload);\n\n // Base64 encode the payload\n const base64Payload = Buffer.from(payloadStr).toString(\"base64url\");\n\n // Create signature\n const signature = hmac(\"sha256\", base64Payload, secret, \"base64url\");\n\n // Combine payload and signature\n return `${base64Payload}.${signature}`;\n}\n\n/**\n * Verifies and decodes a signed token.\n *\n * @param {string} token - The token to verify\n * @param {string} secret - Secret key for verification\n * @returns {object | null} Decoded payload if valid, null if invalid\n */\nexport function verifySignedToken(\n token: string,\n secret: string,\n): Record<string, any> | null {\n try {\n // Split token into parts\n const [payloadB64, signature] = token.split(\".\");\n\n if (!payloadB64 || !signature) return null;\n\n // Verify signature\n const expectedSignature = hmac(\"sha256\", payloadB64, secret, \"base64url\");\n if (!safeCompare(signature, expectedSignature)) return null;\n\n // Decode payload\n const payloadStr = Buffer.from(payloadB64, \"base64url\").toString(\"utf8\");\n const payload = JSON.parse(payloadStr);\n\n // Check expiration\n if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) {\n return null;\n }\n\n return payload;\n } catch {\n return null;\n }\n}\n"]}
@@ -0,0 +1,40 @@
1
+ import "reflect-metadata";
2
+ export interface Request {
3
+ query: any;
4
+ params: any;
5
+ body?: any;
6
+ [key: string]: any;
7
+ }
8
+ export interface Response {
9
+ json: (body: any) => void;
10
+ headersSent: boolean;
11
+ [key: string]: any;
12
+ }
13
+ export type NextFunction = (err?: any) => void;
14
+ export type RequestHandler = (req: Request, res: Response, next: NextFunction) => any;
15
+ export interface Router {
16
+ [method: string]: (path: string, ...handlers: RequestHandler[]) => void;
17
+ }
18
+ export type HttpMethod = "get" | "post" | "put" | "patch" | "delete" | "options" | "head" | "trace" | "connect";
19
+ export declare const Get: (path: string) => MethodDecorator;
20
+ export declare const Post: (path: string) => MethodDecorator;
21
+ export declare const Put: (path: string) => MethodDecorator;
22
+ export declare const Patch: (path: string) => MethodDecorator;
23
+ export declare const Delete: (path: string) => MethodDecorator;
24
+ export declare const Options: (path: string) => MethodDecorator;
25
+ export declare const Head: (path: string) => MethodDecorator;
26
+ export declare const Trace: (path: string) => MethodDecorator;
27
+ export declare const Connect: (path: string) => MethodDecorator;
28
+ export declare function Controller(basePath: string): ClassDecorator;
29
+ export declare function Use(...middlewares: RequestHandler[]): MethodDecorator;
30
+ export declare const Query: (paramKey?: string) => ParameterDecorator;
31
+ export declare const Param: (paramKey?: string) => ParameterDecorator;
32
+ export declare const Body: (paramKey?: string) => ParameterDecorator;
33
+ export declare const Req: (paramKey?: string) => ParameterDecorator;
34
+ export declare const Res: (paramKey?: string) => ParameterDecorator;
35
+ export declare function HttpCode(status: number): MethodDecorator;
36
+ export declare function Header(name: string, value: string): MethodDecorator;
37
+ export declare function Before(fn: Function): MethodDecorator;
38
+ export declare function After(fn: Function): MethodDecorator;
39
+ export declare function registerControllers(router: Router, controllers: any[]): void;
40
+ //# sourceMappingURL=decorators.utils.d.ts.map
@@ -0,0 +1,155 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import "reflect-metadata";
3
+ // --- End sample Express interfaces ---
4
+ const ROUTES_KEY = Symbol("routes");
5
+ const MIDDLEWARE_KEY = Symbol("middlewares");
6
+ const PARAMS_KEY = Symbol("params");
7
+ // ---- Route Decorators ----
8
+ function createRouteDecorator(method) {
9
+ return (path) => {
10
+ return (target, propertyKey, descriptor) => {
11
+ const routes = Reflect.getMetadata(ROUTES_KEY, target.constructor) || [];
12
+ routes.push({
13
+ path,
14
+ method,
15
+ handlerName: propertyKey,
16
+ });
17
+ Reflect.defineMetadata(ROUTES_KEY, routes, target.constructor);
18
+ };
19
+ };
20
+ }
21
+ export const Get = createRouteDecorator("get");
22
+ export const Post = createRouteDecorator("post");
23
+ export const Put = createRouteDecorator("put");
24
+ export const Patch = createRouteDecorator("patch");
25
+ export const Delete = createRouteDecorator("delete");
26
+ export const Options = createRouteDecorator("options");
27
+ export const Head = createRouteDecorator("head");
28
+ export const Trace = createRouteDecorator("trace");
29
+ export const Connect = createRouteDecorator("connect");
30
+ // ---- Controller Decorator ----
31
+ export function Controller(basePath) {
32
+ return (target) => {
33
+ Reflect.defineMetadata("basePath", basePath, target);
34
+ };
35
+ }
36
+ // ---- Middleware Decorator ----
37
+ export function Use(...middlewares) {
38
+ return (target, propertyKey, descriptor) => {
39
+ const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target, propertyKey) || [];
40
+ Reflect.defineMetadata(MIDDLEWARE_KEY, [...existing, ...middlewares], target, propertyKey);
41
+ };
42
+ }
43
+ // ---- Parameter Decorators ----
44
+ function createParamDecorator(type, key) {
45
+ return (paramKey) => {
46
+ return (target, propertyKey, parameterIndex) => {
47
+ const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
48
+ // Ensure parameters are ordered by index
49
+ params.push({ index: parameterIndex, type, key: paramKey || key });
50
+ params.sort((a, b) => a.index - b.index);
51
+ Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
52
+ };
53
+ };
54
+ }
55
+ export const Query = createParamDecorator("query");
56
+ export const Param = createParamDecorator("param");
57
+ export const Body = createParamDecorator("body");
58
+ export const Req = createParamDecorator("req");
59
+ export const Res = createParamDecorator("res");
60
+ // Custom HTTP status code decorator
61
+ const HTTP_CODE_KEY = Symbol("httpCode");
62
+ export function HttpCode(status) {
63
+ return (target, propertyKey, descriptor) => {
64
+ Reflect.defineMetadata(HTTP_CODE_KEY, status, target, propertyKey);
65
+ };
66
+ }
67
+ // Custom header decorator
68
+ const HEADER_KEY = Symbol("headers");
69
+ export function Header(name, value) {
70
+ return (target, propertyKey, descriptor) => {
71
+ const headers = Reflect.getMetadata(HEADER_KEY, target, propertyKey) || {};
72
+ headers[name] = value;
73
+ Reflect.defineMetadata(HEADER_KEY, headers, target, propertyKey);
74
+ };
75
+ }
76
+ // Before/After hooks (not Express middleware, but can be used for logging, etc.)
77
+ const BEFORE_KEY = Symbol("before");
78
+ const AFTER_KEY = Symbol("after");
79
+ export function Before(fn) {
80
+ return (target, propertyKey, descriptor) => {
81
+ const hooks = Reflect.getMetadata(BEFORE_KEY, target, propertyKey) || [];
82
+ hooks.push(fn);
83
+ Reflect.defineMetadata(BEFORE_KEY, hooks, target, propertyKey);
84
+ };
85
+ }
86
+ export function After(fn) {
87
+ return (target, propertyKey, descriptor) => {
88
+ const hooks = Reflect.getMetadata(AFTER_KEY, target, propertyKey) || [];
89
+ hooks.push(fn);
90
+ Reflect.defineMetadata(AFTER_KEY, hooks, target, propertyKey);
91
+ };
92
+ }
93
+ // ---- Register Controllers ----
94
+ export function registerControllers(router, controllers) {
95
+ controllers.forEach((ControllerClass) => {
96
+ const instance = new ControllerClass();
97
+ const basePath = Reflect.getMetadata("basePath", ControllerClass) || "";
98
+ const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];
99
+ routes.forEach(({ path, method, handlerName }) => {
100
+ const middlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];
101
+ const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];
102
+ const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName);
103
+ const headers = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};
104
+ const beforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];
105
+ const afterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];
106
+ const handler = async (req, res, next) => {
107
+ var _a, _b;
108
+ try {
109
+ for (const fn of beforeHooks)
110
+ await fn(req, res);
111
+ const args = [];
112
+ if (params.length) {
113
+ params.forEach(({ index, type, key }) => {
114
+ var _a;
115
+ switch (type) {
116
+ case "query":
117
+ args[index] = key ? req.query[key] : req.query;
118
+ break;
119
+ case "param":
120
+ args[index] = key ? req.params[key] : req.params;
121
+ break;
122
+ case "body":
123
+ args[index] = key ? (_a = req.body) === null || _a === void 0 ? void 0 : _a[key] : req.body;
124
+ break;
125
+ case "req":
126
+ args[index] = req;
127
+ break;
128
+ case "res":
129
+ args[index] = res;
130
+ break;
131
+ }
132
+ });
133
+ }
134
+ const result = instance[handlerName](...args);
135
+ // Support both sync and async handlers
136
+ const awaited = result instanceof Promise ? await result : result;
137
+ if (!res.headersSent && typeof awaited !== "undefined") {
138
+ if (httpCode)
139
+ (_a = res.status) === null || _a === void 0 ? void 0 : _a.call(res, httpCode);
140
+ for (const [k, v] of Object.entries(headers))
141
+ (_b = res.set) === null || _b === void 0 ? void 0 : _b.call(res, k, v);
142
+ res.json(awaited);
143
+ }
144
+ for (const fn of afterHooks)
145
+ await fn(req, res, awaited);
146
+ }
147
+ catch (err) {
148
+ next(err);
149
+ }
150
+ };
151
+ router[method](basePath + path, ...middlewares, handler);
152
+ });
153
+ });
154
+ }
155
+ //# sourceMappingURL=decorators.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorators.utils.js","sourceRoot":"","sources":["../../../src/utils/decorators.utils.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n\nimport \"reflect-metadata\";\n\n// --- Sample Express interfaces for type safety ---\nexport interface Request {\n query: any;\n params: any;\n body?: any;\n [key: string]: any;\n}\nexport interface Response {\n json: (body: any) => void;\n headersSent: boolean;\n [key: string]: any;\n}\nexport type NextFunction = (err?: any) => void;\nexport type RequestHandler = (\n req: Request,\n res: Response,\n next: NextFunction,\n) => any;\nexport interface Router {\n [method: string]: (path: string, ...handlers: RequestHandler[]) => void;\n}\n// --- End sample Express interfaces ---\n\nconst ROUTES_KEY = Symbol(\"routes\");\nconst MIDDLEWARE_KEY = Symbol(\"middlewares\");\nconst PARAMS_KEY = Symbol(\"params\");\n\nexport type HttpMethod =\n | \"get\"\n | \"post\"\n | \"put\"\n | \"patch\"\n | \"delete\"\n | \"options\"\n | \"head\"\n | \"trace\"\n | \"connect\";\n\ninterface RouteDefinition {\n path: string;\n method: HttpMethod;\n handlerName: string;\n}\n\ninterface ParamDefinition {\n index: number;\n type: \"query\" | \"param\" | \"body\" | \"req\" | \"res\";\n key?: string;\n}\n\n// ---- Route Decorators ----\nfunction createRouteDecorator(method: HttpMethod) {\n return (path: string): MethodDecorator => {\n return (target, propertyKey, descriptor) => {\n const routes: RouteDefinition[] =\n Reflect.getMetadata(ROUTES_KEY, target.constructor) || [];\n routes.push({\n path,\n method,\n handlerName: propertyKey as string,\n });\n Reflect.defineMetadata(ROUTES_KEY, routes, target.constructor);\n };\n };\n}\n\nexport const Get = createRouteDecorator(\"get\");\nexport const Post = createRouteDecorator(\"post\");\nexport const Put = createRouteDecorator(\"put\");\nexport const Patch = createRouteDecorator(\"patch\");\nexport const Delete = createRouteDecorator(\"delete\");\nexport const Options = createRouteDecorator(\"options\");\nexport const Head = createRouteDecorator(\"head\");\nexport const Trace = createRouteDecorator(\"trace\");\nexport const Connect = createRouteDecorator(\"connect\");\n\n// ---- Controller Decorator ----\nexport function Controller(basePath: string): ClassDecorator {\n return (target) => {\n Reflect.defineMetadata(\"basePath\", basePath, target);\n };\n}\n\n// ---- Middleware Decorator ----\nexport function Use(...middlewares: RequestHandler[]): MethodDecorator {\n return (target, propertyKey, descriptor) => {\n const existing: RequestHandler[] =\n Reflect.getMetadata(MIDDLEWARE_KEY, target, propertyKey as string) || [];\n Reflect.defineMetadata(\n MIDDLEWARE_KEY,\n [...existing, ...middlewares],\n target,\n propertyKey as string,\n );\n };\n}\n\n// ---- Parameter Decorators ----\nfunction createParamDecorator(type: ParamDefinition[\"type\"], key?: string) {\n return (paramKey?: string): ParameterDecorator => {\n return (target, propertyKey, parameterIndex) => {\n const params: ParamDefinition[] =\n Reflect.getMetadata(PARAMS_KEY, target, propertyKey as string) || [];\n // Ensure parameters are ordered by index\n params.push({ index: parameterIndex, type, key: paramKey || key });\n params.sort((a, b) => a.index - b.index);\n Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey as string);\n };\n };\n}\n\nexport const Query = createParamDecorator(\"query\");\nexport const Param = createParamDecorator(\"param\");\nexport const Body = createParamDecorator(\"body\");\nexport const Req = createParamDecorator(\"req\");\nexport const Res = createParamDecorator(\"res\");\n\n// Custom HTTP status code decorator\nconst HTTP_CODE_KEY = Symbol(\"httpCode\");\nexport function HttpCode(status: number): MethodDecorator {\n return (target, propertyKey, descriptor) => {\n Reflect.defineMetadata(\n HTTP_CODE_KEY,\n status,\n target,\n propertyKey as string,\n );\n };\n}\n\n// Custom header decorator\nconst HEADER_KEY = Symbol(\"headers\");\nexport function Header(name: string, value: string): MethodDecorator {\n return (target, propertyKey, descriptor) => {\n const headers: Record<string, string> =\n Reflect.getMetadata(HEADER_KEY, target, propertyKey as string) || {};\n headers[name] = value;\n Reflect.defineMetadata(HEADER_KEY, headers, target, propertyKey as string);\n };\n}\n\n// Before/After hooks (not Express middleware, but can be used for logging, etc.)\nconst BEFORE_KEY = Symbol(\"before\");\nconst AFTER_KEY = Symbol(\"after\");\nexport function Before(fn: Function): MethodDecorator {\n return (target, propertyKey, descriptor) => {\n const hooks: Function[] =\n Reflect.getMetadata(BEFORE_KEY, target, propertyKey as string) || [];\n hooks.push(fn);\n Reflect.defineMetadata(BEFORE_KEY, hooks, target, propertyKey as string);\n };\n}\nexport function After(fn: Function): MethodDecorator {\n return (target, propertyKey, descriptor) => {\n const hooks: Function[] =\n Reflect.getMetadata(AFTER_KEY, target, propertyKey as string) || [];\n hooks.push(fn);\n Reflect.defineMetadata(AFTER_KEY, hooks, target, propertyKey as string);\n };\n}\n\n// ---- Register Controllers ----\nexport function registerControllers(router: Router, controllers: any[]) {\n controllers.forEach((ControllerClass) => {\n const instance = new ControllerClass();\n const basePath: string =\n Reflect.getMetadata(\"basePath\", ControllerClass) || \"\";\n const routes: RouteDefinition[] =\n Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];\n\n routes.forEach(({ path, method, handlerName }) => {\n const middlewares: RequestHandler[] =\n Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];\n const params: ParamDefinition[] =\n Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];\n\n const httpCode: number | undefined = Reflect.getMetadata(\n HTTP_CODE_KEY,\n instance,\n handlerName,\n );\n const headers: Record<string, string> =\n Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};\n const beforeHooks: Function[] =\n Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];\n const afterHooks: Function[] =\n Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];\n\n const handler: RequestHandler = async (req, res, next) => {\n try {\n for (const fn of beforeHooks) await fn(req, res);\n const args: any[] = [];\n if (params.length) {\n params.forEach(({ index, type, key }) => {\n switch (type) {\n case \"query\":\n args[index] = key ? req.query[key] : req.query;\n break;\n case \"param\":\n args[index] = key ? req.params[key] : req.params;\n break;\n case \"body\":\n args[index] = key ? req.body?.[key] : req.body;\n break;\n case \"req\":\n args[index] = req;\n break;\n case \"res\":\n args[index] = res;\n break;\n }\n });\n }\n const result = (instance as any)[handlerName](...args);\n // Support both sync and async handlers\n const awaited = result instanceof Promise ? await result : result;\n if (!res.headersSent && typeof awaited !== \"undefined\") {\n if (httpCode) res.status?.(httpCode);\n for (const [k, v] of Object.entries(headers)) res.set?.(k, v);\n res.json(awaited);\n }\n for (const fn of afterHooks) await fn(req, res, awaited);\n } catch (err) {\n next(err);\n }\n };\n\n (router as any)[method](basePath + path, ...middlewares, handler);\n });\n });\n}\n"]}