keycloakify 7.3.2 → 7.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/bin/download-builtin-keycloak-theme.js +3 -3
  2. package/bin/download-builtin-keycloak-theme.js.map +1 -1
  3. package/bin/eject-keycloak-page.js +2 -2
  4. package/bin/eject-keycloak-page.js.map +1 -1
  5. package/bin/initialize-email-theme.d.ts +1 -3
  6. package/bin/initialize-email-theme.js +4 -9
  7. package/bin/initialize-email-theme.js.map +1 -1
  8. package/bin/keycloakify/BuildOptions.d.ts +4 -4
  9. package/bin/keycloakify/BuildOptions.js +12 -28
  10. package/bin/keycloakify/BuildOptions.js.map +1 -1
  11. package/bin/keycloakify/build-paths.d.ts +12 -0
  12. package/bin/keycloakify/build-paths.js +93 -0
  13. package/bin/keycloakify/build-paths.js.map +1 -0
  14. package/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +1 -2
  15. package/bin/keycloakify/generateFtl/generateFtl.d.ts +6 -3
  16. package/bin/keycloakify/generateFtl/generateFtl.js +3 -6
  17. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  18. package/bin/keycloakify/generateKeycloakThemeResources.d.ts +1 -0
  19. package/bin/keycloakify/generateKeycloakThemeResources.js +2 -6
  20. package/bin/keycloakify/generateKeycloakThemeResources.js.map +1 -1
  21. package/bin/keycloakify/index.js +1 -1
  22. package/bin/keycloakify/index.js.map +1 -1
  23. package/bin/keycloakify/keycloakify.d.ts +0 -1
  24. package/bin/keycloakify/keycloakify.js +13 -15
  25. package/bin/keycloakify/keycloakify.js.map +1 -1
  26. package/bin/keycloakify/parsed-package-json.d.ts +21 -0
  27. package/bin/keycloakify/parsed-package-json.js +63 -0
  28. package/bin/keycloakify/parsed-package-json.js.map +1 -0
  29. package/bin/tools/downloadAndUnzip.d.ts +1 -1
  30. package/bin/tools/downloadAndUnzip.js +16 -16
  31. package/bin/tools/downloadAndUnzip.js.map +1 -1
  32. package/bin/tools/unzip.d.ts +1 -30
  33. package/bin/tools/unzip.js +99 -288
  34. package/bin/tools/unzip.js.map +1 -1
  35. package/package.json +13 -6
  36. package/src/bin/download-builtin-keycloak-theme.ts +3 -4
  37. package/src/bin/eject-keycloak-page.ts +1 -1
  38. package/src/bin/initialize-email-theme.ts +2 -10
  39. package/src/bin/keycloakify/BuildOptions.ts +15 -52
  40. package/src/bin/keycloakify/build-paths.ts +72 -0
  41. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +1 -2
  42. package/src/bin/keycloakify/generateFtl/generateFtl.ts +22 -17
  43. package/src/bin/keycloakify/generateKeycloakThemeResources.ts +3 -7
  44. package/src/bin/keycloakify/index.ts +1 -1
  45. package/src/bin/keycloakify/keycloakify.ts +12 -16
  46. package/src/bin/keycloakify/parsed-package-json.ts +60 -0
  47. package/src/bin/tools/downloadAndUnzip.ts +5 -11
  48. package/src/bin/tools/unzip.ts +82 -174
  49. package/bin/getThemeSrcDirPath.d.ts +0 -5
  50. package/bin/getThemeSrcDirPath.js +0 -53
  51. package/bin/getThemeSrcDirPath.js.map +0 -1
  52. package/src/bin/getThemeSrcDirPath.ts +0 -33
@@ -1,51 +1,11 @@
1
- import { z } from "zod";
2
1
  import { assert } from "tsafe/assert";
3
- import type { Equals } from "tsafe";
4
2
  import { id } from "tsafe/id";
5
3
  import { parse as urlParse } from "url";
6
4
  import { typeGuard } from "tsafe/typeGuard";
7
5
  import { symToStr } from "tsafe/symToStr";
8
-
9
- const bundlers = ["mvn", "keycloakify", "none"] as const;
10
- type Bundler = (typeof bundlers)[number];
11
- type ParsedPackageJson = {
12
- name: string;
13
- version: string;
14
- homepage?: string;
15
- keycloakify?: {
16
- /** @deprecated: use extraLoginPages instead */
17
- extraPages?: string[];
18
- extraLoginPages?: string[];
19
- extraAccountPages?: string[];
20
- extraThemeProperties?: string[];
21
- areAppAndKeycloakServerSharingSameDomain?: boolean;
22
- artifactId?: string;
23
- groupId?: string;
24
- bundler?: Bundler;
25
- keycloakVersionDefaultAssets?: string;
26
- };
27
- };
28
-
29
- const zParsedPackageJson = z.object({
30
- "name": z.string(),
31
- "version": z.string(),
32
- "homepage": z.string().optional(),
33
- "keycloakify": z
34
- .object({
35
- "extraPages": z.array(z.string()).optional(),
36
- "extraLoginPages": z.array(z.string()).optional(),
37
- "extraAccountPages": z.array(z.string()).optional(),
38
- "extraThemeProperties": z.array(z.string()).optional(),
39
- "areAppAndKeycloakServerSharingSameDomain": z.boolean().optional(),
40
- "artifactId": z.string().optional(),
41
- "groupId": z.string().optional(),
42
- "bundler": z.enum(bundlers).optional(),
43
- "keycloakVersionDefaultAssets": z.string().optional()
44
- })
45
- .optional()
46
- });
47
-
48
- assert<Equals<ReturnType<(typeof zParsedPackageJson)["parse"]>, ParsedPackageJson>>();
6
+ import { bundlers, getParsedPackageJson } from "./parsed-package-json";
7
+ import type { Bundler } from "./parsed-package-json";
8
+ import { getAppInputPath, getKeycloakBuildPath } from "./build-paths";
49
9
 
50
10
  /** Consolidated build option gathered form CLI arguments and config in package.json */
51
11
  export type BuildOptions = BuildOptions.Standalone | BuildOptions.ExternalAssets;
@@ -62,6 +22,11 @@ export namespace BuildOptions {
62
22
  artifactId: string;
63
23
  bundler: Bundler;
64
24
  keycloakVersionDefaultAssets: string;
25
+ // Directory of your built react project. Defaults to {cwd}/build
26
+ appInputPath: string;
27
+ // Directory that keycloakify outputs to. Defaults to {cwd}/build_keycloak
28
+ keycloakBuildPath: string;
29
+ customUserAttributes: string[];
65
30
  };
66
31
 
67
32
  export type Standalone = Common & {
@@ -88,15 +53,10 @@ export namespace BuildOptions {
88
53
  }
89
54
  }
90
55
 
91
- export function readBuildOptions(params: {
92
- packageJson: string;
93
- CNAME: string | undefined;
94
- isExternalAssetsCliParamProvided: boolean;
95
- isSilent: boolean;
96
- }): BuildOptions {
97
- const { packageJson, CNAME, isExternalAssetsCliParamProvided, isSilent } = params;
56
+ export function readBuildOptions(params: { CNAME: string | undefined; isExternalAssetsCliParamProvided: boolean; isSilent: boolean }): BuildOptions {
57
+ const { CNAME, isExternalAssetsCliParamProvided, isSilent } = params;
98
58
 
99
- const parsedPackageJson = zParsedPackageJson.parse(JSON.parse(packageJson));
59
+ const parsedPackageJson = getParsedPackageJson();
100
60
 
101
61
  const url = (() => {
102
62
  const { homepage } = parsedPackageJson;
@@ -172,7 +132,10 @@ export function readBuildOptions(params: {
172
132
  extraAccountPages,
173
133
  extraThemeProperties,
174
134
  isSilent,
175
- "keycloakVersionDefaultAssets": keycloakVersionDefaultAssets ?? "11.0.3"
135
+ "keycloakVersionDefaultAssets": keycloakVersionDefaultAssets ?? "11.0.3",
136
+ appInputPath: getAppInputPath(),
137
+ keycloakBuildPath: getKeycloakBuildPath(),
138
+ "customUserAttributes": keycloakify.customUserAttributes ?? []
176
139
  };
177
140
  })();
178
141
 
@@ -0,0 +1,72 @@
1
+ import * as fs from "fs";
2
+ import { exclude } from "tsafe";
3
+ import { crawl } from "../tools/crawl";
4
+ import { pathJoin } from "../tools/pathJoin";
5
+ import { getParsedPackageJson } from "./parsed-package-json";
6
+
7
+ const DEFAULT_APP_INPUT_PATH = "build";
8
+
9
+ const DEFAULT_KEYCLOAK_BUILD_PATH = "build_keycloak";
10
+
11
+ const THEME_SRC_DIR_BASENAME = "keycloak-theme";
12
+
13
+ export const getReactProjectDirPath = () => process.cwd();
14
+
15
+ export const getCnamePath = () => pathJoin(getReactProjectDirPath(), "public", "CNAME");
16
+
17
+ const parseAppInputPath = (path?: string) => {
18
+ if (!path) {
19
+ return pathJoin(process.cwd(), DEFAULT_APP_INPUT_PATH);
20
+ } else if (path.startsWith("./")) {
21
+ return pathJoin(process.cwd(), path.replace("./", ""));
22
+ }
23
+ return path;
24
+ };
25
+
26
+ const parseKeycloakBuildPath = (path?: string) => {
27
+ if (!path) {
28
+ return pathJoin(process.cwd(), DEFAULT_KEYCLOAK_BUILD_PATH);
29
+ } else if (path.startsWith("./")) {
30
+ return pathJoin(process.cwd(), path.replace("./", ""));
31
+ }
32
+ return path;
33
+ };
34
+
35
+ export const getAppInputPath = () => {
36
+ return parseAppInputPath(getParsedPackageJson().keycloakify?.appInputPath);
37
+ };
38
+
39
+ export const getKeycloakBuildPath = () => {
40
+ return parseKeycloakBuildPath(getParsedPackageJson().keycloakify?.keycloakBuildPath);
41
+ };
42
+ export const getThemeSrcDirPath = () => {
43
+ const srcDirPath = pathJoin(getReactProjectDirPath(), "src");
44
+
45
+ const themeSrcDirPath: string | undefined = crawl(srcDirPath)
46
+ .map(fileRelativePath => {
47
+ const split = fileRelativePath.split(THEME_SRC_DIR_BASENAME);
48
+
49
+ if (split.length !== 2) {
50
+ return undefined;
51
+ }
52
+
53
+ return pathJoin(srcDirPath, split[0] + THEME_SRC_DIR_BASENAME);
54
+ })
55
+ .filter(exclude(undefined))[0];
56
+ if (themeSrcDirPath === undefined) {
57
+ if (fs.existsSync(pathJoin(srcDirPath, "login")) || fs.existsSync(pathJoin(srcDirPath, "account"))) {
58
+ return { "themeSrcDirPath": srcDirPath };
59
+ }
60
+ return { "themeSrcDirPath": undefined };
61
+ }
62
+
63
+ return { themeSrcDirPath };
64
+ };
65
+
66
+ export const getEmailThemeSrcDirPath = () => {
67
+ const { themeSrcDirPath } = getThemeSrcDirPath();
68
+
69
+ const emailThemeSrcDirPath = themeSrcDirPath === undefined ? undefined : pathJoin(themeSrcDirPath, "email");
70
+
71
+ return { emailThemeSrcDirPath };
72
+ };
@@ -13,8 +13,7 @@
13
13
  "totp", "totpSecret", "SAMLRequest", "SAMLResponse", "relayState", "device_user_code", "code",
14
14
  "password-new", "rememberMe", "login", "authenticationExecution", "cancel-aia", "clientDataJSON",
15
15
  "authenticatorData", "signature", "credentialId", "userHandle", "error", "authn_use_chk", "authenticationExecution",
16
- "isSetRetry", "try-again", "attestationObject", "publicKeyCredentialId", "authenticatorLabel",
17
- "location", "occupation"
16
+ "isSetRetry", "try-again", "attestationObject", "publicKeyCredentialId", "authenticatorLabel"CUSTOM_USER_ATTRIBUTES_eKsIY4ZsZ4xeM
18
17
  ]>
19
18
 
20
19
  <#attempt>
@@ -8,7 +8,6 @@ import { objectKeys } from "tsafe/objectKeys";
8
8
  import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
9
9
  import type { BuildOptions } from "../BuildOptions";
10
10
  import { assert } from "tsafe/assert";
11
- import { Reflect } from "tsafe/Reflect";
12
11
 
13
12
  export const themeTypes = ["login", "account"] as const;
14
13
 
@@ -47,7 +46,11 @@ export type AccountThemePageId = (typeof accountThemePageIds)[number];
47
46
  export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.ExternalAssets;
48
47
 
49
48
  export namespace BuildOptionsLike {
50
- export type Standalone = {
49
+ export type Common = {
50
+ customUserAttributes: string[];
51
+ };
52
+
53
+ export type Standalone = Common & {
51
54
  isStandalone: true;
52
55
  urlPathname: string | undefined;
53
56
  };
@@ -59,23 +62,21 @@ export namespace BuildOptionsLike {
59
62
  isStandalone: false;
60
63
  };
61
64
 
62
- export type SameDomain = CommonExternalAssets & {
63
- areAppAndKeycloakServerSharingSameDomain: true;
64
- };
65
-
66
- export type DifferentDomains = CommonExternalAssets & {
67
- areAppAndKeycloakServerSharingSameDomain: false;
68
- urlOrigin: string;
69
- urlPathname: string | undefined;
70
- };
65
+ export type SameDomain = Common &
66
+ CommonExternalAssets & {
67
+ areAppAndKeycloakServerSharingSameDomain: true;
68
+ };
69
+
70
+ export type DifferentDomains = Common &
71
+ CommonExternalAssets & {
72
+ areAppAndKeycloakServerSharingSameDomain: false;
73
+ urlOrigin: string;
74
+ urlPathname: string | undefined;
75
+ };
71
76
  }
72
77
  }
73
78
 
74
- {
75
- const buildOptions = Reflect<BuildOptions>();
76
-
77
- assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
78
- }
79
+ assert<BuildOptions extends BuildOptionsLike ? true : false>();
79
80
 
80
81
  export function generateFtlFilesCodeFactory(params: {
81
82
  indexHtmlCode: string;
@@ -153,7 +154,11 @@ export function generateFtlFilesCodeFactory(params: {
153
154
  '{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }': fs
154
155
  .readFileSync(pathJoin(__dirname, "ftl_object_to_js_code_declaring_an_object.ftl"))
155
156
  .toString("utf8")
156
- .match(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1],
157
+ .match(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1]
158
+ .replace(
159
+ "CUSTOM_USER_ATTRIBUTES_eKsIY4ZsZ4xeM",
160
+ buildOptions.customUserAttributes.length === 0 ? "" : ", " + buildOptions.customUserAttributes.map(name => `"${name}"`).join(", ")
161
+ ),
157
162
  "<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->": [
158
163
  "<#if scripts??>",
159
164
  " <#list scripts as script>",
@@ -9,7 +9,6 @@ import { mockTestingResourcesCommonPath, mockTestingResourcesPath, mockTestingSu
9
9
  import { isInside } from "../tools/isInside";
10
10
  import type { BuildOptions } from "./BuildOptions";
11
11
  import { assert } from "tsafe/assert";
12
- import { Reflect } from "tsafe/Reflect";
13
12
 
14
13
  export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.ExternalAssets;
15
14
 
@@ -20,6 +19,7 @@ export namespace BuildOptionsLike {
20
19
  extraAccountPages?: string[];
21
20
  extraThemeProperties?: string[];
22
21
  isSilent: boolean;
22
+ customUserAttributes: string[];
23
23
  };
24
24
 
25
25
  export type Standalone = Common & {
@@ -46,11 +46,7 @@ export namespace BuildOptionsLike {
46
46
  }
47
47
  }
48
48
 
49
- {
50
- const buildOptions = Reflect<BuildOptions>();
51
-
52
- assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
53
- }
49
+ assert<BuildOptions extends BuildOptionsLike ? true : false>();
54
50
 
55
51
  export async function generateKeycloakThemeResources(params: {
56
52
  reactAppBuildDirPath: string;
@@ -142,7 +138,7 @@ export async function generateKeycloakThemeResources(params: {
142
138
  const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
143
139
  "indexHtmlCode": fs.readFileSync(pathJoin(reactAppBuildDirPath, "index.html")).toString("utf8"),
144
140
  "cssGlobalsToDefine": allCssGlobalsToDefine,
145
- "buildOptions": buildOptions
141
+ buildOptions
146
142
  });
147
143
 
148
144
  return generateFtlFilesCode;
@@ -4,5 +4,5 @@ export * from "./keycloakify";
4
4
  import { main } from "./keycloakify";
5
5
 
6
6
  if (require.main === module) {
7
- main().catch(e => console.error(e));
7
+ main();
8
8
  }
@@ -10,11 +10,8 @@ import { getCliOptions } from "../tools/cliOptions";
10
10
  import jar from "../tools/jar";
11
11
  import { assert } from "tsafe/assert";
12
12
  import { Equals } from "tsafe";
13
- import { getEmailThemeSrcDirPath } from "../initialize-email-theme";
14
-
15
- const reactProjectDirPath = process.cwd();
16
-
17
- export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
13
+ import { getEmailThemeSrcDirPath } from "./build-paths";
14
+ import { getCnamePath, getAppInputPath, getKeycloakBuildPath, getReactProjectDirPath } from "./build-paths";
18
15
 
19
16
  export async function main() {
20
17
  const { isSilent, hasExternalAssets } = getCliOptions(process.argv.slice(2));
@@ -22,9 +19,8 @@ export async function main() {
22
19
  logger.log("🔏 Building the keycloak theme...⌚");
23
20
 
24
21
  const buildOptions = readBuildOptions({
25
- "packageJson": fs.readFileSync(pathJoin(reactProjectDirPath, "package.json")).toString("utf8"),
26
22
  "CNAME": (() => {
27
- const cnameFilePath = pathJoin(reactProjectDirPath, "public", "CNAME");
23
+ const cnameFilePath = getCnamePath();
28
24
 
29
25
  if (!fs.existsSync(cnameFilePath)) {
30
26
  return undefined;
@@ -37,7 +33,7 @@ export async function main() {
37
33
  });
38
34
 
39
35
  const { doBundlesEmailTemplate } = await generateKeycloakThemeResources({
40
- keycloakThemeBuildingDirPath,
36
+ keycloakThemeBuildingDirPath: buildOptions.keycloakBuildPath,
41
37
  "emailThemeSrcDirPath": (() => {
42
38
  const { emailThemeSrcDirPath } = getEmailThemeSrcDirPath();
43
39
 
@@ -47,13 +43,13 @@ export async function main() {
47
43
 
48
44
  return emailThemeSrcDirPath;
49
45
  })(),
50
- "reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
46
+ "reactAppBuildDirPath": getAppInputPath(),
51
47
  buildOptions,
52
48
  "keycloakVersion": buildOptions.keycloakVersionDefaultAssets
53
49
  });
54
50
 
55
51
  const { jarFilePath } = generateJavaStackFiles({
56
- keycloakThemeBuildingDirPath,
52
+ keycloakThemeBuildingDirPath: buildOptions.keycloakBuildPath,
57
53
  doBundlesEmailTemplate,
58
54
  buildOptions
59
55
  });
@@ -65,7 +61,7 @@ export async function main() {
65
61
  case "keycloakify":
66
62
  logger.log("🫶 Let keycloakify do its thang");
67
63
  await jar({
68
- "rootPath": pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources"),
64
+ "rootPath": pathJoin(buildOptions.keycloakBuildPath, "src", "main", "resources"),
69
65
  "version": buildOptions.version,
70
66
  "groupId": buildOptions.groupId,
71
67
  "artifactId": buildOptions.artifactId,
@@ -74,7 +70,7 @@ export async function main() {
74
70
  break;
75
71
  case "mvn":
76
72
  logger.log("🫙 Run maven to deliver a jar");
77
- child_process.execSync("mvn package", { "cwd": keycloakThemeBuildingDirPath });
73
+ child_process.execSync("mvn package", { "cwd": buildOptions.keycloakBuildPath });
78
74
  break;
79
75
  default:
80
76
  assert<Equals<typeof buildOptions.bundler, never>>(false);
@@ -84,7 +80,7 @@ export async function main() {
84
80
  const containerKeycloakVersion = "20.0.1";
85
81
 
86
82
  generateStartKeycloakTestingContainer({
87
- keycloakThemeBuildingDirPath,
83
+ keycloakThemeBuildingDirPath: buildOptions.keycloakBuildPath,
88
84
  "keycloakVersion": containerKeycloakVersion,
89
85
  buildOptions
90
86
  });
@@ -92,7 +88,7 @@ export async function main() {
92
88
  logger.log(
93
89
  [
94
90
  "",
95
- `✅ Your keycloak theme has been generated and bundled into ./${pathRelative(reactProjectDirPath, jarFilePath)} 🚀`,
91
+ `✅ Your keycloak theme has been generated and bundled into ./${pathRelative(getReactProjectDirPath(), jarFilePath)} 🚀`,
96
92
  `It is to be placed in "/opt/keycloak/providers" in the container running a quay.io/keycloak/keycloak Docker image.`,
97
93
  "",
98
94
  //TODO: Restore when we find a good Helm chart for Keycloak.
@@ -127,8 +123,8 @@ export async function main() {
127
123
  `To test your theme locally you can spin up a Keycloak ${containerKeycloakVersion} container image with the theme pre loaded by running:`,
128
124
  "",
129
125
  `👉 $ .${pathSep}${pathRelative(
130
- reactProjectDirPath,
131
- pathJoin(keycloakThemeBuildingDirPath, generateStartKeycloakTestingContainer.basename)
126
+ getReactProjectDirPath(),
127
+ pathJoin(getKeycloakBuildPath(), generateStartKeycloakTestingContainer.basename)
132
128
  )} 👈`,
133
129
  "",
134
130
  `Test with different Keycloak versions by editing the .sh file. see available versions here: https://quay.io/repository/keycloak/keycloak?tab=tags`,
@@ -0,0 +1,60 @@
1
+ import * as fs from "fs";
2
+ import { assert } from "tsafe";
3
+ import type { Equals } from "tsafe";
4
+ import { z } from "zod";
5
+ import { pathJoin } from "../tools/pathJoin";
6
+
7
+ const reactProjectDirPath = process.cwd();
8
+ export const bundlers = ["mvn", "keycloakify", "none"] as const;
9
+ export type Bundler = (typeof bundlers)[number];
10
+ type ParsedPackageJson = {
11
+ name: string;
12
+ version: string;
13
+ homepage?: string;
14
+ keycloakify?: {
15
+ /** @deprecated: use extraLoginPages instead */
16
+ extraPages?: string[];
17
+ extraLoginPages?: string[];
18
+ extraAccountPages?: string[];
19
+ extraThemeProperties?: string[];
20
+ areAppAndKeycloakServerSharingSameDomain?: boolean;
21
+ artifactId?: string;
22
+ groupId?: string;
23
+ bundler?: Bundler;
24
+ keycloakVersionDefaultAssets?: string;
25
+ appInputPath?: string;
26
+ keycloakBuildPath?: string;
27
+ customUserAttributes?: string[];
28
+ };
29
+ };
30
+
31
+ const zParsedPackageJson = z.object({
32
+ "name": z.string(),
33
+ "version": z.string(),
34
+ "homepage": z.string().optional(),
35
+ "keycloakify": z
36
+ .object({
37
+ "extraPages": z.array(z.string()).optional(),
38
+ "extraLoginPages": z.array(z.string()).optional(),
39
+ "extraAccountPages": z.array(z.string()).optional(),
40
+ "extraThemeProperties": z.array(z.string()).optional(),
41
+ "areAppAndKeycloakServerSharingSameDomain": z.boolean().optional(),
42
+ "artifactId": z.string().optional(),
43
+ "groupId": z.string().optional(),
44
+ "bundler": z.enum(bundlers).optional(),
45
+ "keycloakVersionDefaultAssets": z.string().optional(),
46
+ "appInputPath": z.string().optional(),
47
+ "keycloakBuildPath": z.string().optional(),
48
+ "customUserAttributes": z.array(z.string()).optional()
49
+ })
50
+ .optional()
51
+ });
52
+
53
+ assert<Equals<ReturnType<(typeof zParsedPackageJson)["parse"]>, ParsedPackageJson>>();
54
+
55
+ let parsedPackageJson: undefined | ReturnType<(typeof zParsedPackageJson)["parse"]>;
56
+ export const getParsedPackageJson = () => {
57
+ if (parsedPackageJson) return parsedPackageJson;
58
+ parsedPackageJson = zParsedPackageJson.parse(JSON.parse(fs.readFileSync(pathJoin(reactProjectDirPath, "package.json")).toString("utf8")));
59
+ return parsedPackageJson;
60
+ };
@@ -53,25 +53,19 @@ async function getNpmProxyConfig(): Promise<Pick<FetchOptions, "proxy" | "noProx
53
53
  return { proxy, noProxy };
54
54
  }
55
55
 
56
- export async function downloadAndUnzip({
57
- url,
58
- destDirPath,
59
- pathOfDirToExtractInArchive
60
- }: {
61
- url: string;
62
- destDirPath: string;
63
- pathOfDirToExtractInArchive?: string;
64
- }) {
56
+ export async function downloadAndUnzip(params: { url: string; destDirPath: string; pathOfDirToExtractInArchive?: string }) {
57
+ const { url, destDirPath, pathOfDirToExtractInArchive } = params;
58
+
65
59
  const downloadHash = hash(JSON.stringify({ url })).substring(0, 15);
66
60
  const projectRoot = getProjectRoot();
67
- const cacheRoot = process.env.XDG_CACHE_HOME ?? `${projectRoot}/node_modules/.cache`;
61
+ const cacheRoot = process.env.XDG_CACHE_HOME ?? pathJoin(projectRoot, "node_modules", ".cache");
68
62
  const zipFilePath = pathJoin(cacheRoot, "keycloakify", "zip", `_${downloadHash}.zip`);
69
63
  const extractDirPath = pathJoin(cacheRoot, "keycloakify", "unzip", `_${downloadHash}`);
70
64
 
71
65
  if (!(await exists(zipFilePath))) {
72
66
  const proxyOpts = await getNpmProxyConfig();
73
67
  const response = await fetch(url, proxyOpts);
74
- await mkdir(pathDirname(zipFilePath), { recursive: true });
68
+ await mkdir(pathDirname(zipFilePath), { "recursive": true });
75
69
  /**
76
70
  * The correct way to fix this is to upgrade node-fetch beyond 3.2.5
77
71
  * (see https://github.com/node-fetch/node-fetch/issues/1295#issuecomment-1144061991.)