keycloakify 8.0.0-rc.3 → 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.
- package/README.md +14 -54
- package/account/kcContext/KcContext.js.map +1 -1
- package/account/kcContext/createGetKcContext.js +2 -6
- package/account/kcContext/createGetKcContext.js.map +1 -1
- package/account/kcContext/kcContextMocks.js +4 -3
- package/account/kcContext/kcContextMocks.js.map +1 -1
- package/bin/constants.d.ts +7 -0
- package/bin/constants.js +10 -0
- package/bin/constants.js.map +1 -0
- package/bin/copy-keycloak-resources-to-public.js +34 -22
- package/bin/copy-keycloak-resources-to-public.js.map +1 -1
- package/bin/download-builtin-keycloak-theme.d.ts +4 -1
- package/bin/download-builtin-keycloak-theme.js +8 -6
- package/bin/download-builtin-keycloak-theme.js.map +1 -1
- package/bin/eject-keycloak-page.js +5 -3
- package/bin/eject-keycloak-page.js.map +1 -1
- package/bin/getSrcDirPath.d.ts +1 -1
- package/bin/getSrcDirPath.js +4 -4
- package/bin/getSrcDirPath.js.map +1 -1
- package/bin/initialize-email-theme.js +9 -9
- package/bin/initialize-email-theme.js.map +1 -1
- package/bin/keycloakify/BuildOptions.d.ts +8 -6
- package/bin/keycloakify/BuildOptions.js +63 -71
- package/bin/keycloakify/BuildOptions.js.map +1 -1
- package/bin/keycloakify/generateFtl/generateFtl.d.ts +2 -3
- package/bin/keycloakify/generateFtl/generateFtl.js +3 -4
- package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +33 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +76 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +25 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +50 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +424 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +51 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +51 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +91 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +157 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +258 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +515 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +56 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +95 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +34 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +75 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +38 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +93 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +125 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +121 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +115 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +1320 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +64 -0
- package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.d.ts +7 -0
- package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.js +194 -0
- package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.js.map +1 -0
- package/bin/keycloakify/{generateJavaStackFiles.d.ts → generateJavaStackFiles/generateJavaStackFiles.d.ts} +6 -6
- package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js +276 -0
- package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js.map +1 -0
- package/bin/keycloakify/generateJavaStackFiles/index.d.ts +1 -0
- package/bin/keycloakify/generateJavaStackFiles/index.js +18 -0
- package/bin/keycloakify/generateJavaStackFiles/index.js.map +1 -0
- package/bin/keycloakify/generateStartKeycloakTestingContainer.d.ts +1 -3
- package/bin/keycloakify/generateStartKeycloakTestingContainer.js +15 -6
- package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +5 -2
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js +11 -8
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
- package/bin/keycloakify/generateTheme/generateMessageProperties.d.ts +1 -1
- package/bin/keycloakify/generateTheme/generateTheme.d.ts +6 -5
- package/bin/keycloakify/generateTheme/generateTheme.js +59 -49
- package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
- package/bin/keycloakify/generateTheme/readExtraPageNames.d.ts +1 -1
- package/bin/keycloakify/generateTheme/readExtraPageNames.js.map +1 -1
- package/bin/keycloakify/generateTheme/readFieldNameUsage.d.ts +1 -1
- package/bin/keycloakify/generateTheme/readStaticResourcesUsage.d.ts +1 -1
- package/bin/keycloakify/keycloakify.js +49 -90
- package/bin/keycloakify/keycloakify.js.map +1 -1
- package/bin/keycloakify/parsedPackageJson.d.ts +29 -31
- package/bin/keycloakify/parsedPackageJson.js +7 -8
- package/bin/keycloakify/parsedPackageJson.js.map +1 -1
- package/bin/promptKeycloakVersion.js +1 -1
- package/bin/promptKeycloakVersion.js.map +1 -1
- package/bin/tools/downloadAndUnzip.d.ts +1 -1
- package/bin/tools/downloadAndUnzip.js +24 -26
- package/bin/tools/downloadAndUnzip.js.map +1 -1
- package/bin/tools/getAbsoluteAndInOsFormatPath.d.ts +4 -0
- package/bin/tools/getAbsoluteAndInOsFormatPath.js +15 -0
- package/bin/tools/getAbsoluteAndInOsFormatPath.js.map +1 -0
- package/bin/tools/pathJoin.js +1 -1
- package/bin/tools/pathJoin.js.map +1 -1
- package/login/kcContext/KcContext.js.map +1 -1
- package/login/kcContext/createGetKcContext.js +2 -6
- package/login/kcContext/createGetKcContext.js.map +1 -1
- package/login/kcContext/kcContextMocks.js +5 -4
- package/login/kcContext/kcContextMocks.js.map +1 -1
- package/package.json +92 -21
- package/src/account/kcContext/KcContext.ts +2 -1
- package/src/account/kcContext/createGetKcContext.ts +2 -7
- package/src/account/kcContext/kcContextMocks.ts +5 -3
- package/src/bin/constants.ts +9 -0
- package/src/bin/copy-keycloak-resources-to-public.ts +20 -19
- package/src/bin/download-builtin-keycloak-theme.ts +14 -6
- package/src/bin/eject-keycloak-page.ts +5 -9
- package/src/bin/getSrcDirPath.ts +4 -4
- package/src/bin/initialize-email-theme.ts +7 -7
- package/src/bin/keycloakify/BuildOptions.ts +78 -59
- package/src/bin/keycloakify/generateFtl/generateFtl.ts +4 -7
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +33 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +76 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +25 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +50 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +424 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +51 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +51 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +91 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +157 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +258 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +515 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +56 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +95 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +34 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +75 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +38 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +93 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +125 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +121 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +115 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +1320 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +64 -0
- package/src/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.ts +92 -0
- package/src/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.ts +211 -0
- package/src/bin/keycloakify/generateJavaStackFiles/index.ts +1 -0
- package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +21 -22
- package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +19 -15
- package/src/bin/keycloakify/generateTheme/generateMessageProperties.ts +1 -1
- package/src/bin/keycloakify/generateTheme/generateTheme.ts +78 -72
- package/src/bin/keycloakify/generateTheme/readExtraPageNames.ts +2 -1
- package/src/bin/keycloakify/generateTheme/readFieldNameUsage.ts +1 -1
- package/src/bin/keycloakify/generateTheme/readStaticResourcesUsage.ts +1 -1
- package/src/bin/keycloakify/keycloakify.ts +21 -44
- package/src/bin/keycloakify/parsedPackageJson.ts +11 -13
- package/src/bin/promptKeycloakVersion.ts +1 -1
- package/src/bin/tools/downloadAndUnzip.ts +6 -7
- package/src/bin/tools/getAbsoluteAndInOsFormatPath.ts +15 -0
- package/src/bin/tools/pathJoin.ts +1 -1
- package/src/login/kcContext/KcContext.ts +2 -1
- package/src/login/kcContext/createGetKcContext.ts +2 -7
- package/src/login/kcContext/kcContextMocks.ts +7 -5
- package/bin/keycloakify/generateJavaStackFiles.js +0 -103
- package/bin/keycloakify/generateJavaStackFiles.js.map +0 -1
- package/bin/mockTestingResourcesPath.d.ts +0 -3
- package/bin/mockTestingResourcesPath.js +0 -8
- package/bin/mockTestingResourcesPath.js.map +0 -1
- package/bin/tools/jar.d.ts +0 -33
- package/bin/tools/jar.js +0 -241
- package/bin/tools/jar.js.map +0 -1
- package/bin/tools/walk.d.ts +0 -8
- package/bin/tools/walk.js +0 -125
- package/bin/tools/walk.js.map +0 -1
- package/src/bin/keycloakify/generateJavaStackFiles.ts +0 -84
- package/src/bin/mockTestingResourcesPath.ts +0 -5
- package/src/bin/tools/jar.ts +0 -99
- 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
|
7
|
-
import {
|
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
|
-
|
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
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
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(
|
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,
|
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
|
-
|
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(
|
149
|
+
fs.mkdirSync(themeTypeDirPath, { "recursive": true });
|
146
150
|
|
147
|
-
fs.writeFileSync(pathJoin(
|
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(
|
158
|
+
const messagesDirPath = pathJoin(themeTypeDirPath, "messages");
|
155
159
|
|
156
|
-
fs.mkdirSync(pathJoin(
|
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
|
-
|
200
|
-
|
201
|
-
|
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(
|
212
|
-
Buffer.from(
|
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":
|
231
|
+
"destDirPath": getThemeTypeDirPath({ "themeType": "email" })
|
226
232
|
});
|
227
233
|
}
|
228
234
|
}
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import { crawl } from "../../tools/crawl";
|
2
|
-
import {
|
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 "
|
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 "
|
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
|
15
|
+
const reactAppRootDirPath = process.cwd();
|
18
16
|
|
19
17
|
const buildOptions = readBuildOptions({
|
20
|
-
|
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({
|
27
|
+
const { themeSrcDirPath } = getThemeSrcDirPath({ reactAppRootDirPath });
|
30
28
|
|
31
|
-
for (const themeName of
|
29
|
+
for (const themeName of buildOptions.themeNames) {
|
32
30
|
await generateTheme({
|
33
|
-
|
34
|
-
"keycloakThemeBuildingDirPath": buildOptions.keycloakifyBuildDirPath,
|
31
|
+
themeName,
|
35
32
|
themeSrcDirPath,
|
36
33
|
"keycloakifySrcDirPath": pathJoin(keycloakifyDirPath, "src"),
|
37
|
-
|
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
|
-
|
74
|
-
|
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
|
-
|
108
|
-
|
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
|
-
|
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.
|
153
|
-
` Clients -> account -> Login theme: ${buildOptions.
|
154
|
-
`- Enable the email theme (optional): Realm settings -> Themes tab -> Email theme: ${buildOptions.
|
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.
|
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
|
-
|
19
|
-
|
16
|
+
doCreateJar?: boolean;
|
17
|
+
loginThemeResourcesFromKeycloakVersion?: string;
|
20
18
|
reactAppBuildDirPath?: string;
|
21
19
|
keycloakifyBuildDirPath?: string;
|
22
|
-
themeName?: string;
|
23
|
-
|
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
|
-
"
|
38
|
-
"
|
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
|
-
"
|
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: {
|
51
|
-
const {
|
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(
|
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("
|
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
|
-
|
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
|
186
|
-
|
187
|
-
|
188
|
-
const
|
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(
|
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
|
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 {
|
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
|
-
|
112
|
-
"resourcesCommonPath": pathJoin(
|
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
|
},
|