keycloakify 9.6.7 → 10.0.0-rc.0

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 (417) hide show
  1. package/account/Template.js +34 -14
  2. package/account/Template.js.map +1 -1
  3. package/account/i18n/baseMessages/de.d.ts +1 -1
  4. package/account/i18n/baseMessages/de.js +1 -1
  5. package/account/i18n/baseMessages/de.js.map +1 -1
  6. package/account/i18n/baseMessages/en.d.ts +2 -0
  7. package/account/i18n/baseMessages/en.js +2 -0
  8. package/account/i18n/baseMessages/en.js.map +1 -1
  9. package/account/i18n/baseMessages/es.d.ts +230 -0
  10. package/account/i18n/baseMessages/es.js +231 -1
  11. package/account/i18n/baseMessages/es.js.map +1 -1
  12. package/account/i18n/baseMessages/index.d.ts +353 -407
  13. package/account/i18n/baseMessages/index.js +1 -0
  14. package/account/i18n/baseMessages/index.js.map +1 -1
  15. package/account/i18n/baseMessages/pl.d.ts +115 -1
  16. package/account/i18n/baseMessages/pl.js +115 -1
  17. package/account/i18n/baseMessages/pl.js.map +1 -1
  18. package/account/i18n/baseMessages/tr.d.ts +1 -1
  19. package/account/i18n/baseMessages/tr.js +1 -1
  20. package/account/i18n/baseMessages/tr.js.map +1 -1
  21. package/account/i18n/baseMessages/uk.d.ts +337 -0
  22. package/account/i18n/baseMessages/uk.js +342 -0
  23. package/account/i18n/baseMessages/uk.js.map +1 -0
  24. package/account/i18n/baseMessages/zh-CN.d.ts +10 -0
  25. package/account/i18n/baseMessages/zh-CN.js +10 -0
  26. package/account/i18n/baseMessages/zh-CN.js.map +1 -1
  27. package/bin/constants.d.ts +0 -1
  28. package/bin/constants.js +1 -2
  29. package/bin/constants.js.map +1 -1
  30. package/bin/keycloakify/buildJars/buildJar.d.ts +14 -0
  31. package/bin/keycloakify/buildJars/buildJar.js +216 -0
  32. package/bin/keycloakify/buildJars/buildJar.js.map +1 -0
  33. package/bin/keycloakify/buildJars/buildJars.d.ts +10 -0
  34. package/bin/keycloakify/buildJars/buildJars.js +95 -0
  35. package/bin/keycloakify/buildJars/buildJars.js.map +1 -0
  36. package/bin/keycloakify/buildJars/extensionVersions.d.ts +12 -0
  37. package/bin/keycloakify/buildJars/extensionVersions.js +7 -0
  38. package/bin/keycloakify/buildJars/extensionVersions.js.map +1 -0
  39. package/bin/keycloakify/buildJars/generatePom.d.ts +13 -0
  40. package/bin/keycloakify/buildJars/generatePom.js +94 -0
  41. package/bin/keycloakify/buildJars/generatePom.js.map +1 -0
  42. package/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.d.ts +6 -0
  43. package/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.js +35 -0
  44. package/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.js.map +1 -0
  45. package/bin/keycloakify/buildJars/index.d.ts +1 -0
  46. package/bin/keycloakify/buildJars/index.js +18 -0
  47. package/bin/keycloakify/buildJars/index.js.map +1 -0
  48. package/bin/keycloakify/buildOptions/UserProvidedBuildOptions.d.ts +0 -8
  49. package/bin/keycloakify/buildOptions/UserProvidedBuildOptions.js +1 -3
  50. package/bin/keycloakify/buildOptions/UserProvidedBuildOptions.js.map +1 -1
  51. package/bin/keycloakify/buildOptions/buildOptions.d.ts +0 -2
  52. package/bin/keycloakify/buildOptions/buildOptions.js +3 -5
  53. package/bin/keycloakify/buildOptions/buildOptions.js.map +1 -1
  54. package/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +103 -232
  55. package/bin/keycloakify/generateFtl/generateFtl.js +17 -39
  56. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  57. package/bin/keycloakify/generateFtl/pageId.d.ts +1 -1
  58. package/bin/keycloakify/generateFtl/pageId.js +11 -3
  59. package/bin/keycloakify/generateFtl/pageId.js.map +1 -1
  60. package/bin/keycloakify/generateStartKeycloakTestingContainer.d.ts +0 -1
  61. package/bin/keycloakify/generateStartKeycloakTestingContainer.js +3 -6
  62. package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
  63. package/bin/keycloakify/generateTheme/bringInAccountV1.d.ts +1 -1
  64. package/bin/keycloakify/generateTheme/bringInAccountV1.js +5 -9
  65. package/bin/keycloakify/generateTheme/bringInAccountV1.js.map +1 -1
  66. package/bin/keycloakify/generateTheme/generateSrcMainResources.d.ts +21 -0
  67. package/bin/keycloakify/generateTheme/generateSrcMainResources.js +340 -0
  68. package/bin/keycloakify/generateTheme/generateSrcMainResources.js.map +1 -0
  69. package/bin/keycloakify/generateTheme/generateTheme.d.ts +5 -13
  70. package/bin/keycloakify/generateTheme/generateTheme.js +30 -293
  71. package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
  72. package/bin/keycloakify/generateTheme/generateThemeVariants.d.ts +5 -0
  73. package/bin/keycloakify/generateTheme/generateThemeVariants.js +67 -0
  74. package/bin/keycloakify/generateTheme/generateThemeVariants.js.map +1 -0
  75. package/bin/keycloakify/generateTheme/readFieldNameUsage.js +54 -18
  76. package/bin/keycloakify/generateTheme/readFieldNameUsage.js.map +1 -1
  77. package/bin/keycloakify/keycloakify.js +28 -104
  78. package/bin/keycloakify/keycloakify.js.map +1 -1
  79. package/lib/useGetClassName.js +2 -2
  80. package/lib/useGetClassName.js.map +1 -1
  81. package/login/Fallback.d.ts +7 -1
  82. package/login/Fallback.js +32 -8
  83. package/login/Fallback.js.map +1 -1
  84. package/login/Template.js +76 -20
  85. package/login/Template.js.map +1 -1
  86. package/login/TemplateProps.d.ts +4 -2
  87. package/login/UserProfileFormFields.d.ts +22 -0
  88. package/login/UserProfileFormFields.js +327 -0
  89. package/login/UserProfileFormFields.js.map +1 -0
  90. package/login/i18n/baseMessages/ar.d.ts +3 -0
  91. package/login/i18n/baseMessages/ar.js +3 -0
  92. package/login/i18n/baseMessages/ar.js.map +1 -1
  93. package/login/i18n/baseMessages/ca.d.ts +1 -0
  94. package/login/i18n/baseMessages/ca.js +1 -0
  95. package/login/i18n/baseMessages/ca.js.map +1 -1
  96. package/login/i18n/baseMessages/cs.d.ts +3 -0
  97. package/login/i18n/baseMessages/cs.js +3 -0
  98. package/login/i18n/baseMessages/cs.js.map +1 -1
  99. package/login/i18n/baseMessages/da.d.ts +1 -0
  100. package/login/i18n/baseMessages/da.js +1 -0
  101. package/login/i18n/baseMessages/da.js.map +1 -1
  102. package/login/i18n/baseMessages/de.d.ts +1 -0
  103. package/login/i18n/baseMessages/de.js +1 -0
  104. package/login/i18n/baseMessages/de.js.map +1 -1
  105. package/login/i18n/baseMessages/el.d.ts +1 -0
  106. package/login/i18n/baseMessages/el.js +1 -0
  107. package/login/i18n/baseMessages/el.js.map +1 -1
  108. package/login/i18n/baseMessages/en.d.ts +7 -0
  109. package/login/i18n/baseMessages/en.js +23 -16
  110. package/login/i18n/baseMessages/en.js.map +1 -1
  111. package/login/i18n/baseMessages/es.d.ts +239 -0
  112. package/login/i18n/baseMessages/es.js +240 -1
  113. package/login/i18n/baseMessages/es.js.map +1 -1
  114. package/login/i18n/baseMessages/fa.d.ts +1 -0
  115. package/login/i18n/baseMessages/fa.js +1 -0
  116. package/login/i18n/baseMessages/fa.js.map +1 -1
  117. package/login/i18n/baseMessages/fi.d.ts +1 -0
  118. package/login/i18n/baseMessages/fi.js +1 -0
  119. package/login/i18n/baseMessages/fi.js.map +1 -1
  120. package/login/i18n/baseMessages/fr.d.ts +1 -0
  121. package/login/i18n/baseMessages/fr.js +2 -1
  122. package/login/i18n/baseMessages/fr.js.map +1 -1
  123. package/login/i18n/baseMessages/hu.d.ts +1 -0
  124. package/login/i18n/baseMessages/hu.js +1 -0
  125. package/login/i18n/baseMessages/hu.js.map +1 -1
  126. package/login/i18n/baseMessages/index.d.ts +211 -416
  127. package/login/i18n/baseMessages/index.js +1 -0
  128. package/login/i18n/baseMessages/index.js.map +1 -1
  129. package/login/i18n/baseMessages/it.d.ts +1 -0
  130. package/login/i18n/baseMessages/it.js +1 -0
  131. package/login/i18n/baseMessages/it.js.map +1 -1
  132. package/login/i18n/baseMessages/ja.d.ts +1 -0
  133. package/login/i18n/baseMessages/ja.js +1 -0
  134. package/login/i18n/baseMessages/ja.js.map +1 -1
  135. package/login/i18n/baseMessages/lt.d.ts +1 -0
  136. package/login/i18n/baseMessages/lt.js +1 -0
  137. package/login/i18n/baseMessages/lt.js.map +1 -1
  138. package/login/i18n/baseMessages/lv.d.ts +1 -0
  139. package/login/i18n/baseMessages/lv.js +1 -0
  140. package/login/i18n/baseMessages/lv.js.map +1 -1
  141. package/login/i18n/baseMessages/nl.d.ts +1 -0
  142. package/login/i18n/baseMessages/nl.js +1 -0
  143. package/login/i18n/baseMessages/nl.js.map +1 -1
  144. package/login/i18n/baseMessages/no.d.ts +1 -0
  145. package/login/i18n/baseMessages/no.js +1 -0
  146. package/login/i18n/baseMessages/no.js.map +1 -1
  147. package/login/i18n/baseMessages/pl.d.ts +1 -0
  148. package/login/i18n/baseMessages/pl.js +1 -0
  149. package/login/i18n/baseMessages/pl.js.map +1 -1
  150. package/login/i18n/baseMessages/pt-BR.d.ts +1 -0
  151. package/login/i18n/baseMessages/pt-BR.js +1 -0
  152. package/login/i18n/baseMessages/pt-BR.js.map +1 -1
  153. package/login/i18n/baseMessages/ru.d.ts +1 -0
  154. package/login/i18n/baseMessages/ru.js +1 -0
  155. package/login/i18n/baseMessages/ru.js.map +1 -1
  156. package/login/i18n/baseMessages/sk.d.ts +2 -0
  157. package/login/i18n/baseMessages/sk.js +3 -1
  158. package/login/i18n/baseMessages/sk.js.map +1 -1
  159. package/login/i18n/baseMessages/sv.d.ts +1 -0
  160. package/login/i18n/baseMessages/sv.js +1 -0
  161. package/login/i18n/baseMessages/sv.js.map +1 -1
  162. package/login/i18n/baseMessages/th.d.ts +1 -0
  163. package/login/i18n/baseMessages/th.js +1 -0
  164. package/login/i18n/baseMessages/th.js.map +1 -1
  165. package/login/i18n/baseMessages/tr.d.ts +1 -0
  166. package/login/i18n/baseMessages/tr.js +1 -0
  167. package/login/i18n/baseMessages/tr.js.map +1 -1
  168. package/login/i18n/baseMessages/uk.d.ts +433 -0
  169. package/login/i18n/baseMessages/uk.js +438 -0
  170. package/login/i18n/baseMessages/uk.js.map +1 -0
  171. package/login/i18n/baseMessages/zh-CN.d.ts +273 -3
  172. package/login/i18n/baseMessages/zh-CN.js +325 -55
  173. package/login/i18n/baseMessages/zh-CN.js.map +1 -1
  174. package/login/i18n/i18n.d.ts +4 -0
  175. package/login/i18n/i18n.js +6 -2
  176. package/login/i18n/i18n.js.map +1 -1
  177. package/login/kcContext/KcContext.d.ts +181 -105
  178. package/login/kcContext/KcContext.js +1 -1
  179. package/login/kcContext/KcContext.js.map +1 -1
  180. package/login/kcContext/createGetKcContext.js +3 -9
  181. package/login/kcContext/createGetKcContext.js.map +1 -1
  182. package/login/kcContext/kcContextMocks.d.ts +1 -1
  183. package/login/kcContext/kcContextMocks.js +92 -198
  184. package/login/kcContext/kcContextMocks.js.map +1 -1
  185. package/login/lib/useDownloadTerms.d.ts +4 -1
  186. package/login/lib/useDownloadTerms.js +9 -4
  187. package/login/lib/useDownloadTerms.js.map +1 -1
  188. package/login/lib/useGetClassName.js +112 -73
  189. package/login/lib/useGetClassName.js.map +1 -1
  190. package/login/lib/useUserProfileForm.d.ts +74 -0
  191. package/login/lib/useUserProfileForm.js +868 -0
  192. package/login/lib/useUserProfileForm.js.map +1 -0
  193. package/login/pages/{UpdateUserProfile.d.ts → Code.d.ts} +2 -2
  194. package/login/pages/Code.js +13 -0
  195. package/login/pages/Code.js.map +1 -0
  196. package/login/pages/DeleteAccountConfirm.d.ts +7 -0
  197. package/login/pages/DeleteAccountConfirm.js +14 -0
  198. package/login/pages/DeleteAccountConfirm.js.map +1 -0
  199. package/login/pages/{RegisterUserProfile.d.ts → DeleteCredential.d.ts} +2 -2
  200. package/login/pages/DeleteCredential.js +14 -0
  201. package/login/pages/DeleteCredential.js.map +1 -0
  202. package/login/pages/Error.js +2 -2
  203. package/login/pages/Error.js.map +1 -1
  204. package/login/pages/FrontchannelLogout.d.ts +7 -0
  205. package/login/pages/FrontchannelLogout.js +14 -0
  206. package/login/pages/FrontchannelLogout.js.map +1 -0
  207. package/login/pages/IdpReviewUserProfile.d.ts +8 -2
  208. package/login/pages/IdpReviewUserProfile.js +3 -4
  209. package/login/pages/IdpReviewUserProfile.js.map +1 -1
  210. package/login/pages/Info.js +14 -1
  211. package/login/pages/Info.js.map +1 -1
  212. package/login/pages/Login.js +24 -38
  213. package/login/pages/Login.js.map +1 -1
  214. package/login/pages/LoginConfigTotp.js +8 -1
  215. package/login/pages/LoginConfigTotp.js.map +1 -1
  216. package/login/pages/{LoginDeviceVerifyUserCode.d.ts → LoginOauth2DeviceVerifyUserCode.d.ts} +1 -1
  217. package/login/pages/{LoginDeviceVerifyUserCode.js → LoginOauth2DeviceVerifyUserCode.js} +2 -2
  218. package/login/pages/LoginOauth2DeviceVerifyUserCode.js.map +1 -0
  219. package/login/pages/LoginOauthGrant.js +3 -2
  220. package/login/pages/LoginOauthGrant.js.map +1 -1
  221. package/login/pages/LoginOtp.js +4 -6
  222. package/login/pages/LoginOtp.js.map +1 -1
  223. package/login/pages/LoginPageExpired.js +1 -1
  224. package/login/pages/LoginPageExpired.js.map +1 -1
  225. package/login/pages/LoginPassword.d.ts +1 -1
  226. package/login/pages/LoginPassword.js +18 -11
  227. package/login/pages/LoginPassword.js.map +1 -1
  228. package/login/pages/LoginRecoveryAuthnCodeConfig.d.ts +7 -0
  229. package/login/pages/LoginRecoveryAuthnCodeConfig.js +147 -0
  230. package/login/pages/LoginRecoveryAuthnCodeConfig.js.map +1 -0
  231. package/login/pages/LoginRecoveryAuthnCodeInput.d.ts +7 -0
  232. package/login/pages/LoginRecoveryAuthnCodeInput.js +14 -0
  233. package/login/pages/LoginRecoveryAuthnCodeInput.js.map +1 -0
  234. package/login/pages/LoginResetOtp.d.ts +7 -0
  235. package/login/pages/LoginResetOtp.js +15 -0
  236. package/login/pages/LoginResetOtp.js.map +1 -0
  237. package/login/pages/LoginResetPassword.js +4 -3
  238. package/login/pages/LoginResetPassword.js.map +1 -1
  239. package/login/pages/LoginUpdatePassword.js +21 -3
  240. package/login/pages/LoginUpdatePassword.js.map +1 -1
  241. package/login/pages/LoginUpdateProfile.d.ts +8 -2
  242. package/login/pages/LoginUpdateProfile.js +11 -5
  243. package/login/pages/LoginUpdateProfile.js.map +1 -1
  244. package/login/pages/LoginUsername.js +11 -35
  245. package/login/pages/LoginUsername.js.map +1 -1
  246. package/login/pages/LoginVerifyEmail.js +1 -1
  247. package/login/pages/LoginVerifyEmail.js.map +1 -1
  248. package/login/pages/LoginX509Info.d.ts +7 -0
  249. package/login/pages/LoginX509Info.js +14 -0
  250. package/login/pages/LoginX509Info.js.map +1 -0
  251. package/login/pages/LogoutConfirm.js +1 -1
  252. package/login/pages/LogoutConfirm.js.map +1 -1
  253. package/login/pages/Register.d.ts +8 -2
  254. package/login/pages/Register.js +26 -4
  255. package/login/pages/Register.js.map +1 -1
  256. package/login/pages/SamlPostForm.js +1 -1
  257. package/login/pages/SamlPostForm.js.map +1 -1
  258. package/login/pages/SelectAuthenticator.js +5 -21
  259. package/login/pages/SelectAuthenticator.js.map +1 -1
  260. package/login/pages/Terms.js +4 -6
  261. package/login/pages/Terms.js.map +1 -1
  262. package/login/pages/UpdateEmail.d.ts +8 -2
  263. package/login/pages/UpdateEmail.js +16 -5
  264. package/login/pages/UpdateEmail.js.map +1 -1
  265. package/login/pages/WebauthnAuthenticate.js +121 -83
  266. package/login/pages/WebauthnAuthenticate.js.map +1 -1
  267. package/login/pages/WebauthnError.d.ts +7 -0
  268. package/login/pages/WebauthnError.js +21 -0
  269. package/login/pages/WebauthnError.js.map +1 -0
  270. package/login/pages/WebauthnRegister.d.ts +7 -0
  271. package/login/pages/WebauthnRegister.js +193 -0
  272. package/login/pages/WebauthnRegister.js.map +1 -0
  273. package/package.json +138 -43
  274. package/src/account/Template.tsx +41 -14
  275. package/src/account/i18n/baseMessages/de.ts +1 -1
  276. package/src/account/i18n/baseMessages/en.ts +2 -0
  277. package/src/account/i18n/baseMessages/es.ts +231 -1
  278. package/src/account/i18n/baseMessages/index.ts +1 -0
  279. package/src/account/i18n/baseMessages/pl.ts +115 -1
  280. package/src/account/i18n/baseMessages/tr.ts +1 -1
  281. package/src/account/i18n/baseMessages/uk.ts +343 -0
  282. package/src/account/i18n/baseMessages/zh-CN.ts +10 -0
  283. package/src/bin/constants.ts +0 -1
  284. package/src/bin/keycloakify/buildJars/buildJar.ts +163 -0
  285. package/src/bin/keycloakify/buildJars/buildJars.ts +62 -0
  286. package/src/bin/keycloakify/buildJars/extensionVersions.ts +16 -0
  287. package/src/bin/keycloakify/buildJars/generatePom.ts +86 -0
  288. package/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts +37 -0
  289. package/src/bin/keycloakify/buildJars/index.ts +1 -0
  290. package/src/bin/keycloakify/buildOptions/UserProvidedBuildOptions.ts +1 -5
  291. package/src/bin/keycloakify/buildOptions/buildOptions.ts +1 -5
  292. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +103 -232
  293. package/src/bin/keycloakify/generateFtl/generateFtl.ts +15 -31
  294. package/src/bin/keycloakify/generateFtl/pageId.ts +11 -3
  295. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +4 -8
  296. package/src/bin/keycloakify/generateTheme/bringInAccountV1.ts +5 -11
  297. package/src/bin/keycloakify/generateTheme/generateSrcMainResources.ts +267 -0
  298. package/src/bin/keycloakify/generateTheme/generateTheme.ts +22 -309
  299. package/src/bin/keycloakify/generateTheme/generateThemeVariants.ts +50 -0
  300. package/src/bin/keycloakify/generateTheme/readFieldNameUsage.ts +33 -8
  301. package/src/bin/keycloakify/keycloakify.ts +23 -56
  302. package/src/lib/useGetClassName.ts +2 -2
  303. package/src/login/Fallback.tsx +39 -9
  304. package/src/login/Template.tsx +160 -61
  305. package/src/login/TemplateProps.ts +113 -63
  306. package/src/login/UserProfileFormFields.tsx +750 -0
  307. package/src/login/i18n/baseMessages/ar.ts +3 -0
  308. package/src/login/i18n/baseMessages/ca.ts +1 -0
  309. package/src/login/i18n/baseMessages/cs.ts +3 -0
  310. package/src/login/i18n/baseMessages/da.ts +1 -0
  311. package/src/login/i18n/baseMessages/de.ts +1 -0
  312. package/src/login/i18n/baseMessages/el.ts +1 -0
  313. package/src/login/i18n/baseMessages/en.ts +23 -16
  314. package/src/login/i18n/baseMessages/es.ts +240 -1
  315. package/src/login/i18n/baseMessages/fa.ts +1 -0
  316. package/src/login/i18n/baseMessages/fi.ts +1 -0
  317. package/src/login/i18n/baseMessages/fr.ts +2 -1
  318. package/src/login/i18n/baseMessages/hu.ts +1 -0
  319. package/src/login/i18n/baseMessages/index.ts +1 -0
  320. package/src/login/i18n/baseMessages/it.ts +1 -0
  321. package/src/login/i18n/baseMessages/ja.ts +1 -0
  322. package/src/login/i18n/baseMessages/lt.ts +1 -0
  323. package/src/login/i18n/baseMessages/lv.ts +1 -0
  324. package/src/login/i18n/baseMessages/nl.ts +1 -0
  325. package/src/login/i18n/baseMessages/no.ts +1 -0
  326. package/src/login/i18n/baseMessages/pl.ts +1 -0
  327. package/src/login/i18n/baseMessages/pt-BR.ts +1 -0
  328. package/src/login/i18n/baseMessages/ru.ts +1 -0
  329. package/src/login/i18n/baseMessages/sk.ts +3 -1
  330. package/src/login/i18n/baseMessages/sv.ts +1 -0
  331. package/src/login/i18n/baseMessages/th.ts +1 -0
  332. package/src/login/i18n/baseMessages/tr.ts +1 -0
  333. package/src/login/i18n/baseMessages/uk.ts +439 -0
  334. package/src/login/i18n/baseMessages/zh-CN.ts +325 -55
  335. package/src/login/i18n/i18n.tsx +6 -2
  336. package/src/login/kcContext/KcContext.ts +216 -103
  337. package/src/login/kcContext/createGetKcContext.ts +11 -19
  338. package/src/login/kcContext/kcContextMocks.ts +165 -226
  339. package/src/login/lib/useDownloadTerms.ts +15 -7
  340. package/src/login/lib/useGetClassName.ts +112 -83
  341. package/src/login/lib/useUserProfileForm.tsx +1227 -0
  342. package/src/login/pages/Code.tsx +35 -0
  343. package/src/login/pages/DeleteAccountConfirm.tsx +53 -0
  344. package/src/login/pages/DeleteCredential.tsx +45 -0
  345. package/src/login/pages/Error.tsx +2 -2
  346. package/src/login/pages/FrontchannelLogout.tsx +41 -0
  347. package/src/login/pages/IdpReviewUserProfile.tsx +15 -5
  348. package/src/login/pages/Info.tsx +29 -19
  349. package/src/login/pages/Login.tsx +156 -117
  350. package/src/login/pages/LoginConfigTotp.tsx +26 -1
  351. package/src/login/pages/{LoginDeviceVerifyUserCode.tsx → LoginOauth2DeviceVerifyUserCode.tsx} +3 -1
  352. package/src/login/pages/LoginOauthGrant.tsx +38 -2
  353. package/src/login/pages/LoginOtp.tsx +73 -65
  354. package/src/login/pages/LoginPageExpired.tsx +1 -1
  355. package/src/login/pages/LoginPassword.tsx +77 -28
  356. package/src/login/pages/LoginRecoveryAuthnCodeConfig.tsx +260 -0
  357. package/src/login/pages/LoginRecoveryAuthnCodeInput.tsx +73 -0
  358. package/src/login/pages/LoginResetOtp.tsx +70 -0
  359. package/src/login/pages/LoginResetPassword.tsx +11 -4
  360. package/src/login/pages/LoginUpdatePassword.tsx +120 -81
  361. package/src/login/pages/LoginUpdateProfile.tsx +41 -115
  362. package/src/login/pages/LoginUsername.tsx +93 -101
  363. package/src/login/pages/LoginVerifyEmail.tsx +14 -8
  364. package/src/login/pages/LoginX509Info.tsx +94 -0
  365. package/src/login/pages/LogoutConfirm.tsx +2 -2
  366. package/src/login/pages/Register.tsx +83 -131
  367. package/src/login/pages/SamlPostForm.tsx +1 -1
  368. package/src/login/pages/SelectAuthenticator.tsx +29 -52
  369. package/src/login/pages/Terms.tsx +4 -7
  370. package/src/login/pages/UpdateEmail.tsx +69 -54
  371. package/src/login/pages/WebauthnAuthenticate.tsx +205 -165
  372. package/src/login/pages/WebauthnError.tsx +66 -0
  373. package/src/login/pages/WebauthnRegister.tsx +285 -0
  374. package/src/tools/formatNumber.ts +48 -0
  375. package/src/tools/useInsertLinkTags.ts +82 -0
  376. package/src/tools/useInsertScriptTags.ts +106 -0
  377. package/src/tools/useSetClassName.ts +21 -0
  378. package/tools/formatNumber.d.ts +1 -0
  379. package/tools/formatNumber.js +37 -0
  380. package/tools/formatNumber.js.map +1 -0
  381. package/tools/useInsertLinkTags.d.ts +7 -0
  382. package/tools/useInsertLinkTags.js +57 -0
  383. package/tools/useInsertLinkTags.js.map +1 -0
  384. package/tools/useInsertScriptTags.d.ts +20 -0
  385. package/tools/useInsertScriptTags.js +75 -0
  386. package/tools/useInsertScriptTags.js.map +1 -0
  387. package/tools/useSetClassName.d.ts +4 -0
  388. package/tools/useSetClassName.js +16 -0
  389. package/tools/useSetClassName.js.map +1 -0
  390. package/vite-plugin/tsconfig.tsbuildinfo +1 -1
  391. package/bin/keycloakify/generatePom.d.ts +0 -12
  392. package/bin/keycloakify/generatePom.js +0 -59
  393. package/bin/keycloakify/generatePom.js.map +0 -1
  394. package/lib/usePrepareTemplate.d.ts +0 -11
  395. package/lib/usePrepareTemplate.js +0 -80
  396. package/lib/usePrepareTemplate.js.map +0 -1
  397. package/login/lib/useFormValidation.d.ts +0 -47
  398. package/login/lib/useFormValidation.js +0 -316
  399. package/login/lib/useFormValidation.js.map +0 -1
  400. package/login/pages/LoginDeviceVerifyUserCode.js.map +0 -1
  401. package/login/pages/RegisterUserProfile.js +0 -18
  402. package/login/pages/RegisterUserProfile.js.map +0 -1
  403. package/login/pages/UpdateUserProfile.js +0 -17
  404. package/login/pages/UpdateUserProfile.js.map +0 -1
  405. package/login/pages/shared/UserProfileFormFields.d.ts +0 -18
  406. package/login/pages/shared/UserProfileFormFields.js +0 -58
  407. package/login/pages/shared/UserProfileFormFields.js.map +0 -1
  408. package/src/bin/keycloakify/generatePom.ts +0 -70
  409. package/src/lib/usePrepareTemplate.ts +0 -113
  410. package/src/login/lib/useFormValidation.tsx +0 -474
  411. package/src/login/pages/RegisterUserProfile.tsx +0 -72
  412. package/src/login/pages/UpdateUserProfile.tsx +0 -82
  413. package/src/login/pages/shared/UserProfileFormFields.tsx +0 -177
  414. package/src/tools/headInsert.ts +0 -73
  415. package/tools/headInsert.d.ts +0 -12
  416. package/tools/headInsert.js +0 -50
  417. package/tools/headInsert.js.map +0 -1
@@ -0,0 +1,1227 @@
1
+ import "keycloakify/tools/Array.prototype.every";
2
+ import { useMemo, useReducer, useEffect, Fragment, type Dispatch } from "react";
3
+ import { id } from "tsafe/id";
4
+ import type { MessageKey } from "keycloakify/login/i18n/i18n";
5
+ import type { Attribute, Validators } from "keycloakify/login/kcContext/KcContext";
6
+ import { useConstCallback } from "keycloakify/tools/useConstCallback";
7
+ import { emailRegexp } from "keycloakify/tools/emailRegExp";
8
+ import type { KcContext, PasswordPolicies } from "keycloakify/login/kcContext/KcContext";
9
+ import { assert, type Equals } from "tsafe/assert";
10
+ import { formatNumber } from "keycloakify/tools/formatNumber";
11
+ import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
12
+ import type { I18n } from "../i18n";
13
+
14
+ export type FormFieldError = {
15
+ errorMessage: JSX.Element;
16
+ errorMessageStr: string;
17
+ source: FormFieldError.Source;
18
+ fieldIndex: number | undefined;
19
+ };
20
+
21
+ export namespace FormFieldError {
22
+ export type Source = Source.Validator | Source.PasswordPolicy | Source.Server | Source.Other;
23
+
24
+ export namespace Source {
25
+ export type Validator = {
26
+ type: "validator";
27
+ name: keyof Validators;
28
+ };
29
+ export type PasswordPolicy = {
30
+ type: "passwordPolicy";
31
+ name: keyof PasswordPolicies;
32
+ };
33
+ export type Server = {
34
+ type: "server";
35
+ };
36
+
37
+ export type Other = {
38
+ type: "other";
39
+ rule: "passwordConfirmMatchesPassword" | "requiredField";
40
+ };
41
+ }
42
+ }
43
+
44
+ export type FormFieldState = {
45
+ attribute: Attribute;
46
+ displayableErrors: FormFieldError[];
47
+ valueOrValues: string | string[];
48
+ };
49
+
50
+ export type FormState = {
51
+ isFormSubmittable: boolean;
52
+ formFieldStates: FormFieldState[];
53
+ };
54
+
55
+ export type FormAction =
56
+ | {
57
+ action: "update";
58
+ name: string;
59
+ valueOrValues: string | string[];
60
+ }
61
+ | {
62
+ action: "focus lost";
63
+ name: string;
64
+ fieldIndex: number | undefined;
65
+ };
66
+
67
+ export type KcContextLike = {
68
+ messagesPerField: Pick<KcContext.Common["messagesPerField"], "existsError" | "get">;
69
+ profile: {
70
+ attributes: Attribute[];
71
+ html5DataAnnotations?: Record<string, string>;
72
+ };
73
+ passwordRequired?: boolean;
74
+ realm: { registrationEmailAsUsername: boolean };
75
+ passwordPolicies?: PasswordPolicies;
76
+ url: {
77
+ resourcesPath: string;
78
+ };
79
+ };
80
+
81
+ export type ParamsOfUseUserProfileForm = {
82
+ kcContext: KcContextLike;
83
+ i18n: I18n;
84
+ doMakeUserConfirmPassword: boolean;
85
+ };
86
+
87
+ export type ReturnTypeOfUseUserProfileForm = {
88
+ formState: FormState;
89
+ dispatchFormAction: Dispatch<FormAction>;
90
+ };
91
+
92
+ namespace internal {
93
+ export type FormFieldState = {
94
+ attribute: Attribute;
95
+ errors: FormFieldError[];
96
+ hasLostFocusAtLeastOnce: boolean | boolean[];
97
+ valueOrValues: string | string[];
98
+ };
99
+
100
+ export type State = {
101
+ formFieldStates: FormFieldState[];
102
+ };
103
+ }
104
+
105
+ const { useInsertScriptTags } = createUseInsertScriptTags();
106
+
107
+ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTypeOfUseUserProfileForm {
108
+ const { kcContext, i18n, doMakeUserConfirmPassword } = params;
109
+
110
+ const { insertScriptTags } = useInsertScriptTags({
111
+ "scriptTags": Object.keys(kcContext.profile?.html5DataAnnotations ?? {})
112
+ .filter(key => key !== "kcMultivalued" && key !== "kcNumberFormat") // NOTE: Keycloakify handles it.
113
+ .map(key => ({
114
+ "type": "module",
115
+ "src": `${kcContext.url.resourcesPath}/js/${key}.js`
116
+ }))
117
+ });
118
+
119
+ useEffect(() => {
120
+ insertScriptTags();
121
+ }, []);
122
+
123
+ const { getErrors } = useGetErrors({
124
+ kcContext,
125
+ i18n
126
+ });
127
+
128
+ const initialState = useMemo((): internal.State => {
129
+ // NOTE: We don't use te kcContext.profile.attributes directly because
130
+ // they don't includes the password and password confirm fields and we want to add them.
131
+ // Also, we want to polyfill the attributes for older Keycloak version before User Profile was introduced.
132
+ // Finally we want to patch the changes made by Keycloak on the attributes format so we have an homogeneous
133
+ // attributes format to work with.
134
+ const syntheticAttributes = (() => {
135
+ const syntheticAttributes: Attribute[] = [];
136
+
137
+ const attributes = (() => {
138
+ retrocompat_patch: {
139
+ if ("profile" in kcContext && "attributes" in kcContext.profile && kcContext.profile.attributes.length !== 0) {
140
+ break retrocompat_patch;
141
+ }
142
+
143
+ if ("register" in kcContext && kcContext.register instanceof Object && "formData" in kcContext.register) {
144
+ //NOTE: Handle legacy register.ftl page
145
+ return (["firstName", "lastName", "email", "username"] as const)
146
+ .filter(name => (name !== "username" ? true : !kcContext.realm.registrationEmailAsUsername))
147
+ .map(name =>
148
+ id<Attribute>({
149
+ "name": name,
150
+ "displayName": id<`\${${MessageKey}}`>(`\${${name}}`),
151
+ "required": true,
152
+ "value": (kcContext.register as any).formData[name] ?? "",
153
+ "html5DataAnnotations": {},
154
+ "readOnly": false,
155
+ "validators": {},
156
+ "annotations": {},
157
+ "autocomplete": (() => {
158
+ switch (name) {
159
+ case "email":
160
+ return "email";
161
+ case "username":
162
+ return "username";
163
+ default:
164
+ return undefined;
165
+ }
166
+ })()
167
+ })
168
+ );
169
+ }
170
+
171
+ if ("user" in kcContext && kcContext.user instanceof Object) {
172
+ //NOTE: Handle legacy login-update-profile.ftl
173
+ return (["username", "email", "firstName", "lastName"] as const)
174
+ .filter(name => (name !== "username" ? true : (kcContext.user as any).editUsernameAllowed))
175
+ .map(name =>
176
+ id<Attribute>({
177
+ "name": name,
178
+ "displayName": id<`\${${MessageKey}}`>(`\${${name}}`),
179
+ "required": true,
180
+ "value": (kcContext as any).user[name] ?? "",
181
+ "html5DataAnnotations": {},
182
+ "readOnly": false,
183
+ "validators": {},
184
+ "annotations": {},
185
+ "autocomplete": (() => {
186
+ switch (name) {
187
+ case "email":
188
+ return "email";
189
+ case "username":
190
+ return "username";
191
+ default:
192
+ return undefined;
193
+ }
194
+ })()
195
+ })
196
+ );
197
+ }
198
+
199
+ if ("email" in kcContext && kcContext.email instanceof Object) {
200
+ //NOTE: Handle legacy update-email.ftl
201
+ return [
202
+ id<Attribute>({
203
+ "name": "email",
204
+ "displayName": id<`\${${MessageKey}}`>(`\${email}`),
205
+ "required": true,
206
+ "value": (kcContext.email as any).value ?? "",
207
+ "html5DataAnnotations": {},
208
+ "readOnly": false,
209
+ "validators": {},
210
+ "annotations": {},
211
+ "autocomplete": "email"
212
+ })
213
+ ];
214
+ }
215
+
216
+ assert(false, "Unable to mock user profile from the current kcContext");
217
+ }
218
+
219
+ return kcContext.profile.attributes.map(attribute_pre_group_patch => {
220
+ if (typeof attribute_pre_group_patch.group === "string" && attribute_pre_group_patch.group !== "") {
221
+ const { group, groupDisplayHeader, groupDisplayDescription, groupAnnotations, ...rest } =
222
+ attribute_pre_group_patch as Attribute & {
223
+ group: string;
224
+ groupDisplayHeader?: string;
225
+ groupDisplayDescription?: string;
226
+ groupAnnotations: Record<string, string>;
227
+ };
228
+
229
+ return id<Attribute>({
230
+ ...rest,
231
+ "group": {
232
+ "name": group,
233
+ "displayHeader": groupDisplayHeader,
234
+ "displayDescription": groupDisplayDescription,
235
+ "html5DataAnnotations": {}
236
+ }
237
+ });
238
+ }
239
+
240
+ return attribute_pre_group_patch;
241
+ });
242
+ })();
243
+
244
+ for (const attribute of attributes) {
245
+ syntheticAttributes.push(attribute);
246
+
247
+ add_password_and_password_confirm: {
248
+ if (!kcContext.passwordRequired) {
249
+ break add_password_and_password_confirm;
250
+ }
251
+
252
+ if (attribute.name !== (kcContext.realm.registrationEmailAsUsername ? "email" : "username")) {
253
+ // NOTE: We want to add password and password-confirm after the field that identifies the user.
254
+ // It's either email or username.
255
+ break add_password_and_password_confirm;
256
+ }
257
+
258
+ syntheticAttributes.push(
259
+ {
260
+ "name": "password",
261
+ "displayName": id<`\${${MessageKey}}`>("${password}"),
262
+ "required": true,
263
+ "readOnly": false,
264
+ "validators": {},
265
+ "annotations": {},
266
+ "autocomplete": "new-password",
267
+ "html5DataAnnotations": {},
268
+ // NOTE: Compat with Keycloak version prior to 24
269
+ ...({ "groupAnnotations": {} } as {})
270
+ },
271
+ {
272
+ "name": "password-confirm",
273
+ "displayName": id<`\${${MessageKey}}`>("${passwordConfirm}"),
274
+ "required": true,
275
+ "readOnly": false,
276
+ "validators": {},
277
+ "annotations": {},
278
+ "html5DataAnnotations": {},
279
+ "autocomplete": "new-password",
280
+ // NOTE: Compat with Keycloak version prior to 24
281
+ ...({ "groupAnnotations": {} } as {})
282
+ }
283
+ );
284
+ }
285
+ }
286
+
287
+ return syntheticAttributes;
288
+ })();
289
+
290
+ const initialFormFieldState = (() => {
291
+ const out: { attribute: Attribute; valueOrValues: string | string[] }[] = [];
292
+
293
+ for (const attribute of syntheticAttributes) {
294
+ handle_multi_valued_attribute: {
295
+ if (!attribute.multivalued) {
296
+ break handle_multi_valued_attribute;
297
+ }
298
+
299
+ const values = attribute.values ?? [""];
300
+
301
+ apply_validator_min_range: {
302
+ if (attribute.annotations.inputType?.startsWith("multiselect")) {
303
+ break apply_validator_min_range;
304
+ }
305
+
306
+ const validator = attribute.validators.multivalued;
307
+
308
+ if (validator === undefined) {
309
+ break apply_validator_min_range;
310
+ }
311
+
312
+ const { min: minStr } = validator;
313
+
314
+ if (minStr === undefined) {
315
+ break apply_validator_min_range;
316
+ }
317
+
318
+ const min = parseInt(`${minStr}`);
319
+
320
+ for (let index = values.length; index < min; index++) {
321
+ values.push("");
322
+ }
323
+ }
324
+
325
+ out.push({
326
+ attribute,
327
+ "valueOrValues": values
328
+ });
329
+
330
+ continue;
331
+ }
332
+
333
+ out.push({
334
+ attribute,
335
+ "valueOrValues": attribute.value ?? ""
336
+ });
337
+ }
338
+
339
+ return out;
340
+ })();
341
+
342
+ const initialState: internal.State = {
343
+ "formFieldStates": initialFormFieldState.map(({ attribute, valueOrValues }) => ({
344
+ attribute,
345
+ "errors": getErrors({
346
+ "attributeName": attribute.name,
347
+ "formFieldStates": initialFormFieldState
348
+ }),
349
+ "hasLostFocusAtLeastOnce": valueOrValues instanceof Array ? valueOrValues.map(() => false) : false,
350
+ "valueOrValues": valueOrValues
351
+ }))
352
+ };
353
+
354
+ return initialState;
355
+ }, []);
356
+
357
+ const [state, dispatchFormAction] = useReducer(function reducer(state: internal.State, params: FormAction): internal.State {
358
+ const formFieldState = state.formFieldStates.find(({ attribute }) => attribute.name === params.name);
359
+
360
+ assert(formFieldState !== undefined);
361
+
362
+ (() => {
363
+ switch (params.action) {
364
+ case "update":
365
+ formFieldState.valueOrValues = params.valueOrValues;
366
+
367
+ apply_formatters: {
368
+ const { attribute } = formFieldState;
369
+
370
+ const { kcNumberFormat } = attribute.html5DataAnnotations ?? {};
371
+
372
+ if (kcNumberFormat === undefined) {
373
+ break apply_formatters;
374
+ }
375
+
376
+ if (formFieldState.valueOrValues instanceof Array) {
377
+ formFieldState.valueOrValues = formFieldState.valueOrValues.map(value => formatNumber(value, kcNumberFormat));
378
+ } else {
379
+ formFieldState.valueOrValues = formatNumber(formFieldState.valueOrValues, kcNumberFormat);
380
+ }
381
+ }
382
+
383
+ formFieldState.errors = getErrors({
384
+ "attributeName": params.name,
385
+ "formFieldStates": state.formFieldStates
386
+ });
387
+
388
+ update_password_confirm: {
389
+ if (doMakeUserConfirmPassword) {
390
+ break update_password_confirm;
391
+ }
392
+
393
+ if (params.name !== "password") {
394
+ break update_password_confirm;
395
+ }
396
+
397
+ state = reducer(state, {
398
+ "action": "update",
399
+ "name": "password-confirm",
400
+ "valueOrValues": params.valueOrValues
401
+ });
402
+ }
403
+
404
+ return;
405
+ case "focus lost":
406
+ if (formFieldState.hasLostFocusAtLeastOnce instanceof Array) {
407
+ const { fieldIndex } = params;
408
+ assert(fieldIndex !== undefined);
409
+ formFieldState.hasLostFocusAtLeastOnce[fieldIndex] = true;
410
+ return;
411
+ }
412
+
413
+ formFieldState.hasLostFocusAtLeastOnce = true;
414
+ return;
415
+ }
416
+ assert<Equals<typeof params, never>>(false);
417
+ })();
418
+
419
+ return state;
420
+ }, initialState);
421
+
422
+ const formState: FormState = useMemo(
423
+ () => ({
424
+ "formFieldStates": state.formFieldStates.map(
425
+ ({ errors, hasLostFocusAtLeastOnce: hasLostFocusAtLeastOnceOrArr, attribute, ...valueOrValuesWrap }) => ({
426
+ "displayableErrors": errors.filter(error => {
427
+ const hasLostFocusAtLeastOnce =
428
+ typeof hasLostFocusAtLeastOnceOrArr === "boolean"
429
+ ? hasLostFocusAtLeastOnceOrArr
430
+ : error.fieldIndex !== undefined
431
+ ? hasLostFocusAtLeastOnceOrArr[error.fieldIndex]
432
+ : hasLostFocusAtLeastOnceOrArr[hasLostFocusAtLeastOnceOrArr.length - 1];
433
+
434
+ switch (error.source.type) {
435
+ case "server":
436
+ return true;
437
+ case "other":
438
+ switch (error.source.rule) {
439
+ case "requiredField":
440
+ return hasLostFocusAtLeastOnce;
441
+ case "passwordConfirmMatchesPassword":
442
+ return hasLostFocusAtLeastOnce;
443
+ }
444
+ assert<Equals<typeof error.source.rule, never>>(false);
445
+ case "passwordPolicy":
446
+ switch (error.source.name) {
447
+ case "length":
448
+ return hasLostFocusAtLeastOnce;
449
+ case "digits":
450
+ return hasLostFocusAtLeastOnce;
451
+ case "lowerCase":
452
+ return hasLostFocusAtLeastOnce;
453
+ case "upperCase":
454
+ return hasLostFocusAtLeastOnce;
455
+ case "specialChars":
456
+ return hasLostFocusAtLeastOnce;
457
+ case "notUsername":
458
+ return true;
459
+ case "notEmail":
460
+ return true;
461
+ }
462
+ assert<Equals<typeof error.source, never>>(false);
463
+ case "validator":
464
+ switch (error.source.name) {
465
+ case "length":
466
+ return hasLostFocusAtLeastOnce;
467
+ case "pattern":
468
+ return hasLostFocusAtLeastOnce;
469
+ case "email":
470
+ return hasLostFocusAtLeastOnce;
471
+ case "integer":
472
+ return hasLostFocusAtLeastOnce;
473
+ case "multivalued":
474
+ return hasLostFocusAtLeastOnce;
475
+ case "options":
476
+ return hasLostFocusAtLeastOnce;
477
+ }
478
+ assert<Equals<typeof error.source, never>>(false);
479
+ }
480
+ }),
481
+ attribute,
482
+ ...valueOrValuesWrap
483
+ })
484
+ ),
485
+ "isFormSubmittable": state.formFieldStates.every(({ errors }) => errors.length === 0)
486
+ }),
487
+ [state]
488
+ );
489
+
490
+ return {
491
+ formState,
492
+ dispatchFormAction
493
+ };
494
+ }
495
+
496
+ function useGetErrors(params: { kcContext: Pick<KcContextLike, "messagesPerField" | "passwordPolicies">; i18n: I18n }) {
497
+ const { kcContext, i18n } = params;
498
+
499
+ const { messagesPerField, passwordPolicies } = kcContext;
500
+
501
+ const { msg, msgStr, advancedMsg, advancedMsgStr } = i18n;
502
+
503
+ const getErrors = useConstCallback(
504
+ (params: { attributeName: string; formFieldStates: { attribute: Attribute; valueOrValues: string | string[] }[] }): FormFieldError[] => {
505
+ const { attributeName, formFieldStates } = params;
506
+
507
+ const formFieldState = formFieldStates.find(({ attribute }) => attribute.name === attributeName);
508
+
509
+ assert(formFieldState !== undefined);
510
+
511
+ const { attribute } = formFieldState;
512
+
513
+ const valueOrValues = (() => {
514
+ let { valueOrValues } = formFieldState;
515
+
516
+ unFormat_number: {
517
+ const { kcNumberUnFormat } = attribute.html5DataAnnotations ?? {};
518
+
519
+ if (kcNumberUnFormat === undefined) {
520
+ break unFormat_number;
521
+ }
522
+
523
+ if (valueOrValues instanceof Array) {
524
+ valueOrValues = valueOrValues.map(value => formatNumber(value, kcNumberUnFormat));
525
+ } else {
526
+ valueOrValues = formatNumber(valueOrValues, kcNumberUnFormat);
527
+ }
528
+ }
529
+
530
+ return valueOrValues;
531
+ })();
532
+
533
+ assert(attribute !== undefined);
534
+
535
+ server_side_error: {
536
+ if (attribute.multivalued) {
537
+ const defaultValues = attribute.values ?? [""];
538
+
539
+ assert(valueOrValues instanceof Array);
540
+
541
+ const values = valueOrValues;
542
+
543
+ if (JSON.stringify(defaultValues) !== JSON.stringify(values.slice(0, defaultValues.length))) {
544
+ break server_side_error;
545
+ }
546
+ } else {
547
+ const defaultValue = attribute.value ?? "";
548
+
549
+ assert(typeof valueOrValues === "string");
550
+
551
+ const value = valueOrValues;
552
+
553
+ if (defaultValue !== value) {
554
+ break server_side_error;
555
+ }
556
+ }
557
+
558
+ let doesErrorExist: boolean;
559
+
560
+ try {
561
+ doesErrorExist = messagesPerField.existsError(attributeName);
562
+ } catch {
563
+ break server_side_error;
564
+ }
565
+
566
+ if (!doesErrorExist) {
567
+ break server_side_error;
568
+ }
569
+
570
+ const errorMessageStr = messagesPerField.get(attributeName);
571
+
572
+ return [
573
+ {
574
+ errorMessageStr,
575
+ "errorMessage": <span key={0}>{errorMessageStr}</span>,
576
+ "fieldIndex": undefined,
577
+ "source": {
578
+ "type": "server"
579
+ }
580
+ }
581
+ ];
582
+ }
583
+
584
+ handle_multi_valued_multi_fields: {
585
+ if (!attribute.multivalued) {
586
+ break handle_multi_valued_multi_fields;
587
+ }
588
+
589
+ if (attribute.annotations.inputType?.startsWith("multiselect")) {
590
+ break handle_multi_valued_multi_fields;
591
+ }
592
+
593
+ assert(valueOrValues instanceof Array);
594
+
595
+ const values = valueOrValues;
596
+
597
+ const errors = values
598
+ .map((...[, index]) => {
599
+ const specificValueErrors = getErrors({
600
+ attributeName,
601
+ "formFieldStates": formFieldStates.map(formFieldState => {
602
+ if (formFieldState.attribute.name === attributeName) {
603
+ assert(formFieldState.valueOrValues instanceof Array);
604
+ return {
605
+ "attribute": {
606
+ ...attribute,
607
+ "annotations": {
608
+ ...attribute.annotations,
609
+ "inputType": undefined
610
+ },
611
+ "multivalued": false
612
+ },
613
+ "valueOrValues": formFieldState.valueOrValues[index]
614
+ };
615
+ }
616
+
617
+ return formFieldState;
618
+ })
619
+ });
620
+
621
+ return specificValueErrors
622
+ .filter(error => {
623
+ if (error.source.type === "other" && error.source.rule === "requiredField") {
624
+ return false;
625
+ }
626
+
627
+ return true;
628
+ })
629
+ .map((error): FormFieldError => ({ ...error, "fieldIndex": index }));
630
+ })
631
+ .reduce((acc, errors) => [...acc, ...errors], []);
632
+
633
+ required_field: {
634
+ if (!attribute.required) {
635
+ break required_field;
636
+ }
637
+
638
+ if (values.every(value => value !== "")) {
639
+ break required_field;
640
+ }
641
+
642
+ const msgArgs = ["error-user-attribute-required"] as const;
643
+
644
+ errors.push({
645
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
646
+ "errorMessageStr": msgStr(...msgArgs),
647
+ "fieldIndex": undefined,
648
+ "source": {
649
+ "type": "other",
650
+ "rule": "requiredField"
651
+ }
652
+ });
653
+ }
654
+
655
+ return errors;
656
+ }
657
+
658
+ handle_multi_valued_single_field: {
659
+ if (!attribute.multivalued) {
660
+ break handle_multi_valued_single_field;
661
+ }
662
+
663
+ if (!attribute.annotations.inputType?.startsWith("multiselect")) {
664
+ break handle_multi_valued_single_field;
665
+ }
666
+
667
+ const validatorName = "multivalued";
668
+
669
+ const validator = attribute.validators[validatorName];
670
+
671
+ if (validator === undefined) {
672
+ return [];
673
+ }
674
+
675
+ const { min: minStr } = validator;
676
+
677
+ const min = minStr !== undefined ? parseInt(`${minStr}`) : attribute.required ? 1 : 0;
678
+
679
+ assert(!isNaN(min));
680
+
681
+ const { max: maxStr } = validator;
682
+
683
+ const max = maxStr === undefined ? Infinity : parseInt(`${maxStr}`);
684
+
685
+ assert(!isNaN(max));
686
+
687
+ assert(valueOrValues instanceof Array);
688
+
689
+ const values = valueOrValues;
690
+
691
+ if (min <= values.length && values.length <= max) {
692
+ return [];
693
+ }
694
+
695
+ const msgArgs = ["error-invalid-multivalued-size", `${min}`, `${max}`] as const;
696
+
697
+ return [
698
+ {
699
+ "errorMessage": <Fragment key={0}>{msg(...msgArgs)}</Fragment>,
700
+ "errorMessageStr": msgStr(...msgArgs),
701
+ "fieldIndex": undefined,
702
+ "source": {
703
+ "type": "validator",
704
+ "name": validatorName
705
+ }
706
+ }
707
+ ];
708
+ }
709
+
710
+ assert(typeof valueOrValues === "string");
711
+
712
+ const value = valueOrValues;
713
+
714
+ const errors: FormFieldError[] = [];
715
+
716
+ check_password_policies: {
717
+ if (attributeName !== "password") {
718
+ break check_password_policies;
719
+ }
720
+
721
+ if (passwordPolicies === undefined) {
722
+ break check_password_policies;
723
+ }
724
+
725
+ check_password_policy_x: {
726
+ const policyName = "length";
727
+
728
+ const policy = passwordPolicies[policyName];
729
+
730
+ if (policy === undefined) {
731
+ break check_password_policy_x;
732
+ }
733
+
734
+ const minLength = policy;
735
+
736
+ if (value.length >= minLength) {
737
+ break check_password_policy_x;
738
+ }
739
+
740
+ const msgArgs = ["invalidPasswordMinLengthMessage", `${minLength}`] as const;
741
+
742
+ errors.push({
743
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
744
+ "errorMessageStr": msgStr(...msgArgs),
745
+ "fieldIndex": undefined,
746
+ "source": {
747
+ "type": "passwordPolicy",
748
+ "name": policyName
749
+ }
750
+ });
751
+ }
752
+
753
+ check_password_policy_x: {
754
+ const policyName = "digits";
755
+
756
+ const policy = passwordPolicies[policyName];
757
+
758
+ if (policy === undefined) {
759
+ break check_password_policy_x;
760
+ }
761
+
762
+ const minNumberOfDigits = policy;
763
+
764
+ if (value.split("").filter(char => !isNaN(parseInt(char))).length >= minNumberOfDigits) {
765
+ break check_password_policy_x;
766
+ }
767
+
768
+ const msgArgs = ["invalidPasswordMinDigitsMessage", `${minNumberOfDigits}`] as const;
769
+
770
+ errors.push({
771
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
772
+ "errorMessageStr": msgStr(...msgArgs),
773
+ "fieldIndex": undefined,
774
+ "source": {
775
+ "type": "passwordPolicy",
776
+ "name": policyName
777
+ }
778
+ });
779
+ }
780
+
781
+ check_password_policy_x: {
782
+ const policyName = "lowerCase";
783
+
784
+ const policy = passwordPolicies[policyName];
785
+
786
+ if (policy === undefined) {
787
+ break check_password_policy_x;
788
+ }
789
+
790
+ const minNumberOfLowerCaseChar = policy;
791
+
792
+ if (
793
+ value.split("").filter(char => char === char.toLowerCase() && char !== char.toUpperCase()).length >= minNumberOfLowerCaseChar
794
+ ) {
795
+ break check_password_policy_x;
796
+ }
797
+
798
+ const msgArgs = ["invalidPasswordMinLowerCaseCharsMessage", `${minNumberOfLowerCaseChar}`] as const;
799
+
800
+ errors.push({
801
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
802
+ "errorMessageStr": msgStr(...msgArgs),
803
+ "fieldIndex": undefined,
804
+ "source": {
805
+ "type": "passwordPolicy",
806
+ "name": policyName
807
+ }
808
+ });
809
+ }
810
+
811
+ check_password_policy_x: {
812
+ const policyName = "upperCase";
813
+
814
+ const policy = passwordPolicies[policyName];
815
+
816
+ if (policy === undefined) {
817
+ break check_password_policy_x;
818
+ }
819
+
820
+ const minNumberOfUpperCaseChar = policy;
821
+
822
+ if (
823
+ value.split("").filter(char => char === char.toUpperCase() && char !== char.toLowerCase()).length >= minNumberOfUpperCaseChar
824
+ ) {
825
+ break check_password_policy_x;
826
+ }
827
+
828
+ const msgArgs = ["invalidPasswordMinUpperCaseCharsMessage", `${minNumberOfUpperCaseChar}`] as const;
829
+
830
+ errors.push({
831
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
832
+ "errorMessageStr": msgStr(...msgArgs),
833
+ "fieldIndex": undefined,
834
+ "source": {
835
+ "type": "passwordPolicy",
836
+ "name": policyName
837
+ }
838
+ });
839
+ }
840
+
841
+ check_password_policy_x: {
842
+ const policyName = "specialChars";
843
+
844
+ const policy = passwordPolicies[policyName];
845
+
846
+ if (policy === undefined) {
847
+ break check_password_policy_x;
848
+ }
849
+
850
+ const minNumberOfSpecialChar = policy;
851
+
852
+ if (value.split("").filter(char => !char.match(/[a-zA-Z0-9]/)).length >= minNumberOfSpecialChar) {
853
+ break check_password_policy_x;
854
+ }
855
+
856
+ const msgArgs = ["invalidPasswordMinSpecialCharsMessage", `${minNumberOfSpecialChar}`] as const;
857
+
858
+ errors.push({
859
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
860
+ "errorMessageStr": msgStr(...msgArgs),
861
+ "fieldIndex": undefined,
862
+ "source": {
863
+ "type": "passwordPolicy",
864
+ "name": policyName
865
+ }
866
+ });
867
+ }
868
+
869
+ check_password_policy_x: {
870
+ const policyName = "notUsername";
871
+
872
+ const notUsername = passwordPolicies[policyName];
873
+
874
+ if (!notUsername) {
875
+ break check_password_policy_x;
876
+ }
877
+
878
+ const usernameFormFieldState = formFieldStates.find(formFieldState => formFieldState.attribute.name === "username");
879
+
880
+ if (usernameFormFieldState === undefined) {
881
+ break check_password_policy_x;
882
+ }
883
+
884
+ const usernameValue = (() => {
885
+ let { valueOrValues } = usernameFormFieldState;
886
+
887
+ assert(typeof valueOrValues === "string");
888
+
889
+ unFormat_number: {
890
+ const { kcNumberUnFormat } = attribute.html5DataAnnotations ?? {};
891
+
892
+ if (kcNumberUnFormat === undefined) {
893
+ break unFormat_number;
894
+ }
895
+
896
+ valueOrValues = formatNumber(valueOrValues, kcNumberUnFormat);
897
+ }
898
+
899
+ return valueOrValues;
900
+ })();
901
+
902
+ if (value !== usernameValue) {
903
+ break check_password_policy_x;
904
+ }
905
+
906
+ const msgArgs = ["invalidPasswordNotUsernameMessage"] as const;
907
+
908
+ errors.push({
909
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
910
+ "errorMessageStr": msgStr(...msgArgs),
911
+ "fieldIndex": undefined,
912
+ "source": {
913
+ "type": "passwordPolicy",
914
+ "name": policyName
915
+ }
916
+ });
917
+ }
918
+
919
+ check_password_policy_x: {
920
+ const policyName = "notEmail";
921
+
922
+ const notEmail = passwordPolicies[policyName];
923
+
924
+ if (!notEmail) {
925
+ break check_password_policy_x;
926
+ }
927
+
928
+ const emailFormFieldState = formFieldStates.find(formFieldState => formFieldState.attribute.name === "email");
929
+
930
+ if (emailFormFieldState === undefined) {
931
+ break check_password_policy_x;
932
+ }
933
+
934
+ assert(typeof emailFormFieldState.valueOrValues === "string");
935
+
936
+ {
937
+ const emailValue = emailFormFieldState.valueOrValues;
938
+
939
+ if (value !== emailValue) {
940
+ break check_password_policy_x;
941
+ }
942
+ }
943
+
944
+ const msgArgs = ["invalidPasswordNotEmailMessage"] as const;
945
+
946
+ errors.push({
947
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
948
+ "errorMessageStr": msgStr(...msgArgs),
949
+ "fieldIndex": undefined,
950
+ "source": {
951
+ "type": "passwordPolicy",
952
+ "name": policyName
953
+ }
954
+ });
955
+ }
956
+ }
957
+
958
+ password_confirm_matches_password: {
959
+ if (attributeName !== "password-confirm") {
960
+ break password_confirm_matches_password;
961
+ }
962
+
963
+ const passwordFormFieldState = formFieldStates.find(formFieldState => formFieldState.attribute.name === "password");
964
+
965
+ assert(passwordFormFieldState !== undefined);
966
+
967
+ assert(typeof passwordFormFieldState.valueOrValues === "string");
968
+
969
+ {
970
+ const passwordValue = passwordFormFieldState.valueOrValues;
971
+
972
+ if (value === passwordValue) {
973
+ break password_confirm_matches_password;
974
+ }
975
+ }
976
+
977
+ const msgArgs = ["invalidPasswordConfirmMessage"] as const;
978
+
979
+ errors.push({
980
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
981
+ "errorMessageStr": msgStr(...msgArgs),
982
+ "fieldIndex": undefined,
983
+ "source": {
984
+ "type": "other",
985
+ "rule": "passwordConfirmMatchesPassword"
986
+ }
987
+ });
988
+ }
989
+
990
+ const { validators } = attribute;
991
+
992
+ required_field: {
993
+ if (!attribute.required) {
994
+ break required_field;
995
+ }
996
+
997
+ if (value !== "") {
998
+ break required_field;
999
+ }
1000
+
1001
+ const msgArgs = ["error-user-attribute-required"] as const;
1002
+
1003
+ errors.push({
1004
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
1005
+ "errorMessageStr": msgStr(...msgArgs),
1006
+ "fieldIndex": undefined,
1007
+ "source": {
1008
+ "type": "other",
1009
+ "rule": "requiredField"
1010
+ }
1011
+ });
1012
+ }
1013
+
1014
+ validator_x: {
1015
+ const validatorName = "length";
1016
+
1017
+ const validator = validators[validatorName];
1018
+
1019
+ if (validator === undefined) {
1020
+ break validator_x;
1021
+ }
1022
+
1023
+ const { "ignore.empty.value": ignoreEmptyValue = false, max, min } = validator;
1024
+
1025
+ if (ignoreEmptyValue && value === "") {
1026
+ break validator_x;
1027
+ }
1028
+
1029
+ const source: FormFieldError.Source = {
1030
+ "type": "validator",
1031
+ "name": validatorName
1032
+ };
1033
+
1034
+ if (max !== undefined && value.length > parseInt(`${max}`)) {
1035
+ const msgArgs = ["error-invalid-length-too-long", `${max}`] as const;
1036
+
1037
+ errors.push({
1038
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
1039
+ "errorMessageStr": msgStr(...msgArgs),
1040
+ "fieldIndex": undefined,
1041
+ source
1042
+ });
1043
+ }
1044
+
1045
+ if (min !== undefined && value.length < parseInt(`${min}`)) {
1046
+ const msgArgs = ["error-invalid-length-too-short", `${min}`] as const;
1047
+
1048
+ errors.push({
1049
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
1050
+ "errorMessageStr": msgStr(...msgArgs),
1051
+ "fieldIndex": undefined,
1052
+ source
1053
+ });
1054
+ }
1055
+ }
1056
+
1057
+ validator_x: {
1058
+ const validatorName = "pattern";
1059
+
1060
+ const validator = validators[validatorName];
1061
+
1062
+ if (validator === undefined) {
1063
+ break validator_x;
1064
+ }
1065
+
1066
+ const { "ignore.empty.value": ignoreEmptyValue = false, pattern, "error-message": errorMessageKey } = validator;
1067
+
1068
+ if (ignoreEmptyValue && value === "") {
1069
+ break validator_x;
1070
+ }
1071
+
1072
+ if (new RegExp(pattern).test(value)) {
1073
+ break validator_x;
1074
+ }
1075
+
1076
+ const msgArgs = [errorMessageKey ?? id<MessageKey>("shouldMatchPattern"), pattern] as const;
1077
+
1078
+ errors.push({
1079
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{advancedMsg(...msgArgs)}</Fragment>,
1080
+ "errorMessageStr": advancedMsgStr(...msgArgs),
1081
+ "fieldIndex": undefined,
1082
+ "source": {
1083
+ "type": "validator",
1084
+ "name": validatorName
1085
+ }
1086
+ });
1087
+ }
1088
+
1089
+ validator_x: {
1090
+ {
1091
+ const lastError = errors[errors.length - 1];
1092
+ if (lastError !== undefined && lastError.source.type === "validator" && lastError.source.name === "pattern") {
1093
+ break validator_x;
1094
+ }
1095
+ }
1096
+
1097
+ const validatorName = "email";
1098
+
1099
+ const validator = validators[validatorName];
1100
+
1101
+ if (validator === undefined) {
1102
+ break validator_x;
1103
+ }
1104
+
1105
+ const { "ignore.empty.value": ignoreEmptyValue = false } = validator;
1106
+
1107
+ if (ignoreEmptyValue && value === "") {
1108
+ break validator_x;
1109
+ }
1110
+
1111
+ if (emailRegexp.test(value)) {
1112
+ break validator_x;
1113
+ }
1114
+
1115
+ const msgArgs = [id<MessageKey>("invalidEmailMessage")] as const;
1116
+
1117
+ errors.push({
1118
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
1119
+ "errorMessageStr": msgStr(...msgArgs),
1120
+ "fieldIndex": undefined,
1121
+ "source": {
1122
+ "type": "validator",
1123
+ "name": validatorName
1124
+ }
1125
+ });
1126
+ }
1127
+
1128
+ validator_x: {
1129
+ const validatorName = "integer";
1130
+
1131
+ const validator = validators[validatorName];
1132
+
1133
+ if (validator === undefined) {
1134
+ break validator_x;
1135
+ }
1136
+
1137
+ const { "ignore.empty.value": ignoreEmptyValue = false, max, min } = validator;
1138
+
1139
+ if (ignoreEmptyValue && value === "") {
1140
+ break validator_x;
1141
+ }
1142
+
1143
+ const intValue = parseInt(value);
1144
+
1145
+ const source: FormFieldError.Source = {
1146
+ "type": "validator",
1147
+ "name": validatorName
1148
+ };
1149
+
1150
+ if (isNaN(intValue)) {
1151
+ const msgArgs = ["mustBeAnInteger"] as const;
1152
+
1153
+ errors.push({
1154
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
1155
+ "errorMessageStr": msgStr(...msgArgs),
1156
+ "fieldIndex": undefined,
1157
+ source
1158
+ });
1159
+
1160
+ break validator_x;
1161
+ }
1162
+
1163
+ if (max !== undefined && intValue > parseInt(`${max}`)) {
1164
+ const msgArgs = ["error-number-out-of-range-too-big", `${max}`] as const;
1165
+
1166
+ errors.push({
1167
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
1168
+ "errorMessageStr": msgStr(...msgArgs),
1169
+ "fieldIndex": undefined,
1170
+ source
1171
+ });
1172
+
1173
+ break validator_x;
1174
+ }
1175
+
1176
+ if (min !== undefined && intValue < parseInt(`${min}`)) {
1177
+ const msgArgs = ["error-number-out-of-range-too-small", `${min}`] as const;
1178
+
1179
+ errors.push({
1180
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{msg(...msgArgs)}</Fragment>,
1181
+ "errorMessageStr": msgStr(...msgArgs),
1182
+ "fieldIndex": undefined,
1183
+ source
1184
+ });
1185
+
1186
+ break validator_x;
1187
+ }
1188
+ }
1189
+
1190
+ validator_x: {
1191
+ const validatorName = "options";
1192
+
1193
+ const validator = validators[validatorName];
1194
+
1195
+ if (validator === undefined) {
1196
+ break validator_x;
1197
+ }
1198
+
1199
+ if (value === "") {
1200
+ break validator_x;
1201
+ }
1202
+
1203
+ if (validator.options.indexOf(value) >= 0) {
1204
+ break validator_x;
1205
+ }
1206
+
1207
+ const msgArgs = [id<MessageKey>("notAValidOption")] as const;
1208
+
1209
+ errors.push({
1210
+ "errorMessage": <Fragment key={`${attributeName}-${errors.length}`}>{advancedMsg(...msgArgs)}</Fragment>,
1211
+ "errorMessageStr": advancedMsgStr(...msgArgs),
1212
+ "fieldIndex": undefined,
1213
+ "source": {
1214
+ "type": "validator",
1215
+ "name": validatorName
1216
+ }
1217
+ });
1218
+ }
1219
+
1220
+ //TODO: Implement missing validators. See Validators type definition.
1221
+
1222
+ return errors;
1223
+ }
1224
+ );
1225
+
1226
+ return { getErrors };
1227
+ }