@futdevpro/nts-dynamo 1.15.140 → 1.15.141

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 (293) hide show
  1. package/README.md +27 -0
  2. package/__documentations/2026-08-18-standalone-account-security-and-privacy-bedrock.md +131 -0
  3. package/build/_modules/account-security/_enums/account-challenge-purpose.type-enum.d.ts +6 -0
  4. package/build/_modules/account-security/_enums/account-challenge-purpose.type-enum.d.ts.map +1 -0
  5. package/build/_modules/account-security/_enums/account-challenge-purpose.type-enum.js +10 -0
  6. package/build/_modules/account-security/_enums/account-challenge-purpose.type-enum.js.map +1 -0
  7. package/build/_modules/account-security/_enums/account-refresh-token-state.type-enum.d.ts +7 -0
  8. package/build/_modules/account-security/_enums/account-refresh-token-state.type-enum.d.ts.map +1 -0
  9. package/build/_modules/account-security/_enums/account-refresh-token-state.type-enum.js +11 -0
  10. package/build/_modules/account-security/_enums/account-refresh-token-state.type-enum.js.map +1 -0
  11. package/build/_modules/account-security/_enums/account-session-state.type-enum.d.ts +7 -0
  12. package/build/_modules/account-security/_enums/account-session-state.type-enum.d.ts.map +1 -0
  13. package/build/_modules/account-security/_enums/account-session-state.type-enum.js +11 -0
  14. package/build/_modules/account-security/_enums/account-session-state.type-enum.js.map +1 -0
  15. package/build/_modules/account-security/_models/account-challenge-adapter.interface.d.ts +9 -0
  16. package/build/_modules/account-security/_models/account-challenge-adapter.interface.d.ts.map +1 -0
  17. package/build/_modules/account-security/_models/account-challenge-adapter.interface.js +3 -0
  18. package/build/_modules/account-security/_models/account-challenge-adapter.interface.js.map +1 -0
  19. package/build/_modules/account-security/_models/account-challenge-issued.interface.d.ts +7 -0
  20. package/build/_modules/account-security/_models/account-challenge-issued.interface.d.ts.map +1 -0
  21. package/build/_modules/account-security/_models/account-challenge-issued.interface.js +3 -0
  22. package/build/_modules/account-security/_models/account-challenge-issued.interface.js.map +1 -0
  23. package/build/_modules/account-security/_models/account-challenge-record.interface.d.ts +13 -0
  24. package/build/_modules/account-security/_models/account-challenge-record.interface.d.ts.map +1 -0
  25. package/build/_modules/account-security/_models/account-challenge-record.interface.js +3 -0
  26. package/build/_modules/account-security/_models/account-challenge-record.interface.js.map +1 -0
  27. package/build/_modules/account-security/_models/account-challenge-result.interface.d.ts +8 -0
  28. package/build/_modules/account-security/_models/account-challenge-result.interface.d.ts.map +1 -0
  29. package/build/_modules/account-security/_models/account-challenge-result.interface.js +3 -0
  30. package/build/_modules/account-security/_models/account-challenge-result.interface.js.map +1 -0
  31. package/build/_modules/account-security/_models/account-challenge-settings.interface.d.ts +9 -0
  32. package/build/_modules/account-security/_models/account-challenge-settings.interface.d.ts.map +1 -0
  33. package/build/_modules/account-security/_models/account-challenge-settings.interface.js +3 -0
  34. package/build/_modules/account-security/_models/account-challenge-settings.interface.js.map +1 -0
  35. package/build/_modules/account-security/_models/account-password-policy.interface.d.ts +12 -0
  36. package/build/_modules/account-security/_models/account-password-policy.interface.d.ts.map +1 -0
  37. package/build/_modules/account-security/_models/account-password-policy.interface.js +3 -0
  38. package/build/_modules/account-security/_models/account-password-policy.interface.js.map +1 -0
  39. package/build/_modules/account-security/_models/account-password-verification.interface.d.ts +6 -0
  40. package/build/_modules/account-security/_models/account-password-verification.interface.d.ts.map +1 -0
  41. package/build/_modules/account-security/_models/account-password-verification.interface.js +3 -0
  42. package/build/_modules/account-security/_models/account-password-verification.interface.js.map +1 -0
  43. package/build/_modules/account-security/_models/account-refresh-token-record.interface.d.ts +13 -0
  44. package/build/_modules/account-security/_models/account-refresh-token-record.interface.d.ts.map +1 -0
  45. package/build/_modules/account-security/_models/account-refresh-token-record.interface.js +3 -0
  46. package/build/_modules/account-security/_models/account-refresh-token-record.interface.js.map +1 -0
  47. package/build/_modules/account-security/_models/account-session-adapter.interface.d.ts +19 -0
  48. package/build/_modules/account-security/_models/account-session-adapter.interface.d.ts.map +1 -0
  49. package/build/_modules/account-security/_models/account-session-adapter.interface.js +3 -0
  50. package/build/_modules/account-security/_models/account-session-adapter.interface.js.map +1 -0
  51. package/build/_modules/account-security/_models/account-session-claims.interface.d.ts +8 -0
  52. package/build/_modules/account-security/_models/account-session-claims.interface.d.ts.map +1 -0
  53. package/build/_modules/account-security/_models/account-session-claims.interface.js +3 -0
  54. package/build/_modules/account-security/_models/account-session-claims.interface.js.map +1 -0
  55. package/build/_modules/account-security/_models/account-session-context.interface.d.ts +7 -0
  56. package/build/_modules/account-security/_models/account-session-context.interface.d.ts.map +1 -0
  57. package/build/_modules/account-security/_models/account-session-context.interface.js +3 -0
  58. package/build/_modules/account-security/_models/account-session-context.interface.js.map +1 -0
  59. package/build/_modules/account-security/_models/account-session-create.interface.d.ts +8 -0
  60. package/build/_modules/account-security/_models/account-session-create.interface.d.ts.map +1 -0
  61. package/build/_modules/account-security/_models/account-session-create.interface.js +3 -0
  62. package/build/_modules/account-security/_models/account-session-create.interface.js.map +1 -0
  63. package/build/_modules/account-security/_models/account-session-record.interface.d.ts +21 -0
  64. package/build/_modules/account-security/_models/account-session-record.interface.d.ts.map +1 -0
  65. package/build/_modules/account-security/_models/account-session-record.interface.js +3 -0
  66. package/build/_modules/account-security/_models/account-session-record.interface.js.map +1 -0
  67. package/build/_modules/account-security/_models/account-session-rotate.interface.d.ts +11 -0
  68. package/build/_modules/account-security/_models/account-session-rotate.interface.d.ts.map +1 -0
  69. package/build/_modules/account-security/_models/account-session-rotate.interface.js +3 -0
  70. package/build/_modules/account-security/_models/account-session-rotate.interface.js.map +1 -0
  71. package/build/_modules/account-security/_models/account-session-settings.interface.d.ts +11 -0
  72. package/build/_modules/account-security/_models/account-session-settings.interface.d.ts.map +1 -0
  73. package/build/_modules/account-security/_models/account-session-settings.interface.js +3 -0
  74. package/build/_modules/account-security/_models/account-session-settings.interface.js.map +1 -0
  75. package/build/_modules/account-security/_models/account-session-token-pair.interface.d.ts +9 -0
  76. package/build/_modules/account-security/_models/account-session-token-pair.interface.d.ts.map +1 -0
  77. package/build/_modules/account-security/_models/account-session-token-pair.interface.js +3 -0
  78. package/build/_modules/account-security/_models/account-session-token-pair.interface.js.map +1 -0
  79. package/build/_modules/account-security/_models/account-session-view.interface.d.ts +13 -0
  80. package/build/_modules/account-security/_models/account-session-view.interface.d.ts.map +1 -0
  81. package/build/_modules/account-security/_models/account-session-view.interface.js +3 -0
  82. package/build/_modules/account-security/_models/account-session-view.interface.js.map +1 -0
  83. package/build/_modules/account-security/account-challenge.control-service.d.ts +24 -0
  84. package/build/_modules/account-security/account-challenge.control-service.d.ts.map +1 -0
  85. package/build/_modules/account-security/account-challenge.control-service.js +117 -0
  86. package/build/_modules/account-security/account-challenge.control-service.js.map +1 -0
  87. package/build/_modules/account-security/account-password.control-service.d.ts +24 -0
  88. package/build/_modules/account-security/account-password.control-service.d.ts.map +1 -0
  89. package/build/_modules/account-security/account-password.control-service.js +214 -0
  90. package/build/_modules/account-security/account-password.control-service.js.map +1 -0
  91. package/build/_modules/account-security/account-session.control-service.d.ts +39 -0
  92. package/build/_modules/account-security/account-session.control-service.d.ts.map +1 -0
  93. package/build/_modules/account-security/account-session.control-service.js +277 -0
  94. package/build/_modules/account-security/account-session.control-service.js.map +1 -0
  95. package/build/_modules/account-security/index.d.ts +24 -0
  96. package/build/_modules/account-security/index.d.ts.map +1 -0
  97. package/build/_modules/account-security/index.js +16 -0
  98. package/build/_modules/account-security/index.js.map +1 -0
  99. package/build/_modules/privacy-lifecycle/_enums/privacy-consent-decision.type-enum.d.ts +6 -0
  100. package/build/_modules/privacy-lifecycle/_enums/privacy-consent-decision.type-enum.d.ts.map +1 -0
  101. package/build/_modules/privacy-lifecycle/_enums/privacy-consent-decision.type-enum.js +10 -0
  102. package/build/_modules/privacy-lifecycle/_enums/privacy-consent-decision.type-enum.js.map +1 -0
  103. package/build/_modules/privacy-lifecycle/_enums/privacy-contributor-action.type-enum.d.ts +11 -0
  104. package/build/_modules/privacy-lifecycle/_enums/privacy-contributor-action.type-enum.d.ts.map +1 -0
  105. package/build/_modules/privacy-lifecycle/_enums/privacy-contributor-action.type-enum.js +15 -0
  106. package/build/_modules/privacy-lifecycle/_enums/privacy-contributor-action.type-enum.js.map +1 -0
  107. package/build/_modules/privacy-lifecycle/_enums/privacy-contributor-outcome.type-enum.d.ts +8 -0
  108. package/build/_modules/privacy-lifecycle/_enums/privacy-contributor-outcome.type-enum.d.ts.map +1 -0
  109. package/build/_modules/privacy-lifecycle/_enums/privacy-contributor-outcome.type-enum.js +12 -0
  110. package/build/_modules/privacy-lifecycle/_enums/privacy-contributor-outcome.type-enum.js.map +1 -0
  111. package/build/_modules/privacy-lifecycle/_enums/privacy-request-state.type-enum.d.ts +16 -0
  112. package/build/_modules/privacy-lifecycle/_enums/privacy-request-state.type-enum.d.ts.map +1 -0
  113. package/build/_modules/privacy-lifecycle/_enums/privacy-request-state.type-enum.js +20 -0
  114. package/build/_modules/privacy-lifecycle/_enums/privacy-request-state.type-enum.js.map +1 -0
  115. package/build/_modules/privacy-lifecycle/_enums/privacy-request.type-enum.d.ts +10 -0
  116. package/build/_modules/privacy-lifecycle/_enums/privacy-request.type-enum.d.ts.map +1 -0
  117. package/build/_modules/privacy-lifecycle/_enums/privacy-request.type-enum.js +14 -0
  118. package/build/_modules/privacy-lifecycle/_enums/privacy-request.type-enum.js.map +1 -0
  119. package/build/_modules/privacy-lifecycle/_models/privacy-consent-input.interface.d.ts +12 -0
  120. package/build/_modules/privacy-lifecycle/_models/privacy-consent-input.interface.d.ts.map +1 -0
  121. package/build/_modules/privacy-lifecycle/_models/privacy-consent-input.interface.js +3 -0
  122. package/build/_modules/privacy-lifecycle/_models/privacy-consent-input.interface.js.map +1 -0
  123. package/build/_modules/privacy-lifecycle/_models/privacy-consent-persistence-result.interface.d.ts +7 -0
  124. package/build/_modules/privacy-lifecycle/_models/privacy-consent-persistence-result.interface.d.ts.map +1 -0
  125. package/build/_modules/privacy-lifecycle/_models/privacy-consent-persistence-result.interface.js +3 -0
  126. package/build/_modules/privacy-lifecycle/_models/privacy-consent-persistence-result.interface.js.map +1 -0
  127. package/build/_modules/privacy-lifecycle/_models/privacy-consent-record.interface.d.ts +15 -0
  128. package/build/_modules/privacy-lifecycle/_models/privacy-consent-record.interface.d.ts.map +1 -0
  129. package/build/_modules/privacy-lifecycle/_models/privacy-consent-record.interface.js +3 -0
  130. package/build/_modules/privacy-lifecycle/_models/privacy-consent-record.interface.js.map +1 -0
  131. package/build/_modules/privacy-lifecycle/_models/privacy-consent-result.interface.d.ts +7 -0
  132. package/build/_modules/privacy-lifecycle/_models/privacy-consent-result.interface.d.ts.map +1 -0
  133. package/build/_modules/privacy-lifecycle/_models/privacy-consent-result.interface.js +3 -0
  134. package/build/_modules/privacy-lifecycle/_models/privacy-consent-result.interface.js.map +1 -0
  135. package/build/_modules/privacy-lifecycle/_models/privacy-consent-view.interface.d.ts +13 -0
  136. package/build/_modules/privacy-lifecycle/_models/privacy-consent-view.interface.d.ts.map +1 -0
  137. package/build/_modules/privacy-lifecycle/_models/privacy-consent-view.interface.js +3 -0
  138. package/build/_modules/privacy-lifecycle/_models/privacy-consent-view.interface.js.map +1 -0
  139. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-context.interface.d.ts +9 -0
  140. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-context.interface.d.ts.map +1 -0
  141. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-context.interface.js +3 -0
  142. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-context.interface.js.map +1 -0
  143. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-outcome.interface.d.ts +14 -0
  144. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-outcome.interface.d.ts.map +1 -0
  145. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-outcome.interface.js +3 -0
  146. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-outcome.interface.js.map +1 -0
  147. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-plan.interface.d.ts +8 -0
  148. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-plan.interface.d.ts.map +1 -0
  149. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-plan.interface.js +3 -0
  150. package/build/_modules/privacy-lifecycle/_models/privacy-contributor-plan.interface.js.map +1 -0
  151. package/build/_modules/privacy-lifecycle/_models/privacy-contributor.interface.d.ts +11 -0
  152. package/build/_modules/privacy-lifecycle/_models/privacy-contributor.interface.d.ts.map +1 -0
  153. package/build/_modules/privacy-lifecycle/_models/privacy-contributor.interface.js +3 -0
  154. package/build/_modules/privacy-lifecycle/_models/privacy-contributor.interface.js.map +1 -0
  155. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-adapter.interface.d.ts +13 -0
  156. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-adapter.interface.d.ts.map +1 -0
  157. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-adapter.interface.js +3 -0
  158. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-adapter.interface.js.map +1 -0
  159. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-result.interface.d.ts +9 -0
  160. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-result.interface.d.ts.map +1 -0
  161. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-result.interface.js +3 -0
  162. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-result.interface.js.map +1 -0
  163. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-settings.interface.d.ts +7 -0
  164. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-settings.interface.d.ts.map +1 -0
  165. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-settings.interface.js +3 -0
  166. package/build/_modules/privacy-lifecycle/_models/privacy-ledger-settings.interface.js.map +1 -0
  167. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-input.interface.d.ts +11 -0
  168. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-input.interface.d.ts.map +1 -0
  169. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-input.interface.js +3 -0
  170. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-input.interface.js.map +1 -0
  171. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-persistence-result.interface.d.ts +7 -0
  172. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-persistence-result.interface.d.ts.map +1 -0
  173. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-persistence-result.interface.js +3 -0
  174. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-persistence-result.interface.js.map +1 -0
  175. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-result.interface.d.ts +7 -0
  176. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-result.interface.d.ts.map +1 -0
  177. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-result.interface.js +3 -0
  178. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-result.interface.js.map +1 -0
  179. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-view.interface.d.ts +12 -0
  180. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-view.interface.d.ts.map +1 -0
  181. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-view.interface.js +3 -0
  182. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-view.interface.js.map +1 -0
  183. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance.interface.d.ts +14 -0
  184. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance.interface.d.ts.map +1 -0
  185. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance.interface.js +3 -0
  186. package/build/_modules/privacy-lifecycle/_models/privacy-legal-acceptance.interface.js.map +1 -0
  187. package/build/_modules/privacy-lifecycle/_models/privacy-lifecycle-adapter.interface.d.ts +15 -0
  188. package/build/_modules/privacy-lifecycle/_models/privacy-lifecycle-adapter.interface.d.ts.map +1 -0
  189. package/build/_modules/privacy-lifecycle/_models/privacy-lifecycle-adapter.interface.js +3 -0
  190. package/build/_modules/privacy-lifecycle/_models/privacy-lifecycle-adapter.interface.js.map +1 -0
  191. package/build/_modules/privacy-lifecycle/_models/privacy-lifecycle-settings.interface.d.ts +9 -0
  192. package/build/_modules/privacy-lifecycle/_models/privacy-lifecycle-settings.interface.d.ts.map +1 -0
  193. package/build/_modules/privacy-lifecycle/_models/privacy-lifecycle-settings.interface.js +3 -0
  194. package/build/_modules/privacy-lifecycle/_models/privacy-lifecycle-settings.interface.js.map +1 -0
  195. package/build/_modules/privacy-lifecycle/_models/privacy-request-create-result.interface.d.ts +7 -0
  196. package/build/_modules/privacy-lifecycle/_models/privacy-request-create-result.interface.d.ts.map +1 -0
  197. package/build/_modules/privacy-lifecycle/_models/privacy-request-create-result.interface.js +3 -0
  198. package/build/_modules/privacy-lifecycle/_models/privacy-request-create-result.interface.js.map +1 -0
  199. package/build/_modules/privacy-lifecycle/_models/privacy-request-open.interface.d.ts +10 -0
  200. package/build/_modules/privacy-lifecycle/_models/privacy-request-open.interface.d.ts.map +1 -0
  201. package/build/_modules/privacy-lifecycle/_models/privacy-request-open.interface.js +3 -0
  202. package/build/_modules/privacy-lifecycle/_models/privacy-request-open.interface.js.map +1 -0
  203. package/build/_modules/privacy-lifecycle/_models/privacy-request-persistence-create-result.interface.d.ts +7 -0
  204. package/build/_modules/privacy-lifecycle/_models/privacy-request-persistence-create-result.interface.d.ts.map +1 -0
  205. package/build/_modules/privacy-lifecycle/_models/privacy-request-persistence-create-result.interface.js +3 -0
  206. package/build/_modules/privacy-lifecycle/_models/privacy-request-persistence-create-result.interface.js.map +1 -0
  207. package/build/_modules/privacy-lifecycle/_models/privacy-request-record.interface.d.ts +21 -0
  208. package/build/_modules/privacy-lifecycle/_models/privacy-request-record.interface.d.ts.map +1 -0
  209. package/build/_modules/privacy-lifecycle/_models/privacy-request-record.interface.js +3 -0
  210. package/build/_modules/privacy-lifecycle/_models/privacy-request-record.interface.js.map +1 -0
  211. package/build/_modules/privacy-lifecycle/_models/privacy-request-result.interface.d.ts +8 -0
  212. package/build/_modules/privacy-lifecycle/_models/privacy-request-result.interface.d.ts.map +1 -0
  213. package/build/_modules/privacy-lifecycle/_models/privacy-request-result.interface.js +3 -0
  214. package/build/_modules/privacy-lifecycle/_models/privacy-request-result.interface.js.map +1 -0
  215. package/build/_modules/privacy-lifecycle/_models/privacy-request-view.interface.d.ts +20 -0
  216. package/build/_modules/privacy-lifecycle/_models/privacy-request-view.interface.d.ts.map +1 -0
  217. package/build/_modules/privacy-lifecycle/_models/privacy-request-view.interface.js +3 -0
  218. package/build/_modules/privacy-lifecycle/_models/privacy-request-view.interface.js.map +1 -0
  219. package/build/_modules/privacy-lifecycle/index.d.ts +33 -0
  220. package/build/_modules/privacy-lifecycle/index.d.ts.map +1 -0
  221. package/build/_modules/privacy-lifecycle/index.js +18 -0
  222. package/build/_modules/privacy-lifecycle/index.js.map +1 -0
  223. package/build/_modules/privacy-lifecycle/privacy-ledger.control-service.d.ts +28 -0
  224. package/build/_modules/privacy-lifecycle/privacy-ledger.control-service.d.ts.map +1 -0
  225. package/build/_modules/privacy-lifecycle/privacy-ledger.control-service.js +168 -0
  226. package/build/_modules/privacy-lifecycle/privacy-ledger.control-service.js.map +1 -0
  227. package/build/_modules/privacy-lifecycle/privacy-lifecycle.control-service.d.ts +42 -0
  228. package/build/_modules/privacy-lifecycle/privacy-lifecycle.control-service.d.ts.map +1 -0
  229. package/build/_modules/privacy-lifecycle/privacy-lifecycle.control-service.js +364 -0
  230. package/build/_modules/privacy-lifecycle/privacy-lifecycle.control-service.js.map +1 -0
  231. package/package.json +19 -1
  232. package/src/_modules/account-security/_enums/account-challenge-purpose.type-enum.ts +5 -0
  233. package/src/_modules/account-security/_enums/account-refresh-token-state.type-enum.ts +6 -0
  234. package/src/_modules/account-security/_enums/account-session-state.type-enum.ts +6 -0
  235. package/src/_modules/account-security/_models/account-challenge-adapter.interface.ts +17 -0
  236. package/src/_modules/account-security/_models/account-challenge-issued.interface.ts +6 -0
  237. package/src/_modules/account-security/_models/account-challenge-record.interface.ts +13 -0
  238. package/src/_modules/account-security/_models/account-challenge-result.interface.ts +8 -0
  239. package/src/_modules/account-security/_models/account-challenge-settings.interface.ts +9 -0
  240. package/src/_modules/account-security/_models/account-password-policy.interface.ts +11 -0
  241. package/src/_modules/account-security/_models/account-password-verification.interface.ts +5 -0
  242. package/src/_modules/account-security/_models/account-refresh-token-record.interface.ts +13 -0
  243. package/src/_modules/account-security/_models/account-session-adapter.interface.ts +19 -0
  244. package/src/_modules/account-security/_models/account-session-claims.interface.ts +7 -0
  245. package/src/_modules/account-security/_models/account-session-context.interface.ts +6 -0
  246. package/src/_modules/account-security/_models/account-session-create.interface.ts +8 -0
  247. package/src/_modules/account-security/_models/account-session-record.interface.ts +21 -0
  248. package/src/_modules/account-security/_models/account-session-rotate.interface.ts +11 -0
  249. package/src/_modules/account-security/_models/account-session-settings.interface.ts +11 -0
  250. package/src/_modules/account-security/_models/account-session-token-pair.interface.ts +8 -0
  251. package/src/_modules/account-security/_models/account-session-view.interface.ts +13 -0
  252. package/src/_modules/account-security/account-challenge.control-service.spec.ts +195 -0
  253. package/src/_modules/account-security/account-challenge.control-service.ts +164 -0
  254. package/src/_modules/account-security/account-password.control-service.spec.ts +96 -0
  255. package/src/_modules/account-security/account-password.control-service.ts +288 -0
  256. package/src/_modules/account-security/account-session.control-service.spec.ts +294 -0
  257. package/src/_modules/account-security/account-session.control-service.ts +376 -0
  258. package/src/_modules/account-security/index.ts +31 -0
  259. package/src/_modules/privacy-lifecycle/_enums/privacy-consent-decision.type-enum.ts +5 -0
  260. package/src/_modules/privacy-lifecycle/_enums/privacy-contributor-action.type-enum.ts +10 -0
  261. package/src/_modules/privacy-lifecycle/_enums/privacy-contributor-outcome.type-enum.ts +7 -0
  262. package/src/_modules/privacy-lifecycle/_enums/privacy-request-state.type-enum.ts +15 -0
  263. package/src/_modules/privacy-lifecycle/_enums/privacy-request.type-enum.ts +9 -0
  264. package/src/_modules/privacy-lifecycle/_models/privacy-consent-input.interface.ts +12 -0
  265. package/src/_modules/privacy-lifecycle/_models/privacy-consent-persistence-result.interface.ts +7 -0
  266. package/src/_modules/privacy-lifecycle/_models/privacy-consent-record.interface.ts +15 -0
  267. package/src/_modules/privacy-lifecycle/_models/privacy-consent-result.interface.ts +7 -0
  268. package/src/_modules/privacy-lifecycle/_models/privacy-consent-view.interface.ts +13 -0
  269. package/src/_modules/privacy-lifecycle/_models/privacy-contributor-context.interface.ts +9 -0
  270. package/src/_modules/privacy-lifecycle/_models/privacy-contributor-outcome.interface.ts +14 -0
  271. package/src/_modules/privacy-lifecycle/_models/privacy-contributor-plan.interface.ts +8 -0
  272. package/src/_modules/privacy-lifecycle/_models/privacy-contributor.interface.ts +17 -0
  273. package/src/_modules/privacy-lifecycle/_models/privacy-ledger-adapter.interface.ts +21 -0
  274. package/src/_modules/privacy-lifecycle/_models/privacy-ledger-result.interface.ts +9 -0
  275. package/src/_modules/privacy-lifecycle/_models/privacy-ledger-settings.interface.ts +7 -0
  276. package/src/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-input.interface.ts +10 -0
  277. package/src/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-persistence-result.interface.ts +7 -0
  278. package/src/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-result.interface.ts +7 -0
  279. package/src/_modules/privacy-lifecycle/_models/privacy-legal-acceptance-view.interface.ts +11 -0
  280. package/src/_modules/privacy-lifecycle/_models/privacy-legal-acceptance.interface.ts +13 -0
  281. package/src/_modules/privacy-lifecycle/_models/privacy-lifecycle-adapter.interface.ts +19 -0
  282. package/src/_modules/privacy-lifecycle/_models/privacy-lifecycle-settings.interface.ts +9 -0
  283. package/src/_modules/privacy-lifecycle/_models/privacy-request-create-result.interface.ts +7 -0
  284. package/src/_modules/privacy-lifecycle/_models/privacy-request-open.interface.ts +10 -0
  285. package/src/_modules/privacy-lifecycle/_models/privacy-request-persistence-create-result.interface.ts +7 -0
  286. package/src/_modules/privacy-lifecycle/_models/privacy-request-record.interface.ts +21 -0
  287. package/src/_modules/privacy-lifecycle/_models/privacy-request-result.interface.ts +8 -0
  288. package/src/_modules/privacy-lifecycle/_models/privacy-request-view.interface.ts +20 -0
  289. package/src/_modules/privacy-lifecycle/index.ts +40 -0
  290. package/src/_modules/privacy-lifecycle/privacy-ledger.control-service.spec.ts +206 -0
  291. package/src/_modules/privacy-lifecycle/privacy-ledger.control-service.ts +253 -0
  292. package/src/_modules/privacy-lifecycle/privacy-lifecycle.control-service.spec.ts +353 -0
  293. package/src/_modules/privacy-lifecycle/privacy-lifecycle.control-service.ts +586 -0
@@ -0,0 +1,11 @@
1
+ import { DyNTS_AccountSessionAdapter_Interface } from './account-session-adapter.interface';
2
+
3
+ /** Runtime settings for opaque access credentials and rotating one-time refresh families. */
4
+ export interface DyNTS_AccountSessionSettings_Interface {
5
+ adapter: DyNTS_AccountSessionAdapter_Interface;
6
+ accessTtlMs?: number;
7
+ refreshTtlMs?: number;
8
+ tokenBytes?: number;
9
+ maxRefreshRotations?: number;
10
+ clock?: () => Date;
11
+ }
@@ -0,0 +1,8 @@
1
+ /** Raw credentials returned exactly once to the transport layer after an atomic persistence commit. */
2
+ export interface DyNTS_AccountSessionTokenPair_Interface {
3
+ sessionId: string;
4
+ accessToken: string;
5
+ refreshToken: string;
6
+ accessExpiresAt: string;
7
+ refreshExpiresAt: string;
8
+ }
@@ -0,0 +1,13 @@
1
+ import { DyNTS_AccountSessionState_Type } from '../_enums/account-session-state.type-enum';
2
+ import { DyNTS_AccountSessionContext_Interface } from './account-session-context.interface';
3
+
4
+ /** User-safe session list item without access or refresh token hashes. */
5
+ export interface DyNTS_AccountSessionView_Interface {
6
+ sessionId: string;
7
+ state: DyNTS_AccountSessionState_Type;
8
+ createdAt: string;
9
+ lastRotatedAt: string;
10
+ accessExpiresAt: string;
11
+ refreshExpiresAt: string;
12
+ context: DyNTS_AccountSessionContext_Interface;
13
+ }
@@ -0,0 +1,195 @@
1
+ import { createHash } from 'crypto';
2
+
3
+ import { DyFM_Error } from '@futdevpro/fsm-dynamo';
4
+
5
+ import { DyNTS_AccountChallenge_ControlService } from './account-challenge.control-service';
6
+ import { DyNTS_AccountChallengePurpose_Type } from './_enums/account-challenge-purpose.type-enum';
7
+ import { DyNTS_AccountChallengeAdapter_Interface } from './_models/account-challenge-adapter.interface';
8
+ import { DyNTS_AccountChallengeIssued_Interface } from './_models/account-challenge-issued.interface';
9
+ import { DyNTS_AccountChallengeRecord_Interface } from './_models/account-challenge-record.interface';
10
+ import { DyNTS_AccountChallengeResult_Interface } from './_models/account-challenge-result.interface';
11
+
12
+ class DyNTS_TestChallengeAdapter implements DyNTS_AccountChallengeAdapter_Interface {
13
+ public readonly challenges: Map<string, DyNTS_AccountChallengeRecord_Interface> = new Map();
14
+
15
+ /** Revokes the predecessor and persists the replacement atomically in memory. */
16
+ public async replaceActiveChallenge(record: DyNTS_AccountChallengeRecord_Interface): Promise<void> {
17
+ Array.from(this.challenges.values())
18
+ .filter((item: DyNTS_AccountChallengeRecord_Interface): boolean => (
19
+ item.subjectId === record.subjectId
20
+ && item.purpose === record.purpose
21
+ && !item.consumedAt
22
+ && !item.revokedAt
23
+ ))
24
+ .forEach((item: DyNTS_AccountChallengeRecord_Interface): void => {
25
+ item.revokedAt = record.createdAt;
26
+ });
27
+ this.challenges.set(record.tokenHash, { ...record });
28
+ }
29
+
30
+ /** Consumes one active and unexpired test challenge with compare-and-set semantics. */
31
+ public async consumeActiveChallenge(
32
+ tokenHash: string,
33
+ purpose: DyNTS_AccountChallengePurpose_Type,
34
+ consumedAt: string
35
+ ): Promise<DyNTS_AccountChallengeRecord_Interface | null> {
36
+ const record: DyNTS_AccountChallengeRecord_Interface | undefined = this.challenges.get(tokenHash);
37
+
38
+ if (
39
+ record?.purpose !== purpose
40
+ || !!record.consumedAt
41
+ || !!record.revokedAt
42
+ || new Date(record.expiresAt).getTime() <= new Date(consumedAt).getTime()
43
+ ) {
44
+ return null;
45
+ }
46
+
47
+ record.consumedAt = consumedAt;
48
+
49
+ return { ...record };
50
+ }
51
+
52
+ /** Revokes active test challenges for one subject-purpose pair. */
53
+ public async revokeSubjectChallenges(
54
+ subjectId: string,
55
+ purpose: DyNTS_AccountChallengePurpose_Type,
56
+ revokedAt: string
57
+ ): Promise<void> {
58
+ Array.from(this.challenges.values())
59
+ .filter((item: DyNTS_AccountChallengeRecord_Interface): boolean => (
60
+ item.subjectId === subjectId && item.purpose === purpose && !item.consumedAt
61
+ ))
62
+ .forEach((item: DyNTS_AccountChallengeRecord_Interface): void => {
63
+ item.revokedAt = revokedAt;
64
+ });
65
+ }
66
+ }
67
+
68
+ describe('| DyNTS_AccountChallenge_ControlService', (): void => {
69
+ let now: Date;
70
+ let adapter: DyNTS_TestChallengeAdapter;
71
+ let service: DyNTS_AccountChallenge_ControlService;
72
+
73
+ beforeEach((): void => {
74
+ now = new Date('2026-08-18T10:00:00.000Z');
75
+ adapter = new DyNTS_TestChallengeAdapter();
76
+ service = new DyNTS_AccountChallenge_ControlService({
77
+ adapter: adapter,
78
+ ttlMs: 60_000,
79
+ clock: (): Date => new Date(now),
80
+ });
81
+ });
82
+
83
+ it('| persists only the token hash and consumes the subject binding once', async (): Promise<void> => {
84
+ const issued: DyNTS_AccountChallengeIssued_Interface = await service.issueChallenge(
85
+ 'subject-1',
86
+ DyNTS_AccountChallengePurpose_Type.emailVerification
87
+ );
88
+ const stored: DyNTS_AccountChallengeRecord_Interface | undefined =
89
+ adapter.challenges.get(hashToken(issued.token));
90
+ const result: DyNTS_AccountChallengeResult_Interface = await service.consumeChallenge(
91
+ issued.token,
92
+ DyNTS_AccountChallengePurpose_Type.emailVerification
93
+ );
94
+
95
+ expect(stored?.tokenHash).toBe(hashToken(issued.token));
96
+ expect(JSON.stringify(Array.from(adapter.challenges.values()))).not.toContain(issued.token);
97
+ expect(result.subjectId).toBe('subject-1');
98
+ await expectAsync(service.consumeChallenge(
99
+ issued.token,
100
+ DyNTS_AccountChallengePurpose_Type.emailVerification
101
+ )).toBeRejectedWithError(DyFM_Error);
102
+ });
103
+
104
+ it('| replaces the previous active challenge for the same purpose', async (): Promise<void> => {
105
+ const first: DyNTS_AccountChallengeIssued_Interface = await service.issueChallenge(
106
+ 'subject-1',
107
+ DyNTS_AccountChallengePurpose_Type.passwordReset
108
+ );
109
+ const second: DyNTS_AccountChallengeIssued_Interface = await service.issueChallenge(
110
+ 'subject-1',
111
+ DyNTS_AccountChallengePurpose_Type.passwordReset
112
+ );
113
+
114
+ await expectAsync(service.consumeChallenge(
115
+ first.token,
116
+ DyNTS_AccountChallengePurpose_Type.passwordReset
117
+ )).toBeRejectedWithError(DyFM_Error);
118
+ expect((await service.consumeChallenge(
119
+ second.token,
120
+ DyNTS_AccountChallengePurpose_Type.passwordReset
121
+ )).subjectId).toBe('subject-1');
122
+ });
123
+
124
+ it('| rejects purpose confusion and expiry without exposing token content', async (): Promise<void> => {
125
+ const issued: DyNTS_AccountChallengeIssued_Interface = await service.issueChallenge(
126
+ 'subject-1',
127
+ DyNTS_AccountChallengePurpose_Type.emailVerification
128
+ );
129
+ const purposeError: DyFM_Error = await captureError(service.consumeChallenge(
130
+ issued.token,
131
+ DyNTS_AccountChallengePurpose_Type.passwordReset
132
+ ));
133
+
134
+ now = new Date('2026-08-18T10:01:00.001Z');
135
+ const expiryError: DyFM_Error = await captureError(service.consumeChallenge(
136
+ issued.token,
137
+ DyNTS_AccountChallengePurpose_Type.emailVerification
138
+ ));
139
+
140
+ expect(purposeError._message).not.toContain(issued.token);
141
+ expect(expiryError._errorCode).toContain('CHALLENGE_INVALID');
142
+ });
143
+
144
+ it('| revokes outstanding challenges for a subject and purpose', async (): Promise<void> => {
145
+ const issued: DyNTS_AccountChallengeIssued_Interface = await service.issueChallenge(
146
+ 'subject-1',
147
+ DyNTS_AccountChallengePurpose_Type.passwordReset
148
+ );
149
+
150
+ await service.revokeSubjectChallenges('subject-1', DyNTS_AccountChallengePurpose_Type.passwordReset);
151
+
152
+ await expectAsync(service.consumeChallenge(
153
+ issued.token,
154
+ DyNTS_AccountChallengePurpose_Type.passwordReset
155
+ )).toBeRejectedWithError(DyFM_Error);
156
+ });
157
+
158
+ it('| rejects a corrupt expiry and oversized hostile input', async (): Promise<void> => {
159
+ const issued: DyNTS_AccountChallengeIssued_Interface = await service.issueChallenge(
160
+ 'subject-1',
161
+ DyNTS_AccountChallengePurpose_Type.passwordReset
162
+ );
163
+ const stored: DyNTS_AccountChallengeRecord_Interface | undefined =
164
+ adapter.challenges.get(hashToken(issued.token));
165
+
166
+ if (stored) {
167
+ stored.expiresAt = 'not-a-date';
168
+ }
169
+
170
+ await expectAsync(service.consumeChallenge(
171
+ issued.token,
172
+ DyNTS_AccountChallengePurpose_Type.passwordReset
173
+ )).toBeRejectedWithError(DyFM_Error);
174
+ await expectAsync(service.consumeChallenge(
175
+ 'x'.repeat(513),
176
+ DyNTS_AccountChallengePurpose_Type.passwordReset
177
+ )).toBeRejectedWithError(DyFM_Error);
178
+ });
179
+ });
180
+
181
+ function hashToken(token: string): string {
182
+ return createHash('sha256').update(token).digest('hex');
183
+ }
184
+
185
+ async function captureError(promise: Promise<unknown>): Promise<DyFM_Error> {
186
+ try {
187
+ await promise;
188
+ } catch (error: unknown) {
189
+ if (error instanceof DyFM_Error) {
190
+ return error;
191
+ }
192
+ }
193
+
194
+ throw new Error('Expected a DyFM_Error rejection.');
195
+ }
@@ -0,0 +1,164 @@
1
+ import {
2
+ createHash,
3
+ randomBytes,
4
+ randomUUID
5
+ } from 'crypto';
6
+
7
+ import { DyFM_Error } from '@futdevpro/fsm-dynamo';
8
+
9
+ import { DyNTS_global_settings } from '../../_collections/global-settings.const';
10
+ import { DyNTS_AccountChallengePurpose_Type } from './_enums/account-challenge-purpose.type-enum';
11
+ import { DyNTS_AccountChallengeAdapter_Interface } from './_models/account-challenge-adapter.interface';
12
+ import { DyNTS_AccountChallengeIssued_Interface } from './_models/account-challenge-issued.interface';
13
+ import { DyNTS_AccountChallengeRecord_Interface } from './_models/account-challenge-record.interface';
14
+ import { DyNTS_AccountChallengeResult_Interface } from './_models/account-challenge-result.interface';
15
+ import { DyNTS_AccountChallengeSettings_Interface } from './_models/account-challenge-settings.interface';
16
+
17
+ const DEFAULT_CHALLENGE_TTL_MS: number = 15 * 60 * 1000;
18
+ const DEFAULT_TOKEN_BYTES: number = 32;
19
+
20
+ /** Issues and atomically consumes opaque email-verification and password-reset credentials. */
21
+ export class DyNTS_AccountChallenge_ControlService {
22
+ private readonly adapter: DyNTS_AccountChallengeAdapter_Interface;
23
+ private readonly ttlMs: number;
24
+ private readonly tokenBytes: number;
25
+ private readonly clock: () => Date;
26
+
27
+ /** Creates a challenge service over an atomic persistence adapter. */
28
+ constructor(set: DyNTS_AccountChallengeSettings_Interface) {
29
+ this.adapter = set.adapter;
30
+ this.ttlMs = set.ttlMs ?? DEFAULT_CHALLENGE_TTL_MS;
31
+ this.tokenBytes = set.tokenBytes ?? DEFAULT_TOKEN_BYTES;
32
+ this.clock = set.clock ?? ((): Date => new Date());
33
+ this.validateSettings();
34
+ }
35
+
36
+ /** Replaces any active subject-purpose challenge before returning the new raw credential once. */
37
+ public async issueChallenge(
38
+ subjectId: string,
39
+ purpose: DyNTS_AccountChallengePurpose_Type
40
+ ): Promise<DyNTS_AccountChallengeIssued_Interface> {
41
+ if (
42
+ !subjectId
43
+ || subjectId.length > 256
44
+ || !Object.values(DyNTS_AccountChallengePurpose_Type).includes(purpose)
45
+ ) {
46
+ throw this.buildInvalid('CHALLENGE_REQUEST_INVALID');
47
+ }
48
+
49
+ const now: Date = this.clock();
50
+ const token: string = randomBytes(this.tokenBytes).toString('base64url');
51
+ const record: DyNTS_AccountChallengeRecord_Interface = {
52
+ challengeId: randomUUID(),
53
+ subjectId: subjectId,
54
+ purpose: purpose,
55
+ tokenHash: this.hashToken(token),
56
+ createdAt: now.toISOString(),
57
+ expiresAt: new Date(now.getTime() + this.ttlMs).toISOString(),
58
+ consumedAt: '',
59
+ revokedAt: '',
60
+ };
61
+
62
+ await this.adapter.replaceActiveChallenge(record);
63
+
64
+ return {
65
+ challengeId: record.challengeId,
66
+ token: token,
67
+ expiresAt: record.expiresAt,
68
+ };
69
+ }
70
+
71
+ /** Atomically consumes one unexpired challenge and returns its trusted subject binding. */
72
+ public async consumeChallenge(
73
+ token: string,
74
+ purpose: DyNTS_AccountChallengePurpose_Type
75
+ ): Promise<DyNTS_AccountChallengeResult_Interface> {
76
+ if (
77
+ !token
78
+ || token.length > 512
79
+ || !Object.values(DyNTS_AccountChallengePurpose_Type).includes(purpose)
80
+ ) {
81
+ throw this.buildInvalid('CHALLENGE_INVALID');
82
+ }
83
+
84
+ const now: Date = this.clock();
85
+ const tokenHash: string = this.hashToken(token);
86
+ const record: DyNTS_AccountChallengeRecord_Interface | null = await this.adapter.consumeActiveChallenge(
87
+ tokenHash,
88
+ purpose,
89
+ now.toISOString()
90
+ );
91
+
92
+ if (
93
+ record?.purpose !== purpose
94
+ || record.tokenHash !== tokenHash
95
+ || !record.consumedAt
96
+ || !!record.revokedAt
97
+ || !this.isFutureDate(record.expiresAt, now)
98
+ ) {
99
+ throw this.buildInvalid('CHALLENGE_INVALID');
100
+ }
101
+
102
+ return {
103
+ challengeId: record.challengeId,
104
+ subjectId: record.subjectId,
105
+ purpose: record.purpose,
106
+ };
107
+ }
108
+
109
+ /** Revokes every active challenge for a subject-purpose pair. */
110
+ public async revokeSubjectChallenges(
111
+ subjectId: string,
112
+ purpose: DyNTS_AccountChallengePurpose_Type
113
+ ): Promise<void> {
114
+ if (
115
+ !subjectId
116
+ || subjectId.length > 256
117
+ || !Object.values(DyNTS_AccountChallengePurpose_Type).includes(purpose)
118
+ ) {
119
+ throw this.buildInvalid('CHALLENGE_REQUEST_INVALID');
120
+ }
121
+
122
+ await this.adapter.revokeSubjectChallenges(subjectId, purpose, this.clock().toISOString());
123
+ }
124
+
125
+ private hashToken(token: string): string {
126
+ return createHash('sha256').update(token).digest('hex');
127
+ }
128
+
129
+ private validateSettings(): void {
130
+ if (
131
+ !this.adapter
132
+ || !Number.isSafeInteger(this.ttlMs)
133
+ || this.ttlMs < 60_000
134
+ || this.ttlMs > 24 * 60 * 60 * 1000
135
+ || !Number.isSafeInteger(this.tokenBytes)
136
+ || this.tokenBytes < 32
137
+ || this.tokenBytes > 128
138
+ ) {
139
+ throw new DyFM_Error({
140
+ status: 500,
141
+ errorCode: `${DyNTS_global_settings.systemShortCodeName}|ACCOUNT_SECURITY|CHALLENGE_SETTINGS_INVALID`,
142
+ message: 'The account challenge settings are outside supported safe bounds.',
143
+ userMessage: 'The account security service is unavailable.',
144
+ issuerService: this.constructor.name,
145
+ });
146
+ }
147
+ }
148
+
149
+ private isFutureDate(value: string, now: Date): boolean {
150
+ const timestamp: number = new Date(value).getTime();
151
+
152
+ return Number.isFinite(timestamp) && timestamp > now.getTime();
153
+ }
154
+
155
+ private buildInvalid(errorCode: string): DyFM_Error {
156
+ return new DyFM_Error({
157
+ status: 401,
158
+ errorCode: `${DyNTS_global_settings.systemShortCodeName}|ACCOUNT_SECURITY|${errorCode}`,
159
+ message: 'Opaque one-time account challenge validation failed.',
160
+ userMessage: 'The verification request is invalid or has expired. Please request a new one.',
161
+ issuerService: this.constructor.name,
162
+ });
163
+ }
164
+ }
@@ -0,0 +1,96 @@
1
+ import { createHash } from 'crypto';
2
+
3
+ import { DyFM_Error } from '@futdevpro/fsm-dynamo';
4
+
5
+ import { DyNTS_AccountPassword_ControlService } from './account-password.control-service';
6
+ import {
7
+ DyNTS_AccountPasswordVerification_Interface
8
+ } from './_models/account-password-verification.interface';
9
+
10
+ describe('| DyNTS_AccountPassword_ControlService', (): void => {
11
+ it('| hashes with unique salts and verifies the matching password', async (): Promise<void> => {
12
+ const service: DyNTS_AccountPassword_ControlService = new DyNTS_AccountPassword_ControlService();
13
+ const firstHash: string = await service.hashPassword('correct horse battery staple');
14
+ const secondHash: string = await service.hashPassword('correct horse battery staple');
15
+ const result: DyNTS_AccountPasswordVerification_Interface = await service.verifyPassword(
16
+ 'correct horse battery staple',
17
+ firstHash
18
+ );
19
+
20
+ expect(firstHash).not.toBe(secondHash);
21
+ expect(firstHash).not.toContain('correct horse');
22
+ expect(result).toEqual({ isValid: true, needsRehash: false });
23
+ });
24
+
25
+ it('| rejects a wrong password without returning credential material', async (): Promise<void> => {
26
+ const service: DyNTS_AccountPassword_ControlService = new DyNTS_AccountPassword_ControlService();
27
+ const storedHash: string = await service.hashPassword('correct horse battery staple');
28
+ const result: DyNTS_AccountPasswordVerification_Interface = await service.verifyPassword(
29
+ 'wrong password value',
30
+ storedHash
31
+ );
32
+
33
+ expect(result).toEqual({ isValid: false, needsRehash: false });
34
+ expect(Object.keys(result)).toEqual([ 'isValid', 'needsRehash' ]);
35
+ });
36
+
37
+ it('| performs a safe negative result for malformed or attacker-cost hashes', async (): Promise<void> => {
38
+ const service: DyNTS_AccountPassword_ControlService = new DyNTS_AccountPassword_ControlService();
39
+ const malformed: DyNTS_AccountPasswordVerification_Interface = await service.verifyPassword(
40
+ 'candidate password',
41
+ 'dyn-scrypt-v1$1073741824$8$1$c2FsdA$aGFzaA'
42
+ );
43
+
44
+ expect(malformed).toEqual({ isValid: false, needsRehash: false });
45
+ });
46
+
47
+ it('| bounds hostile candidate and stored-hash input before verification work', async (): Promise<void> => {
48
+ const service: DyNTS_AccountPassword_ControlService = new DyNTS_AccountPassword_ControlService();
49
+ const result: DyNTS_AccountPasswordVerification_Interface = await service.verifyPassword(
50
+ 'x'.repeat(129),
51
+ 'x'.repeat(2_000)
52
+ );
53
+
54
+ expect(result).toEqual({ isValid: false, needsRehash: false });
55
+ });
56
+
57
+ it('| reports a valid legacy-cost hash as needing rehash', async (): Promise<void> => {
58
+ const legacy: DyNTS_AccountPassword_ControlService = new DyNTS_AccountPassword_ControlService({
59
+ scryptCost: 8_192,
60
+ });
61
+ const current: DyNTS_AccountPassword_ControlService = new DyNTS_AccountPassword_ControlService();
62
+ const storedHash: string = await legacy.hashPassword('correct horse battery staple');
63
+ const result: DyNTS_AccountPasswordVerification_Interface = await current.verifyPassword(
64
+ 'correct horse battery staple',
65
+ storedHash
66
+ );
67
+
68
+ expect(result).toEqual({ isValid: true, needsRehash: true });
69
+ });
70
+
71
+ it('| rejects configured common passwords with a content-free stable error', (): void => {
72
+ const commonPassword: string = 'very common password';
73
+ const digest: string = createHash('sha256')
74
+ .update(commonPassword)
75
+ .digest('hex');
76
+ const service: DyNTS_AccountPassword_ControlService = new DyNTS_AccountPassword_ControlService({
77
+ commonPasswordSha256: [ digest ],
78
+ });
79
+ let capturedError: DyFM_Error | null = null;
80
+
81
+ try {
82
+ service.validatePassword(commonPassword);
83
+ } catch (error: unknown) {
84
+ capturedError = error instanceof DyFM_Error ? error : null;
85
+ }
86
+
87
+ expect(capturedError?._errorCode).toContain('PASSWORD_POLICY_COMMON');
88
+ expect(capturedError?._message).not.toContain(commonPassword);
89
+ });
90
+
91
+ it('| rejects unsafe policy settings before hashing starts', (): void => {
92
+ expect((): DyNTS_AccountPassword_ControlService => new DyNTS_AccountPassword_ControlService({
93
+ scryptCost: 15_000,
94
+ })).toThrowError(DyFM_Error);
95
+ });
96
+ });