keycloakify 10.0.0-rc.22 → 10.0.0-rc.24

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 (236) hide show
  1. package/PUBLIC_URL.d.ts +1 -1
  2. package/PUBLIC_URL.js +1 -1
  3. package/PUBLIC_URL.js.map +1 -1
  4. package/account/Fallback.js.map +1 -1
  5. package/account/Template.js +3 -3
  6. package/account/Template.js.map +1 -1
  7. package/account/i18n/baseMessages/index.js.map +1 -1
  8. package/account/i18n/i18n.js.map +1 -1
  9. package/account/index.d.ts +2 -2
  10. package/account/index.js +1 -2
  11. package/account/index.js.map +1 -1
  12. package/account/kcContext/KcContext.d.ts +12 -0
  13. package/account/kcContext/KcContext.js.map +1 -1
  14. package/account/kcContext/getKcContextMock.d.ts +24 -0
  15. package/account/kcContext/getKcContextMock.js +28 -0
  16. package/account/kcContext/getKcContextMock.js.map +1 -0
  17. package/account/kcContext/index.d.ts +2 -1
  18. package/account/kcContext/index.js +1 -1
  19. package/account/kcContext/index.js.map +1 -1
  20. package/account/kcContext/kcContextMocks.js +23 -91
  21. package/account/kcContext/kcContextMocks.js.map +1 -1
  22. package/account/pages/Account.js +1 -1
  23. package/account/pages/Account.js.map +1 -1
  24. package/account/pages/Applications.js +2 -2
  25. package/account/pages/Applications.js.map +1 -1
  26. package/account/pages/FederatedIdentity.js +1 -1
  27. package/account/pages/FederatedIdentity.js.map +1 -1
  28. package/account/pages/Log.js +1 -1
  29. package/account/pages/Log.js.map +1 -1
  30. package/account/pages/Password.js +6 -4
  31. package/account/pages/Password.js.map +1 -1
  32. package/account/pages/Sessions.js +1 -1
  33. package/account/pages/Sessions.js.map +1 -1
  34. package/account/pages/Totp.js +1 -1
  35. package/account/pages/Totp.js.map +1 -1
  36. package/bin/main.js +174 -162
  37. package/lib/BASE_URL.js.map +1 -1
  38. package/login/Fallback.js.map +1 -1
  39. package/login/Template.js +7 -7
  40. package/login/Template.js.map +1 -1
  41. package/login/UserProfileFormFields.js +24 -68
  42. package/login/UserProfileFormFields.js.map +1 -1
  43. package/login/i18n/baseMessages/index.js.map +1 -1
  44. package/login/i18n/i18n.d.ts +1 -1
  45. package/login/i18n/i18n.js +1 -1
  46. package/login/i18n/i18n.js.map +1 -1
  47. package/login/index.d.ts +2 -3
  48. package/login/index.js +1 -2
  49. package/login/index.js.map +1 -1
  50. package/login/kcContext/KcContext.d.ts +23 -13
  51. package/login/kcContext/KcContext.js.map +1 -1
  52. package/login/kcContext/getKcContextMock.d.ts +24 -0
  53. package/login/kcContext/getKcContextMock.js +28 -0
  54. package/login/kcContext/getKcContextMock.js.map +1 -0
  55. package/login/kcContext/index.d.ts +2 -1
  56. package/login/kcContext/index.js +1 -1
  57. package/login/kcContext/index.js.map +1 -1
  58. package/login/kcContext/kcContextMocks.js +29 -103
  59. package/login/kcContext/kcContextMocks.js.map +1 -1
  60. package/login/lib/useDownloadTerms.js +8 -14
  61. package/login/lib/useDownloadTerms.js.map +1 -1
  62. package/login/lib/useGetClassName.js +1 -1
  63. package/login/lib/useGetClassName.js.map +1 -1
  64. package/login/lib/useUserProfileForm.d.ts +9 -1
  65. package/login/lib/useUserProfileForm.js +94 -15
  66. package/login/lib/useUserProfileForm.js.map +1 -1
  67. package/login/pages/Code.js +1 -1
  68. package/login/pages/Code.js.map +1 -1
  69. package/login/pages/DeleteAccountConfirm.js +2 -2
  70. package/login/pages/DeleteAccountConfirm.js.map +1 -1
  71. package/login/pages/DeleteCredential.js +1 -1
  72. package/login/pages/DeleteCredential.js.map +1 -1
  73. package/login/pages/Error.js +1 -1
  74. package/login/pages/Error.js.map +1 -1
  75. package/login/pages/FrontchannelLogout.js +1 -1
  76. package/login/pages/FrontchannelLogout.js.map +1 -1
  77. package/login/pages/IdpReviewUserProfile.js +1 -1
  78. package/login/pages/IdpReviewUserProfile.js.map +1 -1
  79. package/login/pages/Info.js +5 -5
  80. package/login/pages/Info.js.map +1 -1
  81. package/login/pages/Login.js +4 -4
  82. package/login/pages/Login.js.map +1 -1
  83. package/login/pages/LoginConfigTotp.js +2 -2
  84. package/login/pages/LoginConfigTotp.js.map +1 -1
  85. package/login/pages/LoginIdpLinkConfirm.js +1 -1
  86. package/login/pages/LoginIdpLinkConfirm.js.map +1 -1
  87. package/login/pages/LoginIdpLinkEmail.js +1 -1
  88. package/login/pages/LoginIdpLinkEmail.js.map +1 -1
  89. package/login/pages/LoginOauth2DeviceVerifyUserCode.js +1 -1
  90. package/login/pages/LoginOauth2DeviceVerifyUserCode.js.map +1 -1
  91. package/login/pages/LoginOauthGrant.js +2 -2
  92. package/login/pages/LoginOauthGrant.js.map +1 -1
  93. package/login/pages/LoginOtp.js +1 -1
  94. package/login/pages/LoginOtp.js.map +1 -1
  95. package/login/pages/LoginPageExpired.js +1 -1
  96. package/login/pages/LoginPageExpired.js.map +1 -1
  97. package/login/pages/LoginPassword.js +3 -3
  98. package/login/pages/LoginPassword.js.map +1 -1
  99. package/login/pages/LoginRecoveryAuthnCodeConfig.js +10 -10
  100. package/login/pages/LoginRecoveryAuthnCodeConfig.js.map +1 -1
  101. package/login/pages/LoginRecoveryAuthnCodeInput.js +1 -1
  102. package/login/pages/LoginRecoveryAuthnCodeInput.js.map +1 -1
  103. package/login/pages/LoginResetOtp.js +1 -1
  104. package/login/pages/LoginResetOtp.js.map +1 -1
  105. package/login/pages/LoginResetPassword.js +2 -2
  106. package/login/pages/LoginResetPassword.js.map +1 -1
  107. package/login/pages/LoginUpdatePassword.js +3 -3
  108. package/login/pages/LoginUpdatePassword.js.map +1 -1
  109. package/login/pages/LoginUpdateProfile.js +4 -2
  110. package/login/pages/LoginUpdateProfile.js.map +1 -1
  111. package/login/pages/LoginUsername.js +3 -3
  112. package/login/pages/LoginUsername.js.map +1 -1
  113. package/login/pages/LoginVerifyEmail.js +1 -1
  114. package/login/pages/LoginVerifyEmail.js.map +1 -1
  115. package/login/pages/LoginX509Info.js +1 -1
  116. package/login/pages/LoginX509Info.js.map +1 -1
  117. package/login/pages/LogoutConfirm.js +1 -1
  118. package/login/pages/LogoutConfirm.js.map +1 -1
  119. package/login/pages/Register.js +8 -4
  120. package/login/pages/Register.js.map +1 -1
  121. package/login/pages/SamlPostForm.js +1 -1
  122. package/login/pages/SamlPostForm.js.map +1 -1
  123. package/login/pages/SelectAuthenticator.js +2 -2
  124. package/login/pages/SelectAuthenticator.js.map +1 -1
  125. package/login/pages/Terms.js +1 -1
  126. package/login/pages/Terms.js.map +1 -1
  127. package/login/pages/UpdateEmail.js +5 -3
  128. package/login/pages/UpdateEmail.js.map +1 -1
  129. package/login/pages/WebauthnAuthenticate.js +8 -8
  130. package/login/pages/WebauthnAuthenticate.js.map +1 -1
  131. package/login/pages/WebauthnError.js +2 -2
  132. package/login/pages/WebauthnError.js.map +1 -1
  133. package/login/pages/WebauthnRegister.js +5 -5
  134. package/login/pages/WebauthnRegister.js.map +1 -1
  135. package/package.json +26 -38
  136. package/src/PUBLIC_URL.ts +1 -1
  137. package/src/account/Template.tsx +2 -3
  138. package/src/account/index.ts +2 -2
  139. package/src/account/kcContext/KcContext.ts +19 -1
  140. package/src/account/kcContext/getKcContextMock.ts +80 -0
  141. package/src/account/kcContext/index.ts +2 -1
  142. package/src/account/kcContext/kcContextMocks.ts +26 -91
  143. package/src/bin/copy-keycloak-resources-to-public.ts +1 -4
  144. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +19 -11
  145. package/src/bin/start-keycloak/start-keycloak.ts +18 -5
  146. package/src/bin/tools/getNpmWorkspaceRootDirPath.ts +25 -25
  147. package/src/login/Template.tsx +4 -5
  148. package/src/login/UserProfileFormFields.tsx +28 -80
  149. package/src/login/i18n/i18n.tsx +3 -3
  150. package/src/login/index.ts +6 -3
  151. package/src/login/kcContext/KcContext.ts +43 -31
  152. package/src/login/kcContext/getKcContextMock.ts +80 -0
  153. package/src/login/kcContext/index.ts +7 -1
  154. package/src/login/kcContext/kcContextMocks.ts +92 -165
  155. package/src/login/lib/useDownloadTerms.ts +10 -24
  156. package/src/login/lib/useGetClassName.ts +1 -1
  157. package/src/login/lib/useUserProfileForm.tsx +117 -13
  158. package/src/login/pages/LoginConfigTotp.tsx +1 -1
  159. package/src/login/pages/LoginRecoveryAuthnCodeConfig.tsx +7 -8
  160. package/src/login/pages/WebauthnAuthenticate.tsx +2 -3
  161. package/src/login/pages/WebauthnRegister.tsx +2 -3
  162. package/src/tools/ExtractAfterStartingWith.ts +4 -0
  163. package/src/tools/StatefulObservable/hooks/useRerenderOnChange.ts +4 -4
  164. package/src/tools/ValueOf.ts +2 -0
  165. package/src/tools/deepAssign.ts +51 -20
  166. package/src/tools/structuredCloneButFunctions.ts +24 -0
  167. package/src/tools/useInsertLinkTags.ts +78 -87
  168. package/src/tools/useInsertScriptTags.ts +69 -78
  169. package/src/tools/useOnFirstMount.ts +18 -0
  170. package/tools/Array.prototype.every.js.map +1 -1
  171. package/tools/ExtractAfterStartingWith.d.ts +1 -0
  172. package/tools/ExtractAfterStartingWith.js +2 -0
  173. package/tools/ExtractAfterStartingWith.js.map +1 -0
  174. package/tools/HTMLElement.prototype.prepend.js.map +1 -1
  175. package/tools/StatefulObservable/StatefulObservable.js.map +1 -1
  176. package/tools/StatefulObservable/hooks/useRerenderOnChange.d.ts +1 -1
  177. package/tools/StatefulObservable/hooks/useRerenderOnChange.js +4 -4
  178. package/tools/StatefulObservable/hooks/useRerenderOnChange.js.map +1 -1
  179. package/tools/ValueOf.d.ts +2 -0
  180. package/tools/ValueOf.js +2 -0
  181. package/tools/ValueOf.js.map +1 -0
  182. package/tools/clsx.js.map +1 -1
  183. package/tools/deepAssign.d.ts +1 -0
  184. package/tools/deepAssign.js +39 -16
  185. package/tools/deepAssign.js.map +1 -1
  186. package/tools/formatNumber.js.map +1 -1
  187. package/tools/structuredCloneButFunctions.d.ts +7 -0
  188. package/tools/structuredCloneButFunctions.js +19 -0
  189. package/tools/structuredCloneButFunctions.js.map +1 -0
  190. package/tools/useInsertLinkTags.d.ts +11 -6
  191. package/tools/useInsertLinkTags.js +53 -53
  192. package/tools/useInsertLinkTags.js.map +1 -1
  193. package/tools/useInsertScriptTags.d.ts +15 -6
  194. package/tools/useInsertScriptTags.js +56 -64
  195. package/tools/useInsertScriptTags.js.map +1 -1
  196. package/tools/useOnFirstMount.d.ts +2 -0
  197. package/tools/useOnFirstMount.js +15 -0
  198. package/tools/useOnFirstMount.js.map +1 -0
  199. package/tools/useSetClassName.js.map +1 -1
  200. package/vite-plugin/index.js +66 -64
  201. package/account/kcContext/createGetKcContext.d.ts +0 -19
  202. package/account/kcContext/createGetKcContext.js +0 -78
  203. package/account/kcContext/createGetKcContext.js.map +0 -1
  204. package/account/kcContext/getKcContext.d.ts +0 -13
  205. package/account/kcContext/getKcContext.js +0 -13
  206. package/account/kcContext/getKcContext.js.map +0 -1
  207. package/account/kcContext/getKcContextFromWindow.d.ts +0 -10
  208. package/account/kcContext/getKcContextFromWindow.js +0 -5
  209. package/account/kcContext/getKcContextFromWindow.js.map +0 -1
  210. package/login/kcContext/createGetKcContext.d.ts +0 -19
  211. package/login/kcContext/createGetKcContext.js +0 -117
  212. package/login/kcContext/createGetKcContext.js.map +0 -1
  213. package/login/kcContext/getKcContext.d.ts +0 -13
  214. package/login/kcContext/getKcContext.js +0 -13
  215. package/login/kcContext/getKcContext.js.map +0 -1
  216. package/login/kcContext/getKcContextFromWindow.d.ts +0 -10
  217. package/login/kcContext/getKcContextFromWindow.js +0 -5
  218. package/login/kcContext/getKcContextFromWindow.js.map +0 -1
  219. package/src/account/kcContext/createGetKcContext.ts +0 -134
  220. package/src/account/kcContext/getKcContext.ts +0 -23
  221. package/src/account/kcContext/getKcContextFromWindow.ts +0 -15
  222. package/src/login/kcContext/createGetKcContext.ts +0 -206
  223. package/src/login/kcContext/getKcContext.ts +0 -23
  224. package/src/login/kcContext/getKcContextFromWindow.ts +0 -15
  225. package/src/tools/AndByDiscriminatingKey.ts +0 -31
  226. package/src/tools/deepClone.ts +0 -19
  227. package/src/tools/memoize.ts +0 -55
  228. package/tools/AndByDiscriminatingKey.d.ts +0 -5
  229. package/tools/AndByDiscriminatingKey.js +0 -2
  230. package/tools/AndByDiscriminatingKey.js.map +0 -1
  231. package/tools/deepClone.d.ts +0 -2
  232. package/tools/deepClone.js +0 -14
  233. package/tools/deepClone.js.map +0 -1
  234. package/tools/memoize.d.ts +0 -7
  235. package/tools/memoize.js +0 -38
  236. package/tools/memoize.js.map +0 -1
@@ -3,15 +3,12 @@ import { assert } from "keycloakify/tools/assert";
3
3
  import { clsx } from "keycloakify/tools/clsx";
4
4
  import { type TemplateProps } from "keycloakify/login/TemplateProps";
5
5
  import { useGetClassName } from "keycloakify/login/lib/useGetClassName";
6
- import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
7
- import { createUseInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
6
+ import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
7
+ import { useInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
8
8
  import { useSetClassName } from "keycloakify/tools/useSetClassName";
9
9
  import type { KcContext } from "./kcContext";
10
10
  import type { I18n } from "./i18n";
11
11
 
12
- const { useInsertLinkTags } = createUseInsertLinkTags();
13
- const { useInsertScriptTags } = createUseInsertScriptTags();
14
-
15
12
  export default function Template(props: TemplateProps<KcContext, I18n>) {
16
13
  const {
17
14
  displayInfo = false,
@@ -63,6 +60,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
63
60
  }, []);
64
61
 
65
62
  const { areAllStyleSheetsLoaded } = useInsertLinkTags({
63
+ componentOrHookName: "Template",
66
64
  hrefs: !doUseDefaultCss
67
65
  ? []
68
66
  : [
@@ -75,6 +73,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
75
73
  });
76
74
 
77
75
  const { insertScriptTags } = useInsertScriptTags({
76
+ componentOrHookName: "Template",
78
77
  scriptTags: [
79
78
  {
80
79
  type: "module",
@@ -1,6 +1,12 @@
1
1
  import { useEffect, useReducer, Fragment } from "react";
2
2
  import type { ClassKey } from "keycloakify/login/TemplateProps";
3
- import { useUserProfileForm, type KcContextLike, type FormAction, type FormFieldError } from "keycloakify/login/lib/useUserProfileForm";
3
+ import {
4
+ useUserProfileForm,
5
+ getButtonToDisplayForMultivaluedAttributeField,
6
+ type KcContextLike,
7
+ type FormAction,
8
+ type FormFieldError
9
+ } from "keycloakify/login/lib/useUserProfileForm";
4
10
  import type { Attribute } from "keycloakify/login/kcContext/KcContext";
5
11
  import { assert } from "tsafe/assert";
6
12
  import type { I18n } from "./i18n";
@@ -413,92 +419,34 @@ function AddRemoveButtonsMultiValuedAttribute(props: {
413
419
 
414
420
  const { msg } = i18n;
415
421
 
416
- const hasRemove = (() => {
417
- if (values.length === 1) {
418
- return false;
419
- }
420
-
421
- const minCount = (() => {
422
- const { multivalued } = attribute.validators;
423
-
424
- if (multivalued === undefined) {
425
- return undefined;
426
- }
427
-
428
- const minStr = multivalued.min;
429
-
430
- if (minStr === undefined) {
431
- return undefined;
432
- }
433
-
434
- return parseInt(`${minStr}`);
435
- })();
436
-
437
- if (minCount === undefined) {
438
- return true;
439
- }
440
-
441
- if (values.length === minCount) {
442
- return false;
443
- }
444
-
445
- return true;
446
- })();
447
-
448
- const hasAdd = (() => {
449
- if (fieldIndex + 1 !== values.length) {
450
- return false;
451
- }
452
-
453
- const maxCount = (() => {
454
- const { multivalued } = attribute.validators;
455
-
456
- if (multivalued === undefined) {
457
- return undefined;
458
- }
459
-
460
- const maxStr = multivalued.max;
461
-
462
- if (maxStr === undefined) {
463
- return undefined;
464
- }
422
+ const { hasAdd, hasRemove } = getButtonToDisplayForMultivaluedAttributeField({ attribute, values, fieldIndex });
465
423
 
466
- return parseInt(`${maxStr}`);
467
- })();
468
-
469
- if (maxCount === undefined) {
470
- return false;
471
- }
472
-
473
- if (values.length === maxCount) {
474
- return false;
475
- }
476
-
477
- return true;
478
- })();
424
+ const idPostfix = `-${attribute.name}-${fieldIndex + 1}`;
479
425
 
480
426
  return (
481
427
  <>
482
428
  {hasRemove && (
483
- <button
484
- id={`kc-remove-${attribute.name}-${fieldIndex + 1}`}
485
- type="button"
486
- className="pf-c-button pf-m-inline pf-m-link"
487
- onClick={() =>
488
- dispatchFormAction({
489
- action: "update",
490
- name: attribute.name,
491
- valueOrValues: values.filter((_, i) => i !== fieldIndex)
492
- })
493
- }
494
- >
495
- {msg("remove")}
496
- {hasRemove ? <>&nbsp;|&nbsp;</> : null}
497
- </button>
429
+ <>
430
+ <button
431
+ id={`kc-remove${idPostfix}`}
432
+ type="button"
433
+ className="pf-c-button pf-m-inline pf-m-link"
434
+ onClick={() =>
435
+ dispatchFormAction({
436
+ action: "update",
437
+ name: attribute.name,
438
+ valueOrValues: values.filter((_, i) => i !== fieldIndex)
439
+ })
440
+ }
441
+ >
442
+ {msg("remove")}
443
+ </button>
444
+ {hasAdd ? <>&nbsp;|&nbsp;</> : null}
445
+ </>
498
446
  )}
499
447
  {hasAdd && (
500
448
  <button
501
- id="kc-add-titles-1"
449
+ id={`kc-add${idPostfix}`}
502
450
  type="button"
503
451
  className="pf-c-button pf-m-inline pf-m-link"
504
452
  onClick={() =>
@@ -580,7 +528,7 @@ function InputTagSelects(props: InputFiledByTypeProps) {
580
528
  className={classInput}
581
529
  aria-invalid={props.displayableErrors.length !== 0}
582
530
  disabled={attribute.readOnly}
583
- checked={valueOrValues.includes(option)}
531
+ checked={valueOrValues instanceof Array ? valueOrValues.includes(option) : valueOrValues === option}
584
532
  onChange={event =>
585
533
  formValidationDispatch({
586
534
  action: "update",
@@ -12,7 +12,7 @@ export type KcContextLike = {
12
12
  currentLanguageTag: string;
13
13
  supported: { languageTag: string; url: string; label: string }[];
14
14
  };
15
- __localizationRealmOverridesUserProfile: Record<string, string>;
15
+ __localizationRealmOverridesUserProfile?: Record<string, string>;
16
16
  };
17
17
 
18
18
  assert<KcContext extends KcContextLike ? true : false>();
@@ -145,7 +145,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
145
145
  function createI18nTranslationFunctions<MessageKey extends string>(params: {
146
146
  fallbackMessages: Record<MessageKey, string>;
147
147
  messages: Record<MessageKey, string>;
148
- __localizationRealmOverridesUserProfile: Record<string, string>;
148
+ __localizationRealmOverridesUserProfile: Record<string, string> | undefined;
149
149
  }): Pick<GenericI18n<MessageKey>, "msg" | "msgStr" | "advancedMsg" | "advancedMsgStr"> {
150
150
  const { fallbackMessages, messages, __localizationRealmOverridesUserProfile } = params;
151
151
 
@@ -203,7 +203,7 @@ function createI18nTranslationFunctions<MessageKey extends string>(params: {
203
203
  function resolveMsgAdvanced(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): JSX.Element | string {
204
204
  const { key, args, doRenderAsHtml } = props;
205
205
 
206
- if (key in __localizationRealmOverridesUserProfile) {
206
+ if (__localizationRealmOverridesUserProfile !== undefined && key in __localizationRealmOverridesUserProfile) {
207
207
  const resolvedMessage = __localizationRealmOverridesUserProfile[key];
208
208
 
209
209
  return doRenderAsHtml ? (
@@ -3,9 +3,12 @@ import Fallback from "keycloakify/login/Fallback";
3
3
  export default Fallback;
4
4
 
5
5
  export { useDownloadTerms } from "keycloakify/login/lib/useDownloadTerms";
6
- export { getKcContext } from "keycloakify/login/kcContext/getKcContext";
7
- export { createGetKcContext } from "keycloakify/login/kcContext/createGetKcContext";
8
- export type { LoginThemePageId as PageId } from "keycloakify/bin/shared/constants";
9
6
  export { createUseI18n } from "keycloakify/login/i18n/i18n";
7
+ export type {
8
+ ExtendKcContext,
9
+ Attribute,
10
+ PasswordPolicies
11
+ } from "keycloakify/login/kcContext";
12
+ export { createGetKcContextMock } from "keycloakify/login/kcContext";
10
13
 
11
14
  export type { PageProps } from "keycloakify/login/pages/PageProps";
@@ -3,14 +3,28 @@ import type {
3
3
  LoginThemePageId,
4
4
  nameOfTheLocalizationRealmOverridesUserProfileProperty
5
5
  } from "keycloakify/bin/shared/constants";
6
+ import type { ExtractAfterStartingWith } from "keycloakify/tools/ExtractAfterStartingWith";
7
+ import type { ValueOf } from "keycloakify/tools/ValueOf";
6
8
  import { assert } from "tsafe/assert";
7
9
  import type { Equals } from "tsafe";
8
10
  import type { MessageKey } from "../i18n/i18n";
9
11
 
10
- type ExtractAfterStartingWith<
11
- Prefix extends string,
12
- StrEnum
13
- > = StrEnum extends `${Prefix}${infer U}` ? U : never;
12
+ export type ExtendKcContext<
13
+ KcContextExtraProperties extends { properties?: Record<string, string | undefined> },
14
+ KcContextExtraPropertiesPerPage extends Record<string, Record<string, unknown>>
15
+ > = ValueOf<{
16
+ [PageId in keyof KcContextExtraPropertiesPerPage | KcContext["pageId"]]: Extract<
17
+ KcContext,
18
+ { pageId: PageId }
19
+ > extends never
20
+ ? KcContext.Common &
21
+ KcContextExtraProperties & {
22
+ pageId: PageId;
23
+ } & KcContextExtraPropertiesPerPage[PageId]
24
+ : Extract<KcContext, { pageId: PageId }> &
25
+ KcContextExtraProperties &
26
+ KcContextExtraPropertiesPerPage[PageId];
27
+ }>;
14
28
 
15
29
  /** Take theses type definition with a grain of salt.
16
30
  * Some values might be undefined on some pages.
@@ -138,13 +152,13 @@ export declare namespace KcContext {
138
152
 
139
153
  getFirstError: (...fieldNames: string[]) => string;
140
154
  };
141
- properties: Record<string, string | undefined>;
142
155
  authenticationSession?: {
143
156
  authSessionId: string;
144
157
  tabId: string;
145
158
  ssoLoginInOtherTabsUrl: string;
146
159
  };
147
- __localizationRealmOverridesUserProfile: Record<string, string>;
160
+ properties: {};
161
+ __localizationRealmOverridesUserProfile?: Record<string, string>;
148
162
  };
149
163
 
150
164
  export type SamlPostForm = Common & {
@@ -585,7 +599,6 @@ export declare namespace KcContext {
585
599
  }
586
600
 
587
601
  export type UserProfile = {
588
- attributes: Attribute[];
589
602
  attributesByName: Record<string, Attribute>;
590
603
  html5DataAnnotations?: Record<string, string>;
591
604
  };
@@ -684,31 +697,31 @@ export type Attribute = {
684
697
  | "photo";
685
698
  };
686
699
 
687
- export type Validators = Partial<{
688
- length: Validators.DoIgnoreEmpty & Validators.Range;
689
- integer: Validators.DoIgnoreEmpty & Validators.Range;
690
- email: Validators.DoIgnoreEmpty;
691
- pattern: Validators.DoIgnoreEmpty & Validators.ErrorMessage & { pattern: string };
692
- options: Validators.Options;
693
- multivalued: Validators.DoIgnoreEmpty & Validators.Range;
700
+ export type Validators = {
701
+ length?: Validators.DoIgnoreEmpty & Validators.Range;
702
+ integer?: Validators.DoIgnoreEmpty & Validators.Range;
703
+ email?: Validators.DoIgnoreEmpty;
704
+ pattern?: Validators.DoIgnoreEmpty & Validators.ErrorMessage & { pattern: string };
705
+ options?: Validators.Options;
706
+ multivalued?: Validators.DoIgnoreEmpty & Validators.Range;
694
707
  // NOTE: Following are the validators for which we don't implement client side validation yet
695
708
  // or for which the validation can't be performed on the client side.
696
709
  /*
697
- double: Validators.DoIgnoreEmpty & Validators.Range;
698
- "up-immutable-attribute": {};
699
- "up-attribute-required-by-metadata-value": {};
700
- "up-username-has-value": {};
701
- "up-duplicate-username": {};
702
- "up-username-mutation": {};
703
- "up-email-exists-as-username": {};
704
- "up-blank-attribute-value": Validators.ErrorMessage & { "fail-on-null": boolean; };
705
- "up-duplicate-email": {};
706
- "local-date": Validators.DoIgnoreEmpty;
707
- "person-name-prohibited-characters": Validators.DoIgnoreEmpty & Validators.ErrorMessage;
708
- uri: Validators.DoIgnoreEmpty;
709
- "username-prohibited-characters": Validators.DoIgnoreEmpty & Validators.ErrorMessage;
710
+ double?: Validators.DoIgnoreEmpty & Validators.Range;
711
+ "up-immutable-attribute"?: {};
712
+ "up-attribute-required-by-metadata-value"?: {};
713
+ "up-username-has-value"?: {};
714
+ "up-duplicate-username"?: {};
715
+ "up-username-mutation"?: {};
716
+ "up-email-exists-as-username"?: {};
717
+ "up-blank-attribute-value"?: Validators.ErrorMessage & { "fail-on-null": boolean; };
718
+ "up-duplicate-email"?: {};
719
+ "local-date"?: Validators.DoIgnoreEmpty;
720
+ "person-name-prohibited-characters"?: Validators.DoIgnoreEmpty & Validators.ErrorMessage;
721
+ uri?: Validators.DoIgnoreEmpty;
722
+ "username-prohibited-characters"?: Validators.DoIgnoreEmpty & Validators.ErrorMessage;
710
723
  */
711
- }>;
724
+ };
712
725
 
713
726
  export declare namespace Validators {
714
727
  export type DoIgnoreEmpty = {
@@ -757,9 +770,8 @@ export type PasswordPolicies = {
757
770
  };
758
771
 
759
772
  assert<
760
- KcContext.Common extends Record<
761
- typeof nameOfTheLocalizationRealmOverridesUserProfileProperty,
762
- unknown
773
+ KcContext.Common extends Partial<
774
+ Record<typeof nameOfTheLocalizationRealmOverridesUserProfileProperty, unknown>
763
775
  >
764
776
  ? true
765
777
  : false
@@ -0,0 +1,80 @@
1
+ import type { ExtendKcContext, KcContext as KcContextBase } from "./KcContext";
2
+ import type { LoginThemePageId } from "keycloakify/bin/shared/constants";
3
+ import type { DeepPartial } from "keycloakify/tools/DeepPartial";
4
+ import { deepAssign } from "keycloakify/tools/deepAssign";
5
+ import { structuredCloneButFunctions } from "keycloakify/tools/structuredCloneButFunctions";
6
+ import { kcContextMocks, kcContextCommonMock } from "./kcContextMocks";
7
+ import { exclude } from "tsafe/exclude";
8
+
9
+ export function createGetKcContextMock<
10
+ KcContextExtraProperties extends { properties?: Record<string, string | undefined> },
11
+ KcContextExtraPropertiesPerPage extends Record<
12
+ `${string}.ftl`,
13
+ Record<string, unknown>
14
+ >
15
+ >(params: {
16
+ kcContextExtraProperties: KcContextExtraProperties;
17
+ kcContextExtraPropertiesPerPage: KcContextExtraPropertiesPerPage;
18
+ overrides?: DeepPartial<KcContextExtraProperties & KcContextBase.Common>;
19
+ overridesPerPage?: {
20
+ [PageId in
21
+ | LoginThemePageId
22
+ | keyof KcContextExtraPropertiesPerPage]?: DeepPartial<
23
+ Extract<
24
+ ExtendKcContext<
25
+ KcContextExtraProperties,
26
+ KcContextExtraPropertiesPerPage
27
+ >,
28
+ { pageId: PageId }
29
+ >
30
+ >;
31
+ };
32
+ }) {
33
+ const {
34
+ kcContextExtraProperties,
35
+ kcContextExtraPropertiesPerPage,
36
+ overrides: overrides_global,
37
+ overridesPerPage: overridesPerPage_global
38
+ } = params;
39
+
40
+ type KcContext = ExtendKcContext<
41
+ KcContextExtraProperties,
42
+ KcContextExtraPropertiesPerPage
43
+ >;
44
+
45
+ function getKcContextMock<
46
+ PageId extends LoginThemePageId | keyof KcContextExtraPropertiesPerPage
47
+ >(params: {
48
+ pageId: PageId;
49
+ overrides?: DeepPartial<Extract<KcContext, { pageId: PageId }>>;
50
+ }): Extract<KcContext, { pageId: PageId }> {
51
+ const { pageId, overrides } = params;
52
+
53
+ const kcContextMock = structuredCloneButFunctions(
54
+ kcContextMocks.find(kcContextMock => kcContextMock.pageId === pageId) ?? {
55
+ ...kcContextCommonMock,
56
+ pageId
57
+ }
58
+ );
59
+
60
+ [
61
+ kcContextExtraProperties,
62
+ kcContextExtraPropertiesPerPage[pageId],
63
+ overrides_global,
64
+ overridesPerPage_global?.[pageId],
65
+ overrides
66
+ ]
67
+ .filter(exclude(undefined))
68
+ .forEach(overrides =>
69
+ deepAssign({
70
+ target: kcContextMock,
71
+ source: overrides
72
+ })
73
+ );
74
+
75
+ // @ts-expect-error
76
+ return kcContextMock;
77
+ }
78
+
79
+ return { getKcContextMock };
80
+ }
@@ -1 +1,7 @@
1
- export type { KcContext } from "./KcContext";
1
+ export type {
2
+ ExtendKcContext,
3
+ KcContext,
4
+ Attribute,
5
+ PasswordPolicies
6
+ } from "./KcContext";
7
+ export { createGetKcContextMock } from "./getKcContextMock";