@digitaldefiance/node-express-suite 1.0.21 → 1.0.23

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 (633) hide show
  1. package/README.md +9 -0
  2. package/package.json +27 -32
  3. package/src/application-base.ts +492 -0
  4. package/src/application.ts +254 -0
  5. package/src/backup-code.ts +336 -0
  6. package/src/constants.ts +69 -0
  7. package/src/controllers/base.ts +440 -0
  8. package/{dist/controllers/index.d.ts → src/controllers/index.ts} +0 -1
  9. package/src/controllers/user.ts +1451 -0
  10. package/src/decorators/base-controller.ts +61 -0
  11. package/src/decorators/controller.ts +109 -0
  12. package/{dist/decorators/index.d.ts → src/decorators/index.ts} +0 -1
  13. package/src/decorators/zod-validation.ts +57 -0
  14. package/src/defaults.ts +94 -0
  15. package/src/documents/base.ts +7 -0
  16. package/src/documents/email-token.ts +14 -0
  17. package/{dist/documents/index.d.ts → src/documents/index.ts} +0 -1
  18. package/{dist/documents/mnemonic.d.ts → src/documents/mnemonic.ts} +5 -2
  19. package/{dist/documents/role.d.ts → src/documents/role.ts} +5 -2
  20. package/src/documents/used-direct-login-token.ts +7 -0
  21. package/{dist/documents/user-role.d.ts → src/documents/user-role.ts} +5 -2
  22. package/{dist/documents/user.d.ts → src/documents/user.ts} +4 -2
  23. package/src/enumerations/base-model-name.ts +41 -0
  24. package/{dist/enumerations/index.d.ts → src/enumerations/index.ts} +0 -1
  25. package/src/enumerations/length-encoding-type.ts +6 -0
  26. package/src/enumerations/schema-collection.ts +33 -0
  27. package/src/enumerations/symmetric-error-type.ts +4 -0
  28. package/src/environment.ts +770 -0
  29. package/src/errors/express-validation.ts +21 -0
  30. package/{dist/errors/index.d.ts → src/errors/index.ts} +0 -1
  31. package/src/errors/invalid-backup-code-version.ts +14 -0
  32. package/src/errors/invalid-jwt-token.ts +10 -0
  33. package/src/errors/invalid-model.ts +11 -0
  34. package/src/errors/invalid-new-password.ts +18 -0
  35. package/src/errors/invalid-password.ts +13 -0
  36. package/src/errors/missing-validated-data.ts +36 -0
  37. package/src/errors/mnemonic-or-password-required.ts +12 -0
  38. package/src/errors/model-not-registered.ts +11 -0
  39. package/src/errors/mongoose-validation.ts +34 -0
  40. package/src/errors/symmetric.ts +41 -0
  41. package/src/errors/token-expired.ts +10 -0
  42. package/src/get-language.ts +53 -0
  43. package/src/get-timezone.ts +45 -0
  44. package/{dist/index.d.ts → src/index.ts} +3 -2
  45. package/{dist/interfaces/api-error-response.d.ts → src/interfaces/api-error-response.ts} +2 -2
  46. package/src/interfaces/api-express-validation-error-response.ts +8 -0
  47. package/src/interfaces/api-message-response.ts +3 -0
  48. package/{dist/interfaces/api-mongo-validation-error-response.d.ts → src/interfaces/api-mongo-validation-error-response.ts} +2 -2
  49. package/{dist/interfaces/api-responses/backup-codes-response.d.ts → src/interfaces/api-responses/backup-codes-response.ts} +2 -2
  50. package/{dist/interfaces/api-responses/challenge-response.d.ts → src/interfaces/api-responses/challenge-response.ts} +3 -3
  51. package/{dist/interfaces/api-responses/code-count-response.d.ts → src/interfaces/api-responses/code-count-response.ts} +2 -2
  52. package/{dist/interfaces/api-responses/index.d.ts → src/interfaces/api-responses/index.ts} +0 -1
  53. package/{dist/interfaces/api-responses/login-response.d.ts → src/interfaces/api-responses/login-response.ts} +4 -4
  54. package/{dist/interfaces/api-responses/mnemonic-response.d.ts → src/interfaces/api-responses/mnemonic-response.ts} +2 -2
  55. package/{dist/interfaces/api-responses/registration-response.d.ts → src/interfaces/api-responses/registration-response.ts} +3 -3
  56. package/{dist/interfaces/api-responses/request-user-response.d.ts → src/interfaces/api-responses/request-user-response.ts} +2 -2
  57. package/{dist/interfaces/application.d.ts → src/interfaces/application.ts} +7 -7
  58. package/src/interfaces/backend-objects/email-token.ts +11 -0
  59. package/{dist/interfaces/backend-objects/index.d.ts → src/interfaces/backend-objects/index.ts} +0 -1
  60. package/{dist/interfaces/backend-objects/request-user.d.ts → src/interfaces/backend-objects/request-user.ts} +7 -2
  61. package/{dist/interfaces/backend-objects/role.d.ts → src/interfaces/backend-objects/role.ts} +1 -1
  62. package/src/interfaces/backend-objects/user.ts +9 -0
  63. package/src/interfaces/checksum-config.ts +4 -0
  64. package/src/interfaces/checksum-consts.ts +13 -0
  65. package/{dist/interfaces/constants.d.ts → src/interfaces/constants.ts} +5 -5
  66. package/src/interfaces/create-user-basics.ts +17 -0
  67. package/src/interfaces/csp-config.ts +35 -0
  68. package/src/interfaces/deep-partial.ts +3 -0
  69. package/{dist/interfaces/discriminator-collections.d.ts → src/interfaces/discriminator-collections.ts} +3 -3
  70. package/src/interfaces/email-service.ts +8 -0
  71. package/src/interfaces/environment-mongo.ts +76 -0
  72. package/src/interfaces/environment.ts +181 -0
  73. package/src/interfaces/failable-result.ts +6 -0
  74. package/src/interfaces/fec-consts.ts +4 -0
  75. package/src/interfaces/handleable-error-options.ts +6 -0
  76. package/{dist/interfaces/index.d.ts → src/interfaces/index.ts} +0 -1
  77. package/src/interfaces/jwt-consts.ts +23 -0
  78. package/src/interfaces/jwt-sign-response.ts +19 -0
  79. package/src/interfaces/mongo-errors.ts +5 -0
  80. package/src/interfaces/request-user.ts +50 -0
  81. package/src/interfaces/required-string-keys.ts +26 -0
  82. package/src/interfaces/schema.ts +31 -0
  83. package/src/interfaces/server-init-result.ts +37 -0
  84. package/src/interfaces/status-code-response.ts +7 -0
  85. package/src/interfaces/symmetric-encryption-results.d.ts +5 -0
  86. package/src/interfaces/symmetric-encryption-results.d.ts.map +1 -0
  87. package/src/interfaces/symmetric-encryption-results.js.map +1 -0
  88. package/src/interfaces/symmetric-encryption-results.ts +4 -0
  89. package/{dist/interfaces/token-response.d.ts → src/interfaces/token-response.ts} +2 -2
  90. package/src/middlewares/authenticate-crypto.ts +243 -0
  91. package/src/middlewares/authenticate-token.ts +152 -0
  92. package/src/middlewares/cleanup-crypto.ts +40 -0
  93. package/{dist/middlewares/index.d.ts → src/middlewares/index.ts} +0 -1
  94. package/src/middlewares/set-global-context-language.ts +24 -0
  95. package/src/middlewares.ts +120 -0
  96. package/src/model-registry.ts +75 -0
  97. package/src/models/email-token.ts +19 -0
  98. package/{dist/models/index.d.ts → src/models/index.ts} +0 -1
  99. package/src/models/mnemonic.ts +19 -0
  100. package/src/models/role.ts +19 -0
  101. package/src/models/used-direct-login-token.ts +23 -0
  102. package/src/models/user-role.ts +17 -0
  103. package/src/models/user.ts +19 -0
  104. package/src/registry/email-service-registry.ts +24 -0
  105. package/{dist/registry/index.d.ts → src/registry/index.ts} +0 -1
  106. package/src/routers/api.ts +151 -0
  107. package/src/routers/app.ts +258 -0
  108. package/src/routers/base.ts +17 -0
  109. package/{dist/routers/index.d.ts → src/routers/index.ts} +0 -1
  110. package/src/schemas/email-token.ts +91 -0
  111. package/{dist/schemas/index.d.ts → src/schemas/index.ts} +1 -2
  112. package/src/schemas/mnemonic.ts +37 -0
  113. package/src/schemas/role.ts +127 -0
  114. package/src/schemas/schema.ts +140 -0
  115. package/src/schemas/used-direct-login-token.ts +38 -0
  116. package/src/schemas/user-role.ts +75 -0
  117. package/src/schemas/user.ts +202 -0
  118. package/src/services/backup-code.ts +316 -0
  119. package/src/services/base.ts +33 -0
  120. package/src/services/checksum.ts +161 -0
  121. package/src/services/crc.ts +213 -0
  122. package/src/services/database-initialization.ts +1479 -0
  123. package/src/services/db-init-cache.d.ts +16 -0
  124. package/src/services/direct-login-token.ts +62 -0
  125. package/src/services/fec-usage-example.ts +102 -0
  126. package/src/services/fec.ts +296 -0
  127. package/{dist/services/index.d.ts → src/services/index.ts} +0 -1
  128. package/src/services/jwt.ts +134 -0
  129. package/src/services/key-wrapping.ts +434 -0
  130. package/src/services/mnemonic.ts +167 -0
  131. package/src/services/request-user.ts +62 -0
  132. package/src/services/role.ts +396 -0
  133. package/src/services/symmetric.ts +139 -0
  134. package/src/services/system-user.ts +82 -0
  135. package/src/services/user.ts +2137 -0
  136. package/src/services/xor.ts +34 -0
  137. package/src/types.d.ts +44 -0
  138. package/src/types.ts +128 -0
  139. package/src/utils.ts +1022 -0
  140. package/dist/application-base.d.ts +0 -112
  141. package/dist/application-base.d.ts.map +0 -1
  142. package/dist/application-base.js +0 -301
  143. package/dist/application-base.js.map +0 -1
  144. package/dist/application.d.ts +0 -23
  145. package/dist/application.d.ts.map +0 -1
  146. package/dist/application.js +0 -126
  147. package/dist/application.js.map +0 -1
  148. package/dist/backup-code.d.ts +0 -67
  149. package/dist/backup-code.d.ts.map +0 -1
  150. package/dist/backup-code.js +0 -270
  151. package/dist/backup-code.js.map +0 -1
  152. package/dist/constants.d.ts +0 -16
  153. package/dist/constants.d.ts.map +0 -1
  154. package/dist/constants.js +0 -54
  155. package/dist/constants.js.map +0 -1
  156. package/dist/controllers/base.d.ts +0 -63
  157. package/dist/controllers/base.d.ts.map +0 -1
  158. package/dist/controllers/base.js +0 -269
  159. package/dist/controllers/base.js.map +0 -1
  160. package/dist/controllers/index.d.ts.map +0 -1
  161. package/dist/controllers/index.js +0 -19
  162. package/dist/controllers/index.js.map +0 -1
  163. package/dist/controllers/user.d.ts +0 -45
  164. package/dist/controllers/user.d.ts.map +0 -1
  165. package/dist/controllers/user.js +0 -750
  166. package/dist/controllers/user.js.map +0 -1
  167. package/dist/decorators/base-controller.d.ts +0 -14
  168. package/dist/decorators/base-controller.d.ts.map +0 -1
  169. package/dist/decorators/base-controller.js +0 -49
  170. package/dist/decorators/base-controller.js.map +0 -1
  171. package/dist/decorators/controller.d.ts +0 -32
  172. package/dist/decorators/controller.d.ts.map +0 -1
  173. package/dist/decorators/controller.js +0 -67
  174. package/dist/decorators/controller.js.map +0 -1
  175. package/dist/decorators/index.d.ts.map +0 -1
  176. package/dist/decorators/index.js +0 -20
  177. package/dist/decorators/index.js.map +0 -1
  178. package/dist/decorators/zod-validation.d.ts +0 -5
  179. package/dist/decorators/zod-validation.d.ts.map +0 -1
  180. package/dist/decorators/zod-validation.js +0 -47
  181. package/dist/decorators/zod-validation.js.map +0 -1
  182. package/dist/defaults.d.ts +0 -7
  183. package/dist/defaults.d.ts.map +0 -1
  184. package/dist/defaults.js +0 -83
  185. package/dist/defaults.js.map +0 -1
  186. package/dist/documents/base.d.ts +0 -3
  187. package/dist/documents/base.d.ts.map +0 -1
  188. package/dist/documents/base.js +0 -3
  189. package/dist/documents/base.js.map +0 -1
  190. package/dist/documents/email-token.d.ts +0 -8
  191. package/dist/documents/email-token.d.ts.map +0 -1
  192. package/dist/documents/email-token.js +0 -3
  193. package/dist/documents/email-token.js.map +0 -1
  194. package/dist/documents/index.d.ts.map +0 -1
  195. package/dist/documents/index.js +0 -3
  196. package/dist/documents/index.js.map +0 -1
  197. package/dist/documents/mnemonic.d.ts.map +0 -1
  198. package/dist/documents/mnemonic.js +0 -3
  199. package/dist/documents/mnemonic.js.map +0 -1
  200. package/dist/documents/role.d.ts.map +0 -1
  201. package/dist/documents/role.js +0 -3
  202. package/dist/documents/role.js.map +0 -1
  203. package/dist/documents/used-direct-login-token.d.ts +0 -5
  204. package/dist/documents/used-direct-login-token.d.ts.map +0 -1
  205. package/dist/documents/used-direct-login-token.js +0 -3
  206. package/dist/documents/used-direct-login-token.js.map +0 -1
  207. package/dist/documents/user-role.d.ts.map +0 -1
  208. package/dist/documents/user-role.js +0 -3
  209. package/dist/documents/user-role.js.map +0 -1
  210. package/dist/documents/user.d.ts.map +0 -1
  211. package/dist/documents/user.js +0 -3
  212. package/dist/documents/user.js.map +0 -1
  213. package/dist/enumerations/base-model-name.d.ts +0 -38
  214. package/dist/enumerations/base-model-name.d.ts.map +0 -1
  215. package/dist/enumerations/base-model-name.js +0 -34
  216. package/dist/enumerations/base-model-name.js.map +0 -1
  217. package/dist/enumerations/index.d.ts.map +0 -1
  218. package/dist/enumerations/index.js +0 -21
  219. package/dist/enumerations/index.js.map +0 -1
  220. package/dist/enumerations/length-encoding-type.d.ts +0 -7
  221. package/dist/enumerations/length-encoding-type.d.ts.map +0 -1
  222. package/dist/enumerations/length-encoding-type.js +0 -11
  223. package/dist/enumerations/length-encoding-type.js.map +0 -1
  224. package/dist/enumerations/schema-collection.d.ts +0 -34
  225. package/dist/enumerations/schema-collection.d.ts.map +0 -1
  226. package/dist/enumerations/schema-collection.js +0 -38
  227. package/dist/enumerations/schema-collection.js.map +0 -1
  228. package/dist/enumerations/symmetric-error-type.d.ts +0 -5
  229. package/dist/enumerations/symmetric-error-type.d.ts.map +0 -1
  230. package/dist/enumerations/symmetric-error-type.js +0 -9
  231. package/dist/enumerations/symmetric-error-type.js.map +0 -1
  232. package/dist/environment.d.ts +0 -189
  233. package/dist/environment.d.ts.map +0 -1
  234. package/dist/environment.js +0 -618
  235. package/dist/environment.js.map +0 -1
  236. package/dist/errors/express-validation.d.ts +0 -9
  237. package/dist/errors/express-validation.d.ts.map +0 -1
  238. package/dist/errors/express-validation.js +0 -17
  239. package/dist/errors/express-validation.js.map +0 -1
  240. package/dist/errors/index.d.ts.map +0 -1
  241. package/dist/errors/index.js +0 -29
  242. package/dist/errors/index.js.map +0 -1
  243. package/dist/errors/invalid-backup-code-version.d.ts +0 -6
  244. package/dist/errors/invalid-backup-code-version.d.ts.map +0 -1
  245. package/dist/errors/invalid-backup-code-version.js +0 -14
  246. package/dist/errors/invalid-backup-code-version.js.map +0 -1
  247. package/dist/errors/invalid-jwt-token.d.ts +0 -5
  248. package/dist/errors/invalid-jwt-token.d.ts.map +0 -1
  249. package/dist/errors/invalid-jwt-token.js +0 -11
  250. package/dist/errors/invalid-jwt-token.js.map +0 -1
  251. package/dist/errors/invalid-model.d.ts +0 -6
  252. package/dist/errors/invalid-model.d.ts.map +0 -1
  253. package/dist/errors/invalid-model.js +0 -13
  254. package/dist/errors/invalid-model.js.map +0 -1
  255. package/dist/errors/invalid-new-password.d.ts +0 -5
  256. package/dist/errors/invalid-new-password.d.ts.map +0 -1
  257. package/dist/errors/invalid-new-password.js +0 -14
  258. package/dist/errors/invalid-new-password.js.map +0 -1
  259. package/dist/errors/invalid-password.d.ts +0 -5
  260. package/dist/errors/invalid-password.d.ts.map +0 -1
  261. package/dist/errors/invalid-password.js +0 -14
  262. package/dist/errors/invalid-password.js.map +0 -1
  263. package/dist/errors/missing-validated-data.d.ts +0 -7
  264. package/dist/errors/missing-validated-data.d.ts.map +0 -1
  265. package/dist/errors/missing-validated-data.js +0 -34
  266. package/dist/errors/missing-validated-data.js.map +0 -1
  267. package/dist/errors/mnemonic-or-password-required.d.ts +0 -5
  268. package/dist/errors/mnemonic-or-password-required.d.ts.map +0 -1
  269. package/dist/errors/mnemonic-or-password-required.js +0 -13
  270. package/dist/errors/mnemonic-or-password-required.js.map +0 -1
  271. package/dist/errors/model-not-registered.d.ts +0 -5
  272. package/dist/errors/model-not-registered.d.ts.map +0 -1
  273. package/dist/errors/model-not-registered.js +0 -12
  274. package/dist/errors/model-not-registered.js.map +0 -1
  275. package/dist/errors/mongoose-validation.d.ts +0 -11
  276. package/dist/errors/mongoose-validation.d.ts.map +0 -1
  277. package/dist/errors/mongoose-validation.js +0 -16
  278. package/dist/errors/mongoose-validation.js.map +0 -1
  279. package/dist/errors/symmetric.d.ts +0 -8
  280. package/dist/errors/symmetric.d.ts.map +0 -1
  281. package/dist/errors/symmetric.js +0 -23
  282. package/dist/errors/symmetric.js.map +0 -1
  283. package/dist/errors/token-expired.d.ts +0 -5
  284. package/dist/errors/token-expired.d.ts.map +0 -1
  285. package/dist/errors/token-expired.js +0 -11
  286. package/dist/errors/token-expired.js.map +0 -1
  287. package/dist/get-language.d.ts +0 -2
  288. package/dist/get-language.d.ts.map +0 -1
  289. package/dist/get-language.js +0 -30
  290. package/dist/get-language.js.map +0 -1
  291. package/dist/get-timezone.d.ts +0 -3
  292. package/dist/get-timezone.d.ts.map +0 -1
  293. package/dist/get-timezone.js +0 -31
  294. package/dist/get-timezone.js.map +0 -1
  295. package/dist/index.d.ts.map +0 -1
  296. package/dist/index.js +0 -40
  297. package/dist/index.js.map +0 -1
  298. package/dist/interfaces/api-error-response.d.ts.map +0 -1
  299. package/dist/interfaces/api-error-response.js +0 -3
  300. package/dist/interfaces/api-error-response.js.map +0 -1
  301. package/dist/interfaces/api-express-validation-error-response.d.ts +0 -7
  302. package/dist/interfaces/api-express-validation-error-response.d.ts.map +0 -1
  303. package/dist/interfaces/api-express-validation-error-response.js +0 -3
  304. package/dist/interfaces/api-express-validation-error-response.js.map +0 -1
  305. package/dist/interfaces/api-message-response.d.ts +0 -4
  306. package/dist/interfaces/api-message-response.d.ts.map +0 -1
  307. package/dist/interfaces/api-message-response.js +0 -3
  308. package/dist/interfaces/api-message-response.js.map +0 -1
  309. package/dist/interfaces/api-mongo-validation-error-response.d.ts.map +0 -1
  310. package/dist/interfaces/api-mongo-validation-error-response.js +0 -3
  311. package/dist/interfaces/api-mongo-validation-error-response.js.map +0 -1
  312. package/dist/interfaces/api-responses/backup-codes-response.d.ts.map +0 -1
  313. package/dist/interfaces/api-responses/backup-codes-response.js +0 -3
  314. package/dist/interfaces/api-responses/backup-codes-response.js.map +0 -1
  315. package/dist/interfaces/api-responses/challenge-response.d.ts.map +0 -1
  316. package/dist/interfaces/api-responses/challenge-response.js +0 -3
  317. package/dist/interfaces/api-responses/challenge-response.js.map +0 -1
  318. package/dist/interfaces/api-responses/code-count-response.d.ts.map +0 -1
  319. package/dist/interfaces/api-responses/code-count-response.js +0 -3
  320. package/dist/interfaces/api-responses/code-count-response.js.map +0 -1
  321. package/dist/interfaces/api-responses/index.d.ts.map +0 -1
  322. package/dist/interfaces/api-responses/index.js +0 -24
  323. package/dist/interfaces/api-responses/index.js.map +0 -1
  324. package/dist/interfaces/api-responses/login-response.d.ts.map +0 -1
  325. package/dist/interfaces/api-responses/login-response.js +0 -3
  326. package/dist/interfaces/api-responses/login-response.js.map +0 -1
  327. package/dist/interfaces/api-responses/mnemonic-response.d.ts.map +0 -1
  328. package/dist/interfaces/api-responses/mnemonic-response.js +0 -3
  329. package/dist/interfaces/api-responses/mnemonic-response.js.map +0 -1
  330. package/dist/interfaces/api-responses/registration-response.d.ts.map +0 -1
  331. package/dist/interfaces/api-responses/registration-response.js +0 -3
  332. package/dist/interfaces/api-responses/registration-response.js.map +0 -1
  333. package/dist/interfaces/api-responses/request-user-response.d.ts.map +0 -1
  334. package/dist/interfaces/api-responses/request-user-response.js +0 -3
  335. package/dist/interfaces/api-responses/request-user-response.js.map +0 -1
  336. package/dist/interfaces/application.d.ts.map +0 -1
  337. package/dist/interfaces/application.js +0 -3
  338. package/dist/interfaces/application.js.map +0 -1
  339. package/dist/interfaces/backend-objects/email-token.d.ts +0 -4
  340. package/dist/interfaces/backend-objects/email-token.d.ts.map +0 -1
  341. package/dist/interfaces/backend-objects/email-token.js +0 -3
  342. package/dist/interfaces/backend-objects/email-token.js.map +0 -1
  343. package/dist/interfaces/backend-objects/index.d.ts.map +0 -1
  344. package/dist/interfaces/backend-objects/index.js +0 -21
  345. package/dist/interfaces/backend-objects/index.js.map +0 -1
  346. package/dist/interfaces/backend-objects/request-user.d.ts.map +0 -1
  347. package/dist/interfaces/backend-objects/request-user.js +0 -3
  348. package/dist/interfaces/backend-objects/request-user.js.map +0 -1
  349. package/dist/interfaces/backend-objects/role.d.ts.map +0 -1
  350. package/dist/interfaces/backend-objects/role.js +0 -3
  351. package/dist/interfaces/backend-objects/role.js.map +0 -1
  352. package/dist/interfaces/backend-objects/user.d.ts +0 -4
  353. package/dist/interfaces/backend-objects/user.d.ts.map +0 -1
  354. package/dist/interfaces/backend-objects/user.js +0 -3
  355. package/dist/interfaces/backend-objects/user.js.map +0 -1
  356. package/dist/interfaces/checksum-config.d.ts +0 -5
  357. package/dist/interfaces/checksum-config.d.ts.map +0 -1
  358. package/dist/interfaces/checksum-config.js +0 -3
  359. package/dist/interfaces/checksum-config.js.map +0 -1
  360. package/dist/interfaces/checksum-consts.d.ts +0 -11
  361. package/dist/interfaces/checksum-consts.d.ts.map +0 -1
  362. package/dist/interfaces/checksum-consts.js +0 -3
  363. package/dist/interfaces/checksum-consts.js.map +0 -1
  364. package/dist/interfaces/constants.d.ts.map +0 -1
  365. package/dist/interfaces/constants.js +0 -3
  366. package/dist/interfaces/constants.js.map +0 -1
  367. package/dist/interfaces/create-user-basics.d.ts +0 -18
  368. package/dist/interfaces/create-user-basics.d.ts.map +0 -1
  369. package/dist/interfaces/create-user-basics.js +0 -3
  370. package/dist/interfaces/create-user-basics.js.map +0 -1
  371. package/dist/interfaces/csp-config.d.ts +0 -14
  372. package/dist/interfaces/csp-config.d.ts.map +0 -1
  373. package/dist/interfaces/csp-config.js +0 -3
  374. package/dist/interfaces/csp-config.js.map +0 -1
  375. package/dist/interfaces/deep-partial.d.ts +0 -4
  376. package/dist/interfaces/deep-partial.d.ts.map +0 -1
  377. package/dist/interfaces/deep-partial.js +0 -3
  378. package/dist/interfaces/deep-partial.js.map +0 -1
  379. package/dist/interfaces/discriminator-collections.d.ts.map +0 -1
  380. package/dist/interfaces/discriminator-collections.js +0 -3
  381. package/dist/interfaces/discriminator-collections.js.map +0 -1
  382. package/dist/interfaces/email-service.d.ts +0 -4
  383. package/dist/interfaces/email-service.d.ts.map +0 -1
  384. package/dist/interfaces/email-service.js +0 -3
  385. package/dist/interfaces/email-service.js.map +0 -1
  386. package/dist/interfaces/environment-mongo.d.ts +0 -76
  387. package/dist/interfaces/environment-mongo.d.ts.map +0 -1
  388. package/dist/interfaces/environment-mongo.js +0 -3
  389. package/dist/interfaces/environment-mongo.js.map +0 -1
  390. package/dist/interfaces/environment.d.ts +0 -181
  391. package/dist/interfaces/environment.d.ts.map +0 -1
  392. package/dist/interfaces/environment.js +0 -3
  393. package/dist/interfaces/environment.js.map +0 -1
  394. package/dist/interfaces/failable-result.d.ts +0 -7
  395. package/dist/interfaces/failable-result.d.ts.map +0 -1
  396. package/dist/interfaces/failable-result.js +0 -3
  397. package/dist/interfaces/failable-result.js.map +0 -1
  398. package/dist/interfaces/fec-consts.d.ts +0 -5
  399. package/dist/interfaces/fec-consts.d.ts.map +0 -1
  400. package/dist/interfaces/fec-consts.js +0 -3
  401. package/dist/interfaces/fec-consts.js.map +0 -1
  402. package/dist/interfaces/handleable-error-options.d.ts +0 -7
  403. package/dist/interfaces/handleable-error-options.d.ts.map +0 -1
  404. package/dist/interfaces/handleable-error-options.js +0 -3
  405. package/dist/interfaces/handleable-error-options.js.map +0 -1
  406. package/dist/interfaces/index.d.ts.map +0 -1
  407. package/dist/interfaces/index.js +0 -46
  408. package/dist/interfaces/index.js.map +0 -1
  409. package/dist/interfaces/jwt-consts.d.ts +0 -11
  410. package/dist/interfaces/jwt-consts.d.ts.map +0 -1
  411. package/dist/interfaces/jwt-consts.js +0 -3
  412. package/dist/interfaces/jwt-consts.js.map +0 -1
  413. package/dist/interfaces/jwt-sign-response.d.ts +0 -11
  414. package/dist/interfaces/jwt-sign-response.d.ts.map +0 -1
  415. package/dist/interfaces/jwt-sign-response.js +0 -3
  416. package/dist/interfaces/jwt-sign-response.js.map +0 -1
  417. package/dist/interfaces/mongo-errors.d.ts +0 -5
  418. package/dist/interfaces/mongo-errors.d.ts.map +0 -1
  419. package/dist/interfaces/mongo-errors.js +0 -3
  420. package/dist/interfaces/mongo-errors.js.map +0 -1
  421. package/dist/interfaces/request-user.d.ts +0 -42
  422. package/dist/interfaces/request-user.d.ts.map +0 -1
  423. package/dist/interfaces/request-user.js +0 -3
  424. package/dist/interfaces/request-user.js.map +0 -1
  425. package/dist/interfaces/required-string-keys.d.ts +0 -22
  426. package/dist/interfaces/required-string-keys.d.ts.map +0 -1
  427. package/dist/interfaces/required-string-keys.js +0 -3
  428. package/dist/interfaces/required-string-keys.js.map +0 -1
  429. package/dist/interfaces/schema.d.ts +0 -29
  430. package/dist/interfaces/schema.d.ts.map +0 -1
  431. package/dist/interfaces/schema.js +0 -3
  432. package/dist/interfaces/schema.js.map +0 -1
  433. package/dist/interfaces/server-init-result.d.ts +0 -35
  434. package/dist/interfaces/server-init-result.d.ts.map +0 -1
  435. package/dist/interfaces/server-init-result.js +0 -3
  436. package/dist/interfaces/server-init-result.js.map +0 -1
  437. package/dist/interfaces/status-code-response.d.ts +0 -7
  438. package/dist/interfaces/status-code-response.d.ts.map +0 -1
  439. package/dist/interfaces/status-code-response.js +0 -3
  440. package/dist/interfaces/status-code-response.js.map +0 -1
  441. package/dist/interfaces/symmetric-encryption-results.d.ts +0 -5
  442. package/dist/interfaces/symmetric-encryption-results.d.ts.map +0 -1
  443. package/dist/interfaces/symmetric-encryption-results.js.map +0 -1
  444. package/dist/interfaces/token-response.d.ts.map +0 -1
  445. package/dist/interfaces/token-response.js +0 -3
  446. package/dist/interfaces/token-response.js.map +0 -1
  447. package/dist/middlewares/authenticate-crypto.d.ts +0 -13
  448. package/dist/middlewares/authenticate-crypto.d.ts.map +0 -1
  449. package/dist/middlewares/authenticate-crypto.js +0 -146
  450. package/dist/middlewares/authenticate-crypto.js.map +0 -1
  451. package/dist/middlewares/authenticate-token.d.ts +0 -24
  452. package/dist/middlewares/authenticate-token.d.ts.map +0 -1
  453. package/dist/middlewares/authenticate-token.js +0 -102
  454. package/dist/middlewares/authenticate-token.js.map +0 -1
  455. package/dist/middlewares/cleanup-crypto.d.ts +0 -7
  456. package/dist/middlewares/cleanup-crypto.d.ts.map +0 -1
  457. package/dist/middlewares/cleanup-crypto.js +0 -32
  458. package/dist/middlewares/cleanup-crypto.js.map +0 -1
  459. package/dist/middlewares/index.d.ts.map +0 -1
  460. package/dist/middlewares/index.js +0 -21
  461. package/dist/middlewares/index.js.map +0 -1
  462. package/dist/middlewares/set-global-context-language.d.ts +0 -3
  463. package/dist/middlewares/set-global-context-language.d.ts.map +0 -1
  464. package/dist/middlewares/set-global-context-language.js +0 -14
  465. package/dist/middlewares/set-global-context-language.js.map +0 -1
  466. package/dist/middlewares.d.ts +0 -18
  467. package/dist/middlewares.d.ts.map +0 -1
  468. package/dist/middlewares.js +0 -76
  469. package/dist/middlewares.js.map +0 -1
  470. package/dist/model-registry.d.ts +0 -23
  471. package/dist/model-registry.d.ts.map +0 -1
  472. package/dist/model-registry.js +0 -47
  473. package/dist/model-registry.js.map +0 -1
  474. package/dist/models/email-token.d.ts +0 -11
  475. package/dist/models/email-token.d.ts.map +0 -1
  476. package/dist/models/email-token.js +0 -11
  477. package/dist/models/email-token.js.map +0 -1
  478. package/dist/models/index.d.ts.map +0 -1
  479. package/dist/models/index.js +0 -23
  480. package/dist/models/index.js.map +0 -1
  481. package/dist/models/mnemonic.d.ts +0 -11
  482. package/dist/models/mnemonic.d.ts.map +0 -1
  483. package/dist/models/mnemonic.js +0 -11
  484. package/dist/models/mnemonic.js.map +0 -1
  485. package/dist/models/role.d.ts +0 -11
  486. package/dist/models/role.d.ts.map +0 -1
  487. package/dist/models/role.js +0 -11
  488. package/dist/models/role.js.map +0 -1
  489. package/dist/models/used-direct-login-token.d.ts +0 -11
  490. package/dist/models/used-direct-login-token.d.ts.map +0 -1
  491. package/dist/models/used-direct-login-token.js +0 -11
  492. package/dist/models/used-direct-login-token.js.map +0 -1
  493. package/dist/models/user-role.d.ts +0 -6
  494. package/dist/models/user-role.d.ts.map +0 -1
  495. package/dist/models/user-role.js +0 -10
  496. package/dist/models/user-role.js.map +0 -1
  497. package/dist/models/user.d.ts +0 -7
  498. package/dist/models/user.d.ts.map +0 -1
  499. package/dist/models/user.js +0 -11
  500. package/dist/models/user.js.map +0 -1
  501. package/dist/registry/email-service-registry.d.ts +0 -9
  502. package/dist/registry/email-service-registry.d.ts.map +0 -1
  503. package/dist/registry/email-service-registry.js +0 -17
  504. package/dist/registry/email-service-registry.js.map +0 -1
  505. package/dist/registry/index.d.ts.map +0 -1
  506. package/dist/registry/index.js +0 -6
  507. package/dist/registry/index.js.map +0 -1
  508. package/dist/routers/api.d.ts +0 -27
  509. package/dist/routers/api.d.ts.map +0 -1
  510. package/dist/routers/api.js +0 -44
  511. package/dist/routers/api.js.map +0 -1
  512. package/dist/routers/app.d.ts +0 -28
  513. package/dist/routers/app.d.ts.map +0 -1
  514. package/dist/routers/app.js +0 -182
  515. package/dist/routers/app.js.map +0 -1
  516. package/dist/routers/base.d.ts +0 -12
  517. package/dist/routers/base.d.ts.map +0 -1
  518. package/dist/routers/base.js +0 -12
  519. package/dist/routers/base.js.map +0 -1
  520. package/dist/routers/index.d.ts.map +0 -1
  521. package/dist/routers/index.js +0 -20
  522. package/dist/routers/index.js.map +0 -1
  523. package/dist/schemas/email-token.d.ts +0 -38
  524. package/dist/schemas/email-token.d.ts.map +0 -1
  525. package/dist/schemas/email-token.js +0 -56
  526. package/dist/schemas/email-token.js.map +0 -1
  527. package/dist/schemas/index.d.ts.map +0 -1
  528. package/dist/schemas/index.js +0 -24
  529. package/dist/schemas/index.js.map +0 -1
  530. package/dist/schemas/mnemonic.d.ts +0 -20
  531. package/dist/schemas/mnemonic.d.ts.map +0 -1
  532. package/dist/schemas/mnemonic.js +0 -30
  533. package/dist/schemas/mnemonic.js.map +0 -1
  534. package/dist/schemas/role.d.ts +0 -32
  535. package/dist/schemas/role.d.ts.map +0 -1
  536. package/dist/schemas/role.js +0 -86
  537. package/dist/schemas/role.js.map +0 -1
  538. package/dist/schemas/schema.d.ts +0 -40
  539. package/dist/schemas/schema.d.ts.map +0 -1
  540. package/dist/schemas/schema.js +0 -64
  541. package/dist/schemas/schema.js.map +0 -1
  542. package/dist/schemas/used-direct-login-token.d.ts +0 -27
  543. package/dist/schemas/used-direct-login-token.d.ts.map +0 -1
  544. package/dist/schemas/used-direct-login-token.js +0 -23
  545. package/dist/schemas/used-direct-login-token.js.map +0 -1
  546. package/dist/schemas/user-role.d.ts +0 -29
  547. package/dist/schemas/user-role.d.ts.map +0 -1
  548. package/dist/schemas/user-role.js +0 -54
  549. package/dist/schemas/user-role.js.map +0 -1
  550. package/dist/schemas/user.d.ts +0 -21
  551. package/dist/schemas/user.d.ts.map +0 -1
  552. package/dist/schemas/user.js +0 -178
  553. package/dist/schemas/user.js.map +0 -1
  554. package/dist/services/backup-code.d.ts +0 -78
  555. package/dist/services/backup-code.d.ts.map +0 -1
  556. package/dist/services/backup-code.js +0 -180
  557. package/dist/services/backup-code.js.map +0 -1
  558. package/dist/services/base.d.ts +0 -13
  559. package/dist/services/base.d.ts.map +0 -1
  560. package/dist/services/base.js +0 -14
  561. package/dist/services/base.js.map +0 -1
  562. package/dist/services/checksum.d.ts +0 -67
  563. package/dist/services/checksum.d.ts.map +0 -1
  564. package/dist/services/checksum.js +0 -175
  565. package/dist/services/checksum.js.map +0 -1
  566. package/dist/services/crc.d.ts +0 -87
  567. package/dist/services/crc.d.ts.map +0 -1
  568. package/dist/services/crc.js +0 -198
  569. package/dist/services/crc.js.map +0 -1
  570. package/dist/services/database-initialization.d.ts +0 -105
  571. package/dist/services/database-initialization.d.ts.map +0 -1
  572. package/dist/services/database-initialization.js +0 -779
  573. package/dist/services/database-initialization.js.map +0 -1
  574. package/dist/services/direct-login-token.d.ts +0 -9
  575. package/dist/services/direct-login-token.d.ts.map +0 -1
  576. package/dist/services/direct-login-token.js +0 -41
  577. package/dist/services/direct-login-token.js.map +0 -1
  578. package/dist/services/fec-usage-example.d.ts +0 -38
  579. package/dist/services/fec-usage-example.d.ts.map +0 -1
  580. package/dist/services/fec-usage-example.js +0 -77
  581. package/dist/services/fec-usage-example.js.map +0 -1
  582. package/dist/services/fec.d.ts +0 -46
  583. package/dist/services/fec.d.ts.map +0 -1
  584. package/dist/services/fec.js +0 -192
  585. package/dist/services/fec.js.map +0 -1
  586. package/dist/services/index.d.ts.map +0 -1
  587. package/dist/services/index.js +0 -35
  588. package/dist/services/index.js.map +0 -1
  589. package/dist/services/jwt.d.ts +0 -33
  590. package/dist/services/jwt.d.ts.map +0 -1
  591. package/dist/services/jwt.js +0 -90
  592. package/dist/services/jwt.js.map +0 -1
  593. package/dist/services/key-wrapping.d.ts +0 -60
  594. package/dist/services/key-wrapping.d.ts.map +0 -1
  595. package/dist/services/key-wrapping.js +0 -311
  596. package/dist/services/key-wrapping.js.map +0 -1
  597. package/dist/services/mnemonic.d.ts +0 -61
  598. package/dist/services/mnemonic.d.ts.map +0 -1
  599. package/dist/services/mnemonic.js +0 -112
  600. package/dist/services/mnemonic.js.map +0 -1
  601. package/dist/services/request-user.d.ts +0 -20
  602. package/dist/services/request-user.d.ts.map +0 -1
  603. package/dist/services/request-user.js +0 -50
  604. package/dist/services/request-user.js.map +0 -1
  605. package/dist/services/role.d.ts +0 -88
  606. package/dist/services/role.d.ts.map +0 -1
  607. package/dist/services/role.js +0 -263
  608. package/dist/services/role.js.map +0 -1
  609. package/dist/services/symmetric.d.ts +0 -42
  610. package/dist/services/symmetric.d.ts.map +0 -1
  611. package/dist/services/symmetric.js +0 -101
  612. package/dist/services/symmetric.js.map +0 -1
  613. package/dist/services/system-user.d.ts +0 -17
  614. package/dist/services/system-user.d.ts.map +0 -1
  615. package/dist/services/system-user.js +0 -46
  616. package/dist/services/system-user.js.map +0 -1
  617. package/dist/services/user.d.ts +0 -320
  618. package/dist/services/user.d.ts.map +0 -1
  619. package/dist/services/user.js +0 -1374
  620. package/dist/services/user.js.map +0 -1
  621. package/dist/services/xor.d.ts +0 -24
  622. package/dist/services/xor.d.ts.map +0 -1
  623. package/dist/services/xor.js +0 -37
  624. package/dist/services/xor.js.map +0 -1
  625. package/dist/types.d.ts +0 -70
  626. package/dist/types.d.ts.map +0 -1
  627. package/dist/types.js +0 -14
  628. package/dist/types.js.map +0 -1
  629. package/dist/utils.d.ts +0 -202
  630. package/dist/utils.d.ts.map +0 -1
  631. package/dist/utils.js +0 -786
  632. package/dist/utils.js.map +0 -1
  633. /package/{dist → src}/interfaces/symmetric-encryption-results.js +0 -0
package/src/utils.ts ADDED
@@ -0,0 +1,1022 @@
1
+ /// <reference path="./types.d.ts" />
2
+ import { I18nEngine } from '@digitaldefiance/i18n-lib';
3
+ import { NextFunction, Request, Response } from 'express';
4
+ import { Result, ValidationError } from 'express-validator';
5
+ import { existsSync, readdirSync } from 'fs';
6
+ import { ClientSession, Connection, Types } from 'mongoose';
7
+ import { resolve } from 'path';
8
+ import { z, ZodType } from 'zod';
9
+ import { ExpressValidationError } from './errors/express-validation';
10
+ import { MongooseValidationError } from './errors/mongoose-validation';
11
+ import { IApiErrorResponse } from './interfaces';
12
+ import { IApiExpressValidationErrorResponse } from './interfaces/api-express-validation-error-response';
13
+ import { IApiMongoValidationErrorResponse } from './interfaces/api-mongo-validation-error-response';
14
+ import { IMongoErrors } from './interfaces/mongo-errors';
15
+ import { RequiredStringKeys } from './interfaces/required-string-keys';
16
+ import { ApiResponse, SendFunction, TransactionCallback } from './types';
17
+
18
+ export type DEBUG_TYPE = 'error' | 'warn' | 'log';
19
+
20
+ /**
21
+ * Optionally prints certain debug messages
22
+ * @param debug Whether to print debug messages
23
+ * @param type What type of message to print
24
+ * @param args Any args to print
25
+ */
26
+ export function debugLog(
27
+ debug: boolean,
28
+ type: DEBUG_TYPE = 'log',
29
+ ...args: any[]
30
+ ): void {
31
+ if (debug && type === 'error') {
32
+ console.error(...args);
33
+ } else if (debug && type === 'warn') {
34
+ console.warn(...args);
35
+ } else if (debug && type === 'log') {
36
+ console.log(...args);
37
+ }
38
+ }
39
+
40
+ // Helper: get value at a dotted path from an object
41
+ export function getValueAtPath(obj: unknown, path: (string | number)[]) {
42
+ return path.reduce<any>((acc, key) => {
43
+ if (acc == null) return undefined;
44
+ try {
45
+ return (acc as any)[key as any];
46
+ } catch {
47
+ return undefined;
48
+ }
49
+ }, obj);
50
+ }
51
+
52
+ // Helper: map Zod issues to express-validator ValidationError[]
53
+ export function mapZodIssuesToValidationErrors(
54
+ issues: z.ZodError<unknown>['issues'],
55
+ source: unknown,
56
+ location: 'body' | 'cookies' | 'headers' | 'params' | 'query' = 'body',
57
+ ): ValidationError[] {
58
+ return issues.map((issue) => ({
59
+ type: 'field',
60
+ location,
61
+ path: issue.path
62
+ .filter((p) => typeof p === 'string' || typeof p === 'number')
63
+ .join('.'),
64
+ value: getValueAtPath(source, issue.path as (string | number)[]),
65
+ msg: issue.message,
66
+ }));
67
+ }
68
+
69
+ /**
70
+ * Verifies the required fields were validated by express-validator and sends an error response if not or calls the callback if they are
71
+ * @param req The request object
72
+ * @param fields The fields to check
73
+ * @param callback The callback to call if the fields are valid
74
+ * @returns The result of the callback
75
+ */
76
+ export async function requireValidatedFieldsAsync<
77
+ T extends ZodType<any, any, any>,
78
+ TResult = void,
79
+ >(
80
+ req: Request,
81
+ schema: T,
82
+ callback: (data: z.output<T>) => Promise<TResult>,
83
+ ): Promise<TResult> {
84
+ if (req.validatedBody === undefined) {
85
+ throw new MissingValidatedDataError();
86
+ }
87
+
88
+ try {
89
+ const validatedData = schema.parse(req.validatedBody) as z.output<T>;
90
+ return await callback(validatedData);
91
+ } catch (error) {
92
+ if (error instanceof z.ZodError) {
93
+ throw new ExpressValidationError(
94
+ mapZodIssuesToValidationErrors(
95
+ error.issues,
96
+ req.validatedBody ?? {},
97
+ 'body',
98
+ ),
99
+ );
100
+ }
101
+ throw error;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Verifies at least one of the required fields were validated by express-validator and sends an error response if not or calls the callback if they are
107
+ * @param req The request object
108
+ * @param fields The fields to check
109
+ * @param callback The callback to call if the fields are valid
110
+ * @returns The result of the callback
111
+ */
112
+ export async function requireOneOfValidatedFieldsAsync<T = void>(
113
+ req: Request,
114
+ fields: string[],
115
+ callback: () => Promise<T>,
116
+ ): Promise<T> {
117
+ if (req.validatedBody === undefined) {
118
+ throw new MissingValidatedDataError();
119
+ }
120
+ const validatedBody = req.validatedBody;
121
+ if (!fields.some((field) => validatedBody?.[field] !== undefined)) {
122
+ throw new MissingValidatedDataError(fields);
123
+ }
124
+ return await callback();
125
+ }
126
+
127
+ /**
128
+ * Verifies the required fields were validated by express-validator and throws an error if not or calls the callback if they are
129
+ * @param req The request object
130
+ * @param fields The fields to check
131
+ * @param callback The callback to call if the fields are valid
132
+ * @returns The result of the callback
133
+ */
134
+ export function requireValidatedFieldsOrThrow<T = void>(
135
+ req: Request,
136
+ fields: string[],
137
+ callback: () => T,
138
+ ): T {
139
+ if (req.validatedBody === undefined) {
140
+ throw new MissingValidatedDataError();
141
+ }
142
+ const validatedBody = req.validatedBody;
143
+ fields.forEach((field) => {
144
+ if (validatedBody[field] === undefined) {
145
+ throw new MissingValidatedDataError(field);
146
+ }
147
+ });
148
+ return callback();
149
+ }
150
+
151
+ /**
152
+ * Checks if the given id is a valid string id
153
+ * @param id The id to check
154
+ * @returns True if the id is a valid string id
155
+ */
156
+ export function isValidStringId(id: unknown): boolean {
157
+ return typeof id === 'string' && Types.ObjectId.isValid(id);
158
+ }
159
+
160
+ /**
161
+ * The default number of retry attempts for transactions
162
+ * Use fewer retries in test environment for faster feedback
163
+ */
164
+ export const DEFAULT_RETRY_ATTEMPTS =
165
+ process.env['NODE_ENV'] === 'test' ? 2 : 3;
166
+ /**
167
+ * The default transaction timeout in milliseconds
168
+ * Use shorter timeout in test environment for faster failure detection
169
+ */
170
+ export const DEFAULT_TRANSACTION_TIMEOUT =
171
+ process.env['NODE_ENV'] === 'test' ? 15000 : 60000;
172
+
173
+ /**
174
+ * The default transaction lock request timeout in milliseconds
175
+ */
176
+ export const DEFAULT_TRANSACTION_LOCK_REQUEST_TIMEOUT =
177
+ process.env['NODE_ENV'] === 'test' ? 10000 : 30000;
178
+
179
+ export interface TransactionOptions {
180
+ timeoutMs?: number;
181
+ retryAttempts?: number;
182
+ baseDelay?: number;
183
+ debugLogEnabled?: boolean;
184
+ }
185
+
186
+ /**
187
+ * Gets the default base delay for transaction retries from environment variables
188
+ * @returns The base delay in milliseconds
189
+ */
190
+ export function getDefaultBaseDelay(): number {
191
+ const envValue = process.env['MONGO_TRANSACTION_RETRY_BASE_DELAY'];
192
+ if (envValue) {
193
+ const parsed = parseInt(envValue);
194
+ if (!isNaN(parsed) && parsed > 0) {
195
+ return parsed;
196
+ }
197
+ }
198
+ // Fallback to hardcoded values if environment variable is not set or invalid
199
+ return process.env['NODE_ENV'] === 'test' ? 25 : 100;
200
+ }
201
+
202
+ /**
203
+ * Wraps a callback in a transaction if necessary
204
+ * @param connection The mongoose connection
205
+ * @param useTransaction Whether to use a transaction
206
+ * @param session The session to use
207
+ * @param callback The callback to wrap
208
+ * @param options Transaction options including timeout and retry attempts
209
+ * @param args The arguments to pass to the callback
210
+ * @returns The result of the callback
211
+ */
212
+ export async function withTransaction<T>(
213
+ connection: Connection,
214
+ useTransaction: boolean,
215
+ session: ClientSession | undefined,
216
+ callback: TransactionCallback<T>,
217
+ options: TransactionOptions = {},
218
+ ...args: any
219
+ ): Promise<T> {
220
+ const engine = getSuiteCoreI18nEngine();
221
+ const isTestEnvironment = process.env['NODE_ENV'] === 'test';
222
+ const {
223
+ timeoutMs = DEFAULT_TRANSACTION_TIMEOUT,
224
+ retryAttempts = DEFAULT_RETRY_ATTEMPTS, // Use consistent retry attempts
225
+ baseDelay = getDefaultBaseDelay(),
226
+ debugLogEnabled,
227
+ } = options;
228
+ if (!useTransaction) {
229
+ return await callback(session, undefined, ...args);
230
+ }
231
+ const needSession = useTransaction && session === undefined;
232
+ const client = connection.getClient();
233
+ if (!client) {
234
+ // If no client is available, fall back to non-transactional execution
235
+ debugLog(
236
+ debugLogEnabled === true,
237
+ 'warn',
238
+ engine.translate(
239
+ SuiteCoreComponentId,
240
+ SuiteCoreStringKey.Admin_NoMongoDbClientFoundFallingBack,
241
+ ),
242
+ );
243
+ return await callback(session, undefined, ...args);
244
+ }
245
+
246
+ let attempt = 0;
247
+ while (attempt < retryAttempts) {
248
+ const s = needSession ? await client.startSession() : session;
249
+ try {
250
+ if (needSession && s !== undefined) {
251
+ await s.startTransaction({
252
+ maxCommitTimeMS: timeoutMs,
253
+ });
254
+ }
255
+
256
+ // Race the callback against the timeout
257
+ const timeoutPromise = new Promise<never>((_, reject) => {
258
+ setTimeout(() => {
259
+ reject(
260
+ new Error(
261
+ engine.translate(
262
+ SuiteCoreComponentId,
263
+ SuiteCoreStringKey.Admin_TransactionTimeoutTemplate,
264
+ { timeMs: timeoutMs },
265
+ ),
266
+ ),
267
+ );
268
+ }, timeoutMs);
269
+ });
270
+
271
+ const result = await Promise.race([callback(s, ...args), timeoutPromise]);
272
+
273
+ if (needSession && s !== undefined) await s.commitTransaction();
274
+ return result;
275
+ } catch (error: any) {
276
+ if (needSession && s !== undefined && s.inTransaction())
277
+ await s.abortTransaction();
278
+
279
+ // Check if this is a transient transaction error that can be retried
280
+ const isTransientError =
281
+ error?.errorLabelSet?.has('TransientTransactionError') ||
282
+ error?.errorLabelSet?.has('UnknownTransactionCommitResult') ||
283
+ error?.code === 251 || // NoSuchTransaction
284
+ error?.code === 112 || // WriteConflict
285
+ error?.code === 11000 || // DuplicateKey - very common in concurrent initialization
286
+ error?.code === 16500 || // TransactionAborted
287
+ error?.code === 244 || // TransactionTooOld
288
+ error?.code === 246 || // ExceededTimeLimit
289
+ error?.code === 13436 || // TransactionTooLargeForCache
290
+ error?.code === 50 || // MaxTimeMSExpired
291
+ error?.message?.includes('Transaction') ||
292
+ error?.message?.includes('aborted') ||
293
+ error?.message?.includes('WriteConflict') ||
294
+ error?.message?.includes('NoSuchTransaction') ||
295
+ error?.message?.includes('TransactionTooOld') ||
296
+ error?.message?.includes('ExceededTimeLimit') ||
297
+ error?.message?.includes('duplicate key error') ||
298
+ error?.message?.includes('E11000') ||
299
+ (error?.code === 11000 && error?.message?.includes('duplicate')); // More specific duplicate key handling
300
+
301
+ if (isTransientError && attempt < retryAttempts - 1) {
302
+ attempt++;
303
+ const jitter = Math.random() * 0.3; // Reduced jitter
304
+ const actualBaseDelay = isTestEnvironment
305
+ ? Math.floor(baseDelay * 0.5)
306
+ : baseDelay; // Shorter base delay in tests
307
+ const delay = Math.floor(
308
+ actualBaseDelay * (1 + attempt * 0.5) * (1 + jitter),
309
+ ); // Linear backoff instead of exponential
310
+ debugLog(
311
+ debugLogEnabled === true,
312
+ 'warn',
313
+ engine.translate(
314
+ SuiteCoreComponentId,
315
+ SuiteCoreStringKey.Admin_TransactionFailedTransientTemplate,
316
+ {
317
+ delayMs: delay,
318
+ attempt,
319
+ attempts: retryAttempts,
320
+ },
321
+ undefined,
322
+ ),
323
+ );
324
+ await new Promise((resolve) => setTimeout(resolve, delay));
325
+ continue;
326
+ }
327
+
328
+ throw error;
329
+ } finally {
330
+ if (needSession && s !== undefined) await s.endSession();
331
+ }
332
+ }
333
+
334
+ const jitter = Math.random() * 0.3; // Reduced jitter
335
+ const actualBaseDelay = isTestEnvironment
336
+ ? Math.floor(baseDelay * 0.5)
337
+ : baseDelay; // Shorter base delay in tests
338
+ const delay = Math.floor(
339
+ actualBaseDelay * (1 + attempt * 0.5) * (1 + jitter),
340
+ ); // Linear backoff instead of exponential
341
+
342
+ throw new TranslatableSuiteError(
343
+ SuiteCoreStringKey.Admin_TransactionFailedTransientTemplate,
344
+ {
345
+ delayMs: delay,
346
+ attempt,
347
+ attempts: retryAttempts,
348
+ },
349
+ );
350
+ }
351
+
352
+ /**
353
+ * Sends an API response with the given status and response object.
354
+ * @param status
355
+ * @param response
356
+ * @param res
357
+ */
358
+ export function sendApiMessageResponse<T extends ApiResponse>(
359
+ status: number,
360
+ response: T,
361
+ res: Response<T>,
362
+ ): void {
363
+ res.status(status).json(response);
364
+ }
365
+
366
+ /**
367
+ * Sends an API response with the given status, message, and error.
368
+ * @param status
369
+ * @param message
370
+ * @param error
371
+ * @param res
372
+ */
373
+ export function sendApiErrorResponse(
374
+ status: number,
375
+ message: string,
376
+ error: unknown,
377
+ res: Response,
378
+ ): void {
379
+ sendApiMessageResponse<IApiErrorResponse>(status, { message, error }, res);
380
+ }
381
+
382
+ /**
383
+ * Sends an API response with the given status and validation errors.
384
+ * @param status
385
+ * @param errors
386
+ * @param res
387
+ */
388
+ export function sendApiExpressValidationErrorResponse(
389
+ status: number,
390
+ errors: ValidationError[],
391
+ res: Response,
392
+ ): void {
393
+ const engine = getSuiteCoreI18nEngine();
394
+ sendApiMessageResponse<IApiExpressValidationErrorResponse>(
395
+ status,
396
+ {
397
+ message: engine.translate(
398
+ SuiteCoreComponentId,
399
+ SuiteCoreStringKey.ValidationError,
400
+ ),
401
+ errors,
402
+ },
403
+ res,
404
+ );
405
+ }
406
+
407
+ /**
408
+ * Sends an API response with the given status, message, and MongoDB validation errors.
409
+ * @param status
410
+ * @param message
411
+ * @param errors
412
+ * @param res
413
+ */
414
+ export function sendApiMongoValidationErrorResponse(
415
+ status: number,
416
+ message: string,
417
+ errors: IMongoErrors,
418
+ res: Response,
419
+ ): void {
420
+ sendApiMessageResponse<IApiMongoValidationErrorResponse>(
421
+ status,
422
+ { message, errors },
423
+ res,
424
+ );
425
+ }
426
+
427
+ /**
428
+ * Sends a raw JSON response with the given status and response object.
429
+ * @param status The status code
430
+ * @param response The response data
431
+ * @param res The response object
432
+ */
433
+ export function sendRawJsonResponse<T>(
434
+ status: number,
435
+ response: T,
436
+ res: Response<T>,
437
+ ) {
438
+ res.status(status).json(response);
439
+ }
440
+
441
+ function isRecursiveError(error: unknown): boolean {
442
+ return (
443
+ error !== null &&
444
+ typeof error === 'object' &&
445
+ '_handlingInProgress' in error &&
446
+ !!(error as any)._handlingInProgress
447
+ );
448
+ }
449
+
450
+ function markErrorAsHandling(error: unknown): void {
451
+ if (error && typeof error === 'object') {
452
+ (error as { _handlingInProgress?: boolean })._handlingInProgress = true;
453
+ }
454
+ }
455
+
456
+ function getSafeErrorMessage(message?: string): string {
457
+ if (message && typeof message === 'string' && message.trim() !== '') {
458
+ return message;
459
+ }
460
+ const engine = getSuiteCoreI18nEngine();
461
+ try {
462
+ const translated = engine.translate(
463
+ SuiteCoreComponentId,
464
+ SuiteCoreStringKey.Common_UnexpectedError,
465
+ );
466
+ return translated &&
467
+ typeof translated === 'string' &&
468
+ translated.trim() !== ''
469
+ ? translated
470
+ : 'An unexpected error occurred';
471
+ } catch {
472
+ return 'An unexpected error occurred';
473
+ }
474
+ }
475
+
476
+ function convertToHandleableError(error: unknown): {
477
+ handleableError: HandleableError;
478
+ alreadyHandled: boolean;
479
+ errorType: string;
480
+ } {
481
+ if (error instanceof HandleableError) {
482
+ return {
483
+ handleableError: error,
484
+ alreadyHandled: error.handled,
485
+ errorType: error.name,
486
+ };
487
+ }
488
+ if (error instanceof Error) {
489
+ return {
490
+ handleableError: new HandleableError(error),
491
+ alreadyHandled: false,
492
+ errorType: error.name,
493
+ };
494
+ }
495
+ const unknownMessage = getSafeErrorMessage(
496
+ typeof error === 'object' &&
497
+ error !== null &&
498
+ 'message' in (error as object)
499
+ ? ((error as Record<string, unknown>)['message'] as string | undefined)
500
+ : undefined,
501
+ );
502
+ const unknownError = new Error(unknownMessage);
503
+ return {
504
+ handleableError: new HandleableError(unknownError, { sourceData: error }),
505
+ alreadyHandled: false,
506
+ errorType: 'UnexpectedError',
507
+ };
508
+ }
509
+
510
+ function sendErrorResponse<TStringKey extends keyof RequiredStringKeys>(
511
+ error: unknown,
512
+ handleableError: HandleableError,
513
+ errorType: string,
514
+ send: SendFunction<
515
+ | IApiErrorResponse
516
+ | IApiExpressValidationErrorResponse
517
+ | IApiMongoValidationErrorResponse
518
+ >,
519
+ res: Response,
520
+ ): void {
521
+ const engine = I18nEngine.getInstance();
522
+ if (error instanceof ExpressValidationError) {
523
+ // amazonq-ignore-next-line false positive
524
+ send(
525
+ handleableError.statusCode,
526
+ {
527
+ message: engine.translate('ValidationError' as TStringKey),
528
+ errors:
529
+ error.errors instanceof Result ? error.errors.array() : error.errors,
530
+ errorType: 'ExpressValidationError',
531
+ },
532
+ res,
533
+ );
534
+ } else if (error instanceof MongooseValidationError) {
535
+ // amazonq-ignore-next-line false positive
536
+ send(
537
+ handleableError.statusCode,
538
+ {
539
+ message: engine.translate('ValidationError' as TStringKey),
540
+ errors: error.errors,
541
+ errorType: 'MongooseValidationError',
542
+ },
543
+ res,
544
+ );
545
+ } else {
546
+ // amazonq-ignore-next-line false positive
547
+ send(
548
+ handleableError.statusCode,
549
+ {
550
+ message: handleableError.message,
551
+ error: handleableError,
552
+ errorType: errorType,
553
+ },
554
+ res,
555
+ );
556
+ }
557
+ }
558
+
559
+ export function handleError(
560
+ error: unknown,
561
+ res: Response,
562
+ send: SendFunction<
563
+ | IApiErrorResponse
564
+ | IApiExpressValidationErrorResponse
565
+ | IApiMongoValidationErrorResponse
566
+ >,
567
+ next: NextFunction,
568
+ ): void {
569
+ if (isRecursiveError(error)) {
570
+ const fallbackError = new HandleableError(
571
+ new Error('Recursive error handling detected'),
572
+ );
573
+ // amazonq-ignore-next-line false positive
574
+ send(
575
+ fallbackError.statusCode,
576
+ {
577
+ message: fallbackError.message,
578
+ error: fallbackError,
579
+ errorType: 'RecursiveError',
580
+ },
581
+ res,
582
+ );
583
+ return;
584
+ }
585
+
586
+ markErrorAsHandling(error);
587
+ const { handleableError, alreadyHandled, errorType } =
588
+ convertToHandleableError(error);
589
+
590
+ if (!(error instanceof ExpressValidationError)) {
591
+ console.error(
592
+ '[handleError]',
593
+ 'type=' + errorType.replace(/[\r\n]/g, ''),
594
+ 'status=' + String(handleableError.statusCode).replace(/[\r\n]/g, ''),
595
+ 'message=' +
596
+ (handleableError.message || '')
597
+ .replace(/[\r\n]/g, ''),
598
+ );
599
+ }
600
+
601
+ if (!res.headersSent) {
602
+ sendErrorResponse(error, handleableError, errorType, send, res);
603
+ handleableError.handled = true;
604
+ }
605
+
606
+ if (!alreadyHandled) {
607
+ handleableError.handled = true;
608
+ next(handleableError);
609
+ }
610
+ }
611
+
612
+ export function locatePEMRoot(devRootDir: string): string | undefined {
613
+ try {
614
+ const normalizedDir = resolve(devRootDir);
615
+ if (normalizedDir.includes('..') || !normalizedDir.startsWith(resolve('.'))) {
616
+ return undefined;
617
+ }
618
+ const files = readdirSync(normalizedDir);
619
+ const pemFiles = files.filter(
620
+ (file: string) =>
621
+ // Prevent path traversal by rejecting files with path separators
622
+ !file.includes('/') &&
623
+ !file.includes('\\') &&
624
+ !file.includes('..') &&
625
+ (file.match(/localhost\+\d+-key\.pem$/) ||
626
+ file.match(/localhost\+\d+\.pem$/)),
627
+ );
628
+ if (pemFiles.length < 2) {
629
+ return undefined;
630
+ }
631
+ const roots = pemFiles.map((file: string) => {
632
+ const resolved = resolve(normalizedDir, file);
633
+ if (!resolved.startsWith(normalizedDir)) {
634
+ return undefined;
635
+ }
636
+ const result = /(.*)\/(localhost\+\d+)(.*)\.pem/.exec(resolved);
637
+ return result ? `${result[1]}/${result[2]}` : undefined;
638
+ });
639
+ if (roots.some((root) => root !== roots[0])) {
640
+ return undefined;
641
+ }
642
+ if (!existsSync(roots[0] + '.pem') || !existsSync(roots[0] + '-key.pem')) {
643
+ return undefined;
644
+ }
645
+ return roots[0]!;
646
+ } catch {
647
+ return undefined;
648
+ }
649
+ }
650
+
651
+ /**
652
+ * Encodes the length of the data in the buffer
653
+ * @param buffer The buffer to encode
654
+ * @returns The encoded buffer
655
+ */
656
+ export function lengthEncodeData(buffer: Buffer): Buffer {
657
+ const lengthType: LengthEncodingType = getLengthEncodingTypeForLength(
658
+ buffer.length,
659
+ );
660
+ const lengthTypeSize: number = getLengthForLengthType(lengthType);
661
+ const result: Buffer = Buffer.alloc(1 + lengthTypeSize + buffer.length);
662
+ result.writeUInt8(lengthType, 0);
663
+ switch (lengthType) {
664
+ case LengthEncodingType.UInt8:
665
+ result.writeUInt8(buffer.length, 1);
666
+ break;
667
+ case LengthEncodingType.UInt16:
668
+ result.writeUInt16BE(buffer.length, 1);
669
+ break;
670
+ case LengthEncodingType.UInt32:
671
+ result.writeUInt32BE(buffer.length, 1);
672
+ break;
673
+ case LengthEncodingType.UInt64:
674
+ result.writeBigUInt64BE(BigInt(buffer.length), 1);
675
+ break;
676
+ }
677
+ buffer.copy(result, 1 + lengthTypeSize);
678
+ return result;
679
+ }
680
+
681
+ export function decodeLengthEncodedData(buffer: Buffer): {
682
+ data: Buffer;
683
+ totalLength: number;
684
+ } {
685
+ if (buffer.length < 1) {
686
+ throw new RangeError('Buffer is too short to read length type.');
687
+ }
688
+ const lengthType: LengthEncodingType = getLengthEncodingTypeFromValue(
689
+ buffer.readUint8(0),
690
+ );
691
+ const lengthTypeSize: number = getLengthForLengthType(lengthType);
692
+
693
+ if (buffer.length < 1 + lengthTypeSize) {
694
+ throw new RangeError('Buffer is too short to read the full length value.');
695
+ }
696
+
697
+ let length: number | BigInt;
698
+ switch (lengthType) {
699
+ case LengthEncodingType.UInt8:
700
+ length = buffer.readUint8(1);
701
+ break;
702
+ case LengthEncodingType.UInt16:
703
+ length = buffer.readUint16BE(1);
704
+ break;
705
+ case LengthEncodingType.UInt32:
706
+ length = buffer.readUint32BE(1);
707
+ break;
708
+ case LengthEncodingType.UInt64:
709
+ length = buffer.readBigUInt64BE(1);
710
+ if (Number(length) > Number.MAX_SAFE_INTEGER) {
711
+ throw new RangeError('Length exceeds maximum safe integer value');
712
+ }
713
+ break;
714
+ default:
715
+ throw new TranslatableSuiteError(
716
+ SuiteCoreStringKey.Error_LengthIsInvalidType,
717
+ );
718
+ }
719
+
720
+ const totalLength = 1 + lengthTypeSize + Number(length);
721
+ if (totalLength > buffer.length) {
722
+ throw new RangeError('Buffer is too short for declared data length');
723
+ }
724
+ return {
725
+ data: buffer.subarray(1 + lengthTypeSize, totalLength),
726
+ totalLength,
727
+ };
728
+ }
729
+
730
+ import { HandleableError } from '@digitaldefiance/i18n-lib';
731
+ import {
732
+ getSuiteCoreI18nEngine,
733
+ SuiteCoreComponentId,
734
+ SuiteCoreStringKey,
735
+ TranslatableSuiteError,
736
+ } from '@digitaldefiance/suite-core-lib';
737
+ import moment from 'moment-timezone';
738
+ import { BackupCode } from './backup-code';
739
+ import { LengthEncodingType } from './enumerations/length-encoding-type';
740
+ import { MissingValidatedDataError } from './errors';
741
+
742
+ export function isValidTimezone(timezone: string): boolean {
743
+ return moment.tz.zone(timezone) !== null;
744
+ }
745
+
746
+ /**
747
+ * Omits keys from an object
748
+ */
749
+ export function omit<T extends object, K extends keyof T>(
750
+ obj: T,
751
+ keys: K[],
752
+ ): Omit<T, K> {
753
+ const keysToOmit = new Set(keys);
754
+ return Object.keys(obj).reduce((result, key) => {
755
+ if (!keysToOmit.has(key as K)) {
756
+ result[key as keyof T] = obj[key as keyof T];
757
+ }
758
+ return result;
759
+ }, {} as T) as Omit<T, K>;
760
+ }
761
+
762
+ /**
763
+ * Validates that a collection contains exactly the keys from an enum
764
+ * @param collection The collection to validate
765
+ * @param enumObject The enum object to validate against
766
+ * @param collectionName Optional name for the collection (for better error messages)
767
+ * @param enumName Optional name for the enum (for better error messages)
768
+ * @throws Error if collection has missing, extra, or invalid keys
769
+ */
770
+ export function validateEnumCollection<T extends Record<string, any>>(
771
+ collection: Record<string, unknown>,
772
+ enumObject: T,
773
+ collectionName?: string,
774
+ enumName?: string,
775
+ ): void {
776
+ // For numeric enums, filter out reverse mappings (number -> string)
777
+ const enumKeys = Object.keys(enumObject).filter((key) => isNaN(Number(key)));
778
+ const allEnumValues = enumKeys.map((key) => enumObject[key]);
779
+ const collectionKeys = Object.keys(collection);
780
+
781
+ const collectionLabel = collectionName || 'Collection';
782
+ const enumLabel = enumName || `enum with keys [${enumKeys.join(', ')}]`;
783
+
784
+ if (collectionKeys.length !== allEnumValues.length) {
785
+ throw new Error(
786
+ `${collectionLabel} must contain exactly ${
787
+ allEnumValues.length
788
+ } keys to match ${enumLabel}. Found ${
789
+ collectionKeys.length
790
+ } keys: [${collectionKeys.join(', ')}]`,
791
+ );
792
+ }
793
+
794
+ const invalidKeys = collectionKeys.filter(
795
+ (key) => !allEnumValues.includes(key),
796
+ );
797
+ if (invalidKeys.length > 0) {
798
+ throw new Error(
799
+ `${collectionLabel} contains invalid keys for ${enumLabel}: [${invalidKeys.join(
800
+ ', ',
801
+ )}]. Valid keys are: [${allEnumValues.join(', ')}]`,
802
+ );
803
+ }
804
+
805
+ const missingKeys = allEnumValues.filter((value) => !(value in collection));
806
+ if (missingKeys.length > 0) {
807
+ throw new Error(
808
+ `${collectionLabel} is missing required keys for ${enumLabel}: [${missingKeys.join(
809
+ ', ',
810
+ )}]`,
811
+ );
812
+ }
813
+ }
814
+
815
+ export function uint8ArrayToBase64(uint8Array: Uint8Array): string {
816
+ let binaryString = '';
817
+ for (let i = 0; i < uint8Array.length; i++) {
818
+ binaryString += String.fromCharCode(uint8Array[i]);
819
+ }
820
+ return btoa(binaryString);
821
+ }
822
+
823
+ export function base64ToUint8Array(base64String: string): Uint8Array {
824
+ const binaryString = atob(base64String);
825
+ const len = binaryString.length;
826
+ const bytes = new Uint8Array(len);
827
+ for (let i = 0; i < len; i++) {
828
+ bytes[i] = binaryString.charCodeAt(i);
829
+ }
830
+ return bytes;
831
+ }
832
+
833
+ export function uint8ArrayToHex(uint8Array: Uint8Array): string {
834
+ return Array.from(uint8Array)
835
+ .map((byte) => byte.toString(16).padStart(2, '0'))
836
+ .join('');
837
+ }
838
+
839
+ export function hexToUint8Array(hexString: string): Uint8Array {
840
+ const len = hexString.length;
841
+ const bytes = new Uint8Array(len / 2);
842
+ for (let i = 0; i < len; i += 2) {
843
+ bytes[i / 2] = parseInt(hexString.substring(i, i + 2), 16);
844
+ }
845
+ return bytes;
846
+ }
847
+
848
+ /**
849
+ * Utility functions for browser ECIES implementation
850
+ */
851
+
852
+ /**
853
+ * CRC16-CCITT implementation for data integrity checking
854
+ * Uses the same algorithm as the server-side implementation (CRC16-CCITT-FALSE)
855
+ */
856
+ export function crc16(data: Uint8Array): Uint8Array {
857
+ let crc = 0xffff; // Initial value for CRC16-CCITT-FALSE
858
+ const polynomial = 0x1021; // CRC16-CCITT polynomial
859
+
860
+ for (let i = 0; i < data.length; i++) {
861
+ crc ^= data[i] << 8;
862
+ for (let j = 0; j < 8; j++) {
863
+ if (crc & 0x8000) {
864
+ crc = (crc << 1) ^ polynomial;
865
+ } else {
866
+ crc = crc << 1;
867
+ }
868
+ crc &= 0xffff; // Keep it 16-bit
869
+ }
870
+ }
871
+
872
+ const result = new Uint8Array(2);
873
+ result[0] = (crc >>> 8) & 0xff; // Big-endian
874
+ result[1] = crc & 0xff;
875
+ return result;
876
+ }
877
+
878
+ /**
879
+ * Convert string to Uint8Array (UTF-8 encoding)
880
+ */
881
+ export function stringToUint8Array(str: string): Uint8Array {
882
+ return new TextEncoder().encode(str);
883
+ }
884
+
885
+ /**
886
+ * Convert Uint8Array to string (UTF-8 decoding)
887
+ */
888
+ export function uint8ArrayToString(array: Uint8Array): string {
889
+ return new TextDecoder().decode(array);
890
+ }
891
+
892
+ /**
893
+ * Secure random bytes generation
894
+ */
895
+ export function randomBytes(length: number): Uint8Array {
896
+ return crypto.getRandomValues(new Uint8Array(length));
897
+ }
898
+
899
+ /**
900
+ * Compare two Uint8Arrays for equality
901
+ */
902
+ export function arraysEqual(a: Uint8Array, b: Uint8Array): boolean {
903
+ if (a.length !== b.length) return false;
904
+ for (let i = 0; i < a.length; i++) {
905
+ if (a[i] !== b[i]) return false;
906
+ }
907
+ return true;
908
+ }
909
+
910
+ /**
911
+ * Concatenate multiple Uint8Arrays
912
+ */
913
+ export function concatUint8Arrays(...arrays: Uint8Array[]): Uint8Array {
914
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
915
+ const result = new Uint8Array(totalLength);
916
+ let offset = 0;
917
+ for (const array of arrays) {
918
+ result.set(array, offset);
919
+ offset += array.length;
920
+ }
921
+ return result;
922
+ }
923
+
924
+ /**
925
+ * Get the length encoding type for a given length
926
+ * @param length The length to evaluate
927
+ * @returns The corresponding LengthEncodingType
928
+ */
929
+ export function getLengthEncodingTypeForLength(
930
+ length: number | BigInt,
931
+ ): LengthEncodingType {
932
+ if (typeof length === 'number') {
933
+ if (length < 256) {
934
+ return LengthEncodingType.UInt8;
935
+ } else if (length < 65536) {
936
+ return LengthEncodingType.UInt16;
937
+ } else if (length < 4294967296) {
938
+ return LengthEncodingType.UInt32;
939
+ } else if (length < Number.MAX_SAFE_INTEGER) {
940
+ return LengthEncodingType.UInt64;
941
+ } else {
942
+ throw new TranslatableSuiteError(
943
+ SuiteCoreStringKey.Error_LengthExceedsMaximum,
944
+ );
945
+ }
946
+ } else if (typeof length === 'bigint') {
947
+ if (length < 256n) {
948
+ return LengthEncodingType.UInt8;
949
+ } else if (length < 65536n) {
950
+ return LengthEncodingType.UInt16;
951
+ } else if (length < 4294967296n) {
952
+ return LengthEncodingType.UInt32;
953
+ } else if (length < 18446744073709551616n) {
954
+ return LengthEncodingType.UInt64;
955
+ } else {
956
+ throw new TranslatableSuiteError(
957
+ SuiteCoreStringKey.Error_LengthExceedsMaximum,
958
+ );
959
+ }
960
+ } else {
961
+ throw new TranslatableSuiteError(
962
+ SuiteCoreStringKey.Error_LengthIsInvalidType,
963
+ );
964
+ }
965
+ }
966
+
967
+ /**
968
+ * Get the length encoding type for a given value
969
+ * @param value The value to evaluate
970
+ * @returns The corresponding LengthEncodingType
971
+ */
972
+ export function getLengthEncodingTypeFromValue(
973
+ value: number,
974
+ ): LengthEncodingType {
975
+ for (const length of Object.values(LengthEncodingType)) {
976
+ if (length === value) {
977
+ return length;
978
+ }
979
+ }
980
+ throw new TranslatableSuiteError(
981
+ SuiteCoreStringKey.Error_LengthIsInvalidType,
982
+ );
983
+ }
984
+
985
+ /**
986
+ * Get the length in bytes for a given LengthEncodingType
987
+ * @param type The LengthEncodingType to evaluate
988
+ * @returns The length in bytes
989
+ */
990
+ export function getLengthForLengthType(type: LengthEncodingType): number {
991
+ switch (type) {
992
+ case LengthEncodingType.UInt8:
993
+ return 1;
994
+ case LengthEncodingType.UInt16:
995
+ return 2;
996
+ case LengthEncodingType.UInt32:
997
+ return 4;
998
+ case LengthEncodingType.UInt64:
999
+ return 8;
1000
+ default:
1001
+ throw new TranslatableSuiteError(
1002
+ SuiteCoreStringKey.Error_LengthIsInvalidType,
1003
+ );
1004
+ }
1005
+ }
1006
+
1007
+ export function parseBackupCodes(
1008
+ user: 'admin' | 'member' | 'system',
1009
+ environment: object,
1010
+ ): BackupCode[] {
1011
+ const envVarMap: Record<'admin' | 'member' | 'system', string> = {
1012
+ admin: 'ADMIN_BACKUP_CODES',
1013
+ member: 'MEMBER_BACKUP_CODES',
1014
+ system: 'SYSTEM_BACKUP_CODES',
1015
+ };
1016
+ const envVar = envVarMap[user];
1017
+ const backupCodes =
1018
+ (environment as any)[envVar]
1019
+ ?.split(',')
1020
+ .map((code: string) => new BackupCode(code.trim())) || [];
1021
+ return backupCodes;
1022
+ }