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