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.
- 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 +2265 -2028
- 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 +232 -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/ftl_object_to_js_code_declaring_an_object.ftl +20 -2
- 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/appBuild.ts +128 -0
- package/src/bin/start-keycloak/index.ts +1 -0
- package/src/bin/start-keycloak/keycloakifyBuild.ts +41 -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 +469 -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 +132 -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 +985 -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
@@ -1,203 +0,0 @@
|
|
1
|
-
import { createHash } from "crypto";
|
2
|
-
import { mkdir, writeFile, unlink } from "fs/promises";
|
3
|
-
import fetch from "make-fetch-happen";
|
4
|
-
import { dirname as pathDirname, join as pathJoin, basename as pathBasename } from "path";
|
5
|
-
import { assert } from "tsafe/assert";
|
6
|
-
import { transformCodebase } from "../tools/transformCodebase";
|
7
|
-
import { unzip, zip } from "../tools/unzip";
|
8
|
-
import { rm } from "../tools/fs.rm";
|
9
|
-
import * as child_process from "child_process";
|
10
|
-
import { existsAsync } from "../tools/fs.existsAsync";
|
11
|
-
import type { BuildOptions } from "./buildOptions";
|
12
|
-
import { getProxyFetchOptions } from "../tools/fetchProxyOptions";
|
13
|
-
|
14
|
-
export type BuildOptionsLike = {
|
15
|
-
cacheDirPath: string;
|
16
|
-
npmWorkspaceRootDirPath: string;
|
17
|
-
};
|
18
|
-
|
19
|
-
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
20
|
-
|
21
|
-
export async function downloadAndUnzip(params: {
|
22
|
-
url: string;
|
23
|
-
destDirPath: string;
|
24
|
-
specificDirsToExtract?: string[];
|
25
|
-
preCacheTransform?: {
|
26
|
-
actionCacheId: string;
|
27
|
-
action: (params: { destDirPath: string }) => Promise<void>;
|
28
|
-
};
|
29
|
-
buildOptions: BuildOptionsLike;
|
30
|
-
}) {
|
31
|
-
const { url, destDirPath, specificDirsToExtract, preCacheTransform, buildOptions } = params;
|
32
|
-
|
33
|
-
const { extractDirPath, zipFilePath } = (() => {
|
34
|
-
const zipFileBasenameWithoutExt = generateFileNameFromURL({
|
35
|
-
url,
|
36
|
-
"preCacheTransform":
|
37
|
-
preCacheTransform === undefined
|
38
|
-
? undefined
|
39
|
-
: {
|
40
|
-
"actionCacheId": preCacheTransform.actionCacheId,
|
41
|
-
"actionFootprint": preCacheTransform.action.toString()
|
42
|
-
}
|
43
|
-
});
|
44
|
-
|
45
|
-
const zipFilePath = pathJoin(buildOptions.cacheDirPath, `${zipFileBasenameWithoutExt}.zip`);
|
46
|
-
const extractDirPath = pathJoin(buildOptions.cacheDirPath, `tmp_unzip_${zipFileBasenameWithoutExt}`);
|
47
|
-
|
48
|
-
return { zipFilePath, extractDirPath };
|
49
|
-
})();
|
50
|
-
|
51
|
-
download_zip_and_transform: {
|
52
|
-
if (await existsAsync(zipFilePath)) {
|
53
|
-
break download_zip_and_transform;
|
54
|
-
}
|
55
|
-
|
56
|
-
const { response, isFromRemoteCache } = await (async () => {
|
57
|
-
const proxyFetchOptions = await getProxyFetchOptions({
|
58
|
-
"npmWorkspaceRootDirPath": buildOptions.npmWorkspaceRootDirPath
|
59
|
-
});
|
60
|
-
|
61
|
-
const response = await fetch(
|
62
|
-
`https://github.com/keycloakify/keycloakify/releases/download/v0.0.1/${pathBasename(zipFilePath)}`,
|
63
|
-
proxyFetchOptions
|
64
|
-
);
|
65
|
-
|
66
|
-
if (response.status === 200) {
|
67
|
-
return {
|
68
|
-
response,
|
69
|
-
"isFromRemoteCache": true
|
70
|
-
};
|
71
|
-
}
|
72
|
-
|
73
|
-
return {
|
74
|
-
"response": await fetch(url, proxyFetchOptions),
|
75
|
-
"isFromRemoteCache": false
|
76
|
-
};
|
77
|
-
})();
|
78
|
-
|
79
|
-
await mkdir(pathDirname(zipFilePath), { "recursive": true });
|
80
|
-
|
81
|
-
/**
|
82
|
-
* The correct way to fix this is to upgrade node-fetch beyond 3.2.5
|
83
|
-
* (see https://github.com/node-fetch/node-fetch/issues/1295#issuecomment-1144061991.)
|
84
|
-
* Unfortunately, octokit (a dependency of keycloakify) also uses node-fetch, and
|
85
|
-
* does not support node-fetch 3.x. So we stick around with this band-aid until
|
86
|
-
* octokit upgrades.
|
87
|
-
*/
|
88
|
-
response.body?.setMaxListeners(Number.MAX_VALUE);
|
89
|
-
assert(typeof response.body !== "undefined" && response.body != null);
|
90
|
-
|
91
|
-
await writeFile(zipFilePath, response.body);
|
92
|
-
|
93
|
-
if (isFromRemoteCache) {
|
94
|
-
break download_zip_and_transform;
|
95
|
-
}
|
96
|
-
|
97
|
-
if (specificDirsToExtract === undefined && preCacheTransform === undefined) {
|
98
|
-
break download_zip_and_transform;
|
99
|
-
}
|
100
|
-
|
101
|
-
await unzip(zipFilePath, extractDirPath, specificDirsToExtract);
|
102
|
-
|
103
|
-
try {
|
104
|
-
await preCacheTransform?.action({
|
105
|
-
"destDirPath": extractDirPath
|
106
|
-
});
|
107
|
-
} catch (error) {
|
108
|
-
await Promise.all([rm(extractDirPath, { "recursive": true }), unlink(zipFilePath)]);
|
109
|
-
|
110
|
-
throw error;
|
111
|
-
}
|
112
|
-
|
113
|
-
await unlink(zipFilePath);
|
114
|
-
|
115
|
-
await zip(extractDirPath, zipFilePath);
|
116
|
-
|
117
|
-
await rm(extractDirPath, { "recursive": true });
|
118
|
-
|
119
|
-
upload_to_remote_cache_if_admin: {
|
120
|
-
const githubToken = process.env["KEYCLOAKIFY_ADMIN_GITHUB_PERSONAL_ACCESS_TOKEN"];
|
121
|
-
|
122
|
-
if (!githubToken) {
|
123
|
-
break upload_to_remote_cache_if_admin;
|
124
|
-
}
|
125
|
-
|
126
|
-
console.log("uploading to remote cache");
|
127
|
-
|
128
|
-
try {
|
129
|
-
child_process.execSync(`which putasset`);
|
130
|
-
} catch {
|
131
|
-
child_process.execSync(`npm install -g putasset`);
|
132
|
-
}
|
133
|
-
|
134
|
-
try {
|
135
|
-
child_process.execFileSync("putasset", [
|
136
|
-
"--owner",
|
137
|
-
"keycloakify",
|
138
|
-
"--repo",
|
139
|
-
"keycloakify",
|
140
|
-
"--tag",
|
141
|
-
"v0.0.1",
|
142
|
-
"--filename",
|
143
|
-
zipFilePath,
|
144
|
-
"--token",
|
145
|
-
githubToken
|
146
|
-
]);
|
147
|
-
} catch {
|
148
|
-
console.log("upload failed, asset probably already exists in remote cache");
|
149
|
-
}
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
await unzip(zipFilePath, extractDirPath);
|
154
|
-
|
155
|
-
transformCodebase({
|
156
|
-
"srcDirPath": extractDirPath,
|
157
|
-
"destDirPath": destDirPath
|
158
|
-
});
|
159
|
-
|
160
|
-
await rm(extractDirPath, { "recursive": true });
|
161
|
-
}
|
162
|
-
|
163
|
-
function generateFileNameFromURL(params: {
|
164
|
-
url: string;
|
165
|
-
preCacheTransform:
|
166
|
-
| {
|
167
|
-
actionCacheId: string;
|
168
|
-
actionFootprint: string;
|
169
|
-
}
|
170
|
-
| undefined;
|
171
|
-
}): string {
|
172
|
-
const { preCacheTransform } = params;
|
173
|
-
|
174
|
-
// Parse the URL
|
175
|
-
const url = new URL(params.url);
|
176
|
-
|
177
|
-
// Extract pathname and remove leading slashes
|
178
|
-
let fileName = url.pathname.replace(/^\//, "").replace(/\//g, "_");
|
179
|
-
|
180
|
-
// Optionally, add query parameters replacing special characters
|
181
|
-
if (url.search) {
|
182
|
-
fileName += url.search.replace(/[&=?]/g, "-");
|
183
|
-
}
|
184
|
-
|
185
|
-
// Replace any characters that are not valid in filenames
|
186
|
-
fileName = fileName.replace(/[^a-zA-Z0-9-_]/g, "");
|
187
|
-
|
188
|
-
// Trim or pad the fileName to a specific length
|
189
|
-
fileName = fileName.substring(0, 50);
|
190
|
-
|
191
|
-
add_pre_cache_transform: {
|
192
|
-
if (preCacheTransform === undefined) {
|
193
|
-
break add_pre_cache_transform;
|
194
|
-
}
|
195
|
-
|
196
|
-
// Sanitize actionCacheId the same way as other components
|
197
|
-
const sanitizedActionCacheId = preCacheTransform.actionCacheId.replace(/[^a-zA-Z0-9-_]/g, "_");
|
198
|
-
|
199
|
-
fileName += `_${sanitizedActionCacheId}_${createHash("sha256").update(preCacheTransform.actionFootprint).digest("hex").substring(0, 5)}`;
|
200
|
-
}
|
201
|
-
|
202
|
-
return fileName;
|
203
|
-
}
|
@@ -1,309 +0,0 @@
|
|
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, skipBuildJarsEnvName } 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, posix as pathPosix } 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 { getThemeSrcDirPath } from "./shared/getThemeSrcDirPath";
|
17
|
-
import { Deferred } from "evt/tools/Deferred";
|
18
|
-
|
19
|
-
export type CliCommandOptions = CliCommandOptions_common & {
|
20
|
-
port: number;
|
21
|
-
keycloakVersion: string | undefined;
|
22
|
-
};
|
23
|
-
|
24
|
-
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
|
25
|
-
exit_if_docker_not_installed: {
|
26
|
-
let commandOutput: Buffer | undefined = undefined;
|
27
|
-
|
28
|
-
try {
|
29
|
-
commandOutput = child_process.execSync("docker --version", { "stdio": ["ignore", "pipe", "ignore"] });
|
30
|
-
} catch {}
|
31
|
-
|
32
|
-
if (commandOutput?.toString("utf8").includes("Docker")) {
|
33
|
-
break exit_if_docker_not_installed;
|
34
|
-
}
|
35
|
-
|
36
|
-
console.log(
|
37
|
-
[
|
38
|
-
`${chalk.red("Docker required.")}`,
|
39
|
-
`Install it with Docker Desktop: ${chalk.bold.underline("https://www.docker.com/products/docker-desktop/")}`,
|
40
|
-
`(or any other way)`
|
41
|
-
].join(" ")
|
42
|
-
);
|
43
|
-
|
44
|
-
process.exit(1);
|
45
|
-
}
|
46
|
-
|
47
|
-
exit_if_docker_not_running: {
|
48
|
-
let isDockerRunning: boolean;
|
49
|
-
|
50
|
-
try {
|
51
|
-
child_process.execSync("docker info", { "stdio": "ignore" });
|
52
|
-
isDockerRunning = true;
|
53
|
-
} catch {
|
54
|
-
isDockerRunning = false;
|
55
|
-
}
|
56
|
-
|
57
|
-
if (isDockerRunning) {
|
58
|
-
break exit_if_docker_not_running;
|
59
|
-
}
|
60
|
-
|
61
|
-
console.log([`${chalk.red("Docker daemon is not running.")}`, `Please start Docker Desktop and try again.`].join(" "));
|
62
|
-
|
63
|
-
process.exit(1);
|
64
|
-
}
|
65
|
-
|
66
|
-
const { cliCommandOptions } = params;
|
67
|
-
|
68
|
-
const buildOptions = readBuildOptions({ cliCommandOptions });
|
69
|
-
|
70
|
-
exit_if_theme_not_built: {
|
71
|
-
if (fs.existsSync(buildOptions.keycloakifyBuildDirPath)) {
|
72
|
-
break exit_if_theme_not_built;
|
73
|
-
}
|
74
|
-
|
75
|
-
console.log(
|
76
|
-
[`${chalk.red("The theme has not been built.")}`, `Please run ${chalk.bold("npx vite && npx keycloakify build")} first.`].join(" ")
|
77
|
-
);
|
78
|
-
process.exit(1);
|
79
|
-
}
|
80
|
-
|
81
|
-
const metaInfKeycloakThemes = readMetaInfKeycloakThemes({
|
82
|
-
"keycloakifyBuildDirPath": buildOptions.keycloakifyBuildDirPath
|
83
|
-
});
|
84
|
-
|
85
|
-
const doesImplementAccountTheme = metaInfKeycloakThemes.themes.some(({ name }) => name === accountV1ThemeName);
|
86
|
-
|
87
|
-
const { keycloakVersion, keycloakMajorNumber } = await (async function getKeycloakMajor(): Promise<{
|
88
|
-
keycloakVersion: string;
|
89
|
-
keycloakMajorNumber: number;
|
90
|
-
}> {
|
91
|
-
if (cliCommandOptions.keycloakVersion !== undefined) {
|
92
|
-
return {
|
93
|
-
"keycloakVersion": cliCommandOptions.keycloakVersion,
|
94
|
-
"keycloakMajorNumber": SemVer.parse(cliCommandOptions.keycloakVersion).major
|
95
|
-
};
|
96
|
-
}
|
97
|
-
|
98
|
-
console.log(chalk.cyan("On which version of Keycloak do you want to test your theme?"));
|
99
|
-
|
100
|
-
const { keycloakVersion } = await promptKeycloakVersion({
|
101
|
-
"startingFromMajor": 17,
|
102
|
-
"cacheDirPath": buildOptions.cacheDirPath
|
103
|
-
});
|
104
|
-
|
105
|
-
console.log(`→ ${keycloakVersion}`);
|
106
|
-
|
107
|
-
const keycloakMajorNumber = SemVer.parse(keycloakVersion).major;
|
108
|
-
|
109
|
-
if (doesImplementAccountTheme && keycloakMajorNumber === 22) {
|
110
|
-
console.log(
|
111
|
-
[
|
112
|
-
"Unfortunately, Keycloakify themes that implements an account theme do not work on Keycloak 22",
|
113
|
-
"Please select any other Keycloak version"
|
114
|
-
].join(" ")
|
115
|
-
);
|
116
|
-
return getKeycloakMajor();
|
117
|
-
}
|
118
|
-
|
119
|
-
return { keycloakVersion, keycloakMajorNumber };
|
120
|
-
})();
|
121
|
-
|
122
|
-
const keycloakVersionRange: KeycloakVersionRange = (() => {
|
123
|
-
if (doesImplementAccountTheme) {
|
124
|
-
const keycloakVersionRange = (() => {
|
125
|
-
if (keycloakMajorNumber <= 21) {
|
126
|
-
return "21-and-below" as const;
|
127
|
-
}
|
128
|
-
|
129
|
-
assert(keycloakMajorNumber !== 22);
|
130
|
-
|
131
|
-
if (keycloakMajorNumber === 23) {
|
132
|
-
return "23" as const;
|
133
|
-
}
|
134
|
-
|
135
|
-
return "24-and-above" as const;
|
136
|
-
})();
|
137
|
-
|
138
|
-
assert<Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithAccountTheme>>();
|
139
|
-
|
140
|
-
return keycloakVersionRange;
|
141
|
-
} else {
|
142
|
-
const keycloakVersionRange = (() => {
|
143
|
-
if (keycloakMajorNumber <= 21) {
|
144
|
-
return "21-and-below" as const;
|
145
|
-
}
|
146
|
-
|
147
|
-
return "22-and-above" as const;
|
148
|
-
})();
|
149
|
-
|
150
|
-
assert<Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithoutAccountTheme>>();
|
151
|
-
|
152
|
-
return keycloakVersionRange;
|
153
|
-
}
|
154
|
-
})();
|
155
|
-
|
156
|
-
const { jarFileBasename } = getJarFileBasename({ keycloakVersionRange });
|
157
|
-
|
158
|
-
console.log(`Using Keycloak ${chalk.bold(jarFileBasename)}`);
|
159
|
-
|
160
|
-
const mountTargets = buildOptions.themeNames
|
161
|
-
.map(themeName => {
|
162
|
-
const themeEntry = metaInfKeycloakThemes.themes.find(({ name }) => name === themeName);
|
163
|
-
|
164
|
-
assert(themeEntry !== undefined);
|
165
|
-
|
166
|
-
return themeEntry.types
|
167
|
-
.map(themeType => {
|
168
|
-
const localPathDirname = pathJoin(
|
169
|
-
buildOptions.keycloakifyBuildDirPath,
|
170
|
-
"src",
|
171
|
-
"main",
|
172
|
-
"resources",
|
173
|
-
"theme",
|
174
|
-
themeName,
|
175
|
-
themeType
|
176
|
-
);
|
177
|
-
|
178
|
-
return fs
|
179
|
-
.readdirSync(localPathDirname)
|
180
|
-
.filter(fileOrDirectoryBasename => !fileOrDirectoryBasename.endsWith(".properties"))
|
181
|
-
.map(fileOrDirectoryBasename => ({
|
182
|
-
"localPath": pathJoin(localPathDirname, fileOrDirectoryBasename),
|
183
|
-
"containerPath": pathPosix.join("/", "opt", "keycloak", "themes", themeName, themeType, fileOrDirectoryBasename)
|
184
|
-
}));
|
185
|
-
})
|
186
|
-
.flat();
|
187
|
-
})
|
188
|
-
.flat();
|
189
|
-
|
190
|
-
const containerName = "keycloak-keycloakify";
|
191
|
-
|
192
|
-
try {
|
193
|
-
child_process.execSync(`docker rm --force ${containerName}`, { "stdio": "ignore" });
|
194
|
-
} catch {}
|
195
|
-
|
196
|
-
const spawnParams = [
|
197
|
-
"docker",
|
198
|
-
[
|
199
|
-
"run",
|
200
|
-
...["-p", `${cliCommandOptions.port}:8080`],
|
201
|
-
...["--name", containerName],
|
202
|
-
...["-e", "KEYCLOAK_ADMIN=admin"],
|
203
|
-
...["-e", "KEYCLOAK_ADMIN_PASSWORD=admin"],
|
204
|
-
...["-v", `${pathJoin(buildOptions.keycloakifyBuildDirPath, jarFileBasename)}:/opt/keycloak/providers/keycloak-theme.jar`],
|
205
|
-
...(keycloakMajorNumber <= 20 ? ["-e", "JAVA_OPTS=-Dkeycloak.profile=preview"] : []),
|
206
|
-
...mountTargets.map(({ localPath, containerPath }) => ["-v", `${localPath}:${containerPath}:rw`]).flat(),
|
207
|
-
`quay.io/keycloak/keycloak:${keycloakVersion}`,
|
208
|
-
"start-dev",
|
209
|
-
...(21 <= keycloakMajorNumber && keycloakMajorNumber < 24 ? ["--features=declarative-user-profile"] : [])
|
210
|
-
],
|
211
|
-
{
|
212
|
-
"cwd": buildOptions.keycloakifyBuildDirPath
|
213
|
-
}
|
214
|
-
] as const;
|
215
|
-
|
216
|
-
const child = child_process.spawn(...spawnParams);
|
217
|
-
|
218
|
-
child.stdout.on("data", data => process.stdout.write(data));
|
219
|
-
|
220
|
-
child.stderr.on("data", data => process.stderr.write(data));
|
221
|
-
|
222
|
-
child.on("exit", process.exit);
|
223
|
-
|
224
|
-
const { themeSrcDirPath } = getThemeSrcDirPath({ "reactAppRootDirPath": buildOptions.reactAppRootDirPath });
|
225
|
-
|
226
|
-
{
|
227
|
-
const handler = async (data: Buffer) => {
|
228
|
-
if (!data.toString("utf8").includes("Listening on: http://0.0.0.0:8080")) {
|
229
|
-
return;
|
230
|
-
}
|
231
|
-
|
232
|
-
child.stdout.off("data", handler);
|
233
|
-
|
234
|
-
await new Promise(resolve => setTimeout(resolve, 1_000));
|
235
|
-
|
236
|
-
console.log(
|
237
|
-
[
|
238
|
-
"",
|
239
|
-
`${chalk.green("Your theme is accessible at:")}`,
|
240
|
-
`${chalk.green("➜")} ${chalk.cyan.bold("https://test.keycloakify.dev/")}`,
|
241
|
-
"",
|
242
|
-
`Keycloak Admin console: ${chalk.cyan.bold(`http://localhost:${cliCommandOptions.port}`)}`,
|
243
|
-
`- user: ${chalk.cyan.bold("admin")}`,
|
244
|
-
`- password: ${chalk.cyan.bold("admin")}`,
|
245
|
-
"",
|
246
|
-
`Watching for changes in ${chalk.bold(`.${pathSep}${pathRelative(process.cwd(), themeSrcDirPath)}`)} ...`
|
247
|
-
].join("\n")
|
248
|
-
);
|
249
|
-
};
|
250
|
-
|
251
|
-
child.stdout.on("data", handler);
|
252
|
-
}
|
253
|
-
|
254
|
-
{
|
255
|
-
const { waitForDebounce } = waitForDebounceFactory({ "delay": 400 });
|
256
|
-
|
257
|
-
chokidar.watch(themeSrcDirPath, { "ignoreInitial": true }).on("all", async (...eventArgs) => {
|
258
|
-
console.log({ eventArgs });
|
259
|
-
|
260
|
-
await waitForDebounce();
|
261
|
-
|
262
|
-
console.log(chalk.cyan("Detected changes in the theme. Rebuilding ..."));
|
263
|
-
|
264
|
-
const dViteBuildDone = new Deferred<void>();
|
265
|
-
|
266
|
-
{
|
267
|
-
const child = child_process.spawn("npx", ["vite", "build"], {
|
268
|
-
"cwd": buildOptions.reactAppRootDirPath,
|
269
|
-
"env": process.env
|
270
|
-
});
|
271
|
-
|
272
|
-
child.stdout.on("data", data => process.stdout.write(data));
|
273
|
-
|
274
|
-
child.stderr.on("data", data => process.stderr.write(data));
|
275
|
-
|
276
|
-
child.on("exit", code => {
|
277
|
-
if (code === 0) {
|
278
|
-
dViteBuildDone.resolve();
|
279
|
-
}
|
280
|
-
});
|
281
|
-
}
|
282
|
-
|
283
|
-
await dViteBuildDone.pr;
|
284
|
-
|
285
|
-
{
|
286
|
-
const child = child_process.spawn("npx", ["keycloakify", "build"], {
|
287
|
-
"cwd": buildOptions.reactAppRootDirPath,
|
288
|
-
"env": {
|
289
|
-
...process.env,
|
290
|
-
[skipBuildJarsEnvName]: "true"
|
291
|
-
}
|
292
|
-
});
|
293
|
-
|
294
|
-
child.stdout.on("data", data => process.stdout.write(data));
|
295
|
-
|
296
|
-
child.stderr.on("data", data => process.stderr.write(data));
|
297
|
-
|
298
|
-
child.on("exit", code => {
|
299
|
-
if (code !== 0) {
|
300
|
-
console.log(chalk.yellow("Theme not updated, build failed"));
|
301
|
-
return;
|
302
|
-
}
|
303
|
-
|
304
|
-
console.log(chalk.green("Rebuild done"));
|
305
|
-
});
|
306
|
-
}
|
307
|
-
});
|
308
|
-
}
|
309
|
-
}
|
package/src/bin/tools/unzip.ts
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
import fsp from "node:fs/promises";
|
2
|
-
import fs from "fs";
|
3
|
-
import path from "node:path";
|
4
|
-
import yauzl from "yauzl";
|
5
|
-
import yazl from "yazl";
|
6
|
-
import stream from "node:stream";
|
7
|
-
import { promisify } from "node:util";
|
8
|
-
|
9
|
-
const pipeline = promisify(stream.pipeline);
|
10
|
-
|
11
|
-
async function pathExists(path: string) {
|
12
|
-
try {
|
13
|
-
await fsp.stat(path);
|
14
|
-
return true;
|
15
|
-
} catch (error) {
|
16
|
-
if ((error as { code: string }).code === "ENOENT") {
|
17
|
-
return false;
|
18
|
-
}
|
19
|
-
throw error;
|
20
|
-
}
|
21
|
-
}
|
22
|
-
|
23
|
-
// Handlings of non posix path is not implemented correctly
|
24
|
-
// it work by coincidence. Don't have the time to fix but it should be fixed.
|
25
|
-
export async function unzip(file: string, targetFolder: string, specificDirsToExtract?: string[]) {
|
26
|
-
specificDirsToExtract = specificDirsToExtract?.map(dirPath => {
|
27
|
-
if (!dirPath.endsWith("/") || !dirPath.endsWith("\\")) {
|
28
|
-
dirPath += "/";
|
29
|
-
}
|
30
|
-
|
31
|
-
return dirPath;
|
32
|
-
});
|
33
|
-
|
34
|
-
if (!targetFolder.endsWith("/") || !targetFolder.endsWith("\\")) {
|
35
|
-
targetFolder += "/";
|
36
|
-
}
|
37
|
-
if (!fs.existsSync(targetFolder)) {
|
38
|
-
fs.mkdirSync(targetFolder, { recursive: true });
|
39
|
-
}
|
40
|
-
|
41
|
-
return new Promise<void>((resolve, reject) => {
|
42
|
-
yauzl.open(file, { lazyEntries: true }, async (err, zipfile) => {
|
43
|
-
if (err) {
|
44
|
-
reject(err);
|
45
|
-
return;
|
46
|
-
}
|
47
|
-
|
48
|
-
zipfile.readEntry();
|
49
|
-
|
50
|
-
zipfile.on("entry", async entry => {
|
51
|
-
if (specificDirsToExtract !== undefined) {
|
52
|
-
const dirPath = specificDirsToExtract.find(dirPath => entry.fileName.startsWith(dirPath));
|
53
|
-
|
54
|
-
// Skip files outside of the unzipSubPath
|
55
|
-
if (dirPath === undefined) {
|
56
|
-
zipfile.readEntry();
|
57
|
-
return;
|
58
|
-
}
|
59
|
-
|
60
|
-
// Remove the unzipSubPath from the file name
|
61
|
-
entry.fileName = entry.fileName.substring(dirPath.length);
|
62
|
-
}
|
63
|
-
|
64
|
-
const target = path.join(targetFolder, entry.fileName);
|
65
|
-
|
66
|
-
// Directory file names end with '/'.
|
67
|
-
// Note that entries for directories themselves are optional.
|
68
|
-
// An entry's fileName implicitly requires its parent directories to exist.
|
69
|
-
if (/[\/\\]$/.test(target)) {
|
70
|
-
await fsp.mkdir(target, { recursive: true });
|
71
|
-
|
72
|
-
zipfile.readEntry();
|
73
|
-
return;
|
74
|
-
}
|
75
|
-
|
76
|
-
// Skip existing files
|
77
|
-
if (await pathExists(target)) {
|
78
|
-
zipfile.readEntry();
|
79
|
-
return;
|
80
|
-
}
|
81
|
-
|
82
|
-
zipfile.openReadStream(entry, async (err, readStream) => {
|
83
|
-
if (err) {
|
84
|
-
reject(err);
|
85
|
-
return;
|
86
|
-
}
|
87
|
-
|
88
|
-
await fsp.mkdir(path.dirname(target), { "recursive": true });
|
89
|
-
|
90
|
-
await pipeline(readStream, fs.createWriteStream(target));
|
91
|
-
|
92
|
-
zipfile.readEntry();
|
93
|
-
});
|
94
|
-
});
|
95
|
-
|
96
|
-
zipfile.once("end", function () {
|
97
|
-
zipfile.close();
|
98
|
-
resolve();
|
99
|
-
});
|
100
|
-
});
|
101
|
-
});
|
102
|
-
}
|
103
|
-
|
104
|
-
// NOTE: This code was directly copied from ChatGPT and appears to function as expected.
|
105
|
-
// However, confidence in its complete accuracy and robustness is limited.
|
106
|
-
export async function zip(sourceFolder: string, targetZip: string) {
|
107
|
-
return new Promise<void>(async (resolve, reject) => {
|
108
|
-
const zipfile = new yazl.ZipFile();
|
109
|
-
const files: string[] = [];
|
110
|
-
|
111
|
-
// Recursive function to explore directories and their subdirectories
|
112
|
-
async function exploreDir(dir: string) {
|
113
|
-
const dirContent = await fsp.readdir(dir);
|
114
|
-
for (const file of dirContent) {
|
115
|
-
const filePath = path.join(dir, file);
|
116
|
-
const stat = await fsp.stat(filePath);
|
117
|
-
if (stat.isDirectory()) {
|
118
|
-
await exploreDir(filePath);
|
119
|
-
} else if (stat.isFile()) {
|
120
|
-
files.push(filePath);
|
121
|
-
}
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
// Collecting all files to be zipped
|
126
|
-
await exploreDir(sourceFolder);
|
127
|
-
|
128
|
-
// Adding files to zip
|
129
|
-
for (const file of files) {
|
130
|
-
const relativePath = path.relative(sourceFolder, file);
|
131
|
-
zipfile.addFile(file, relativePath);
|
132
|
-
}
|
133
|
-
|
134
|
-
zipfile.outputStream
|
135
|
-
.pipe(fs.createWriteStream(targetZip))
|
136
|
-
.on("close", () => resolve())
|
137
|
-
.on("error", err => reject(err)); // Listen to error events
|
138
|
-
|
139
|
-
zipfile.end();
|
140
|
-
});
|
141
|
-
}
|