keycloakify 8.0.0 → 9.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 (160) hide show
  1. package/README.md +14 -54
  2. package/account/kcContext/KcContext.js.map +1 -1
  3. package/account/kcContext/createGetKcContext.js +2 -6
  4. package/account/kcContext/createGetKcContext.js.map +1 -1
  5. package/account/kcContext/kcContextMocks.js +4 -3
  6. package/account/kcContext/kcContextMocks.js.map +1 -1
  7. package/bin/constants.d.ts +7 -0
  8. package/bin/constants.js +10 -0
  9. package/bin/constants.js.map +1 -0
  10. package/bin/copy-keycloak-resources-to-public.js +34 -22
  11. package/bin/copy-keycloak-resources-to-public.js.map +1 -1
  12. package/bin/download-builtin-keycloak-theme.d.ts +4 -1
  13. package/bin/download-builtin-keycloak-theme.js +8 -6
  14. package/bin/download-builtin-keycloak-theme.js.map +1 -1
  15. package/bin/eject-keycloak-page.js +5 -3
  16. package/bin/eject-keycloak-page.js.map +1 -1
  17. package/bin/getSrcDirPath.d.ts +1 -1
  18. package/bin/getSrcDirPath.js +4 -4
  19. package/bin/getSrcDirPath.js.map +1 -1
  20. package/bin/initialize-email-theme.js +9 -9
  21. package/bin/initialize-email-theme.js.map +1 -1
  22. package/bin/keycloakify/BuildOptions.d.ts +8 -6
  23. package/bin/keycloakify/BuildOptions.js +63 -71
  24. package/bin/keycloakify/BuildOptions.js.map +1 -1
  25. package/bin/keycloakify/generateFtl/generateFtl.d.ts +2 -3
  26. package/bin/keycloakify/generateFtl/generateFtl.js +3 -4
  27. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  28. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +33 -0
  29. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +76 -0
  30. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +25 -0
  31. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +50 -0
  32. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +424 -0
  33. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +51 -0
  34. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +51 -0
  35. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +91 -0
  36. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +157 -0
  37. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +258 -0
  38. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +515 -0
  39. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +56 -0
  40. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +95 -0
  41. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +34 -0
  42. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +75 -0
  43. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +38 -0
  44. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +93 -0
  45. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +125 -0
  46. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +121 -0
  47. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +115 -0
  48. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +1320 -0
  49. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +64 -0
  50. package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.d.ts +7 -0
  51. package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.js +194 -0
  52. package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.js.map +1 -0
  53. package/bin/keycloakify/{generateJavaStackFiles.d.ts → generateJavaStackFiles/generateJavaStackFiles.d.ts} +6 -6
  54. package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js +276 -0
  55. package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js.map +1 -0
  56. package/bin/keycloakify/generateJavaStackFiles/index.d.ts +1 -0
  57. package/bin/keycloakify/generateJavaStackFiles/index.js +18 -0
  58. package/bin/keycloakify/generateJavaStackFiles/index.js.map +1 -0
  59. package/bin/keycloakify/generateStartKeycloakTestingContainer.d.ts +1 -3
  60. package/bin/keycloakify/generateStartKeycloakTestingContainer.js +15 -6
  61. package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
  62. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +5 -2
  63. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js +11 -8
  64. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
  65. package/bin/keycloakify/generateTheme/generateMessageProperties.d.ts +1 -1
  66. package/bin/keycloakify/generateTheme/generateTheme.d.ts +6 -5
  67. package/bin/keycloakify/generateTheme/generateTheme.js +59 -49
  68. package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
  69. package/bin/keycloakify/generateTheme/readExtraPageNames.d.ts +1 -1
  70. package/bin/keycloakify/generateTheme/readExtraPageNames.js.map +1 -1
  71. package/bin/keycloakify/generateTheme/readFieldNameUsage.d.ts +1 -1
  72. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.d.ts +1 -1
  73. package/bin/keycloakify/keycloakify.js +49 -90
  74. package/bin/keycloakify/keycloakify.js.map +1 -1
  75. package/bin/keycloakify/parsedPackageJson.d.ts +29 -31
  76. package/bin/keycloakify/parsedPackageJson.js +7 -8
  77. package/bin/keycloakify/parsedPackageJson.js.map +1 -1
  78. package/bin/promptKeycloakVersion.js +1 -1
  79. package/bin/promptKeycloakVersion.js.map +1 -1
  80. package/bin/tools/downloadAndUnzip.d.ts +1 -1
  81. package/bin/tools/downloadAndUnzip.js +24 -26
  82. package/bin/tools/downloadAndUnzip.js.map +1 -1
  83. package/bin/tools/getAbsoluteAndInOsFormatPath.d.ts +4 -0
  84. package/bin/tools/getAbsoluteAndInOsFormatPath.js +15 -0
  85. package/bin/tools/getAbsoluteAndInOsFormatPath.js.map +1 -0
  86. package/bin/tools/pathJoin.js +1 -1
  87. package/bin/tools/pathJoin.js.map +1 -1
  88. package/login/kcContext/KcContext.js.map +1 -1
  89. package/login/kcContext/createGetKcContext.js +2 -6
  90. package/login/kcContext/createGetKcContext.js.map +1 -1
  91. package/login/kcContext/kcContextMocks.js +5 -4
  92. package/login/kcContext/kcContextMocks.js.map +1 -1
  93. package/package.json +92 -21
  94. package/src/account/kcContext/KcContext.ts +2 -1
  95. package/src/account/kcContext/createGetKcContext.ts +2 -7
  96. package/src/account/kcContext/kcContextMocks.ts +5 -3
  97. package/src/bin/constants.ts +9 -0
  98. package/src/bin/copy-keycloak-resources-to-public.ts +20 -19
  99. package/src/bin/download-builtin-keycloak-theme.ts +14 -6
  100. package/src/bin/eject-keycloak-page.ts +5 -9
  101. package/src/bin/getSrcDirPath.ts +4 -4
  102. package/src/bin/initialize-email-theme.ts +7 -7
  103. package/src/bin/keycloakify/BuildOptions.ts +78 -59
  104. package/src/bin/keycloakify/generateFtl/generateFtl.ts +4 -7
  105. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +33 -0
  106. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +76 -0
  107. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +25 -0
  108. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +50 -0
  109. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +424 -0
  110. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +51 -0
  111. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +51 -0
  112. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +91 -0
  113. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +157 -0
  114. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +258 -0
  115. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +515 -0
  116. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +56 -0
  117. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +95 -0
  118. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +34 -0
  119. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +75 -0
  120. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +38 -0
  121. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +93 -0
  122. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +125 -0
  123. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +121 -0
  124. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +115 -0
  125. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +1320 -0
  126. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +64 -0
  127. package/src/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.ts +92 -0
  128. package/src/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.ts +211 -0
  129. package/src/bin/keycloakify/generateJavaStackFiles/index.ts +1 -0
  130. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +21 -22
  131. package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +19 -15
  132. package/src/bin/keycloakify/generateTheme/generateMessageProperties.ts +1 -1
  133. package/src/bin/keycloakify/generateTheme/generateTheme.ts +78 -72
  134. package/src/bin/keycloakify/generateTheme/readExtraPageNames.ts +2 -1
  135. package/src/bin/keycloakify/generateTheme/readFieldNameUsage.ts +1 -1
  136. package/src/bin/keycloakify/generateTheme/readStaticResourcesUsage.ts +1 -1
  137. package/src/bin/keycloakify/keycloakify.ts +21 -44
  138. package/src/bin/keycloakify/parsedPackageJson.ts +11 -13
  139. package/src/bin/promptKeycloakVersion.ts +1 -1
  140. package/src/bin/tools/downloadAndUnzip.ts +6 -7
  141. package/src/bin/tools/getAbsoluteAndInOsFormatPath.ts +15 -0
  142. package/src/bin/tools/pathJoin.ts +1 -1
  143. package/src/login/kcContext/KcContext.ts +2 -1
  144. package/src/login/kcContext/createGetKcContext.ts +2 -7
  145. package/src/login/kcContext/kcContextMocks.ts +7 -5
  146. package/bin/keycloakify/generateJavaStackFiles.js +0 -103
  147. package/bin/keycloakify/generateJavaStackFiles.js.map +0 -1
  148. package/bin/mockTestingResourcesPath.d.ts +0 -3
  149. package/bin/mockTestingResourcesPath.js +0 -8
  150. package/bin/mockTestingResourcesPath.js.map +0 -1
  151. package/bin/tools/jar.d.ts +0 -33
  152. package/bin/tools/jar.js +0 -241
  153. package/bin/tools/jar.js.map +0 -1
  154. package/bin/tools/walk.d.ts +0 -8
  155. package/bin/tools/walk.js +0 -125
  156. package/bin/tools/walk.js.map +0 -1
  157. package/src/bin/keycloakify/generateJavaStackFiles.ts +0 -84
  158. package/src/bin/mockTestingResourcesPath.ts +0 -5
  159. package/src/bin/tools/jar.ts +0 -99
  160. package/src/bin/tools/walk.ts +0 -19
@@ -1,13 +1,13 @@
1
1
  import { transformCodebase } from "../../tools/transformCodebase";
2
2
  import * as fs from "fs";
3
- import { join as pathJoin } from "path";
3
+ import { join as pathJoin, basename as pathBasename, resolve as pathResolve } from "path";
4
4
  import { replaceImportsFromStaticInJsCode } from "../replacers/replaceImportsFromStaticInJsCode";
5
5
  import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode";
6
- import { generateFtlFilesCodeFactory, loginThemePageIds, accountThemePageIds, themeTypes, type ThemeType } from "../generateFtl";
7
- import { basenameOfKeycloakDirInPublicDir } from "../../mockTestingResourcesPath";
6
+ import { generateFtlFilesCodeFactory, loginThemePageIds, accountThemePageIds } from "../generateFtl";
7
+ import { themeTypes, type ThemeType, lastKeycloakVersionWithAccountV1, keycloak_resources, retrocompatPostfix, accountV1 } from "../../constants";
8
8
  import { isInside } from "../../tools/isInside";
9
9
  import type { BuildOptions } from "../BuildOptions";
10
- import { assert } from "tsafe/assert";
10
+ import { assert, type Equals } from "tsafe/assert";
11
11
  import { downloadKeycloakStaticResources } from "./downloadKeycloakStaticResources";
12
12
  import { readFieldNameUsage } from "./readFieldNameUsage";
13
13
  import { readExtraPagesNames } from "./readExtraPageNames";
@@ -15,36 +15,39 @@ import { generateMessageProperties } from "./generateMessageProperties";
15
15
  import { readStaticResourcesUsage } from "./readStaticResourcesUsage";
16
16
 
17
17
  export type BuildOptionsLike = {
18
- themeName: string;
19
18
  extraThemeProperties: string[] | undefined;
20
19
  themeVersion: string;
21
- keycloakVersionDefaultAssets: string;
20
+ loginThemeResourcesFromKeycloakVersion: string;
22
21
  urlPathname: string | undefined;
22
+ keycloakifyBuildDirPath: string;
23
+ reactAppBuildDirPath: string;
24
+ cacheDirPath: string;
25
+ doBuildRetrocompatAccountTheme: boolean;
23
26
  };
24
27
 
25
28
  assert<BuildOptions extends BuildOptionsLike ? true : false>();
26
29
 
27
30
  export async function generateTheme(params: {
28
- projectDirPath: string;
29
- reactAppBuildDirPath: string;
30
- keycloakThemeBuildingDirPath: string;
31
+ themeName: string;
31
32
  themeSrcDirPath: string;
32
33
  keycloakifySrcDirPath: string;
33
34
  buildOptions: BuildOptionsLike;
34
35
  keycloakifyVersion: string;
35
36
  }): Promise<void> {
36
- const {
37
- projectDirPath,
38
- reactAppBuildDirPath,
39
- keycloakThemeBuildingDirPath,
40
- themeSrcDirPath,
41
- keycloakifySrcDirPath,
42
- buildOptions,
43
- keycloakifyVersion
44
- } = params;
45
-
46
- const getThemeDirPath = (themeType: ThemeType | "email") =>
47
- pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", buildOptions.themeName, themeType);
37
+ const { themeName, themeSrcDirPath, keycloakifySrcDirPath, buildOptions, keycloakifyVersion } = params;
38
+
39
+ const getThemeTypeDirPath = (params: { themeType: ThemeType | "email"; isRetrocompat?: true }) => {
40
+ const { themeType, isRetrocompat = false } = params;
41
+ return pathJoin(
42
+ buildOptions.keycloakifyBuildDirPath,
43
+ "src",
44
+ "main",
45
+ "resources",
46
+ "theme",
47
+ `${themeName}${isRetrocompat ? retrocompatPostfix : ""}`,
48
+ themeType
49
+ );
50
+ };
48
51
 
49
52
  let allCssGlobalsToDefine: Record<string, string> = {};
50
53
 
@@ -55,7 +58,7 @@ export async function generateTheme(params: {
55
58
  continue;
56
59
  }
57
60
 
58
- const themeDirPath = getThemeDirPath(themeType);
61
+ const themeTypeDirPath = getThemeTypeDirPath({ themeType });
59
62
 
60
63
  copy_app_resources_to_theme_path: {
61
64
  const isFirstPass = themeType.indexOf(themeType) === 0;
@@ -65,13 +68,13 @@ export async function generateTheme(params: {
65
68
  }
66
69
 
67
70
  transformCodebase({
68
- "destDirPath": pathJoin(themeDirPath, "resources", "build"),
69
- "srcDirPath": reactAppBuildDirPath,
71
+ "destDirPath": pathJoin(themeTypeDirPath, "resources", "build"),
72
+ "srcDirPath": buildOptions.reactAppBuildDirPath,
70
73
  "transformSourceCode": ({ filePath, sourceCode }) => {
71
74
  //NOTE: Prevent cycles, excludes the folder we generated for debug in public/
72
75
  if (
73
76
  isInside({
74
- "dirPath": pathJoin(reactAppBuildDirPath, basenameOfKeycloakDirInPublicDir),
77
+ "dirPath": pathJoin(buildOptions.reactAppBuildDirPath, keycloak_resources),
75
78
  filePath
76
79
  })
77
80
  ) {
@@ -114,7 +117,8 @@ export async function generateTheme(params: {
114
117
  generateFtlFilesCode_glob !== undefined
115
118
  ? generateFtlFilesCode_glob
116
119
  : generateFtlFilesCodeFactory({
117
- "indexHtmlCode": fs.readFileSync(pathJoin(reactAppBuildDirPath, "index.html")).toString("utf8"),
120
+ themeName,
121
+ "indexHtmlCode": fs.readFileSync(pathJoin(buildOptions.reactAppBuildDirPath, "index.html")).toString("utf8"),
118
122
  "cssGlobalsToDefine": allCssGlobalsToDefine,
119
123
  buildOptions,
120
124
  keycloakifyVersion,
@@ -142,75 +146,77 @@ export async function generateTheme(params: {
142
146
  ].forEach(pageId => {
143
147
  const { ftlCode } = generateFtlFilesCode({ pageId });
144
148
 
145
- fs.mkdirSync(themeDirPath, { "recursive": true });
149
+ fs.mkdirSync(themeTypeDirPath, { "recursive": true });
146
150
 
147
- fs.writeFileSync(pathJoin(themeDirPath, pageId), Buffer.from(ftlCode, "utf8"));
151
+ fs.writeFileSync(pathJoin(themeTypeDirPath, pageId), Buffer.from(ftlCode, "utf8"));
148
152
  });
149
153
 
150
154
  generateMessageProperties({
151
155
  themeSrcDirPath,
152
156
  themeType
153
157
  }).forEach(({ languageTag, propertiesFileSource }) => {
154
- const messagesDirPath = pathJoin(themeDirPath, "messages");
158
+ const messagesDirPath = pathJoin(themeTypeDirPath, "messages");
155
159
 
156
- fs.mkdirSync(pathJoin(themeDirPath, "messages"), { "recursive": true });
160
+ fs.mkdirSync(pathJoin(themeTypeDirPath, "messages"), { "recursive": true });
157
161
 
158
162
  const propertiesFilePath = pathJoin(messagesDirPath, `messages_${languageTag}.properties`);
159
163
 
160
164
  fs.writeFileSync(propertiesFilePath, Buffer.from(propertiesFileSource, "utf8"));
161
165
  });
162
166
 
163
- //TODO: Remove this block we left it for now only for backward compatibility
164
- // we now have a separate script for this
165
- copy_keycloak_resources_to_public: {
166
- const keycloakDirInPublicDir = pathJoin(reactAppBuildDirPath, "..", "public", basenameOfKeycloakDirInPublicDir);
167
-
168
- if (fs.existsSync(keycloakDirInPublicDir)) {
169
- break copy_keycloak_resources_to_public;
170
- }
171
-
172
- await downloadKeycloakStaticResources({
173
- projectDirPath,
174
- "keycloakVersion": buildOptions.keycloakVersionDefaultAssets,
175
- "themeDirPath": keycloakDirInPublicDir,
176
- themeType,
177
- "usedResources": undefined
178
- });
179
-
180
- if (themeType !== themeTypes[0]) {
181
- break copy_keycloak_resources_to_public;
182
- }
183
-
184
- fs.writeFileSync(
185
- pathJoin(keycloakDirInPublicDir, "README.txt"),
186
- Buffer.from(
187
- // prettier-ignore
188
- [
189
- "This is just a test folder that helps develop",
190
- "the login and register page without having to run a Keycloak container"
191
- ].join(" ")
192
- )
193
- );
194
-
195
- fs.writeFileSync(pathJoin(keycloakDirInPublicDir, ".gitignore"), Buffer.from("*", "utf8"));
196
- }
197
-
198
167
  await downloadKeycloakStaticResources({
199
- projectDirPath,
200
- "keycloakVersion": buildOptions.keycloakVersionDefaultAssets,
201
- themeDirPath,
168
+ "keycloakVersion": (() => {
169
+ switch (themeType) {
170
+ case "account":
171
+ return lastKeycloakVersionWithAccountV1;
172
+ case "login":
173
+ return buildOptions.loginThemeResourcesFromKeycloakVersion;
174
+ }
175
+ })(),
176
+ "themeDirPath": pathResolve(pathJoin(themeTypeDirPath, "..")),
202
177
  themeType,
203
178
  "usedResources": readStaticResourcesUsage({
204
179
  keycloakifySrcDirPath,
205
180
  themeSrcDirPath,
206
181
  themeType
207
- })
182
+ }),
183
+ buildOptions
208
184
  });
209
185
 
210
186
  fs.writeFileSync(
211
- pathJoin(themeDirPath, "theme.properties"),
212
- Buffer.from([`parent=keycloak`, ...(buildOptions.extraThemeProperties ?? [])].join("\n\n"), "utf8")
187
+ pathJoin(themeTypeDirPath, "theme.properties"),
188
+ Buffer.from(
189
+ [
190
+ `parent=${(() => {
191
+ switch (themeType) {
192
+ case "account":
193
+ return accountV1;
194
+ case "login":
195
+ return "keycloak";
196
+ }
197
+ assert<Equals<typeof themeType, never>>(false);
198
+ })()}`,
199
+ ...(buildOptions.extraThemeProperties ?? [])
200
+ ].join("\n\n"),
201
+ "utf8"
202
+ )
213
203
  );
204
+
205
+ if (themeType === "account" && buildOptions.doBuildRetrocompatAccountTheme) {
206
+ transformCodebase({
207
+ "srcDirPath": themeTypeDirPath,
208
+ "destDirPath": getThemeTypeDirPath({ themeType, "isRetrocompat": true }),
209
+ "transformSourceCode": ({ filePath, sourceCode }) => {
210
+ if (pathBasename(filePath) === "theme.properties") {
211
+ return {
212
+ "modifiedSourceCode": Buffer.from(sourceCode.toString("utf8").replace(`parent=${accountV1}`, "parent=keycloak"), "utf8")
213
+ };
214
+ }
215
+
216
+ return { "modifiedSourceCode": sourceCode };
217
+ }
218
+ });
219
+ }
214
220
  }
215
221
 
216
222
  email: {
@@ -222,7 +228,7 @@ export async function generateTheme(params: {
222
228
 
223
229
  transformCodebase({
224
230
  "srcDirPath": emailThemeSrcDirPath,
225
- "destDirPath": getThemeDirPath("email")
231
+ "destDirPath": getThemeTypeDirPath({ "themeType": "email" })
226
232
  });
227
233
  }
228
234
  }
@@ -1,9 +1,10 @@
1
1
  import { crawl } from "../../tools/crawl";
2
- import { type ThemeType, accountThemePageIds, loginThemePageIds } from "../generateFtl";
2
+ import { accountThemePageIds, loginThemePageIds } from "../generateFtl";
3
3
  import { id } from "tsafe/id";
4
4
  import { removeDuplicates } from "evt/tools/reducers/removeDuplicates";
5
5
  import * as fs from "fs";
6
6
  import { join as pathJoin } from "path";
7
+ import type { ThemeType } from "../../constants";
7
8
 
8
9
  export function readExtraPagesNames(params: { themeSrcDirPath: string; themeType: ThemeType }): string[] {
9
10
  const { themeSrcDirPath, themeType } = params;
@@ -2,7 +2,7 @@ import { crawl } from "../../tools/crawl";
2
2
  import { removeDuplicates } from "evt/tools/reducers/removeDuplicates";
3
3
  import { join as pathJoin } from "path";
4
4
  import * as fs from "fs";
5
- import type { ThemeType } from "../generateFtl";
5
+ import type { ThemeType } from "../../constants";
6
6
 
7
7
  /** Assumes the theme type exists */
8
8
  export function readFieldNameUsage(params: { keycloakifySrcDirPath: string; themeSrcDirPath: string; themeType: ThemeType }): string[] {
@@ -1,7 +1,7 @@
1
1
  import { crawl } from "../../tools/crawl";
2
2
  import { join as pathJoin } from "path";
3
3
  import * as fs from "fs";
4
- import type { ThemeType } from "../generateFtl";
4
+ import type { ThemeType } from "../../constants";
5
5
 
6
6
  /** Assumes the theme type exists */
7
7
  export function readStaticResourcesUsage(params: { keycloakifySrcDirPath: string; themeSrcDirPath: string; themeType: ThemeType }): {
@@ -6,18 +6,16 @@ import { generateStartKeycloakTestingContainer } from "./generateStartKeycloakTe
6
6
  import * as fs from "fs";
7
7
  import { readBuildOptions } from "./BuildOptions";
8
8
  import { getLogger } from "../tools/logger";
9
- import jar from "../tools/jar";
10
9
  import { assert } from "tsafe/assert";
11
- import { Equals } from "tsafe";
12
10
  import { getThemeSrcDirPath } from "../getSrcDirPath";
13
11
  import { getProjectRoot } from "../tools/getProjectRoot";
14
12
  import { objectKeys } from "tsafe/objectKeys";
15
13
 
16
14
  export async function main() {
17
- const projectDirPath = process.cwd();
15
+ const reactAppRootDirPath = process.cwd();
18
16
 
19
17
  const buildOptions = readBuildOptions({
20
- projectDirPath,
18
+ reactAppRootDirPath,
21
19
  "processArgv": process.argv.slice(2)
22
20
  });
23
21
 
@@ -26,19 +24,14 @@ export async function main() {
26
24
 
27
25
  const keycloakifyDirPath = getProjectRoot();
28
26
 
29
- const { themeSrcDirPath } = getThemeSrcDirPath({ projectDirPath });
27
+ const { themeSrcDirPath } = getThemeSrcDirPath({ reactAppRootDirPath });
30
28
 
31
- for (const themeName of [buildOptions.themeName, ...buildOptions.extraThemeNames]) {
29
+ for (const themeName of buildOptions.themeNames) {
32
30
  await generateTheme({
33
- projectDirPath,
34
- "keycloakThemeBuildingDirPath": buildOptions.keycloakifyBuildDirPath,
31
+ themeName,
35
32
  themeSrcDirPath,
36
33
  "keycloakifySrcDirPath": pathJoin(keycloakifyDirPath, "src"),
37
- "reactAppBuildDirPath": buildOptions.reactAppBuildDirPath,
38
- "buildOptions": {
39
- ...buildOptions,
40
- "themeName": themeName
41
- },
34
+ buildOptions,
42
35
  "keycloakifyVersion": (() => {
43
36
  const version = JSON.parse(fs.readFileSync(pathJoin(keycloakifyDirPath, "package.json")).toString("utf8"))["version"];
44
37
 
@@ -49,8 +42,7 @@ export async function main() {
49
42
  });
50
43
  }
51
44
 
52
- const { jarFilePath } = generateJavaStackFiles({
53
- "keycloakThemeBuildingDirPath": buildOptions.keycloakifyBuildDirPath,
45
+ const { jarFilePath } = await generateJavaStackFiles({
54
46
  "implementedThemeTypes": (() => {
55
47
  const implementedThemeTypes = {
56
48
  "login": false,
@@ -70,33 +62,14 @@ export async function main() {
70
62
  buildOptions
71
63
  });
72
64
 
73
- switch (buildOptions.bundler) {
74
- case "none":
75
- logger.log("😱 Skipping bundling step, there will be no jar");
76
- break;
77
- case "keycloakify":
78
- logger.log("🫶 Let keycloakify do its thang");
79
- await jar({
80
- "rootPath": buildOptions.keycloakifyBuildDirPath,
81
- "version": buildOptions.themeVersion,
82
- "groupId": buildOptions.groupId,
83
- "artifactId": buildOptions.artifactId,
84
- "targetPath": jarFilePath
85
- });
86
- break;
87
- case "mvn":
88
- logger.log("🫙 Run maven to deliver a jar");
89
- child_process.execSync("mvn package", { "cwd": buildOptions.keycloakifyBuildDirPath });
90
- break;
91
- default:
92
- assert<Equals<typeof buildOptions.bundler, never>>(false);
65
+ if (buildOptions.doCreateJar) {
66
+ child_process.execSync("mvn package", { "cwd": buildOptions.keycloakifyBuildDirPath });
93
67
  }
94
68
 
95
69
  // We want, however, to test in a container running the latest Keycloak version
96
70
  const containerKeycloakVersion = "21.1.2";
97
71
 
98
72
  generateStartKeycloakTestingContainer({
99
- keycloakThemeBuildingDirPath: buildOptions.keycloakifyBuildDirPath,
100
73
  "keycloakVersion": containerKeycloakVersion,
101
74
  buildOptions
102
75
  });
@@ -104,9 +77,13 @@ export async function main() {
104
77
  logger.log(
105
78
  [
106
79
  "",
107
- `✅ Your keycloak theme has been generated and bundled into .${pathSep}${pathRelative(projectDirPath, jarFilePath)} 🚀`,
108
- `It is to be placed in "/opt/keycloak/providers" in the container running a quay.io/keycloak/keycloak Docker image.`,
109
- "",
80
+ ...(!buildOptions.doCreateJar
81
+ ? []
82
+ : [
83
+ `✅ Your keycloak theme has been generated and bundled into .${pathSep}${pathRelative(reactAppRootDirPath, jarFilePath)} 🚀`,
84
+ `It is to be placed in "/opt/keycloak/providers" in the container running a quay.io/keycloak/keycloak Docker image.`,
85
+ ""
86
+ ]),
110
87
  //TODO: Restore when we find a good Helm chart for Keycloak.
111
88
  //"Using Helm (https://github.com/codecentric/helm-charts), edit to reflect:",
112
89
  "",
@@ -139,7 +116,7 @@ export async function main() {
139
116
  `To test your theme locally you can spin up a Keycloak ${containerKeycloakVersion} container image with the theme pre loaded by running:`,
140
117
  "",
141
118
  `👉 $ .${pathSep}${pathRelative(
142
- projectDirPath,
119
+ reactAppRootDirPath,
143
120
  pathJoin(buildOptions.keycloakifyBuildDirPath, generateStartKeycloakTestingContainer.basename)
144
121
  )} 👈`,
145
122
  "",
@@ -149,15 +126,15 @@ export async function main() {
149
126
  "- Log into the admin console 👉 http://localhost:8080/admin username: admin, password: admin 👈",
150
127
  `- Create a realm: Master -> AddRealm -> Name: myrealm`,
151
128
  `- Enable registration: Realm settings -> Login tab -> User registration: on`,
152
- `- Enable the Account theme (optional): Realm settings -> Themes tab -> Account theme: ${buildOptions.themeName}`,
153
- ` Clients -> account -> Login theme: ${buildOptions.themeName}`,
154
- `- Enable the email theme (optional): Realm settings -> Themes tab -> Email theme: ${buildOptions.themeName} (option will appear only if you have ran npx initialize-email-theme)`,
129
+ `- Enable the Account theme (optional): Realm settings -> Themes tab -> Account theme: ${buildOptions.themeNames[0]}`,
130
+ ` Clients -> account -> Login theme: ${buildOptions.themeNames[0]}`,
131
+ `- Enable the email theme (optional): Realm settings -> Themes tab -> Email theme: ${buildOptions.themeNames[0]} (option will appear only if you have ran npx initialize-email-theme)`,
155
132
  `- Create a client Clients -> Create -> Client ID: myclient`,
156
133
  ` Root URL: https://www.keycloak.org/app/`,
157
134
  ` Valid redirect URIs: https://www.keycloak.org/app* http://localhost* (localhost is optional)`,
158
135
  ` Valid post logout redirect URIs: https://www.keycloak.org/app* http://localhost*`,
159
136
  ` Web origins: *`,
160
- ` Login Theme: ${buildOptions.themeName}`,
137
+ ` Login Theme: ${buildOptions.themeNames[0]}`,
161
138
  ` Save (button at the bottom of the page)`,
162
139
  ``,
163
140
  `- Go to 👉 https://www.keycloak.org/app/ 👈 Click "Save" then "Sign in". You should see your login page`,
@@ -4,8 +4,6 @@ import type { Equals } from "tsafe";
4
4
  import { z } from "zod";
5
5
  import { pathJoin } from "../tools/pathJoin";
6
6
 
7
- export const bundlers = ["mvn", "keycloakify", "none"] as const;
8
- export type Bundler = (typeof bundlers)[number];
9
7
  export type ParsedPackageJson = {
10
8
  name: string;
11
9
  version?: string;
@@ -15,12 +13,12 @@ export type ParsedPackageJson = {
15
13
  areAppAndKeycloakServerSharingSameDomain?: boolean;
16
14
  artifactId?: string;
17
15
  groupId?: string;
18
- bundler?: Bundler;
19
- keycloakVersionDefaultAssets?: string;
16
+ doCreateJar?: boolean;
17
+ loginThemeResourcesFromKeycloakVersion?: string;
20
18
  reactAppBuildDirPath?: string;
21
19
  keycloakifyBuildDirPath?: string;
22
- themeName?: string;
23
- extraThemeNames?: string[];
20
+ themeName?: string | string[];
21
+ doBuildRetrocompatAccountTheme?: boolean;
24
22
  };
25
23
  };
26
24
 
@@ -34,12 +32,12 @@ export const zParsedPackageJson = z.object({
34
32
  "areAppAndKeycloakServerSharingSameDomain": z.boolean().optional(),
35
33
  "artifactId": z.string().optional(),
36
34
  "groupId": z.string().optional(),
37
- "bundler": z.enum(bundlers).optional(),
38
- "keycloakVersionDefaultAssets": z.string().optional(),
35
+ "doCreateJar": z.boolean().optional(),
36
+ "loginThemeResourcesFromKeycloakVersion": z.string().optional(),
39
37
  "reactAppBuildDirPath": z.string().optional(),
40
38
  "keycloakifyBuildDirPath": z.string().optional(),
41
- "themeName": z.string().optional(),
42
- "extraThemeNames": z.array(z.string()).optional()
39
+ "themeName": z.union([z.string(), z.array(z.string())]).optional(),
40
+ "doBuildRetrocompatAccountTheme": z.boolean().optional()
43
41
  })
44
42
  .optional()
45
43
  });
@@ -47,11 +45,11 @@ export const zParsedPackageJson = z.object({
47
45
  assert<Equals<ReturnType<(typeof zParsedPackageJson)["parse"]>, ParsedPackageJson>>();
48
46
 
49
47
  let parsedPackageJson: undefined | ReturnType<(typeof zParsedPackageJson)["parse"]>;
50
- export function getParsedPackageJson(params: { projectDirPath: string }) {
51
- const { projectDirPath } = params;
48
+ export function getParsedPackageJson(params: { reactAppRootDirPath: string }) {
49
+ const { reactAppRootDirPath } = params;
52
50
  if (parsedPackageJson) {
53
51
  return parsedPackageJson;
54
52
  }
55
- parsedPackageJson = zParsedPackageJson.parse(JSON.parse(fs.readFileSync(pathJoin(projectDirPath, "package.json")).toString("utf8")));
53
+ parsedPackageJson = zParsedPackageJson.parse(JSON.parse(fs.readFileSync(pathJoin(reactAppRootDirPath, "package.json")).toString("utf8")));
56
54
  return parsedPackageJson;
57
55
  }
@@ -17,7 +17,7 @@ export async function promptKeycloakVersion() {
17
17
  return { getLatestsSemVersionedTag };
18
18
  })();
19
19
 
20
- console.log("Initialize the directory with email template from which keycloak version?");
20
+ console.log("Select Keycloak version?");
21
21
 
22
22
  const tags = [
23
23
  ...(await getLatestsSemVersionedTag({
@@ -162,7 +162,7 @@ export async function downloadAndUnzip(
162
162
  } & (
163
163
  | {
164
164
  doUseCache: true;
165
- projectDirPath: string;
165
+ cacheDirPath: string;
166
166
  }
167
167
  | {
168
168
  doUseCache: false;
@@ -182,11 +182,10 @@ export async function downloadAndUnzip(
182
182
  }
183
183
  });
184
184
 
185
- const cacheRoot = !rest.doUseCache
186
- ? `tmp_${Math.random().toString().slice(2, 12)}`
187
- : pathJoin(process.env.XDG_CACHE_HOME ?? pathJoin(rest.projectDirPath, "node_modules", ".cache"), "keycloakify");
188
- const zipFilePath = pathJoin(cacheRoot, `${zipFileBasename}.zip`);
189
- const extractDirPath = pathJoin(cacheRoot, `tmp_unzip_${zipFileBasename}`);
185
+ const cacheDirPath = !rest.doUseCache ? `tmp_${Math.random().toString().slice(2, 12)}` : rest.cacheDirPath;
186
+
187
+ const zipFilePath = pathJoin(cacheDirPath, `${zipFileBasename}.zip`);
188
+ const extractDirPath = pathJoin(cacheDirPath, `tmp_unzip_${zipFileBasename}`);
190
189
 
191
190
  if (!(await exists(zipFilePath))) {
192
191
  const opts = await getFetchOptions();
@@ -226,7 +225,7 @@ export async function downloadAndUnzip(
226
225
  });
227
226
 
228
227
  if (!rest.doUseCache) {
229
- await rm(cacheRoot, { "recursive": true });
228
+ await rm(cacheDirPath, { "recursive": true });
230
229
  } else {
231
230
  await rm(extractDirPath, { "recursive": true });
232
231
  }
@@ -0,0 +1,15 @@
1
+ import { isAbsolute as pathIsAbsolute, sep as pathSep, join as pathJoin } from "path";
2
+
3
+ export function getAbsoluteAndInOsFormatPath(params: { pathIsh: string; cwd: string }): string {
4
+ const { pathIsh, cwd } = params;
5
+
6
+ let pathOut = pathIsh;
7
+
8
+ pathOut = pathOut.replace(/\//g, pathSep);
9
+
10
+ if (!pathIsAbsolute(pathOut)) {
11
+ pathOut = pathJoin(cwd, pathOut);
12
+ }
13
+
14
+ return pathOut;
15
+ }
@@ -2,5 +2,5 @@ export function pathJoin(...path: string[]): string {
2
2
  return path
3
3
  .map((part, i) => (i === 0 ? part : part.replace(/^\/+/, "")))
4
4
  .map((part, i) => (i === path.length - 1 ? part : part.replace(/\/+$/, "")))
5
- .join("/");
5
+ .join(typeof process !== "undefined" && process.platform === "win32" ? "\\" : "/");
6
6
  }
@@ -1,4 +1,5 @@
1
- import type { LoginThemePageId, ThemeType } from "keycloakify/bin/keycloakify/generateFtl";
1
+ import type { LoginThemePageId } from "keycloakify/bin/keycloakify/generateFtl";
2
+ import { type ThemeType } from "keycloakify/bin/constants";
2
3
  import { assert } from "tsafe/assert";
3
4
  import type { Equals } from "tsafe";
4
5
  import type { MessageKey } from "../i18n/i18n";
@@ -8,9 +8,8 @@ import { assert } from "tsafe/assert";
8
8
  import type { ExtendKcContext } from "./getKcContextFromWindow";
9
9
  import { getKcContextFromWindow } from "./getKcContextFromWindow";
10
10
  import { pathJoin } from "keycloakify/bin/tools/pathJoin";
11
- import { pathBasename } from "keycloakify/tools/pathBasename";
12
- import { resourcesCommonDirPathRelativeToPublicDir } from "keycloakify/bin/mockTestingResourcesPath";
13
11
  import { symToStr } from "tsafe/symToStr";
12
+ import { resources_common } from "keycloakify/bin/constants";
14
13
 
15
14
  export function createGetKcContext<KcContextExtension extends { pageId: string } = never>(params?: {
16
15
  mockData?: readonly DeepPartial<ExtendKcContext<KcContextExtension>>[];
@@ -148,11 +147,7 @@ export function createGetKcContext<KcContextExtension extends { pageId: string }
148
147
  return { "kcContext": undefined as any };
149
148
  }
150
149
 
151
- {
152
- const { url } = realKcContext;
153
-
154
- url.resourcesCommonPath = pathJoin(url.resourcesPath, pathBasename(resourcesCommonDirPathRelativeToPublicDir));
155
- }
150
+ realKcContext.url.resourcesCommonPath = pathJoin(realKcContext.url.resourcesPath, resources_common);
156
151
 
157
152
  return { "kcContext": realKcContext as any };
158
153
  }
@@ -1,13 +1,11 @@
1
1
  import "minimal-polyfills/Object.fromEntries";
2
2
  import type { KcContext, Attribute } from "./KcContext";
3
- import { resourcesCommonDirPathRelativeToPublicDir, resourcesDirPathRelativeToPublicDir } from "keycloakify/bin/mockTestingResourcesPath";
3
+ import { resources_common, keycloak_resources } from "keycloakify/bin/constants";
4
4
  import { pathJoin } from "keycloakify/bin/tools/pathJoin";
5
5
  import { id } from "tsafe/id";
6
6
  import { assert, type Equals } from "tsafe/assert";
7
7
  import type { LoginThemePageId } from "keycloakify/bin/keycloakify/generateFtl";
8
8
 
9
- const PUBLIC_URL = (typeof process !== "object" ? undefined : process.env?.["PUBLIC_URL"]) || "/";
10
-
11
9
  const attributes: Attribute[] = [
12
10
  {
13
11
  "validators": {
@@ -102,14 +100,18 @@ const attributes: Attribute[] = [
102
100
 
103
101
  const attributesByName = Object.fromEntries(attributes.map(attribute => [attribute.name, attribute])) as any;
104
102
 
103
+ const PUBLIC_URL = (typeof process !== "object" ? undefined : process.env?.["PUBLIC_URL"]) || "/";
104
+
105
+ const resourcesPath = pathJoin(PUBLIC_URL, keycloak_resources, "login", "resources");
106
+
105
107
  export const kcContextCommonMock: KcContext.Common = {
106
108
  "keycloakifyVersion": "0.0.0",
107
109
  "themeType": "login",
108
110
  "themeName": "my-theme-name",
109
111
  "url": {
110
112
  "loginAction": "#",
111
- "resourcesPath": pathJoin(PUBLIC_URL, resourcesDirPathRelativeToPublicDir),
112
- "resourcesCommonPath": pathJoin(PUBLIC_URL, resourcesCommonDirPathRelativeToPublicDir),
113
+ resourcesPath,
114
+ "resourcesCommonPath": pathJoin(resourcesPath, resources_common),
113
115
  "loginRestartFlowUrl": "/auth/realms/myrealm/login-actions/restart?client_id=account&tab_id=HoAx28ja4xg",
114
116
  "loginUrl": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg"
115
117
  },