keycloakify 10.0.0-rc.90 → 10.0.0-rc.92

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 (31) hide show
  1. package/bin/193.index.js +3 -3
  2. package/bin/{751.index.js → 31.index.js} +183 -131
  3. package/bin/440.index.js +7 -12
  4. package/bin/453.index.js +1 -1
  5. package/bin/526.index.js +79 -68
  6. package/bin/538.index.js +1 -1
  7. package/bin/{837.index.js → 893.index.js} +7 -89
  8. package/bin/932.index.js +2 -2
  9. package/bin/97.index.js +1 -1
  10. package/bin/main.js +7 -7
  11. package/bin/shared/buildContext.d.ts +9 -2
  12. package/bin/shared/buildContext.js.map +1 -1
  13. package/bin/shared/copyKeycloakResourcesToPublic.js.map +1 -1
  14. package/bin/shared/downloadKeycloakDefaultTheme.d.ts +2 -1
  15. package/bin/shared/downloadKeycloakDefaultTheme.js.map +1 -1
  16. package/package.json +7 -9
  17. package/src/bin/keycloakify/generateFtl/generateFtl.ts +14 -10
  18. package/src/bin/keycloakify/generateResources/generateResourcesForMainTheme.ts +2 -1
  19. package/src/bin/keycloakify/keycloakify.ts +1 -7
  20. package/src/bin/keycloakify/replacers/replaceImportsInJsCode/replaceImportsInJsCode.ts +2 -2
  21. package/src/bin/shared/buildContext.ts +170 -92
  22. package/src/bin/shared/copyKeycloakResourcesToPublic.ts +1 -4
  23. package/src/bin/shared/downloadKeycloakDefaultTheme.ts +2 -2
  24. package/src/bin/start-keycloak/appBuild.ts +131 -94
  25. package/src/bin/start-keycloak/keycloakifyBuild.ts +0 -1
  26. package/src/bin/start-keycloak/start-keycloak.ts +1 -1
  27. package/src/bin/tools/{downloadAndExtractArchive/downloadAndExtractArchive.ts → downloadAndExtractArchive.ts} +9 -17
  28. package/src/bin/tools/{downloadAndExtractArchive/fetchProxyOptions.ts → fetchProxyOptions.ts} +52 -60
  29. package/vite-plugin/index.js +190 -228
  30. package/src/bin/tools/downloadAndExtractArchive/index.ts +0 -1
  31. package/src/bin/tools/getNpmWorkspaceRootDirPath.ts +0 -84
@@ -1,16 +1,14 @@
1
1
  import * as child_process from "child_process";
2
2
  import { Deferred } from "evt/tools/Deferred";
3
3
  import { assert } from "tsafe/assert";
4
- import { is } from "tsafe/is";
5
4
  import type { BuildContext } from "../shared/buildContext";
6
- import * as fs from "fs";
7
- import { join as pathJoin } from "path";
5
+ import chalk from "chalk";
6
+ import { sep as pathSep, join as pathJoin } from "path";
8
7
 
9
8
  export type BuildContextLike = {
10
9
  projectDirPath: string;
11
10
  keycloakifyBuildDirPath: string;
12
- bundler: "vite" | "webpack";
13
- npmWorkspaceRootDirPath: string;
11
+ bundler: BuildContext["bundler"];
14
12
  projectBuildDirPath: string;
15
13
  };
16
14
 
@@ -21,95 +19,29 @@ export async function appBuild(params: {
21
19
  }): Promise<{ isAppBuildSuccess: boolean }> {
22
20
  const { buildContext } = params;
23
21
 
24
- const { bundler } = buildContext;
25
-
26
- const { command, args, cwd } = (() => {
27
- switch (bundler) {
28
- case "vite":
29
- return {
30
- command: "npx",
31
- args: ["vite", "build"],
32
- cwd: buildContext.projectDirPath
33
- };
34
- case "webpack": {
35
- for (const dirPath of [
36
- buildContext.projectDirPath,
37
- buildContext.npmWorkspaceRootDirPath
38
- ]) {
39
- try {
40
- const parsedPackageJson = JSON.parse(
41
- fs
42
- .readFileSync(pathJoin(dirPath, "package.json"))
43
- .toString("utf8")
44
- );
45
-
46
- const [scriptName] =
47
- Object.entries(parsedPackageJson.scripts).find(
48
- ([, scriptValue]) => {
49
- assert(is<string>(scriptValue));
50
- if (
51
- scriptValue.includes("webpack") &&
52
- scriptValue.includes("--mode production")
53
- ) {
54
- return true;
55
- }
56
-
57
- if (
58
- scriptValue.includes("react-scripts") &&
59
- scriptValue.includes("build")
60
- ) {
61
- return true;
62
- }
63
-
64
- if (
65
- scriptValue.includes("react-app-rewired") &&
66
- scriptValue.includes("build")
67
- ) {
68
- return true;
69
- }
70
-
71
- if (
72
- scriptValue.includes("craco") &&
73
- scriptValue.includes("build")
74
- ) {
75
- return true;
76
- }
77
-
78
- if (
79
- scriptValue.includes("ng") &&
80
- scriptValue.includes("build")
81
- ) {
82
- return true;
83
- }
84
-
85
- return false;
86
- }
87
- ) ?? [];
88
-
89
- if (scriptName === undefined) {
90
- continue;
91
- }
92
-
93
- return {
94
- command: "npm",
95
- args: ["run", scriptName],
96
- cwd: dirPath
97
- };
98
- } catch {
99
- continue;
100
- }
101
- }
102
-
103
- throw new Error(
104
- "Keycloakify was unable to determine which script is responsible for building the app."
105
- );
106
- }
107
- }
108
- })();
22
+ switch (buildContext.bundler.type) {
23
+ case "vite":
24
+ return appBuild_vite({ buildContext });
25
+ case "webpack":
26
+ return appBuild_webpack({ buildContext });
27
+ }
28
+ }
29
+
30
+ async function appBuild_vite(params: {
31
+ buildContext: BuildContextLike;
32
+ }): Promise<{ isAppBuildSuccess: boolean }> {
33
+ const { buildContext } = params;
34
+
35
+ assert(buildContext.bundler.type === "vite");
109
36
 
110
- const dResult = new Deferred<{ isSuccess: boolean }>();
37
+ const dIsSuccess = new Deferred<boolean>();
111
38
 
112
- const child = child_process.spawn(command, args, { cwd, shell: true });
39
+ console.log(chalk.blue("Running: 'npx vite build'"));
40
+
41
+ const child = child_process.spawn("npx", ["vite", "build"], {
42
+ cwd: buildContext.projectDirPath,
43
+ shell: true
44
+ });
113
45
 
114
46
  child.stdout.on("data", data => {
115
47
  if (data.toString("utf8").includes("gzip:")) {
@@ -121,9 +53,114 @@ export async function appBuild(params: {
121
53
 
122
54
  child.stderr.on("data", data => process.stderr.write(data));
123
55
 
124
- child.on("exit", code => dResult.resolve({ isSuccess: code === 0 }));
56
+ child.on("exit", code => dIsSuccess.resolve(code === 0));
125
57
 
126
- const { isSuccess } = await dResult.pr;
58
+ const isSuccess = await dIsSuccess.pr;
127
59
 
128
60
  return { isAppBuildSuccess: isSuccess };
129
61
  }
62
+
63
+ async function appBuild_webpack(params: {
64
+ buildContext: BuildContextLike;
65
+ }): Promise<{ isAppBuildSuccess: boolean }> {
66
+ const { buildContext } = params;
67
+
68
+ assert(buildContext.bundler.type === "webpack");
69
+
70
+ const entries = Object.entries(buildContext.bundler.packageJsonScripts).filter(
71
+ ([, scriptCommand]) => scriptCommand.includes("keycloakify build")
72
+ );
73
+
74
+ if (entries.length === 0) {
75
+ console.log(
76
+ chalk.red(
77
+ [
78
+ `You should have a script in your package.json at ${buildContext.bundler.packageJsonDirPath}`,
79
+ `that includes the 'keycloakify build' command`
80
+ ].join(" ")
81
+ )
82
+ );
83
+ process.exit(-1);
84
+ }
85
+
86
+ const entry =
87
+ entries.length === 1
88
+ ? entries[0]
89
+ : entries.find(([scriptName]) => scriptName === "build-keycloak-theme");
90
+
91
+ if (entry === undefined) {
92
+ console.log(
93
+ chalk.red(
94
+ "There's multiple candidate script for building your app, name one 'build-keycloak-theme'"
95
+ )
96
+ );
97
+ process.exit(-1);
98
+ }
99
+
100
+ const [scriptName, scriptCommand] = entry;
101
+
102
+ const { appBuildSubCommands } = (() => {
103
+ const appBuildSubCommands: string[] = [];
104
+
105
+ for (const subCmd of scriptCommand.split("&&").map(s => s.trim())) {
106
+ if (subCmd.includes("keycloakify build")) {
107
+ break;
108
+ }
109
+
110
+ appBuildSubCommands.push(subCmd);
111
+ }
112
+
113
+ return { appBuildSubCommands };
114
+ })();
115
+
116
+ if (appBuildSubCommands.length === 0) {
117
+ console.log(
118
+ chalk.red(
119
+ `Your ${scriptName} script should look like "... && keycloakify build ..."`
120
+ )
121
+ );
122
+ process.exit(-1);
123
+ }
124
+
125
+ for (const subCommand of appBuildSubCommands) {
126
+ const dIsSuccess = new Deferred<boolean>();
127
+
128
+ console.log(chalk.blue(`Running: '${subCommand}'`));
129
+
130
+ const [command, ...args] = subCommand.split(" ");
131
+
132
+ const child = child_process.spawn(command, args, {
133
+ cwd: buildContext.bundler.packageJsonDirPath,
134
+ env: {
135
+ ...process.env,
136
+ PATH: (() => {
137
+ const separator = pathSep === "/" ? ":" : ";";
138
+
139
+ return [
140
+ pathJoin(
141
+ buildContext.bundler.packageJsonDirPath,
142
+ "node_modules",
143
+ ".bin"
144
+ ),
145
+ ...(process.env.PATH ?? "").split(separator)
146
+ ].join(separator);
147
+ })()
148
+ },
149
+ shell: true
150
+ });
151
+
152
+ child.stdout.on("data", data => process.stdout.write(data));
153
+
154
+ child.stderr.on("data", data => process.stderr.write(data));
155
+
156
+ child.on("exit", code => dIsSuccess.resolve(code === 0));
157
+
158
+ const isSuccess = await dIsSuccess.pr;
159
+
160
+ if (!isSuccess) {
161
+ return { isAppBuildSuccess: false };
162
+ }
163
+ }
164
+
165
+ return { isAppBuildSuccess: true };
166
+ }
@@ -7,7 +7,6 @@ import type { BuildContext } from "../shared/buildContext";
7
7
  export type BuildContextLike = {
8
8
  projectDirPath: string;
9
9
  keycloakifyBuildDirPath: string;
10
- bundler: "vite" | "webpack";
11
10
  };
12
11
 
13
12
  assert<BuildContext extends BuildContextLike ? true : false>();
@@ -121,7 +121,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
121
121
  if (!isAppBuildSuccess) {
122
122
  console.log(
123
123
  chalk.red(
124
- `App build failed, exiting. Try running 'npm run build' and see what's wrong.`
124
+ `App build failed, exiting. Try building your app (e.g 'npm run build') and see what's wrong.`
125
125
  )
126
126
  );
127
127
  process.exit(1);
@@ -1,12 +1,12 @@
1
- import fetch from "make-fetch-happen";
1
+ import fetch, { type FetchOptions } from "make-fetch-happen";
2
2
  import { mkdir, unlink, writeFile, readdir, readFile } from "fs/promises";
3
3
  import { dirname as pathDirname, join as pathJoin } from "path";
4
4
  import { assert } from "tsafe/assert";
5
- import { extractArchive } from "../extractArchive";
6
- import { existsAsync } from "../fs.existsAsync";
7
- import { getProxyFetchOptions } from "./fetchProxyOptions";
5
+ import { extractArchive } from "./extractArchive";
6
+ import { existsAsync } from "./fs.existsAsync";
7
+
8
8
  import * as crypto from "crypto";
9
- import { rm } from "../fs.rm";
9
+ import { rm } from "./fs.rm";
10
10
 
11
11
  export async function downloadAndExtractArchive(params: {
12
12
  url: string;
@@ -20,15 +20,10 @@ export async function downloadAndExtractArchive(params: {
20
20
  }) => Promise<void>;
21
21
  }) => Promise<void>;
22
22
  cacheDirPath: string;
23
- npmWorkspaceRootDirPath: string;
23
+ fetchOptions: FetchOptions | undefined;
24
24
  }): Promise<{ extractedDirPath: string }> {
25
- const {
26
- url,
27
- uniqueIdOfOnOnArchiveFile,
28
- onArchiveFile,
29
- cacheDirPath,
30
- npmWorkspaceRootDirPath
31
- } = params;
25
+ const { url, uniqueIdOfOnOnArchiveFile, onArchiveFile, cacheDirPath, fetchOptions } =
26
+ params;
32
27
 
33
28
  const archiveFileBasename = url.split("?")[0].split("/").reverse()[0];
34
29
 
@@ -55,10 +50,7 @@ export async function downloadAndExtractArchive(params: {
55
50
 
56
51
  await mkdir(pathDirname(archiveFilePath), { recursive: true });
57
52
 
58
- const response = await fetch(
59
- url,
60
- await getProxyFetchOptions({ npmWorkspaceRootDirPath })
61
- );
53
+ const response = await fetch(url, fetchOptions);
62
54
 
63
55
  response.body?.setMaxListeners(Number.MAX_VALUE);
64
56
  assert(typeof response.body !== "undefined" && response.body != null);
@@ -1,61 +1,40 @@
1
- import { exec as execCallback } from "child_process";
2
- import { readFile } from "fs/promises";
3
1
  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(
15
- "Illegal configuration, expected a single value but found multiple: " +
16
- arg0.map(String).join(", ")
17
- );
18
- }
19
-
20
- type NPMConfig = Record<string, string | string[]>;
21
-
22
- /**
23
- * Get npm configuration as map
24
- */
25
- async function getNmpConfig(params: { npmWorkspaceRootDirPath: string }) {
26
- const { npmWorkspaceRootDirPath } = params;
27
-
28
- const exec = promisify(execCallback);
29
-
30
- const stdout = await exec("npm config get", {
31
- encoding: "utf8",
32
- cwd: npmWorkspaceRootDirPath
33
- }).then(({ stdout }) => stdout);
34
-
35
- const npmConfigReducer = (cfg: NPMConfig, [key, value]: [string, string]) =>
36
- key in cfg
37
- ? { ...cfg, [key]: [...ensureArray(cfg[key]), value] }
38
- : { ...cfg, [key]: value };
39
-
40
- return stdout
41
- .split("\n")
42
- .filter(line => !line.startsWith(";"))
43
- .map(line => line.trim())
44
- .map(line => line.split("=", 2) as [string, string])
45
- .reduce(npmConfigReducer, {} as NPMConfig);
46
- }
2
+ import * as child_process from "child_process";
3
+ import * as fs from "fs";
47
4
 
48
5
  export type ProxyFetchOptions = Pick<
49
6
  FetchOptions,
50
7
  "proxy" | "noProxy" | "strictSSL" | "cert" | "ca"
51
8
  >;
52
9
 
53
- export async function getProxyFetchOptions(params: {
54
- npmWorkspaceRootDirPath: string;
55
- }): Promise<ProxyFetchOptions> {
56
- const { npmWorkspaceRootDirPath } = params;
57
-
58
- const cfg = await getNmpConfig({ npmWorkspaceRootDirPath });
10
+ export function getProxyFetchOptions(params: {
11
+ npmConfigGetCwd: string;
12
+ }): ProxyFetchOptions {
13
+ const { npmConfigGetCwd } = params;
14
+
15
+ const cfg = (() => {
16
+ const output = child_process
17
+ .execSync("npm config get", {
18
+ cwd: npmConfigGetCwd
19
+ })
20
+ .toString("utf8");
21
+
22
+ return output
23
+ .split("\n")
24
+ .filter(line => !line.startsWith(";"))
25
+ .map(line => line.trim())
26
+ .map(line => line.split("=", 2) as [string, string])
27
+ .reduce(
28
+ (
29
+ cfg: Record<string, string | string[]>,
30
+ [key, value]: [string, string]
31
+ ) =>
32
+ key in cfg
33
+ ? { ...cfg, [key]: [...ensureArray(cfg[key]), value] }
34
+ : { ...cfg, [key]: value },
35
+ {}
36
+ );
37
+ })();
59
38
 
60
39
  const proxy = ensureSingleOrNone(cfg["https-proxy"] ?? cfg["proxy"]);
61
40
  const noProxy = cfg["noproxy"] ?? cfg["no-proxy"];
@@ -71,17 +50,16 @@ export async function getProxyFetchOptions(params: {
71
50
 
72
51
  if (typeof cafile !== "undefined" && cafile !== "null") {
73
52
  ca.push(
74
- ...(await (async () => {
75
- function chunks<T>(arr: T[], size: number = 2) {
76
- return arr
77
- .map((_, i) => i % size == 0 && arr.slice(i, i + size))
78
- .filter(Boolean) as T[][];
79
- }
80
-
81
- const cafileContent = await readFile(cafile, "utf-8");
53
+ ...(() => {
54
+ const cafileContent = fs.readFileSync(cafile).toString("utf8");
82
55
 
83
56
  const newLinePlaceholder = "NEW_LINE_PLACEHOLDER_xIsPsK23svt";
84
57
 
58
+ const chunks = <T>(arr: T[], size: number = 2) =>
59
+ arr
60
+ .map((_, i) => i % size == 0 && arr.slice(i, i + size))
61
+ .filter(Boolean) as T[][];
62
+
85
63
  return chunks(cafileContent.split(/(-----END CERTIFICATE-----)/), 2).map(
86
64
  ca =>
87
65
  ca
@@ -90,7 +68,7 @@ export async function getProxyFetchOptions(params: {
90
68
  .replace(new RegExp(`^${newLinePlaceholder}`), "")
91
69
  .replace(new RegExp(newLinePlaceholder, "g"), "\\n")
92
70
  );
93
- })())
71
+ })()
94
72
  );
95
73
  }
96
74
 
@@ -102,3 +80,17 @@ export async function getProxyFetchOptions(params: {
102
80
  ca: ca.length === 0 ? undefined : ca
103
81
  };
104
82
  }
83
+
84
+ function ensureArray<T>(arg0: T | T[]) {
85
+ return Array.isArray(arg0) ? arg0 : typeof arg0 === "undefined" ? [] : [arg0];
86
+ }
87
+
88
+ function ensureSingleOrNone<T>(arg0: T | T[]) {
89
+ if (!Array.isArray(arg0)) return arg0;
90
+ if (arg0.length === 0) return undefined;
91
+ if (arg0.length === 1) return arg0[0];
92
+ throw new Error(
93
+ "Illegal configuration, expected a single value but found multiple: " +
94
+ arg0.map(String).join(", ")
95
+ );
96
+ }