keycloakify 9.4.0-rc.9 → 9.4.1

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 (103) hide show
  1. package/README.md +4 -0
  2. package/account/i18n/baseMessages/index.d.ts +358 -0
  3. package/account/i18n/baseMessages/index.js +2 -1
  4. package/account/i18n/baseMessages/index.js.map +1 -1
  5. package/account/pages/PageProps.d.ts +3 -2
  6. package/bin/constants.d.ts +1 -1
  7. package/bin/constants.js +1 -1
  8. package/bin/constants.js.map +1 -1
  9. package/bin/copy-keycloak-resources-to-public.d.ts +13 -1
  10. package/bin/copy-keycloak-resources-to-public.js +134 -68
  11. package/bin/copy-keycloak-resources-to-public.js.map +1 -1
  12. package/bin/download-builtin-keycloak-theme.d.ts +1 -0
  13. package/bin/download-builtin-keycloak-theme.js +2 -3
  14. package/bin/download-builtin-keycloak-theme.js.map +1 -1
  15. package/bin/{tools/downloadAndUnzip.d.ts → downloadAndUnzip.d.ts} +6 -6
  16. package/bin/downloadAndUnzip.js +255 -0
  17. package/bin/downloadAndUnzip.js.map +1 -0
  18. package/bin/eject-keycloak-page.js +6 -3
  19. package/bin/eject-keycloak-page.js.map +1 -1
  20. package/bin/keycloakify/buildOptions/buildOptions.d.ts +1 -0
  21. package/bin/keycloakify/buildOptions/buildOptions.js +54 -39
  22. package/bin/keycloakify/buildOptions/buildOptions.js.map +1 -1
  23. package/bin/keycloakify/buildOptions/getCacheDirPath.d.ts +5 -0
  24. package/bin/keycloakify/buildOptions/getCacheDirPath.js +22 -0
  25. package/bin/keycloakify/buildOptions/getCacheDirPath.js.map +1 -0
  26. package/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.d.ts +5 -0
  27. package/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.js +86 -0
  28. package/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.js.map +1 -0
  29. package/bin/keycloakify/buildOptions/getReactAppRootDirPath.d.ts +5 -0
  30. package/bin/keycloakify/buildOptions/getReactAppRootDirPath.js +26 -0
  31. package/bin/keycloakify/buildOptions/getReactAppRootDirPath.js.map +1 -0
  32. package/bin/keycloakify/buildOptions/resolvedViteConfig.d.ts +3 -4
  33. package/bin/keycloakify/buildOptions/resolvedViteConfig.js +4 -11
  34. package/bin/keycloakify/buildOptions/resolvedViteConfig.js.map +1 -1
  35. package/bin/keycloakify/generateTheme/bringInAccountV1.d.ts +1 -0
  36. package/bin/keycloakify/generateTheme/bringInAccountV1.js.map +1 -1
  37. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +1 -0
  38. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
  39. package/bin/keycloakify/generateTheme/generateTheme.d.ts +1 -0
  40. package/bin/keycloakify/generateTheme/generateTheme.js +7 -3
  41. package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
  42. package/bin/keycloakify/keycloakify.js +8 -12
  43. package/bin/keycloakify/keycloakify.js.map +1 -1
  44. package/bin/tools/fetchProxyOptions.d.ts +5 -0
  45. package/bin/tools/fetchProxyOptions.js +172 -0
  46. package/bin/tools/fetchProxyOptions.js.map +1 -0
  47. package/bin/tools/fs.existsAsync.d.ts +1 -0
  48. package/bin/tools/fs.existsAsync.js +86 -0
  49. package/bin/tools/fs.existsAsync.js.map +1 -0
  50. package/bin/tools/getThisCodebaseRootDirPath.d.ts +1 -0
  51. package/bin/tools/{getProjectRoot.js → getThisCodebaseRootDirPath.js} +7 -7
  52. package/bin/tools/getThisCodebaseRootDirPath.js.map +1 -0
  53. package/bin/tools/grant-exec-perms.js +6 -4
  54. package/bin/tools/grant-exec-perms.js.map +1 -1
  55. package/bin/tools/readThisNpmProjectVersion.d.ts +1 -0
  56. package/bin/tools/readThisNpmProjectVersion.js +37 -0
  57. package/bin/tools/readThisNpmProjectVersion.js.map +1 -0
  58. package/lib/isStorybook.js +1 -2
  59. package/lib/isStorybook.js.map +1 -1
  60. package/login/i18n/baseMessages/index.d.ts +458 -0
  61. package/login/i18n/baseMessages/index.js +2 -1
  62. package/login/i18n/baseMessages/index.js.map +1 -1
  63. package/login/pages/PageProps.d.ts +3 -2
  64. package/package.json +41 -19
  65. package/src/account/i18n/baseMessages/index.ts +2 -1
  66. package/src/account/pages/PageProps.ts +3 -2
  67. package/src/bin/constants.ts +1 -1
  68. package/src/bin/copy-keycloak-resources-to-public.ts +75 -9
  69. package/src/bin/download-builtin-keycloak-theme.ts +3 -3
  70. package/src/bin/downloadAndUnzip.ts +203 -0
  71. package/src/bin/eject-keycloak-page.ts +6 -3
  72. package/src/bin/keycloakify/buildOptions/buildOptions.ts +28 -39
  73. package/src/bin/keycloakify/buildOptions/getCacheDirPath.ts +25 -0
  74. package/src/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.ts +49 -0
  75. package/src/bin/keycloakify/buildOptions/getReactAppRootDirPath.ts +23 -0
  76. package/src/bin/keycloakify/buildOptions/resolvedViteConfig.ts +7 -21
  77. package/src/bin/keycloakify/generateTheme/bringInAccountV1.ts +1 -0
  78. package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +1 -0
  79. package/src/bin/keycloakify/generateTheme/generateTheme.ts +9 -2
  80. package/src/bin/keycloakify/keycloakify.ts +8 -14
  81. package/src/bin/tools/fetchProxyOptions.ts +73 -0
  82. package/src/bin/tools/fs.existsAsync.ts +11 -0
  83. package/src/bin/tools/{getProjectRoot.ts → getThisCodebaseRootDirPath.ts} +4 -4
  84. package/src/bin/tools/grant-exec-perms.ts +5 -3
  85. package/src/bin/tools/readThisNpmProjectVersion.ts +12 -0
  86. package/src/lib/isStorybook.ts +1 -3
  87. package/src/login/i18n/baseMessages/index.ts +2 -1
  88. package/src/login/pages/PageProps.ts +3 -2
  89. package/src/vite-plugin/vite-plugin.ts +48 -25
  90. package/vite-plugin/tsconfig.tsbuildinfo +1 -1
  91. package/vite-plugin/vite-plugin.d.ts +1 -2
  92. package/vite-plugin/vite-plugin.js +35 -20
  93. package/vite-plugin/vite-plugin.js.map +1 -1
  94. package/bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath.d.ts +0 -7
  95. package/bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath.js +0 -27
  96. package/bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath.js.map +0 -1
  97. package/bin/tools/downloadAndUnzip.js +0 -445
  98. package/bin/tools/downloadAndUnzip.js.map +0 -1
  99. package/bin/tools/getProjectRoot.d.ts +0 -1
  100. package/bin/tools/getProjectRoot.js.map +0 -1
  101. package/src/bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath.ts +0 -33
  102. package/src/bin/tools/downloadAndUnzip.ts +0 -301
  103. package/src/vite-plugin/config.json +0 -232
@@ -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
  }
@@ -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>();
@@ -20,6 +20,7 @@ import { readFieldNameUsage } from "./readFieldNameUsage";
20
20
  import { readExtraPagesNames } from "./readExtraPageNames";
21
21
  import { generateMessageProperties } from "./generateMessageProperties";
22
22
  import { bringInAccountV1 } from "./bringInAccountV1";
23
+ import { rmSync } from "../../tools/fs.rmSync";
23
24
 
24
25
  export type BuildOptionsLike = {
25
26
  bundler: "vite" | "webpack";
@@ -33,6 +34,7 @@ export type BuildOptionsLike = {
33
34
  urlPathname: string | undefined;
34
35
  doBuildRetrocompatAccountTheme: boolean;
35
36
  themeNames: string[];
37
+ npmWorkspaceRootDirPath: string;
36
38
  };
37
39
 
38
40
  assert<BuildOptions extends BuildOptionsLike ? true : false>();
@@ -77,6 +79,11 @@ export async function generateTheme(params: {
77
79
  const themeTypeDirPath = getThemeTypeDirPath({ themeType });
78
80
 
79
81
  apply_replacers_and_move_to_theme_resources: {
82
+ const destDirPath = pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir);
83
+
84
+ // NOTE: Prevent accumulation of files in the assets dir, as names are hashed they pile up.
85
+ rmSync(destDirPath, { "recursive": true, "force": true });
86
+
80
87
  if (themeType === "account" && implementedThemeTypes.login) {
81
88
  // NOTE: We prevend doing it twice, it has been done for the login theme.
82
89
 
@@ -88,7 +95,7 @@ export async function generateTheme(params: {
88
95
  "resources",
89
96
  basenameOfTheKeycloakifyResourcesDir
90
97
  ),
91
- "destDirPath": pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir)
98
+ destDirPath
92
99
  });
93
100
 
94
101
  break apply_replacers_and_move_to_theme_resources;
@@ -96,7 +103,7 @@ export async function generateTheme(params: {
96
103
 
97
104
  transformCodebase({
98
105
  "srcDirPath": buildOptions.reactAppBuildDirPath,
99
- "destDirPath": pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir),
106
+ destDirPath,
100
107
  "transformSourceCode": ({ filePath, sourceCode }) => {
101
108
  //NOTE: Prevent cycles, excludes the folder we generated for debug in public/
102
109
  // This should not happen if users follow the new instruction setup but we keep it for retrocompatibility.
@@ -6,9 +6,9 @@ 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
14
  const buildOptions = readBuildOptions({
@@ -18,23 +18,15 @@ export async function main() {
18
18
  const logger = getLogger({ "isSilent": buildOptions.isSilent });
19
19
  logger.log("🔏 Building the keycloak theme...⌚");
20
20
 
21
- const keycloakifyDirPath = getProjectRoot();
22
-
23
21
  const { themeSrcDirPath } = getThemeSrcDirPath({ "reactAppRootDirPath": buildOptions.reactAppRootDirPath });
24
22
 
25
23
  for (const themeName of buildOptions.themeNames) {
26
24
  await generateTheme({
27
25
  themeName,
28
26
  themeSrcDirPath,
29
- "keycloakifySrcDirPath": pathJoin(keycloakifyDirPath, "src"),
30
- buildOptions,
31
- "keycloakifyVersion": (() => {
32
- const version = JSON.parse(fs.readFileSync(pathJoin(keycloakifyDirPath, "package.json")).toString("utf8"))["version"];
33
-
34
- assert(typeof version === "string");
35
-
36
- return version;
37
- })()
27
+ "keycloakifySrcDirPath": pathJoin(getThisCodebaseRootDirPath(), "src"),
28
+ "keycloakifyVersion": readThisNpmProjectVersion(),
29
+ buildOptions
38
30
  });
39
31
  }
40
32
 
@@ -67,7 +59,7 @@ export async function main() {
67
59
  );
68
60
  }
69
61
 
70
- const containerKeycloakVersion = "23.0.0";
62
+ const containerKeycloakVersion = "23.0.6";
71
63
 
72
64
  generateStartKeycloakTestingContainer({
73
65
  "keycloakVersion": containerKeycloakVersion,
@@ -75,6 +67,8 @@ export async function main() {
75
67
  buildOptions
76
68
  });
77
69
 
70
+ fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), Buffer.from("*", "utf8"));
71
+
78
72
  logger.log(
79
73
  [
80
74
  "",
@@ -0,0 +1,73 @@
1
+ import { exec as execCallback } from "child_process";
2
+ import { readFile } from "fs/promises";
3
+ import { type FetchOptions } from "make-fetch-happen";
4
+ import { promisify } from "util";
5
+
6
+ function ensureArray<T>(arg0: T | T[]) {
7
+ return Array.isArray(arg0) ? arg0 : typeof arg0 === "undefined" ? [] : [arg0];
8
+ }
9
+
10
+ function ensureSingleOrNone<T>(arg0: T | T[]) {
11
+ if (!Array.isArray(arg0)) return arg0;
12
+ if (arg0.length === 0) return undefined;
13
+ if (arg0.length === 1) return arg0[0];
14
+ throw new Error("Illegal configuration, expected a single value but found multiple: " + arg0.map(String).join(", "));
15
+ }
16
+
17
+ type NPMConfig = Record<string, string | string[]>;
18
+
19
+ /**
20
+ * Get npm configuration as map
21
+ */
22
+ async function getNmpConfig(params: { npmWorkspaceRootDirPath: string }) {
23
+ const { npmWorkspaceRootDirPath } = params;
24
+
25
+ const exec = promisify(execCallback);
26
+
27
+ const stdout = await exec("npm config get", { "encoding": "utf8", "cwd": npmWorkspaceRootDirPath }).then(({ stdout }) => stdout);
28
+
29
+ const npmConfigReducer = (cfg: NPMConfig, [key, value]: [string, string]) =>
30
+ key in cfg ? { ...cfg, [key]: [...ensureArray(cfg[key]), value] } : { ...cfg, [key]: value };
31
+
32
+ return stdout
33
+ .split("\n")
34
+ .filter(line => !line.startsWith(";"))
35
+ .map(line => line.trim())
36
+ .map(line => line.split("=", 2) as [string, string])
37
+ .reduce(npmConfigReducer, {} as NPMConfig);
38
+ }
39
+
40
+ export type ProxyFetchOptions = Pick<FetchOptions, "proxy" | "noProxy" | "strictSSL" | "cert" | "ca">;
41
+
42
+ export async function getProxyFetchOptions(params: { npmWorkspaceRootDirPath: string }): Promise<ProxyFetchOptions> {
43
+ const { npmWorkspaceRootDirPath } = params;
44
+
45
+ const cfg = await getNmpConfig({ npmWorkspaceRootDirPath });
46
+
47
+ const proxy = ensureSingleOrNone(cfg["https-proxy"] ?? cfg["proxy"]);
48
+ const noProxy = cfg["noproxy"] ?? cfg["no-proxy"];
49
+
50
+ function maybeBoolean(arg0: string | undefined) {
51
+ return typeof arg0 === "undefined" ? undefined : Boolean(arg0);
52
+ }
53
+
54
+ const strictSSL = maybeBoolean(ensureSingleOrNone(cfg["strict-ssl"]));
55
+ const cert = cfg["cert"];
56
+ const ca = ensureArray(cfg["ca"] ?? cfg["ca[]"]);
57
+ const cafile = ensureSingleOrNone(cfg["cafile"]);
58
+
59
+ if (typeof cafile !== "undefined" && cafile !== "null") {
60
+ ca.push(
61
+ ...(await (async () => {
62
+ function chunks<T>(arr: T[], size: number = 2) {
63
+ return arr.map((_, i) => i % size == 0 && arr.slice(i, i + size)).filter(Boolean) as T[][];
64
+ }
65
+
66
+ const cafileContent = await readFile(cafile, "utf-8");
67
+ return chunks(cafileContent.split(/(-----END CERTIFICATE-----)/), 2).map(ca => ca.join("").replace(/^\n/, "").replace(/\n/g, "\\n"));
68
+ })())
69
+ );
70
+ }
71
+
72
+ return { proxy, noProxy, strictSSL, cert, "ca": ca.length === 0 ? undefined : ca };
73
+ }
@@ -0,0 +1,11 @@
1
+ import * as fs from "fs/promises";
2
+
3
+ export async function existsAsync(path: string) {
4
+ try {
5
+ await fs.stat(path);
6
+ return true;
7
+ } catch (error) {
8
+ if ((error as Error & { code: string }).code === "ENOENT") return false;
9
+ throw error;
10
+ }
11
+ }
@@ -1,19 +1,19 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
3
 
4
- function getProjectRootRec(dirPath: string): string {
4
+ function getThisCodebaseRootDirPath_rec(dirPath: string): string {
5
5
  if (fs.existsSync(path.join(dirPath, "package.json"))) {
6
6
  return dirPath;
7
7
  }
8
- return getProjectRootRec(path.join(dirPath, ".."));
8
+ return getThisCodebaseRootDirPath_rec(path.join(dirPath, ".."));
9
9
  }
10
10
 
11
11
  let result: string | undefined = undefined;
12
12
 
13
- export function getProjectRoot(): string {
13
+ export function getThisCodebaseRootDirPath(): string {
14
14
  if (result !== undefined) {
15
15
  return result;
16
16
  }
17
17
 
18
- return (result = getProjectRootRec(__dirname));
18
+ return (result = getThisCodebaseRootDirPath_rec(__dirname));
19
19
  }
@@ -1,13 +1,15 @@
1
- import { getProjectRoot } from "./getProjectRoot";
1
+ import { getThisCodebaseRootDirPath } from "./getThisCodebaseRootDirPath";
2
2
  import { join as pathJoin } from "path";
3
3
  import { constants } from "fs";
4
4
  import { chmod, stat } from "fs/promises";
5
5
 
6
6
  (async () => {
7
- const { bin } = await import(pathJoin(getProjectRoot(), "package.json"));
7
+ const thisCodebaseRootDirPath = getThisCodebaseRootDirPath();
8
+
9
+ const { bin } = await import(pathJoin(thisCodebaseRootDirPath, "package.json"));
8
10
 
9
11
  const promises = Object.values<string>(bin).map(async scriptPath => {
10
- const fullPath = pathJoin(getProjectRoot(), scriptPath);
12
+ const fullPath = pathJoin(thisCodebaseRootDirPath, scriptPath);
11
13
  const oldMode = (await stat(fullPath)).mode;
12
14
  const newMode = oldMode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH;
13
15
  await chmod(fullPath, newMode);
@@ -0,0 +1,12 @@
1
+ import { getThisCodebaseRootDirPath } from "./getThisCodebaseRootDirPath";
2
+ import { assert } from "tsafe/assert";
3
+ import * as fs from "fs";
4
+ import { join as pathJoin } from "path";
5
+
6
+ export function readThisNpmProjectVersion(): string {
7
+ const version = JSON.parse(fs.readFileSync(pathJoin(getThisCodebaseRootDirPath(), "package.json")).toString("utf8"))["version"];
8
+
9
+ assert(typeof version === "string");
10
+
11
+ return version;
12
+ }
@@ -1,3 +1 @@
1
- import { BASE_URL } from "./BASE_URL";
2
-
3
- export const isStorybook = BASE_URL.startsWith(".");
1
+ export const isStorybook = typeof window === "object" && Object.keys(window).find(key => key.startsWith("__STORYBOOK")) !== undefined;
@@ -1,16 +1,17 @@
1
1
  //This code was automatically generated by running scripts/generate-i18n-messages.ts
2
2
  //PLEASE DO NOT EDIT MANUALLY
3
+ import * as en from "./en";
3
4
 
4
5
  export async function getMessages(currentLanguageTag: string) {
5
6
  const { default: messages } = await (() => {
6
7
  switch (currentLanguageTag) {
8
+ case "en": return en;
7
9
  case "ar": return import("./ar");
8
10
  case "ca": return import("./ca");
9
11
  case "cs": return import("./cs");
10
12
  case "da": return import("./da");
11
13
  case "de": return import("./de");
12
14
  case "el": return import("./el");
13
- case "en": return import("./en");
14
15
  case "es": return import("./es");
15
16
  case "fa": return import("./fa");
16
17
  case "fi": return import("./fi");
@@ -1,10 +1,11 @@
1
1
  import type { I18n } from "keycloakify/login/i18n";
2
2
  import { type TemplateProps, type ClassKey } from "keycloakify/login/TemplateProps";
3
3
  import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
4
+ import type { KcContext } from "keycloakify/account/kcContext";
4
5
 
5
- export type PageProps<KcContext, I18nExtended extends I18n> = {
6
+ export type PageProps<NarowedKcContext = KcContext, I18nExtended extends I18n = I18n> = {
6
7
  Template: LazyOrNot<(props: TemplateProps<any, any>) => JSX.Element | null>;
7
- kcContext: KcContext;
8
+ kcContext: NarowedKcContext;
8
9
  i18n: I18nExtended;
9
10
  doUseDefaultCss: boolean;
10
11
  classes?: Partial<Record<ClassKey, string>>;
@@ -1,28 +1,39 @@
1
1
  import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path";
2
- import { readParsedPackageJson } from "../bin/keycloakify/buildOptions/parsedPackageJson";
3
2
  import type { Plugin } from "vite";
4
- import { assert } from "tsafe/assert";
5
3
  import * as fs from "fs";
6
4
  import { resolvedViteConfigJsonBasename, nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir, keycloak_resources } from "../bin/constants";
7
5
  import type { ResolvedViteConfig } from "../bin/keycloakify/buildOptions/resolvedViteConfig";
8
- import { getKeycloakifyBuildDirPath } from "../bin/keycloakify/buildOptions/getKeycloakifyBuildDirPath";
6
+ import { getCacheDirPath } from "../bin/keycloakify/buildOptions/getCacheDirPath";
9
7
  import { replaceAll } from "../bin/tools/String.prototype.replaceAll";
10
8
  import { id } from "tsafe/id";
11
9
  import { rm } from "../bin/tools/fs.rm";
10
+ import { copyKeycloakResourcesToPublic } from "../bin/copy-keycloak-resources-to-public";
11
+ import { assert } from "tsafe/assert";
12
12
 
13
- export function keycloakify(): Plugin {
13
+ export function keycloakify() {
14
14
  let reactAppRootDirPath: string | undefined = undefined;
15
15
  let urlPathname: string | undefined = undefined;
16
16
  let buildDirPath: string | undefined = undefined;
17
+ let command: "build" | "serve" | undefined = undefined;
18
+
19
+ const plugin = {
20
+ "name": "keycloakify" as const,
21
+ "configResolved": async resolvedConfig => {
22
+ command = resolvedConfig.command;
17
23
 
18
- return {
19
- "name": "keycloakify",
20
- "apply": "build",
21
- "configResolved": resolvedConfig => {
22
24
  reactAppRootDirPath = resolvedConfig.root;
23
25
  urlPathname = (() => {
24
26
  let out = resolvedConfig.env.BASE_URL;
25
27
 
28
+ if (out.startsWith(".") && command === "build") {
29
+ throw new Error(
30
+ [
31
+ `BASE_URL=${out} is not supported By Keycloakify. Use an absolute URL instead.`,
32
+ `If this is a problem, please open an issue at https://github.com/keycloakify/keycloakify/issues/new`
33
+ ].join("\n")
34
+ );
35
+ }
36
+
26
37
  if (out === undefined) {
27
38
  return undefined;
28
39
  }
@@ -40,19 +51,16 @@ export function keycloakify(): Plugin {
40
51
 
41
52
  buildDirPath = pathJoin(reactAppRootDirPath, resolvedConfig.build.outDir);
42
53
 
43
- const { keycloakifyBuildDirPath } = getKeycloakifyBuildDirPath({
44
- "parsedPackageJson_keycloakify_keycloakifyBuildDirPath": readParsedPackageJson({ reactAppRootDirPath }).keycloakify
45
- ?.keycloakifyBuildDirPath,
46
- reactAppRootDirPath,
47
- "bundler": "vite"
54
+ const { cacheDirPath } = getCacheDirPath({
55
+ reactAppRootDirPath
48
56
  });
49
57
 
50
- if (!fs.existsSync(keycloakifyBuildDirPath)) {
51
- fs.mkdirSync(keycloakifyBuildDirPath);
58
+ if (!fs.existsSync(cacheDirPath)) {
59
+ fs.mkdirSync(cacheDirPath, { "recursive": true });
52
60
  }
53
61
 
54
62
  fs.writeFileSync(
55
- pathJoin(keycloakifyBuildDirPath, resolvedViteConfigJsonBasename),
63
+ pathJoin(cacheDirPath, resolvedViteConfigJsonBasename),
56
64
  Buffer.from(
57
65
  JSON.stringify(
58
66
  id<ResolvedViteConfig>({
@@ -67,8 +75,18 @@ export function keycloakify(): Plugin {
67
75
  "utf8"
68
76
  )
69
77
  );
78
+
79
+ await copyKeycloakResourcesToPublic({
80
+ "processArgv": ["--project", reactAppRootDirPath]
81
+ });
70
82
  },
71
83
  "transform": (code, id) => {
84
+ assert(command !== undefined);
85
+
86
+ if (command !== "build") {
87
+ return;
88
+ }
89
+
72
90
  assert(reactAppRootDirPath !== undefined);
73
91
 
74
92
  let transformedCode: string | undefined = undefined;
@@ -82,9 +100,8 @@ export function keycloakify(): Plugin {
82
100
  }
83
101
  }
84
102
 
85
- const isJavascriptFile = id.endsWith(".js") || id.endsWith(".jsx");
86
-
87
103
  {
104
+ const isJavascriptFile = id.endsWith(".js") || id.endsWith(".jsx");
88
105
  const isTypeScriptFile = id.endsWith(".ts") || id.endsWith(".tsx");
89
106
 
90
107
  if (!isTypeScriptFile && !isJavascriptFile) {
@@ -92,8 +109,6 @@ export function keycloakify(): Plugin {
92
109
  }
93
110
  }
94
111
 
95
- const windowToken = isJavascriptFile ? "window" : "(window as any)";
96
-
97
112
  if (transformedCode === undefined) {
98
113
  transformedCode = code;
99
114
  }
@@ -103,9 +118,9 @@ export function keycloakify(): Plugin {
103
118
  "import.meta.env.BASE_URL",
104
119
  [
105
120
  `(`,
106
- `(${windowToken}.${nameOfTheGlobal} === undefined || import.meta.env.MODE === "development") ?`,
107
- ` "${urlPathname ?? "/"}" :`,
108
- ` \`\${${windowToken}.${nameOfTheGlobal}.url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/\``,
121
+ `(window.${nameOfTheGlobal} === undefined || import.meta.env.MODE === "development")?`,
122
+ `"${urlPathname ?? "/"}":`,
123
+ `(window.${nameOfTheGlobal}.url.resourcesPath + "/${basenameOfTheKeycloakifyResourcesDir}/")`,
109
124
  `)`
110
125
  ].join("")
111
126
  );
@@ -119,10 +134,18 @@ export function keycloakify(): Plugin {
119
134
  "code": transformedCode
120
135
  };
121
136
  },
122
- "buildEnd": async () => {
137
+ "closeBundle": async () => {
138
+ assert(command !== undefined);
139
+
140
+ if (command !== "build") {
141
+ return;
142
+ }
143
+
123
144
  assert(buildDirPath !== undefined);
124
145
 
125
146
  await rm(pathJoin(buildDirPath, keycloak_resources), { "recursive": true, "force": true });
126
147
  }
127
- };
148
+ } satisfies Plugin;
149
+
150
+ return plugin as any;
128
151
  }