keycloakify 10.0.0-rc.17 → 10.0.0-rc.19

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 (208) hide show
  1. package/PUBLIC_URL.js.map +1 -1
  2. package/account/Template.js +5 -5
  3. package/account/Template.js.map +1 -1
  4. package/account/i18n/i18n.js +37 -29
  5. package/account/i18n/i18n.js.map +1 -1
  6. package/account/kcContext/KcContext.js.map +1 -1
  7. package/account/kcContext/createGetKcContext.js +20 -15
  8. package/account/kcContext/createGetKcContext.js.map +1 -1
  9. package/account/kcContext/getKcContext.js.map +1 -1
  10. package/account/kcContext/getKcContextFromWindow.d.ts +3 -1
  11. package/account/kcContext/getKcContextFromWindow.js.map +1 -1
  12. package/account/kcContext/kcContextMocks.js +148 -144
  13. package/account/kcContext/kcContextMocks.js.map +1 -1
  14. package/account/lib/useGetClassName.js +14 -14
  15. package/account/lib/useGetClassName.js.map +1 -1
  16. package/account/pages/Account.js +1 -1
  17. package/account/pages/Account.js.map +1 -1
  18. package/account/pages/Password.js +7 -7
  19. package/account/pages/Password.js.map +1 -1
  20. package/account/pages/Totp.js +4 -4
  21. package/account/pages/Totp.js.map +1 -1
  22. package/bin/main.js +2265 -2028
  23. package/bin/shared/constants.d.ts +1 -0
  24. package/bin/shared/constants.js +4 -3
  25. package/bin/shared/constants.js.map +1 -1
  26. package/lib/isStorybook.js +2 -1
  27. package/lib/isStorybook.js.map +1 -1
  28. package/lib/useGetClassName.js.map +1 -1
  29. package/login/Template.js +13 -13
  30. package/login/Template.js.map +1 -1
  31. package/login/UserProfileFormFields.js +43 -41
  32. package/login/UserProfileFormFields.js.map +1 -1
  33. package/login/i18n/baseMessages/ca.d.ts +1 -1
  34. package/login/i18n/baseMessages/ca.js +1 -1
  35. package/login/i18n/baseMessages/el.d.ts +0 -1
  36. package/login/i18n/baseMessages/el.js +0 -1
  37. package/login/i18n/baseMessages/el.js.map +1 -1
  38. package/login/i18n/baseMessages/en.d.ts +1 -1
  39. package/login/i18n/baseMessages/en.js +1 -1
  40. package/login/i18n/baseMessages/es.d.ts +1 -1
  41. package/login/i18n/baseMessages/es.js +1 -1
  42. package/login/i18n/baseMessages/fa.d.ts +0 -1
  43. package/login/i18n/baseMessages/fa.js +0 -1
  44. package/login/i18n/baseMessages/fa.js.map +1 -1
  45. package/login/i18n/baseMessages/hu.d.ts +1 -1
  46. package/login/i18n/baseMessages/hu.js +1 -1
  47. package/login/i18n/baseMessages/index.d.ts +1 -2
  48. package/login/i18n/baseMessages/zh-CN.d.ts +1 -1
  49. package/login/i18n/baseMessages/zh-CN.js +1 -1
  50. package/login/i18n/i18n.js +39 -31
  51. package/login/i18n/i18n.js.map +1 -1
  52. package/login/kcContext/KcContext.js.map +1 -1
  53. package/login/kcContext/createGetKcContext.js +30 -22
  54. package/login/kcContext/createGetKcContext.js.map +1 -1
  55. package/login/kcContext/getKcContext.js.map +1 -1
  56. package/login/kcContext/getKcContextFromWindow.d.ts +3 -1
  57. package/login/kcContext/getKcContextFromWindow.js.map +1 -1
  58. package/login/kcContext/kcContextMocks.js +233 -231
  59. package/login/kcContext/kcContextMocks.js.map +1 -1
  60. package/login/lib/useDownloadTerms.js.map +1 -1
  61. package/login/lib/useGetClassName.js +112 -112
  62. package/login/lib/useGetClassName.js.map +1 -1
  63. package/login/lib/useUserProfileForm.js +181 -181
  64. package/login/lib/useUserProfileForm.js.map +1 -1
  65. package/login/pages/DeleteAccountConfirm.js +5 -1
  66. package/login/pages/DeleteAccountConfirm.js.map +1 -1
  67. package/login/pages/FrontchannelLogout.js +1 -1
  68. package/login/pages/FrontchannelLogout.js.map +1 -1
  69. package/login/pages/Login.js.map +1 -1
  70. package/login/pages/LoginRecoveryAuthnCodeConfig.js +3 -3
  71. package/login/pages/LoginRecoveryAuthnCodeConfig.js.map +1 -1
  72. package/login/pages/LoginResetPassword.js.map +1 -1
  73. package/login/pages/LoginUsername.js.map +1 -1
  74. package/login/pages/WebauthnAuthenticate.js +11 -8
  75. package/login/pages/WebauthnAuthenticate.js.map +1 -1
  76. package/login/pages/WebauthnRegister.js +7 -7
  77. package/login/pages/WebauthnRegister.js.map +1 -1
  78. package/package.json +232 -226
  79. package/src/PUBLIC_URL.ts +4 -1
  80. package/src/account/Template.tsx +5 -5
  81. package/src/account/TemplateProps.ts +4 -1
  82. package/src/account/i18n/i18n.tsx +40 -30
  83. package/src/account/kcContext/KcContext.ts +4 -1
  84. package/src/account/kcContext/createGetKcContext.ts +48 -22
  85. package/src/account/kcContext/getKcContext.ts +3 -1
  86. package/src/account/kcContext/getKcContextFromWindow.ts +6 -2
  87. package/src/account/kcContext/kcContextMocks.ts +164 -160
  88. package/src/account/lib/useGetClassName.ts +15 -14
  89. package/src/account/pages/Account.tsx +2 -2
  90. package/src/account/pages/Password.tsx +8 -8
  91. package/src/account/pages/Totp.tsx +4 -6
  92. package/src/bin/copy-keycloak-resources-to-public.ts +2 -2
  93. package/src/bin/download-keycloak-default-theme.ts +30 -8
  94. package/src/bin/eject-page.ts +48 -11
  95. package/src/bin/initialize-email-theme.ts +25 -17
  96. package/src/bin/keycloakify/buildJars/buildJar.ts +179 -104
  97. package/src/bin/keycloakify/buildJars/buildJars.ts +35 -16
  98. package/src/bin/keycloakify/buildJars/extensionVersions.ts +2 -1
  99. package/src/bin/keycloakify/buildJars/generatePom.ts +11 -3
  100. package/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts +33 -8
  101. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +20 -2
  102. package/src/bin/keycloakify/generateFtl/generateFtl.ts +49 -12
  103. package/src/bin/keycloakify/generateSrcMainResources/bringInAccountV1.ts +29 -18
  104. package/src/bin/keycloakify/generateSrcMainResources/generateMessageProperties.ts +35 -12
  105. package/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResources.ts +3 -1
  106. package/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts +86 -41
  107. package/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForThemeVariant.ts +39 -15
  108. package/src/bin/keycloakify/generateSrcMainResources/readExtraPageNames.ts +21 -7
  109. package/src/bin/keycloakify/generateSrcMainResources/readFieldNameUsage.ts +34 -7
  110. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +19 -5
  111. package/src/bin/keycloakify/keycloakify.ts +28 -9
  112. package/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts +24 -5
  113. package/src/bin/keycloakify/replacers/replaceImportsInInlineCssCode.ts +6 -2
  114. package/src/bin/keycloakify/replacers/replaceImportsInJsCode/replaceImportsInJsCode.ts +6 -3
  115. package/src/bin/keycloakify/replacers/replaceImportsInJsCode/vite.ts +24 -6
  116. package/src/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.ts +49 -11
  117. package/src/bin/main.ts +78 -41
  118. package/src/bin/shared/KeycloakVersionRange.ts +3 -1
  119. package/src/bin/shared/buildOptions.ts +70 -43
  120. package/src/bin/shared/constants.ts +4 -2
  121. package/src/bin/shared/copyKeycloakResourcesToPublic.ts +27 -13
  122. package/src/bin/shared/downloadKeycloakDefaultTheme.ts +161 -218
  123. package/src/bin/shared/downloadKeycloakStaticResources.ts +25 -21
  124. package/src/bin/shared/getJarFileBasename.ts +3 -1
  125. package/src/bin/shared/getThemeSrcDirPath.ts +5 -2
  126. package/src/bin/shared/metaInfKeycloakThemes.ts +35 -8
  127. package/src/bin/shared/promptKeycloakVersion.ts +33 -14
  128. package/src/bin/start-keycloak/appBuild.ts +128 -0
  129. package/src/bin/start-keycloak/index.ts +1 -0
  130. package/src/bin/start-keycloak/keycloakifyBuild.ts +41 -0
  131. package/src/bin/start-keycloak/myrealm-realm-23.json +2142 -0
  132. package/src/bin/start-keycloak/myrealm-realm-24.json +2318 -0
  133. package/src/bin/start-keycloak/start-keycloak.ts +469 -0
  134. package/src/bin/tools/SemVer.ts +32 -13
  135. package/src/bin/tools/String.prototype.replaceAll.ts +9 -2
  136. package/src/bin/tools/crawl.ts +4 -1
  137. package/src/bin/tools/crc32.ts +42 -24
  138. package/src/bin/tools/downloadAndExtractArchive/downloadAndExtractArchive.ts +262 -0
  139. package/src/bin/tools/downloadAndExtractArchive/fetchProxyOptions.ts +96 -0
  140. package/src/bin/tools/downloadAndExtractArchive/index.ts +1 -0
  141. package/src/bin/tools/extractArchive.ts +132 -0
  142. package/src/bin/tools/fetchProxyOptions.ts +31 -8
  143. package/src/bin/tools/getAbsoluteAndInOsFormatPath.ts +10 -2
  144. package/src/bin/tools/getNpmWorkspaceRootDirPath.ts +18 -5
  145. package/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts +8 -2
  146. package/src/bin/tools/octokit-addons/listTags.ts +15 -4
  147. package/src/bin/tools/partitionPromiseSettledResults.ts +12 -3
  148. package/src/bin/tools/readThisNpmPackageVersion.ts +5 -1
  149. package/src/bin/tools/transformCodebase.ts +29 -10
  150. package/src/bin/tools/trimIndent.ts +4 -1
  151. package/src/lib/isStorybook.ts +3 -1
  152. package/src/lib/useGetClassName.ts +12 -3
  153. package/src/login/Template.tsx +14 -14
  154. package/src/login/TemplateProps.ts +4 -1
  155. package/src/login/UserProfileFormFields.tsx +44 -42
  156. package/src/login/i18n/baseMessages/ca.ts +1 -1
  157. package/src/login/i18n/baseMessages/el.ts +0 -1
  158. package/src/login/i18n/baseMessages/en.ts +1 -1
  159. package/src/login/i18n/baseMessages/es.ts +1 -1
  160. package/src/login/i18n/baseMessages/fa.ts +0 -1
  161. package/src/login/i18n/baseMessages/hu.ts +1 -1
  162. package/src/login/i18n/baseMessages/zh-CN.ts +1 -1
  163. package/src/login/i18n/i18n.tsx +42 -32
  164. package/src/login/kcContext/KcContext.ts +8 -2
  165. package/src/login/kcContext/createGetKcContext.ts +84 -37
  166. package/src/login/kcContext/getKcContext.ts +3 -1
  167. package/src/login/kcContext/getKcContextFromWindow.ts +6 -2
  168. package/src/login/kcContext/kcContextMocks.ts +339 -325
  169. package/src/login/lib/useDownloadTerms.ts +6 -4
  170. package/src/login/lib/useGetClassName.ts +119 -112
  171. package/src/login/lib/useUserProfileForm.tsx +219 -205
  172. package/src/login/pages/DeleteAccountConfirm.tsx +9 -3
  173. package/src/login/pages/FrontchannelLogout.tsx +1 -1
  174. package/src/login/pages/Login.tsx +2 -2
  175. package/src/login/pages/LoginRecoveryAuthnCodeConfig.tsx +3 -3
  176. package/src/login/pages/LoginResetPassword.tsx +2 -2
  177. package/src/login/pages/LoginUsername.tsx +2 -2
  178. package/src/login/pages/WebauthnAuthenticate.tsx +11 -8
  179. package/src/login/pages/WebauthnRegister.tsx +7 -7
  180. package/src/tools/AndByDiscriminatingKey.ts +12 -6
  181. package/src/tools/Array.prototype.every.ts +4 -1
  182. package/src/tools/LazyOrNot.ts +3 -1
  183. package/src/tools/clsx.ts +7 -1
  184. package/src/tools/deepAssign.ts +15 -8
  185. package/src/tools/deepClone.ts +3 -1
  186. package/src/tools/formatNumber.ts +4 -1
  187. package/src/tools/useConstCallback.ts +3 -1
  188. package/src/tools/useInsertLinkTags.ts +20 -7
  189. package/src/tools/useInsertScriptTags.ts +7 -2
  190. package/src/tools/useSetClassName.ts +4 -1
  191. package/src/vite-plugin/vite-plugin.ts +45 -21
  192. package/tools/Array.prototype.every.js +2 -1
  193. package/tools/Array.prototype.every.js.map +1 -1
  194. package/tools/clsx.js.map +1 -1
  195. package/tools/deepAssign.js +9 -7
  196. package/tools/deepAssign.js.map +1 -1
  197. package/tools/deepClone.js.map +1 -1
  198. package/tools/formatNumber.js.map +1 -1
  199. package/tools/useConstCallback.js.map +1 -1
  200. package/tools/useInsertLinkTags.js +5 -4
  201. package/tools/useInsertLinkTags.js.map +1 -1
  202. package/tools/useInsertScriptTags.js +5 -2
  203. package/tools/useInsertScriptTags.js.map +1 -1
  204. package/tools/useSetClassName.js.map +1 -1
  205. package/vite-plugin/index.js +985 -1651
  206. package/src/bin/shared/downloadAndUnzip.ts +0 -203
  207. package/src/bin/start-keycloak.ts +0 -309
  208. package/src/bin/tools/unzip.ts +0 -141
@@ -0,0 +1,469 @@
1
+ import { readBuildOptions } from "../shared/buildOptions";
2
+ import type { CliCommandOptions as CliCommandOptions_common } from "../main";
3
+ import { promptKeycloakVersion } from "../shared/promptKeycloakVersion";
4
+ import { readMetaInfKeycloakThemes } from "../shared/metaInfKeycloakThemes";
5
+ import { accountV1ThemeName, containerName } from "../shared/constants";
6
+ import { SemVer } from "../tools/SemVer";
7
+ import type { KeycloakVersionRange } from "../shared/KeycloakVersionRange";
8
+ import { getJarFileBasename } from "../shared/getJarFileBasename";
9
+ import { assert, type Equals } from "tsafe/assert";
10
+ import * as fs from "fs";
11
+ import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path";
12
+ import * as child_process from "child_process";
13
+ import chalk from "chalk";
14
+ import chokidar from "chokidar";
15
+ import { waitForDebounceFactory } from "powerhooks/tools/waitForDebounce";
16
+ import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
17
+ import { getAbsoluteAndInOsFormatPath } from "../tools/getAbsoluteAndInOsFormatPath";
18
+ import cliSelect from "cli-select";
19
+ import * as runExclusive from "run-exclusive";
20
+ import { extractArchive } from "../tools/extractArchive";
21
+ import { appBuild } from "./appBuild";
22
+ import { keycloakifyBuild } from "./keycloakifyBuild";
23
+
24
+ export type CliCommandOptions = CliCommandOptions_common & {
25
+ port: number;
26
+ keycloakVersion: string | undefined;
27
+ realmJsonFilePath: string | undefined;
28
+ };
29
+
30
+ export async function command(params: { cliCommandOptions: CliCommandOptions }) {
31
+ exit_if_docker_not_installed: {
32
+ let commandOutput: Buffer | undefined = undefined;
33
+
34
+ try {
35
+ commandOutput = child_process.execSync("docker --version", {
36
+ stdio: ["ignore", "pipe", "ignore"]
37
+ });
38
+ } catch {}
39
+
40
+ if (commandOutput?.toString("utf8").includes("Docker")) {
41
+ break exit_if_docker_not_installed;
42
+ }
43
+
44
+ console.log(
45
+ [
46
+ `${chalk.red("Docker required.")}`,
47
+ `Install it with Docker Desktop: ${chalk.bold.underline(
48
+ "https://www.docker.com/products/docker-desktop/"
49
+ )}`,
50
+ `(or any other way)`
51
+ ].join(" ")
52
+ );
53
+
54
+ process.exit(1);
55
+ }
56
+
57
+ exit_if_docker_not_running: {
58
+ let isDockerRunning: boolean;
59
+
60
+ try {
61
+ child_process.execSync("docker info", { stdio: "ignore" });
62
+ isDockerRunning = true;
63
+ } catch {
64
+ isDockerRunning = false;
65
+ }
66
+
67
+ if (isDockerRunning) {
68
+ break exit_if_docker_not_running;
69
+ }
70
+
71
+ console.log(
72
+ [
73
+ `${chalk.red("Docker daemon is not running.")}`,
74
+ `Please start Docker Desktop and try again.`
75
+ ].join(" ")
76
+ );
77
+
78
+ process.exit(1);
79
+ }
80
+
81
+ const { cliCommandOptions } = params;
82
+
83
+ const buildOptions = readBuildOptions({ cliCommandOptions });
84
+
85
+ {
86
+ const { isAppBuildSuccess } = await appBuild({
87
+ doSkipIfReactAppBuildDirExists: true,
88
+ buildOptions
89
+ });
90
+
91
+ if (!isAppBuildSuccess) {
92
+ console.log(
93
+ chalk.red(
94
+ `App build failed, exiting. Try running 'yarn build-keycloak-theme' and see what's wrong.`
95
+ )
96
+ );
97
+ process.exit(1);
98
+ }
99
+
100
+ const { isKeycloakifyBuildSuccess } = await keycloakifyBuild({
101
+ doSkipBuildJars: false,
102
+ buildOptions
103
+ });
104
+
105
+ if (!isKeycloakifyBuildSuccess) {
106
+ console.log(
107
+ chalk.red(
108
+ `Keycloakify build failed, exiting. Try running 'yarn build-keycloak-theme' and see what's wrong.`
109
+ )
110
+ );
111
+ process.exit(1);
112
+ }
113
+ }
114
+
115
+ const metaInfKeycloakThemes = readMetaInfKeycloakThemes({
116
+ keycloakifyBuildDirPath: buildOptions.keycloakifyBuildDirPath
117
+ });
118
+
119
+ const doesImplementAccountTheme = metaInfKeycloakThemes.themes.some(
120
+ ({ name }) => name === accountV1ThemeName
121
+ );
122
+
123
+ const { keycloakVersion, keycloakMajorNumber: keycloakMajorVersionNumber } =
124
+ await (async function getKeycloakMajor(): Promise<{
125
+ keycloakVersion: string;
126
+ keycloakMajorNumber: number;
127
+ }> {
128
+ if (cliCommandOptions.keycloakVersion !== undefined) {
129
+ return {
130
+ keycloakVersion: cliCommandOptions.keycloakVersion,
131
+ keycloakMajorNumber: SemVer.parse(cliCommandOptions.keycloakVersion)
132
+ .major
133
+ };
134
+ }
135
+
136
+ console.log(
137
+ chalk.cyan("On which version of Keycloak do you want to test your theme?")
138
+ );
139
+
140
+ const { keycloakVersion } = await promptKeycloakVersion({
141
+ startingFromMajor: 17,
142
+ cacheDirPath: buildOptions.cacheDirPath
143
+ });
144
+
145
+ console.log(`→ ${keycloakVersion}`);
146
+
147
+ const keycloakMajorNumber = SemVer.parse(keycloakVersion).major;
148
+
149
+ if (doesImplementAccountTheme && keycloakMajorNumber === 22) {
150
+ console.log(
151
+ [
152
+ "Unfortunately, Keycloakify themes that implements an account theme do not work on Keycloak 22",
153
+ "Please select any other Keycloak version"
154
+ ].join(" ")
155
+ );
156
+ return getKeycloakMajor();
157
+ }
158
+
159
+ return { keycloakVersion, keycloakMajorNumber };
160
+ })();
161
+
162
+ const keycloakVersionRange: KeycloakVersionRange = (() => {
163
+ if (doesImplementAccountTheme) {
164
+ const keycloakVersionRange = (() => {
165
+ if (keycloakMajorVersionNumber <= 21) {
166
+ return "21-and-below" as const;
167
+ }
168
+
169
+ assert(keycloakMajorVersionNumber !== 22);
170
+
171
+ if (keycloakMajorVersionNumber === 23) {
172
+ return "23" as const;
173
+ }
174
+
175
+ return "24-and-above" as const;
176
+ })();
177
+
178
+ assert<
179
+ Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithAccountTheme>
180
+ >();
181
+
182
+ return keycloakVersionRange;
183
+ } else {
184
+ const keycloakVersionRange = (() => {
185
+ if (keycloakMajorVersionNumber <= 21) {
186
+ return "21-and-below" as const;
187
+ }
188
+
189
+ return "22-and-above" as const;
190
+ })();
191
+
192
+ assert<
193
+ Equals<
194
+ typeof keycloakVersionRange,
195
+ KeycloakVersionRange.WithoutAccountTheme
196
+ >
197
+ >();
198
+
199
+ return keycloakVersionRange;
200
+ }
201
+ })();
202
+
203
+ const { jarFileBasename } = getJarFileBasename({ keycloakVersionRange });
204
+
205
+ console.log(`Using Keycloak ${chalk.bold(jarFileBasename)}`);
206
+
207
+ const realmJsonFilePath = await (async () => {
208
+ if (cliCommandOptions.realmJsonFilePath !== undefined) {
209
+ console.log(
210
+ chalk.green(
211
+ `Using realm json file: ${cliCommandOptions.realmJsonFilePath}`
212
+ )
213
+ );
214
+
215
+ return getAbsoluteAndInOsFormatPath({
216
+ pathIsh: cliCommandOptions.realmJsonFilePath,
217
+ cwd: process.cwd()
218
+ });
219
+ }
220
+
221
+ const dirPath = pathJoin(
222
+ getThisCodebaseRootDirPath(),
223
+ "src",
224
+ "bin",
225
+ "start-keycloak"
226
+ );
227
+
228
+ const filePath = pathJoin(
229
+ dirPath,
230
+ `myrealm-realm-${keycloakMajorVersionNumber}.json`
231
+ );
232
+
233
+ if (fs.existsSync(filePath)) {
234
+ return filePath;
235
+ }
236
+
237
+ console.log(
238
+ `${chalk.yellow(
239
+ `Keycloakify do not have a realm configuration for Keycloak ${keycloakMajorVersionNumber} yet.`
240
+ )}`
241
+ );
242
+
243
+ console.log(chalk.cyan("Select what configuration to use:"));
244
+
245
+ const { value } = await cliSelect<string>({
246
+ values: [
247
+ ...fs
248
+ .readdirSync(dirPath)
249
+ .filter(fileBasename => fileBasename.endsWith(".json")),
250
+ "none"
251
+ ]
252
+ }).catch(() => {
253
+ process.exit(-1);
254
+ });
255
+
256
+ if (value === "none") {
257
+ return undefined;
258
+ }
259
+
260
+ return pathJoin(dirPath, value);
261
+ })();
262
+
263
+ const jarFilePath = pathJoin(buildOptions.keycloakifyBuildDirPath, jarFileBasename);
264
+
265
+ const { doUseBuiltInAccountV1Theme } = await (async () => {
266
+ let doUseBuiltInAccountV1Theme = false;
267
+
268
+ await extractArchive({
269
+ archiveFilePath: jarFilePath,
270
+ onArchiveFile: async ({ relativeFilePathInArchive, readFile, earlyExit }) => {
271
+ for (const themeName of buildOptions.themeNames) {
272
+ if (
273
+ relativeFilePathInArchive ===
274
+ pathJoin("theme", themeName, "account", "theme.properties")
275
+ ) {
276
+ if (
277
+ (await readFile())
278
+ .toString("utf8")
279
+ .includes("parent=keycloak")
280
+ ) {
281
+ doUseBuiltInAccountV1Theme = true;
282
+ }
283
+
284
+ earlyExit();
285
+ }
286
+ }
287
+ }
288
+ });
289
+
290
+ return { doUseBuiltInAccountV1Theme };
291
+ })();
292
+
293
+ const accountThemePropertyPatch = !doUseBuiltInAccountV1Theme
294
+ ? undefined
295
+ : () => {
296
+ for (const themeName of buildOptions.themeNames) {
297
+ const filePath = pathJoin(
298
+ buildOptions.keycloakifyBuildDirPath,
299
+ "src",
300
+ "main",
301
+ "resources",
302
+ "theme",
303
+ themeName,
304
+ "account",
305
+ "theme.properties"
306
+ );
307
+
308
+ const sourceCode = fs.readFileSync(filePath);
309
+
310
+ const modifiedSourceCode = Buffer.from(
311
+ sourceCode
312
+ .toString("utf8")
313
+ .replace(`parent=${accountV1ThemeName}`, "parent=keycloak"),
314
+ "utf8"
315
+ );
316
+
317
+ assert(Buffer.compare(modifiedSourceCode, sourceCode) !== 0);
318
+
319
+ fs.writeFileSync(filePath, modifiedSourceCode);
320
+ }
321
+ };
322
+
323
+ accountThemePropertyPatch?.();
324
+
325
+ try {
326
+ child_process.execSync(`docker rm --force ${containerName}`, {
327
+ stdio: "ignore"
328
+ });
329
+ } catch {}
330
+
331
+ const spawnArgs = [
332
+ "docker",
333
+ [
334
+ "run",
335
+ ...["-p", `${cliCommandOptions.port}:8080`],
336
+ ...["--name", containerName],
337
+ ...["-e", "KEYCLOAK_ADMIN=admin"],
338
+ ...["-e", "KEYCLOAK_ADMIN_PASSWORD=admin"],
339
+ ...(realmJsonFilePath === undefined
340
+ ? []
341
+ : [
342
+ "-v",
343
+ `${realmJsonFilePath}:/opt/keycloak/data/import/myrealm-realm.json`
344
+ ]),
345
+ ...["-v", `${jarFilePath}:/opt/keycloak/providers/keycloak-theme.jar`],
346
+ ...(keycloakMajorVersionNumber <= 20
347
+ ? ["-e", "JAVA_OPTS=-Dkeycloak.profile=preview"]
348
+ : []),
349
+ ...[
350
+ ...buildOptions.themeNames,
351
+ ...(doUseBuiltInAccountV1Theme ? [] : [accountV1ThemeName])
352
+ ]
353
+ .map(themeName => ({
354
+ localDirPath: pathJoin(
355
+ buildOptions.keycloakifyBuildDirPath,
356
+ "src",
357
+ "main",
358
+ "resources",
359
+ "theme",
360
+ themeName
361
+ ),
362
+ containerDirPath: `/opt/keycloak/themes/${themeName}`
363
+ }))
364
+ .map(({ localDirPath, containerDirPath }) => [
365
+ "-v",
366
+ `${localDirPath}:${containerDirPath}:rw`
367
+ ])
368
+ .flat(),
369
+ `quay.io/keycloak/keycloak:${keycloakVersion}`,
370
+ "start-dev",
371
+ ...(21 <= keycloakMajorVersionNumber && keycloakMajorVersionNumber < 24
372
+ ? ["--features=declarative-user-profile"]
373
+ : []),
374
+ ...(realmJsonFilePath === undefined ? [] : ["--import-realm"])
375
+ ],
376
+ {
377
+ cwd: buildOptions.keycloakifyBuildDirPath
378
+ }
379
+ ] as const;
380
+
381
+ const child = child_process.spawn(...spawnArgs);
382
+
383
+ child.stdout.on("data", data => process.stdout.write(data));
384
+
385
+ child.stderr.on("data", data => process.stderr.write(data));
386
+
387
+ child.on("exit", process.exit);
388
+
389
+ const srcDirPath = pathJoin(buildOptions.reactAppRootDirPath, "src");
390
+
391
+ {
392
+ const handler = async (data: Buffer) => {
393
+ if (!data.toString("utf8").includes("Listening on: http://0.0.0.0:8080")) {
394
+ return;
395
+ }
396
+
397
+ child.stdout.off("data", handler);
398
+
399
+ await new Promise(resolve => setTimeout(resolve, 1_000));
400
+
401
+ console.log(
402
+ [
403
+ "",
404
+ `Keycloak Admin console: ${chalk.cyan.bold(
405
+ `http://localhost:${cliCommandOptions.port}`
406
+ )}`,
407
+ `- user: ${chalk.cyan.bold("admin")}`,
408
+ `- password: ${chalk.cyan.bold("admin")}`,
409
+ "",
410
+ "",
411
+ `${chalk.green("Your theme is accessible at:")}`,
412
+ `${chalk.green("➜")} ${chalk.cyan.bold(
413
+ `https://my-theme.keycloakify.dev${cliCommandOptions.port === 8080 ? "" : `?port=${cliCommandOptions.port}`}`
414
+ )}`,
415
+ "",
416
+ "You can login with the following credentials:",
417
+ `- username: ${chalk.cyan.bold("testuser")}`,
418
+ `- password: ${chalk.cyan.bold("password123")}`,
419
+ "",
420
+ `Watching for changes in ${chalk.bold(
421
+ `.${pathSep}${pathRelative(process.cwd(), srcDirPath)}`
422
+ )}`
423
+ ].join("\n")
424
+ );
425
+ };
426
+
427
+ child.stdout.on("data", handler);
428
+ }
429
+
430
+ {
431
+ const runFullBuild = runExclusive.build(async () => {
432
+ console.log(chalk.cyan("Detected changes in the theme. Rebuilding ..."));
433
+
434
+ const { isAppBuildSuccess } = await appBuild({
435
+ doSkipIfReactAppBuildDirExists: false,
436
+ buildOptions
437
+ });
438
+
439
+ if (!isAppBuildSuccess) {
440
+ return;
441
+ }
442
+
443
+ const { isKeycloakifyBuildSuccess } = await keycloakifyBuild({
444
+ doSkipBuildJars: true,
445
+ buildOptions
446
+ });
447
+
448
+ if (!isKeycloakifyBuildSuccess) {
449
+ return;
450
+ }
451
+
452
+ accountThemePropertyPatch?.();
453
+
454
+ console.log(chalk.green("Theme rebuilt and updated in Keycloak."));
455
+ });
456
+
457
+ const { waitForDebounce } = waitForDebounceFactory({ delay: 400 });
458
+
459
+ chokidar
460
+ .watch([srcDirPath, pathJoin(getThisCodebaseRootDirPath(), "src")], {
461
+ ignoreInitial: true
462
+ })
463
+ .on("all", async () => {
464
+ await waitForDebounce();
465
+
466
+ runFullBuild();
467
+ });
468
+ }
469
+ }
@@ -12,35 +12,39 @@ export namespace SemVer {
12
12
  export type BumpType = (typeof bumpTypes)[number];
13
13
 
14
14
  export function parse(versionStr: string): SemVer {
15
- const match = versionStr.match(/^v?([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-rc.([0-9]+))?$/);
15
+ const match = versionStr.match(
16
+ /^v?([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-rc.([0-9]+))?$/
17
+ );
16
18
 
17
19
  if (!match) {
18
20
  throw new Error(`${versionStr} is not a valid semantic version`);
19
21
  }
20
22
 
21
23
  const semVer: Omit<SemVer, "parsedFrom"> = {
22
- "major": parseInt(match[1]),
23
- "minor": parseInt(match[2]),
24
- "patch": (() => {
24
+ major: parseInt(match[1]),
25
+ minor: parseInt(match[2]),
26
+ patch: (() => {
25
27
  const str = match[3];
26
28
 
27
29
  return str === undefined ? 0 : parseInt(str);
28
30
  })(),
29
31
  ...(() => {
30
32
  const str = match[4];
31
- return str === undefined ? {} : { "rc": parseInt(str) };
33
+ return str === undefined ? {} : { rc: parseInt(str) };
32
34
  })()
33
35
  };
34
36
 
35
37
  const initialStr = stringify(semVer);
36
38
 
37
39
  Object.defineProperty(semVer, "parsedFrom", {
38
- "enumerable": true,
39
- "get": function () {
40
+ enumerable: true,
41
+ get: function () {
40
42
  const currentStr = stringify(this);
41
43
 
42
44
  if (currentStr !== initialStr) {
43
- throw new Error(`SemVer.parsedFrom can't be read anymore, the version have been modified from ${initialStr} to ${currentStr}`);
45
+ throw new Error(
46
+ `SemVer.parsedFrom can't be read anymore, the version have been modified from ${initialStr} to ${currentStr}`
47
+ );
44
48
  }
45
49
 
46
50
  return versionStr;
@@ -51,7 +55,9 @@ export namespace SemVer {
51
55
  }
52
56
 
53
57
  export function stringify(v: Omit<SemVer, "parsedFrom">): string {
54
- return `${v.major}.${v.minor}.${v.patch}${v.rc === undefined ? "" : `-rc.${v.rc}`}`;
58
+ return `${v.major}.${v.minor}.${v.patch}${
59
+ v.rc === undefined ? "" : `-rc.${v.rc}`
60
+ }`;
55
61
  }
56
62
 
57
63
  /**
@@ -80,12 +86,25 @@ export namespace SemVer {
80
86
  console.log(compare(parse("3.0.0-rc.3"), parse("4.0.0")) === -1 )
81
87
  */
82
88
 
83
- export function bumpType(params: { versionBehind: string | SemVer; versionAhead: string | SemVer }): BumpType | "no bump" {
84
- const versionAhead = typeof params.versionAhead === "string" ? parse(params.versionAhead) : params.versionAhead;
85
- const versionBehind = typeof params.versionBehind === "string" ? parse(params.versionBehind) : params.versionBehind;
89
+ export function bumpType(params: {
90
+ versionBehind: string | SemVer;
91
+ versionAhead: string | SemVer;
92
+ }): BumpType | "no bump" {
93
+ const versionAhead =
94
+ typeof params.versionAhead === "string"
95
+ ? parse(params.versionAhead)
96
+ : params.versionAhead;
97
+ const versionBehind =
98
+ typeof params.versionBehind === "string"
99
+ ? parse(params.versionBehind)
100
+ : params.versionBehind;
86
101
 
87
102
  if (compare(versionBehind, versionAhead) === 1) {
88
- throw new Error(`Version regression ${stringify(versionBehind)} -> ${stringify(versionAhead)}`);
103
+ throw new Error(
104
+ `Version regression ${stringify(versionBehind)} -> ${stringify(
105
+ versionAhead
106
+ )}`
107
+ );
89
108
  }
90
109
 
91
110
  for (const level of ["major", "minor", "patch", "rc"] as const) {
@@ -1,4 +1,8 @@
1
- export function replaceAll(string: string, searchValue: string | RegExp, replaceValue: string): string {
1
+ export function replaceAll(
2
+ string: string,
3
+ searchValue: string | RegExp,
4
+ replaceValue: string
5
+ ): string {
2
6
  if ((string as any).replaceAll !== undefined) {
3
7
  return (string as any).replaceAll(searchValue, replaceValue);
4
8
  }
@@ -24,7 +28,10 @@ export function replaceAll(string: string, searchValue: string | RegExp, replace
24
28
 
25
29
  // Convert searchValue to string if it's not a string or RegExp
26
30
  var searchString = String(searchValue);
27
- var regexFromString = new RegExp(searchString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
31
+ var regexFromString = new RegExp(
32
+ searchString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
33
+ "g"
34
+ );
28
35
 
29
36
  return string.replace(regexFromString, replaceValue);
30
37
  }
@@ -16,7 +16,10 @@ const crawlRec = (dirPath: string, filePaths: string[]) => {
16
16
  };
17
17
 
18
18
  /** List all files in a given directory return paths relative to the dir_path */
19
- export function crawl(params: { dirPath: string; returnedPathsType: "absolute" | "relative to dirPath" }): string[] {
19
+ export function crawl(params: {
20
+ dirPath: string;
21
+ returnedPathsType: "absolute" | "relative to dirPath";
22
+ }): string[] {
20
23
  const { dirPath, returnedPathsType } = params;
21
24
 
22
25
  const filePaths: string[] = [];