keycloakify 9.4.0-rc.1 → 9.4.0-rc.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/PUBLIC_URL.d.ts +5 -0
  2. package/PUBLIC_URL.js +15 -0
  3. package/PUBLIC_URL.js.map +1 -0
  4. package/account/kcContext/createGetKcContext.js +7 -4
  5. package/account/kcContext/createGetKcContext.js.map +1 -1
  6. package/account/kcContext/kcContextMocks.js +3 -5
  7. package/account/kcContext/kcContextMocks.js.map +1 -1
  8. package/bin/constants.d.ts +1 -1
  9. package/bin/constants.js +1 -1
  10. package/bin/constants.js.map +1 -1
  11. package/bin/copy-keycloak-resources-to-public.d.ts +12 -1
  12. package/bin/copy-keycloak-resources-to-public.js +133 -70
  13. package/bin/copy-keycloak-resources-to-public.js.map +1 -1
  14. package/bin/download-builtin-keycloak-theme.d.ts +1 -0
  15. package/bin/download-builtin-keycloak-theme.js +37 -27
  16. package/bin/download-builtin-keycloak-theme.js.map +1 -1
  17. package/bin/{tools/downloadAndUnzip.d.ts → downloadAndUnzip.d.ts} +6 -6
  18. package/bin/downloadAndUnzip.js +255 -0
  19. package/bin/downloadAndUnzip.js.map +1 -0
  20. package/bin/eject-keycloak-page.js +6 -3
  21. package/bin/eject-keycloak-page.js.map +1 -1
  22. package/bin/initialize-email-theme.js +2 -4
  23. package/bin/initialize-email-theme.js.map +1 -1
  24. package/bin/keycloakify/buildOptions/buildOptions.d.ts +1 -1
  25. package/bin/keycloakify/buildOptions/buildOptions.js +56 -32
  26. package/bin/keycloakify/buildOptions/buildOptions.js.map +1 -1
  27. package/bin/keycloakify/buildOptions/getCacheDirPath.d.ts +5 -0
  28. package/bin/keycloakify/buildOptions/getCacheDirPath.js +22 -0
  29. package/bin/keycloakify/buildOptions/getCacheDirPath.js.map +1 -0
  30. package/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.d.ts +5 -0
  31. package/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.js +86 -0
  32. package/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.js.map +1 -0
  33. package/bin/keycloakify/buildOptions/getReactAppRootDirPath.d.ts +5 -0
  34. package/bin/keycloakify/buildOptions/getReactAppRootDirPath.js +26 -0
  35. package/bin/keycloakify/buildOptions/getReactAppRootDirPath.js.map +1 -0
  36. package/bin/keycloakify/buildOptions/resolvedViteConfig.d.ts +3 -4
  37. package/bin/keycloakify/buildOptions/resolvedViteConfig.js +4 -11
  38. package/bin/keycloakify/buildOptions/resolvedViteConfig.js.map +1 -1
  39. package/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +8 -0
  40. package/bin/keycloakify/generateFtl/generateFtl.js +2 -1
  41. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  42. package/bin/keycloakify/generateStartKeycloakTestingContainer.js +0 -1
  43. package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
  44. package/bin/keycloakify/generateTheme/bringInAccountV1.d.ts +1 -0
  45. package/bin/keycloakify/generateTheme/bringInAccountV1.js.map +1 -1
  46. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +1 -0
  47. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
  48. package/bin/keycloakify/generateTheme/generateTheme.d.ts +1 -0
  49. package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
  50. package/bin/keycloakify/keycloakify.js +11 -16
  51. package/bin/keycloakify/keycloakify.js.map +1 -1
  52. package/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.js +0 -5
  53. package/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.js.map +1 -1
  54. package/bin/tools/fetchProxyOptions.d.ts +5 -0
  55. package/bin/tools/fetchProxyOptions.js +172 -0
  56. package/bin/tools/fetchProxyOptions.js.map +1 -0
  57. package/bin/tools/fs.existsAsync.d.ts +1 -0
  58. package/bin/tools/fs.existsAsync.js +86 -0
  59. package/bin/tools/fs.existsAsync.js.map +1 -0
  60. package/bin/tools/getThisCodebaseRootDirPath.d.ts +1 -0
  61. package/bin/tools/{getProjectRoot.js → getThisCodebaseRootDirPath.js} +7 -7
  62. package/bin/tools/getThisCodebaseRootDirPath.js.map +1 -0
  63. package/bin/tools/grant-exec-perms.js +6 -4
  64. package/bin/tools/grant-exec-perms.js.map +1 -1
  65. package/bin/tools/readThisNpmProjectVersion.d.ts +1 -0
  66. package/bin/tools/readThisNpmProjectVersion.js +37 -0
  67. package/bin/tools/readThisNpmProjectVersion.js.map +1 -0
  68. package/bin/tools/transformCodebase.js +5 -5
  69. package/bin/tools/transformCodebase.js.map +1 -1
  70. package/lib/BASE_URL.d.ts +10 -0
  71. package/lib/BASE_URL.js +38 -0
  72. package/lib/BASE_URL.js.map +1 -0
  73. package/lib/isStorybook.d.ts +1 -0
  74. package/lib/isStorybook.js +3 -0
  75. package/lib/isStorybook.js.map +1 -0
  76. package/lib/keycloakJsAdapter.d.ts +4 -0
  77. package/lib/keycloakJsAdapter.js +4 -0
  78. package/lib/keycloakJsAdapter.js.map +1 -1
  79. package/login/kcContext/createGetKcContext.js +7 -4
  80. package/login/kcContext/createGetKcContext.js.map +1 -1
  81. package/login/kcContext/kcContextMocks.js +3 -5
  82. package/login/kcContext/kcContextMocks.js.map +1 -1
  83. package/package.json +56 -23
  84. package/src/PUBLIC_URL.ts +21 -0
  85. package/src/account/kcContext/createGetKcContext.ts +8 -5
  86. package/src/account/kcContext/kcContextMocks.ts +3 -5
  87. package/src/bin/constants.ts +1 -1
  88. package/src/bin/copy-keycloak-resources-to-public.ts +73 -12
  89. package/src/bin/download-builtin-keycloak-theme.ts +40 -27
  90. package/src/bin/downloadAndUnzip.ts +203 -0
  91. package/src/bin/eject-keycloak-page.ts +6 -3
  92. package/src/bin/initialize-email-theme.ts +1 -4
  93. package/src/bin/keycloakify/buildOptions/buildOptions.ts +35 -35
  94. package/src/bin/keycloakify/buildOptions/getCacheDirPath.ts +25 -0
  95. package/src/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.ts +49 -0
  96. package/src/bin/keycloakify/buildOptions/getReactAppRootDirPath.ts +23 -0
  97. package/src/bin/keycloakify/buildOptions/resolvedViteConfig.ts +7 -21
  98. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +8 -0
  99. package/src/bin/keycloakify/generateFtl/generateFtl.ts +3 -2
  100. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +0 -1
  101. package/src/bin/keycloakify/generateTheme/bringInAccountV1.ts +1 -0
  102. package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +1 -0
  103. package/src/bin/keycloakify/generateTheme/generateTheme.ts +1 -0
  104. package/src/bin/keycloakify/keycloakify.ts +13 -19
  105. package/src/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.ts +0 -14
  106. package/src/bin/tools/fetchProxyOptions.ts +73 -0
  107. package/src/bin/tools/fs.existsAsync.ts +11 -0
  108. package/src/bin/tools/{getProjectRoot.ts → getThisCodebaseRootDirPath.ts} +4 -4
  109. package/src/bin/tools/grant-exec-perms.ts +5 -3
  110. package/src/bin/tools/readThisNpmProjectVersion.ts +12 -0
  111. package/src/bin/tools/transformCodebase.ts +6 -5
  112. package/src/lib/BASE_URL.ts +44 -0
  113. package/src/lib/isStorybook.ts +3 -0
  114. package/src/lib/keycloakJsAdapter.ts +4 -0
  115. package/src/login/kcContext/createGetKcContext.ts +8 -5
  116. package/src/login/kcContext/kcContextMocks.ts +3 -5
  117. package/src/vite-plugin/vite-plugin.ts +12 -11
  118. package/vite-plugin/tsconfig.tsbuildinfo +1 -1
  119. package/vite-plugin/vite-plugin.js +11 -11
  120. package/vite-plugin/vite-plugin.js.map +1 -1
  121. package/bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath.d.ts +0 -7
  122. package/bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath.js +0 -27
  123. package/bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath.js.map +0 -1
  124. package/bin/tools/downloadAndUnzip.js +0 -445
  125. package/bin/tools/downloadAndUnzip.js.map +0 -1
  126. package/bin/tools/getProjectRoot.d.ts +0 -1
  127. package/bin/tools/getProjectRoot.js.map +0 -1
  128. package/bin/tools/pathJoin.d.ts +0 -1
  129. package/bin/tools/pathJoin.js +0 -15
  130. package/bin/tools/pathJoin.js.map +0 -1
  131. package/src/bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath.ts +0 -33
  132. package/src/bin/tools/downloadAndUnzip.ts +0 -301
  133. package/src/bin/tools/pathJoin.ts +0 -6
  134. package/src/vite-plugin/config.json +0 -232
@@ -0,0 +1,203 @@
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 "./keycloakify/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_remot_cache_if_admin: {
120
+ const githubToken = process.env["KEYCLOAKIFY_ADMIN_GITHUB_PERSONAL_ACCESS_TOKEN"];
121
+
122
+ if (githubToken === undefined) {
123
+ break upload_to_remot_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,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { getProjectRoot } from "./tools/getProjectRoot";
3
+ import { getThisCodebaseRootDirPath } from "./tools/getThisCodebaseRootDirPath";
4
4
  import cliSelect from "cli-select";
5
5
  import { loginThemePageIds, accountThemePageIds, type LoginThemePageId, type AccountThemePageId } from "./keycloakify/generateFtl";
6
6
  import { capitalize } from "tsafe/capitalize";
@@ -11,11 +11,14 @@ import { kebabCaseToCamelCase } from "./tools/kebabCaseToSnakeCase";
11
11
  import { assert, Equals } from "tsafe/assert";
12
12
  import { getThemeSrcDirPath } from "./getThemeSrcDirPath";
13
13
  import { themeTypes, type ThemeType } from "./constants";
14
+ import { getReactAppRootDirPath } from "./keycloakify/buildOptions/getReactAppRootDirPath";
14
15
 
15
16
  (async () => {
16
17
  console.log("Select a theme type");
17
18
 
18
- const reactAppRootDirPath = process.cwd();
19
+ const { reactAppRootDirPath } = getReactAppRootDirPath({
20
+ "processArgv": process.argv.slice(2)
21
+ });
19
22
 
20
23
  const { value: themeType } = await cliSelect<ThemeType>({
21
24
  "values": [...themeTypes]
@@ -55,7 +58,7 @@ import { themeTypes, type ThemeType } from "./constants";
55
58
  process.exit(-1);
56
59
  }
57
60
 
58
- await writeFile(targetFilePath, await readFile(pathJoin(getProjectRoot(), "src", themeType, "pages", pageBasename)));
61
+ await writeFile(targetFilePath, await readFile(pathJoin(getThisCodebaseRootDirPath(), "src", themeType, "pages", pageBasename)));
59
62
 
60
63
  console.log(`${pathRelative(process.cwd(), targetFilePath)} created`);
61
64
  })();
@@ -11,17 +11,14 @@ import { getThemeSrcDirPath } from "./getThemeSrcDirPath";
11
11
  import { rmSync } from "./tools/fs.rmSync";
12
12
 
13
13
  export async function main() {
14
- const reactAppRootDirPath = process.cwd();
15
-
16
14
  const buildOptions = readBuildOptions({
17
- reactAppRootDirPath,
18
15
  "processArgv": process.argv.slice(2)
19
16
  });
20
17
 
21
18
  const logger = getLogger({ "isSilent": buildOptions.isSilent });
22
19
 
23
20
  const { themeSrcDirPath } = getThemeSrcDirPath({
24
- reactAppRootDirPath
21
+ "reactAppRootDirPath": buildOptions.reactAppRootDirPath
25
22
  });
26
23
 
27
24
  const emailThemeSrcDirPath = pathJoin(themeSrcDirPath, "email");
@@ -4,7 +4,10 @@ import { join as pathJoin } from "path";
4
4
  import parseArgv from "minimist";
5
5
  import { getAbsoluteAndInOsFormatPath } from "../../tools/getAbsoluteAndInOsFormatPath";
6
6
  import { readResolvedViteConfig } from "./resolvedViteConfig";
7
- import { getKeycloakifyBuildDirPath } from "./getKeycloakifyBuildDirPath";
7
+ import * as fs from "fs";
8
+ import { getCacheDirPath } from "./getCacheDirPath";
9
+ import { getReactAppRootDirPath } from "./getReactAppRootDirPath";
10
+ import { getNpmWorkspaceRootDirPath } from "./getNpmWorkspaceRootDirPath";
8
11
 
9
12
  /** Consolidated build option gathered form CLI arguments and config in package.json */
10
13
  export type BuildOptions = {
@@ -28,18 +31,23 @@ export type BuildOptions = {
28
31
  urlPathname: string | undefined;
29
32
  assetsDirPath: string;
30
33
  doBuildRetrocompatAccountTheme: boolean;
34
+ npmWorkspaceRootDirPath: string;
31
35
  };
32
36
 
33
- export function readBuildOptions(params: { reactAppRootDirPath: string; processArgv: string[] }): BuildOptions {
34
- const { reactAppRootDirPath, processArgv } = params;
37
+ export function readBuildOptions(params: { processArgv: string[] }): BuildOptions {
38
+ const { processArgv } = params;
35
39
 
36
- const parsedPackageJson = readParsedPackageJson({ reactAppRootDirPath });
40
+ const { reactAppRootDirPath } = getReactAppRootDirPath({ processArgv });
41
+
42
+ const { cacheDirPath } = getCacheDirPath({ reactAppRootDirPath });
43
+
44
+ const { resolvedViteConfig } = readResolvedViteConfig({ cacheDirPath });
37
45
 
38
- const { resolvedViteConfig } =
39
- readResolvedViteConfig({
40
- "parsedPackageJson_keycloakify_keycloakifyBuildDirPath": parsedPackageJson.keycloakify?.keycloakifyBuildDirPath,
41
- reactAppRootDirPath
42
- }) ?? {};
46
+ if (resolvedViteConfig === undefined && fs.existsSync(pathJoin(reactAppRootDirPath, "vite.config.ts"))) {
47
+ throw new Error("Keycloakify's Vite plugin output not found");
48
+ }
49
+
50
+ const parsedPackageJson = readParsedPackageJson({ reactAppRootDirPath });
43
51
 
44
52
  const themeNames = (() => {
45
53
  if (parsedPackageJson.keycloakify?.themeName === undefined) {
@@ -58,12 +66,6 @@ export function readBuildOptions(params: { reactAppRootDirPath: string; processA
58
66
  return parsedPackageJson.keycloakify.themeName;
59
67
  })();
60
68
 
61
- const { keycloakifyBuildDirPath } = getKeycloakifyBuildDirPath({
62
- "parsedPackageJson_keycloakify_keycloakifyBuildDirPath": parsedPackageJson.keycloakify?.keycloakifyBuildDirPath,
63
- reactAppRootDirPath,
64
- "bundler": resolvedViteConfig !== undefined ? "vite" : "webpack"
65
- });
66
-
67
69
  const reactAppBuildDirPath = (() => {
68
70
  webpack: {
69
71
  if (resolvedViteConfig !== undefined) {
@@ -83,13 +85,13 @@ export function readBuildOptions(params: { reactAppRootDirPath: string; processA
83
85
  return pathJoin(reactAppRootDirPath, resolvedViteConfig.buildDir);
84
86
  })();
85
87
 
88
+ const argv = parseArgv(processArgv);
89
+
90
+ const { npmWorkspaceRootDirPath } = getNpmWorkspaceRootDirPath({ reactAppRootDirPath });
91
+
86
92
  return {
87
93
  "bundler": resolvedViteConfig !== undefined ? "vite" : "webpack",
88
- "isSilent": (() => {
89
- const argv = parseArgv(processArgv);
90
-
91
- return typeof argv["silent"] === "boolean" ? argv["silent"] : false;
92
- })(),
94
+ "isSilent": typeof argv["silent"] === "boolean" ? argv["silent"] : false,
93
95
  "themeVersion": process.env.KEYCLOAKIFY_THEME_VERSION ?? parsedPackageJson.version ?? "0.0.0",
94
96
  themeNames,
95
97
  "extraThemeProperties": parsedPackageJson.keycloakify?.extraThemeProperties,
@@ -113,7 +115,16 @@ export function readBuildOptions(params: { reactAppRootDirPath: string; processA
113
115
  "loginThemeResourcesFromKeycloakVersion": parsedPackageJson.keycloakify?.loginThemeResourcesFromKeycloakVersion ?? "11.0.3",
114
116
  reactAppRootDirPath,
115
117
  reactAppBuildDirPath,
116
- keycloakifyBuildDirPath,
118
+ "keycloakifyBuildDirPath": (() => {
119
+ if (parsedPackageJson.keycloakify?.keycloakifyBuildDirPath !== undefined) {
120
+ return getAbsoluteAndInOsFormatPath({
121
+ "pathIsh": parsedPackageJson.keycloakify?.keycloakifyBuildDirPath,
122
+ "cwd": reactAppRootDirPath
123
+ });
124
+ }
125
+
126
+ return resolvedViteConfig?.buildDir === undefined ? "build_keycloak" : `${resolvedViteConfig.buildDir}_keycloak`;
127
+ })(),
117
128
  "publicDirPath": (() => {
118
129
  webpack: {
119
130
  if (resolvedViteConfig !== undefined) {
@@ -132,19 +143,7 @@ export function readBuildOptions(params: { reactAppRootDirPath: string; processA
132
143
 
133
144
  return pathJoin(reactAppRootDirPath, resolvedViteConfig.publicDir);
134
145
  })(),
135
- "cacheDirPath": pathJoin(
136
- (() => {
137
- if (process.env.XDG_CACHE_HOME !== undefined) {
138
- return getAbsoluteAndInOsFormatPath({
139
- "pathIsh": process.env.XDG_CACHE_HOME,
140
- "cwd": reactAppRootDirPath
141
- });
142
- }
143
-
144
- return pathJoin(reactAppRootDirPath, "node_modules", ".cache");
145
- })(),
146
- "keycloakify"
147
- ),
146
+ cacheDirPath,
148
147
  "urlPathname": (() => {
149
148
  webpack: {
150
149
  if (resolvedViteConfig !== undefined) {
@@ -180,6 +179,7 @@ export function readBuildOptions(params: { reactAppRootDirPath: string; processA
180
179
 
181
180
  return pathJoin(reactAppBuildDirPath, resolvedViteConfig.assetsDir);
182
181
  })(),
183
- "doBuildRetrocompatAccountTheme": parsedPackageJson.keycloakify?.doBuildRetrocompatAccountTheme ?? true
182
+ "doBuildRetrocompatAccountTheme": parsedPackageJson.keycloakify?.doBuildRetrocompatAccountTheme ?? true,
183
+ npmWorkspaceRootDirPath
184
184
  };
185
185
  }
@@ -0,0 +1,25 @@
1
+ import { join as pathJoin } from "path";
2
+ import { getAbsoluteAndInOsFormatPath } from "../../tools/getAbsoluteAndInOsFormatPath";
3
+ import { getNpmWorkspaceRootDirPath } from "./getNpmWorkspaceRootDirPath";
4
+
5
+ export function getCacheDirPath(params: { reactAppRootDirPath: string }) {
6
+ const { reactAppRootDirPath } = params;
7
+
8
+ const { npmWorkspaceRootDirPath } = getNpmWorkspaceRootDirPath({ reactAppRootDirPath });
9
+
10
+ const cacheDirPath = pathJoin(
11
+ (() => {
12
+ if (process.env.XDG_CACHE_HOME !== undefined) {
13
+ return getAbsoluteAndInOsFormatPath({
14
+ "pathIsh": process.env.XDG_CACHE_HOME,
15
+ "cwd": reactAppRootDirPath
16
+ });
17
+ }
18
+
19
+ return pathJoin(npmWorkspaceRootDirPath, "node_modules", ".cache");
20
+ })(),
21
+ "keycloakify"
22
+ );
23
+
24
+ return { cacheDirPath };
25
+ }
@@ -0,0 +1,49 @@
1
+ import * as child_process from "child_process";
2
+ import { join as pathJoin, resolve as pathResolve, sep as pathSep } from "path";
3
+ import { assert } from "tsafe/assert";
4
+
5
+ let cache:
6
+ | {
7
+ reactAppRootDirPath: string;
8
+ npmWorkspaceRootDirPath: string;
9
+ }
10
+ | undefined = undefined;
11
+
12
+ export function getNpmWorkspaceRootDirPath(params: { reactAppRootDirPath: string }) {
13
+ const { reactAppRootDirPath } = params;
14
+
15
+ use_cache: {
16
+ if (cache === undefined || cache.reactAppRootDirPath !== reactAppRootDirPath) {
17
+ break use_cache;
18
+ }
19
+
20
+ const { npmWorkspaceRootDirPath } = cache;
21
+
22
+ return { npmWorkspaceRootDirPath };
23
+ }
24
+
25
+ const npmWorkspaceRootDirPath = (function callee(depth: number): string {
26
+ const cwd = pathResolve(pathJoin(...[reactAppRootDirPath, ...Array(depth).fill("..")]));
27
+
28
+ try {
29
+ child_process.execSync("npm config get", { cwd: cwd });
30
+ } catch (error) {
31
+ if (String(error).includes("ENOWORKSPACES")) {
32
+ assert(cwd !== pathSep, "NPM workspace not found");
33
+
34
+ return callee(depth + 1);
35
+ }
36
+
37
+ throw error;
38
+ }
39
+
40
+ return cwd;
41
+ })(0);
42
+
43
+ cache = {
44
+ reactAppRootDirPath,
45
+ npmWorkspaceRootDirPath
46
+ };
47
+
48
+ return { npmWorkspaceRootDirPath };
49
+ }
@@ -0,0 +1,23 @@
1
+ import parseArgv from "minimist";
2
+ import { getAbsoluteAndInOsFormatPath } from "../../tools/getAbsoluteAndInOsFormatPath";
3
+
4
+ export function getReactAppRootDirPath(params: { processArgv: string[] }) {
5
+ const { processArgv } = params;
6
+
7
+ const argv = parseArgv(processArgv);
8
+
9
+ const reactAppRootDirPath = (() => {
10
+ const arg = argv["project"] ?? argv["p"];
11
+
12
+ if (typeof arg !== "string") {
13
+ return process.cwd();
14
+ }
15
+
16
+ return getAbsoluteAndInOsFormatPath({
17
+ "pathIsh": arg,
18
+ "cwd": process.cwd()
19
+ });
20
+ })();
21
+
22
+ return { reactAppRootDirPath };
23
+ }
@@ -5,7 +5,6 @@ import { z } from "zod";
5
5
  import { join as pathJoin } from "path";
6
6
  import { resolvedViteConfigJsonBasename } from "../../constants";
7
7
  import type { OptionalIfCanBeUndefined } from "../../tools/OptionalIfCanBeUndefined";
8
- import { getKeycloakifyBuildDirPath } from "./getKeycloakifyBuildDirPath";
9
8
 
10
9
  export type ResolvedViteConfig = {
11
10
  buildDir: string;
@@ -28,31 +27,18 @@ const zResolvedViteConfig = z.object({
28
27
  assert<Equals<Got, Expected>>();
29
28
  }
30
29
 
31
- export function readResolvedViteConfig(params: {
32
- reactAppRootDirPath: string;
33
- parsedPackageJson_keycloakify_keycloakifyBuildDirPath: string | undefined;
34
- }):
35
- | {
36
- resolvedViteConfig: ResolvedViteConfig;
37
- }
38
- | undefined {
39
- const { reactAppRootDirPath, parsedPackageJson_keycloakify_keycloakifyBuildDirPath } = params;
30
+ export function readResolvedViteConfig(params: { cacheDirPath: string }): {
31
+ resolvedViteConfig: ResolvedViteConfig | undefined;
32
+ } {
33
+ const { cacheDirPath } = params;
40
34
 
41
- const viteConfigTsFilePath = pathJoin(reactAppRootDirPath, "vite.config.ts");
35
+ const resolvedViteConfigJsonFilePath = pathJoin(cacheDirPath, resolvedViteConfigJsonBasename);
42
36
 
43
- if (!fs.existsSync(viteConfigTsFilePath)) {
44
- return undefined;
37
+ if (!fs.existsSync(resolvedViteConfigJsonFilePath)) {
38
+ return { "resolvedViteConfig": undefined };
45
39
  }
46
40
 
47
- const { keycloakifyBuildDirPath } = getKeycloakifyBuildDirPath({
48
- reactAppRootDirPath,
49
- parsedPackageJson_keycloakify_keycloakifyBuildDirPath,
50
- "bundler": "vite"
51
- });
52
-
53
41
  const resolvedViteConfig = (() => {
54
- const resolvedViteConfigJsonFilePath = pathJoin(keycloakifyBuildDirPath, resolvedViteConfigJsonBasename);
55
-
56
42
  if (!fs.existsSync(resolvedViteConfigJsonFilePath)) {
57
43
  throw new Error("Missing Keycloakify Vite plugin output.");
58
44
  }
@@ -408,6 +408,14 @@
408
408
  out["themeName"] = "KEYCLOAKIFY_THEME_NAME_cXxKd3xEer";
409
409
  out["pageId"] = "${pageId}";
410
410
 
411
+ try {
412
+
413
+ out["url"]["resourcesCommonPath"] = out["url"]["resourcesPath"] + "/" + "RESOURCES_COMMON_cLsLsMrtDkpVv";
414
+
415
+ } catch(error) {
416
+
417
+ }
418
+
411
419
  return out;
412
420
 
413
421
  })()
@@ -7,7 +7,7 @@ import { join as pathJoin } from "path";
7
7
  import { objectKeys } from "tsafe/objectKeys";
8
8
  import type { BuildOptions } from "../buildOptions";
9
9
  import { assert } from "tsafe/assert";
10
- import { type ThemeType, nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir } from "../../constants";
10
+ import { type ThemeType, nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir, resources_common } from "../../constants";
11
11
 
12
12
  export type BuildOptionsLike = {
13
13
  bundler: "vite" | "webpack";
@@ -105,7 +105,8 @@ export function generateFtlFilesCodeFactory(params: {
105
105
  .replace("KEYCLOAKIFY_VERSION_xEdKd3xEdr", keycloakifyVersion)
106
106
  .replace("KEYCLOAKIFY_THEME_VERSION_sIgKd3xEdr3dx", buildOptions.themeVersion)
107
107
  .replace("KEYCLOAKIFY_THEME_TYPE_dExKd3xEdr", themeType)
108
- .replace("KEYCLOAKIFY_THEME_NAME_cXxKd3xEer", themeName),
108
+ .replace("KEYCLOAKIFY_THEME_NAME_cXxKd3xEer", themeName)
109
+ .replace("RESOURCES_COMMON_cLsLsMrtDkpVv", resources_common),
109
110
  "<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->": [
110
111
  "<#if scripts??>",
111
112
  " <#list scripts as script>",
@@ -30,7 +30,6 @@ export function generateStartKeycloakTestingContainer(params: { jarFilePath: str
30
30
  Buffer.from(
31
31
  [
32
32
  "#!/usr/bin/env bash",
33
- `# If you want to test with Keycloak version prior to 23 use the retrocompat-${pathBasename(jarFilePath)}`,
34
33
  "",
35
34
  `docker rm ${containerName} || true`,
36
35
  "",
@@ -11,6 +11,7 @@ import { rmSync } from "../../tools/fs.rmSync";
11
11
  type BuildOptionsLike = {
12
12
  keycloakifyBuildDirPath: string;
13
13
  cacheDirPath: string;
14
+ npmWorkspaceRootDirPath: string;
14
15
  };
15
16
 
16
17
  {
@@ -9,6 +9,7 @@ import { rmSync } from "../../tools/fs.rmSync";
9
9
 
10
10
  export type BuildOptionsLike = {
11
11
  cacheDirPath: string;
12
+ npmWorkspaceRootDirPath: string;
12
13
  };
13
14
 
14
15
  assert<BuildOptions extends BuildOptionsLike ? true : false>();
@@ -33,6 +33,7 @@ export type BuildOptionsLike = {
33
33
  urlPathname: string | undefined;
34
34
  doBuildRetrocompatAccountTheme: boolean;
35
35
  themeNames: string[];
36
+ npmWorkspaceRootDirPath: string;
36
37
  };
37
38
 
38
39
  assert<BuildOptions extends BuildOptionsLike ? true : false>();
@@ -6,38 +6,27 @@ 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 { assert } from "tsafe/assert";
10
9
  import { getThemeSrcDirPath } from "../getThemeSrcDirPath";
11
- import { getProjectRoot } from "../tools/getProjectRoot";
10
+ import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
11
+ import { readThisNpmProjectVersion } from "../tools/readThisNpmProjectVersion";
12
12
 
13
13
  export async function main() {
14
- const reactAppRootDirPath = process.cwd();
15
-
16
14
  const buildOptions = readBuildOptions({
17
- reactAppRootDirPath,
18
15
  "processArgv": process.argv.slice(2)
19
16
  });
20
17
 
21
18
  const logger = getLogger({ "isSilent": buildOptions.isSilent });
22
19
  logger.log("🔏 Building the keycloak theme...⌚");
23
20
 
24
- const keycloakifyDirPath = getProjectRoot();
25
-
26
- const { themeSrcDirPath } = getThemeSrcDirPath({ reactAppRootDirPath });
21
+ const { themeSrcDirPath } = getThemeSrcDirPath({ "reactAppRootDirPath": buildOptions.reactAppRootDirPath });
27
22
 
28
23
  for (const themeName of buildOptions.themeNames) {
29
24
  await generateTheme({
30
25
  themeName,
31
26
  themeSrcDirPath,
32
- "keycloakifySrcDirPath": pathJoin(keycloakifyDirPath, "src"),
33
- buildOptions,
34
- "keycloakifyVersion": (() => {
35
- const version = JSON.parse(fs.readFileSync(pathJoin(keycloakifyDirPath, "package.json")).toString("utf8"))["version"];
36
-
37
- assert(typeof version === "string");
38
-
39
- return version;
40
- })()
27
+ "keycloakifySrcDirPath": pathJoin(getThisCodebaseRootDirPath(), "src"),
28
+ "keycloakifyVersion": readThisNpmProjectVersion(),
29
+ buildOptions
41
30
  });
42
31
  }
43
32
 
@@ -83,12 +72,17 @@ export async function main() {
83
72
  "",
84
73
  ...(!buildOptions.doCreateJar
85
74
  ? []
86
- : [`✅ Your keycloak theme has been generated and bundled into .${pathSep}${pathRelative(reactAppRootDirPath, jarFilePath)} 🚀`]),
75
+ : [
76
+ `✅ Your keycloak theme has been generated and bundled into .${pathSep}${pathRelative(
77
+ buildOptions.reactAppRootDirPath,
78
+ jarFilePath
79
+ )} 🚀`
80
+ ]),
87
81
  "",
88
82
  `To test your theme locally you can spin up a Keycloak ${containerKeycloakVersion} container image with the theme pre loaded by running:`,
89
83
  "",
90
84
  `👉 $ .${pathSep}${pathRelative(
91
- reactAppRootDirPath,
85
+ buildOptions.reactAppRootDirPath,
92
86
  pathJoin(buildOptions.keycloakifyBuildDirPath, generateStartKeycloakTestingContainer.basename)
93
87
  )} 👈`,
94
88
  ``,