keycloakify 7.3.2 → 7.3.3

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 (42) 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 +3 -4
  9. package/bin/keycloakify/BuildOptions.js +8 -25
  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/index.js +1 -1
  15. package/bin/keycloakify/index.js.map +1 -1
  16. package/bin/keycloakify/keycloakify.d.ts +0 -1
  17. package/bin/keycloakify/keycloakify.js +13 -15
  18. package/bin/keycloakify/keycloakify.js.map +1 -1
  19. package/bin/keycloakify/parsed-package-json.d.ts +20 -0
  20. package/bin/keycloakify/parsed-package-json.js +62 -0
  21. package/bin/keycloakify/parsed-package-json.js.map +1 -0
  22. package/bin/tools/downloadAndUnzip.d.ts +1 -1
  23. package/bin/tools/downloadAndUnzip.js +16 -16
  24. package/bin/tools/downloadAndUnzip.js.map +1 -1
  25. package/bin/tools/unzip.d.ts +1 -30
  26. package/bin/tools/unzip.js +99 -288
  27. package/bin/tools/unzip.js.map +1 -1
  28. package/package.json +13 -6
  29. package/src/bin/download-builtin-keycloak-theme.ts +3 -4
  30. package/src/bin/eject-keycloak-page.ts +1 -1
  31. package/src/bin/initialize-email-theme.ts +2 -10
  32. package/src/bin/keycloakify/BuildOptions.ts +13 -52
  33. package/src/bin/keycloakify/build-paths.ts +72 -0
  34. package/src/bin/keycloakify/index.ts +1 -1
  35. package/src/bin/keycloakify/keycloakify.ts +12 -16
  36. package/src/bin/keycloakify/parsed-package-json.ts +58 -0
  37. package/src/bin/tools/downloadAndUnzip.ts +5 -11
  38. package/src/bin/tools/unzip.ts +82 -174
  39. package/bin/getThemeSrcDirPath.d.ts +0 -5
  40. package/bin/getThemeSrcDirPath.js +0 -53
  41. package/bin/getThemeSrcDirPath.js.map +0 -1
  42. package/src/bin/getThemeSrcDirPath.ts +0 -33
@@ -1,11 +1,10 @@
1
1
  #!/usr/bin/env node
2
-
3
- import { keycloakThemeBuildingDirPath } from "./keycloakify";
4
2
  import { join as pathJoin } from "path";
5
3
  import { downloadAndUnzip } from "./tools/downloadAndUnzip";
6
4
  import { promptKeycloakVersion } from "./promptKeycloakVersion";
7
5
  import { getCliOptions } from "./tools/cliOptions";
8
6
  import { getLogger } from "./tools/logger";
7
+ import { getKeycloakBuildPath } from "./keycloakify/build-paths";
9
8
 
10
9
  export async function downloadBuiltinKeycloakTheme(params: { keycloakVersion: string; destDirPath: string; isSilent: boolean }) {
11
10
  const { keycloakVersion, destDirPath } = params;
@@ -26,7 +25,7 @@ async function main() {
26
25
  const logger = getLogger({ isSilent });
27
26
  const { keycloakVersion } = await promptKeycloakVersion();
28
27
 
29
- const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme");
28
+ const destDirPath = pathJoin(getKeycloakBuildPath(), "src", "main", "resources", "theme");
30
29
 
31
30
  logger.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`);
32
31
 
@@ -38,5 +37,5 @@ async function main() {
38
37
  }
39
38
 
40
39
  if (require.main === module) {
41
- main().catch(e => console.error(e));
40
+ main();
42
41
  }
@@ -16,7 +16,7 @@ import { existsSync } from "fs";
16
16
  import { join as pathJoin, relative as pathRelative } from "path";
17
17
  import { kebabCaseToCamelCase } from "./tools/kebabCaseToSnakeCase";
18
18
  import { assert, Equals } from "tsafe/assert";
19
- import { getThemeSrcDirPath } from "./getThemeSrcDirPath";
19
+ import { getThemeSrcDirPath } from "./keycloakify/build-paths";
20
20
 
21
21
  (async () => {
22
22
  const projectRootDir = getProjectRoot();
@@ -7,17 +7,9 @@ import { promptKeycloakVersion } from "./promptKeycloakVersion";
7
7
  import * as fs from "fs";
8
8
  import { getCliOptions } from "./tools/cliOptions";
9
9
  import { getLogger } from "./tools/logger";
10
- import { getThemeSrcDirPath } from "./getThemeSrcDirPath";
10
+ import { getEmailThemeSrcDirPath } from "./keycloakify/build-paths";
11
11
 
12
- export function getEmailThemeSrcDirPath() {
13
- const { themeSrcDirPath } = getThemeSrcDirPath();
14
-
15
- const emailThemeSrcDirPath = themeSrcDirPath === undefined ? undefined : pathJoin(themeSrcDirPath, "email");
16
-
17
- return { emailThemeSrcDirPath };
18
- }
19
-
20
- async function main() {
12
+ export async function main() {
21
13
  const { isSilent } = getCliOptions(process.argv.slice(2));
22
14
  const logger = getLogger({ isSilent });
23
15
 
@@ -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,10 @@ 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;
65
29
  };
66
30
 
67
31
  export type Standalone = Common & {
@@ -88,15 +52,10 @@ export namespace BuildOptions {
88
52
  }
89
53
  }
90
54
 
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;
55
+ export function readBuildOptions(params: { CNAME: string | undefined; isExternalAssetsCliParamProvided: boolean; isSilent: boolean }): BuildOptions {
56
+ const { CNAME, isExternalAssetsCliParamProvided, isSilent } = params;
98
57
 
99
- const parsedPackageJson = zParsedPackageJson.parse(JSON.parse(packageJson));
58
+ const parsedPackageJson = getParsedPackageJson();
100
59
 
101
60
  const url = (() => {
102
61
  const { homepage } = parsedPackageJson;
@@ -172,7 +131,9 @@ export function readBuildOptions(params: {
172
131
  extraAccountPages,
173
132
  extraThemeProperties,
174
133
  isSilent,
175
- "keycloakVersionDefaultAssets": keycloakVersionDefaultAssets ?? "11.0.3"
134
+ "keycloakVersionDefaultAssets": keycloakVersionDefaultAssets ?? "11.0.3",
135
+ appInputPath: getAppInputPath(),
136
+ keycloakBuildPath: getKeycloakBuildPath()
176
137
  };
177
138
  })();
178
139
 
@@ -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
+ };
@@ -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,58 @@
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
+ };
28
+ };
29
+
30
+ const zParsedPackageJson = z.object({
31
+ "name": z.string(),
32
+ "version": z.string(),
33
+ "homepage": z.string().optional(),
34
+ "keycloakify": z
35
+ .object({
36
+ "extraPages": z.array(z.string()).optional(),
37
+ "extraLoginPages": z.array(z.string()).optional(),
38
+ "extraAccountPages": z.array(z.string()).optional(),
39
+ "extraThemeProperties": z.array(z.string()).optional(),
40
+ "areAppAndKeycloakServerSharingSameDomain": z.boolean().optional(),
41
+ "artifactId": z.string().optional(),
42
+ "groupId": z.string().optional(),
43
+ "bundler": z.enum(bundlers).optional(),
44
+ "keycloakVersionDefaultAssets": z.string().optional(),
45
+ "appInputPath": z.string().optional(),
46
+ "keycloakBuildPath": z.string().optional()
47
+ })
48
+ .optional()
49
+ });
50
+
51
+ assert<Equals<ReturnType<(typeof zParsedPackageJson)["parse"]>, ParsedPackageJson>>();
52
+
53
+ let parsedPackageJson: undefined | ReturnType<(typeof zParsedPackageJson)["parse"]>;
54
+ export const getParsedPackageJson = () => {
55
+ if (parsedPackageJson) return parsedPackageJson;
56
+ parsedPackageJson = zParsedPackageJson.parse(JSON.parse(fs.readFileSync(pathJoin(reactProjectDirPath, "package.json")).toString("utf8")));
57
+ return parsedPackageJson;
58
+ };
@@ -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.)