keycloakify 10.0.0-rc.16 → 10.0.0-rc.17

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.
@@ -10,6 +10,7 @@ export declare const vitePluginSubScriptEnvNames: {
10
10
  readonly runPostBuildScript: "KEYCLOAKIFY_RUN_POST_BUILD_SCRIPT";
11
11
  readonly resolveViteConfig: "KEYCLOAKIFY_RESOLVE_VITE_CONFIG";
12
12
  };
13
+ export declare const skipBuildJarsEnvName = "KEYCLOAKIFY_SKIP_BUILD_JAR";
13
14
  export declare const loginThemePageIds: readonly ["login.ftl", "login-username.ftl", "login-password.ftl", "webauthn-authenticate.ftl", "webauthn-register.ftl", "register.ftl", "info.ftl", "error.ftl", "login-reset-password.ftl", "login-verify-email.ftl", "terms.ftl", "login-oauth2-device-verify-user-code.ftl", "login-oauth-grant.ftl", "login-otp.ftl", "login-update-profile.ftl", "login-update-password.ftl", "login-idp-link-confirm.ftl", "login-idp-link-email.ftl", "login-page-expired.ftl", "login-config-totp.ftl", "logout-confirm.ftl", "idp-review-user-profile.ftl", "update-email.ftl", "select-authenticator.ftl", "saml-post-form.ftl", "delete-credential.ftl", "code.ftl", "delete-account-confirm.ftl", "frontchannel-logout.ftl", "login-recovery-authn-code-config.ftl", "login-recovery-authn-code-input.ftl", "login-reset-otp.ftl", "login-x509-info.ftl", "webauthn-error.ftl"];
14
15
  export declare const accountThemePageIds: readonly ["password.ftl", "account.ftl", "sessions.ftl", "totp.ftl", "applications.ftl", "log.ftl", "federatedIdentity.ftl"];
15
16
  export type LoginThemePageId = (typeof loginThemePageIds)[number];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.accountThemePageIds = exports.loginThemePageIds = exports.vitePluginSubScriptEnvNames = exports.accountV1ThemeName = exports.themeTypes = exports.basenameOfTheKeycloakifyResourcesDir = exports.lastKeycloakVersionWithAccountV1 = exports.resources_common = exports.keycloak_resources = exports.nameOfTheGlobal = void 0;
3
+ exports.accountThemePageIds = exports.loginThemePageIds = exports.skipBuildJarsEnvName = exports.vitePluginSubScriptEnvNames = exports.accountV1ThemeName = exports.themeTypes = exports.basenameOfTheKeycloakifyResourcesDir = exports.lastKeycloakVersionWithAccountV1 = exports.resources_common = exports.keycloak_resources = exports.nameOfTheGlobal = void 0;
4
4
  exports.nameOfTheGlobal = "kcContext";
5
5
  exports.keycloak_resources = "keycloak-resources";
6
6
  exports.resources_common = "resources-common";
@@ -12,6 +12,7 @@ exports.vitePluginSubScriptEnvNames = {
12
12
  "runPostBuildScript": "KEYCLOAKIFY_RUN_POST_BUILD_SCRIPT",
13
13
  "resolveViteConfig": "KEYCLOAKIFY_RESOLVE_VITE_CONFIG"
14
14
  };
15
+ exports.skipBuildJarsEnvName = "KEYCLOAKIFY_SKIP_BUILD_JAR";
15
16
  exports.loginThemePageIds = [
16
17
  "login.ftl",
17
18
  "login-username.ftl",
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/bin/shared/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAAG,WAAW,CAAC;AAC9B,QAAA,kBAAkB,GAAG,oBAAoB,CAAC;AAC1C,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AACtC,QAAA,gCAAgC,GAAG,QAAQ,CAAC;AAC5C,QAAA,oCAAoC,GAAG,OAAO,CAAC;AAE/C,QAAA,UAAU,GAAG,CAAC,OAAO,EAAE,SAAS,CAAU,CAAC;AAC3C,QAAA,kBAAkB,GAAG,YAAY,CAAC;AAIlC,QAAA,2BAA2B,GAAG;IACvC,oBAAoB,EAAE,mCAAmC;IACzD,mBAAmB,EAAE,iCAAiC;CAChD,CAAC;AAEE,QAAA,iBAAiB,GAAG;IAC7B,WAAW;IACX,oBAAoB;IACpB,oBAAoB;IACpB,2BAA2B;IAC3B,uBAAuB;IACvB,cAAc;IACd,UAAU;IACV,WAAW;IACX,0BAA0B;IAC1B,wBAAwB;IACxB,WAAW;IACX,0CAA0C;IAC1C,uBAAuB;IACvB,eAAe;IACf,0BAA0B;IAC1B,2BAA2B;IAC3B,4BAA4B;IAC5B,0BAA0B;IAC1B,wBAAwB;IACxB,uBAAuB;IACvB,oBAAoB;IACpB,6BAA6B;IAC7B,kBAAkB;IAClB,0BAA0B;IAC1B,oBAAoB;IACpB,uBAAuB;IACvB,UAAU;IACV,4BAA4B;IAC5B,yBAAyB;IACzB,sCAAsC;IACtC,qCAAqC;IACrC,qBAAqB;IACrB,qBAAqB;IACrB,oBAAoB;CACd,CAAC;AAEE,QAAA,mBAAmB,GAAG;IAC/B,cAAc;IACd,aAAa;IACb,cAAc;IACd,UAAU;IACV,kBAAkB;IAClB,SAAS;IACT,uBAAuB;CACjB,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/bin/shared/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAAG,WAAW,CAAC;AAC9B,QAAA,kBAAkB,GAAG,oBAAoB,CAAC;AAC1C,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AACtC,QAAA,gCAAgC,GAAG,QAAQ,CAAC;AAC5C,QAAA,oCAAoC,GAAG,OAAO,CAAC;AAE/C,QAAA,UAAU,GAAG,CAAC,OAAO,EAAE,SAAS,CAAU,CAAC;AAC3C,QAAA,kBAAkB,GAAG,YAAY,CAAC;AAIlC,QAAA,2BAA2B,GAAG;IACvC,oBAAoB,EAAE,mCAAmC;IACzD,mBAAmB,EAAE,iCAAiC;CAChD,CAAC;AAEE,QAAA,oBAAoB,GAAG,4BAA4B,CAAC;AAEpD,QAAA,iBAAiB,GAAG;IAC7B,WAAW;IACX,oBAAoB;IACpB,oBAAoB;IACpB,2BAA2B;IAC3B,uBAAuB;IACvB,cAAc;IACd,UAAU;IACV,WAAW;IACX,0BAA0B;IAC1B,wBAAwB;IACxB,WAAW;IACX,0CAA0C;IAC1C,uBAAuB;IACvB,eAAe;IACf,0BAA0B;IAC1B,2BAA2B;IAC3B,4BAA4B;IAC5B,0BAA0B;IAC1B,wBAAwB;IACxB,uBAAuB;IACvB,oBAAoB;IACpB,6BAA6B;IAC7B,kBAAkB;IAClB,0BAA0B;IAC1B,oBAAoB;IACpB,uBAAuB;IACvB,UAAU;IACV,4BAA4B;IAC5B,yBAAyB;IACzB,sCAAsC;IACtC,qCAAqC;IACrC,qBAAqB;IACrB,qBAAqB;IACrB,oBAAoB;CACd,CAAC;AAEE,QAAA,mBAAmB,GAAG;IAC/B,cAAc;IACd,aAAa;IACb,cAAc;IACd,UAAU;IACV,kBAAkB;IAClB,SAAS;IACT,uBAAuB;CACjB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keycloakify",
3
- "version": "10.0.0-rc.16",
3
+ "version": "10.0.0-rc.17",
4
4
  "description": "Create Keycloak themes using React",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,7 +24,11 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
24
24
  const destDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme");
25
25
 
26
26
  console.log(
27
- `Downloading builtins theme of Keycloak ${keycloakVersion} here ${chalk.bold(`.${pathSep}${pathRelative(process.cwd(), destDirPath)}`)}`
27
+ [
28
+ `Downloading builtins theme of Keycloak ${keycloakVersion} here:`,
29
+ `- ${chalk.bold(`.${pathSep}${pathJoin(pathRelative(process.cwd(), destDirPath), "base")}`)}`,
30
+ `- ${chalk.bold(`.${pathSep}${pathJoin(pathRelative(process.cwd(), destDirPath), "keycloak")}`)}`
31
+ ].join("\n")
28
32
  );
29
33
 
30
34
  await downloadKeycloakDefaultTheme({
@@ -10,7 +10,8 @@ import { readFileSync } from "fs";
10
10
  import { isInside } from "../../tools/isInside";
11
11
  import child_process from "child_process";
12
12
  import { rmSync } from "../../tools/fs.rmSync";
13
- import { getMetaInfKeycloakThemesJsonPath } from "../../shared/metaInfKeycloakThemes";
13
+ import { getMetaInfKeycloakThemesJsonFilePath } from "../../shared/metaInfKeycloakThemes";
14
+ import type { Param0 } from "tsafe";
14
15
 
15
16
  export type BuildOptionsLike = BuildOptionsLike_generatePom & {
16
17
  keycloakifyBuildDirPath: string;
@@ -35,50 +36,98 @@ export async function buildJar(params: {
35
36
  rmSync(keycloakifyBuildTmpDirPath, { "recursive": true, "force": true });
36
37
 
37
38
  {
38
- const keycloakThemesJsonFilePath = getMetaInfKeycloakThemesJsonPath({ "keycloakifyBuildDirPath": "" });
39
+ const metaInfKeycloakThemesJsonRelativePath = getMetaInfKeycloakThemesJsonFilePath({ "keycloakifyBuildDirPath": "" });
39
40
 
40
- const themePropertiesFilePathSet = new Set(
41
- ...buildOptions.themeNames.map(themeName => pathJoin("src", "main", "resources", "theme", themeName, "account", "theme.properties"))
42
- );
41
+ const { transformCodebase_common } = (() => {
42
+ const includingAccountV1ThemeNames = [...buildOptions.themeNames, accountV1ThemeName];
43
+
44
+ const transformCodebase_common: Param0<typeof transformCodebase>["transformSourceCode"] = ({ fileRelativePath, sourceCode }) => {
45
+ if (metaInfKeycloakThemesJsonRelativePath === fileRelativePath) {
46
+ return { "modifiedSourceCode": sourceCode };
47
+ }
48
+
49
+ for (const themeName of includingAccountV1ThemeNames) {
50
+ if (isInside({ "dirPath": pathJoin("src", "main", "resources", "theme", themeName), "filePath": fileRelativePath })) {
51
+ return { "modifiedSourceCode": sourceCode };
52
+ }
53
+ }
54
+
55
+ return undefined;
56
+ };
57
+
58
+ return { transformCodebase_common };
59
+ })();
60
+
61
+ const { transformCodebase_patchForUsingBuiltinAccountV1 } = (() => {
62
+ if (keycloakAccountV1Version !== null) {
63
+ return { "transformCodebase_patchForUsingBuiltinAccountV1": undefined };
64
+ }
65
+
66
+ const themePropertiesFileRelativePathSet = new Set(
67
+ ...buildOptions.themeNames.map(themeName => pathJoin("src", "main", "resources", "theme", themeName, "account", "theme.properties"))
68
+ );
69
+
70
+ const accountV1RelativeDirPath = pathJoin("src", "main", "resources", "theme", accountV1ThemeName);
71
+
72
+ const transformCodebase_patchForUsingBuiltinAccountV1: Param0<typeof transformCodebase>["transformSourceCode"] = ({
73
+ fileRelativePath,
74
+ sourceCode
75
+ }) => {
76
+ if (isInside({ "dirPath": accountV1RelativeDirPath, "filePath": fileRelativePath })) {
77
+ return undefined;
78
+ }
79
+
80
+ if (fileRelativePath === metaInfKeycloakThemesJsonRelativePath) {
81
+ const keycloakThemesJsonParsed = JSON.parse(sourceCode.toString("utf8")) as {
82
+ themes: { name: string; types: string[] }[];
83
+ };
43
84
 
44
- const accountV1RelativeDirPath = pathJoin("src", "main", "resources", "theme", accountV1ThemeName);
85
+ keycloakThemesJsonParsed.themes = keycloakThemesJsonParsed.themes.filter(({ name }) => name !== accountV1ThemeName);
86
+
87
+ return { "modifiedSourceCode": Buffer.from(JSON.stringify(keycloakThemesJsonParsed, null, 2), "utf8") };
88
+ }
89
+
90
+ if (themePropertiesFileRelativePathSet.has(fileRelativePath)) {
91
+ const modifiedSourceCode = Buffer.from(
92
+ sourceCode.toString("utf8").replace(`parent=${accountV1ThemeName}`, "parent=keycloak"),
93
+ "utf8"
94
+ );
95
+
96
+ // assert modifiedSourceCode !== sourceCode
97
+ assert(Buffer.compare(modifiedSourceCode, sourceCode) !== 0);
98
+
99
+ return { modifiedSourceCode };
100
+ }
101
+
102
+ return { "modifiedSourceCode": sourceCode };
103
+ };
104
+
105
+ return { transformCodebase_patchForUsingBuiltinAccountV1 };
106
+ })();
45
107
 
46
108
  transformCodebase({
47
109
  "srcDirPath": buildOptions.keycloakifyBuildDirPath,
48
110
  "destDirPath": keycloakifyBuildTmpDirPath,
49
- "transformSourceCode":
50
- keycloakAccountV1Version !== null
51
- ? undefined
52
- : ({ fileRelativePath, sourceCode }) => {
53
- if (fileRelativePath === keycloakThemesJsonFilePath) {
54
- const keycloakThemesJsonParsed = JSON.parse(sourceCode.toString("utf8")) as {
55
- themes: { name: string; types: string[] }[];
56
- };
57
-
58
- keycloakThemesJsonParsed.themes = keycloakThemesJsonParsed.themes.filter(({ name }) => name !== accountV1ThemeName);
59
-
60
- return { "modifiedSourceCode": Buffer.from(JSON.stringify(keycloakThemesJsonParsed, null, 2), "utf8") };
61
- }
62
-
63
- if (isInside({ "dirPath": "target", "filePath": fileRelativePath })) {
64
- return undefined;
65
- }
66
-
67
- if (isInside({ "dirPath": accountV1RelativeDirPath, "filePath": fileRelativePath })) {
68
- return undefined;
69
- }
70
-
71
- if (themePropertiesFilePathSet.has(fileRelativePath)) {
72
- return {
73
- "modifiedSourceCode": Buffer.from(
74
- sourceCode.toString("utf8").replace(`parent=${accountV1ThemeName}`, "parent=keycloak"),
75
- "utf8"
76
- )
77
- };
78
- }
79
-
80
- return { "modifiedSourceCode": sourceCode };
81
- }
111
+ "transformSourceCode": params => {
112
+ const resultCommon = transformCodebase_common(params);
113
+
114
+ if (resultCommon === undefined) {
115
+ return undefined;
116
+ }
117
+
118
+ if (transformCodebase_patchForUsingBuiltinAccountV1 === undefined) {
119
+ return resultCommon;
120
+ }
121
+
122
+ const { modifiedSourceCode, newFileName } = resultCommon;
123
+
124
+ assert(newFileName === undefined);
125
+
126
+ return transformCodebase_patchForUsingBuiltinAccountV1?.({
127
+ ...params,
128
+ "sourceCode": modifiedSourceCode
129
+ });
130
+ }
82
131
  });
83
132
  }
84
133
 
@@ -3,7 +3,7 @@ import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path
3
3
  import * as child_process from "child_process";
4
4
  import * as fs from "fs";
5
5
  import { readBuildOptions } from "../shared/buildOptions";
6
- import { vitePluginSubScriptEnvNames } from "../shared/constants";
6
+ import { vitePluginSubScriptEnvNames, skipBuildJarsEnvName } from "../shared/constants";
7
7
  import { buildJars } from "./buildJars";
8
8
  import type { CliCommandOptions } from "../main";
9
9
  import chalk from "chalk";
@@ -76,7 +76,13 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
76
76
  });
77
77
  }
78
78
 
79
- await buildJars({ buildOptions });
79
+ build_jars: {
80
+ if (process.env[skipBuildJarsEnvName]) {
81
+ break build_jars;
82
+ }
83
+
84
+ await buildJars({ buildOptions });
85
+ }
80
86
 
81
87
  console.log(chalk.green(`✓ built in ${((Date.now() - startTime) / 1000).toFixed(2)}s`));
82
88
  }
@@ -163,7 +163,10 @@ export function readBuildOptions(params: { cliCommandOptions: CliCommandOptions
163
163
  return pathJoin(reactAppRootDirPath, resolvedViteConfig.buildDir);
164
164
  })();
165
165
 
166
- const { npmWorkspaceRootDirPath } = getNpmWorkspaceRootDirPath({ reactAppRootDirPath });
166
+ const { npmWorkspaceRootDirPath } = getNpmWorkspaceRootDirPath({
167
+ reactAppRootDirPath,
168
+ "dependencyExpected": "keycloakify"
169
+ });
167
170
 
168
171
  return {
169
172
  "bundler": resolvedViteConfig !== undefined ? "vite" : "webpack",
@@ -14,6 +14,8 @@ export const vitePluginSubScriptEnvNames = {
14
14
  "resolveViteConfig": "KEYCLOAKIFY_RESOLVE_VITE_CONFIG"
15
15
  } as const;
16
16
 
17
+ export const skipBuildJarsEnvName = "KEYCLOAKIFY_SKIP_BUILD_JAR";
18
+
17
19
  export const loginThemePageIds = [
18
20
  "login.ftl",
19
21
  "login-username.ftl",
@@ -6,7 +6,7 @@ export type MetaInfKeycloakTheme = {
6
6
  themes: { name: string; types: (ThemeType | "email")[] }[];
7
7
  };
8
8
 
9
- export function getMetaInfKeycloakThemesJsonPath(params: { keycloakifyBuildDirPath: string }) {
9
+ export function getMetaInfKeycloakThemesJsonFilePath(params: { keycloakifyBuildDirPath: string }) {
10
10
  const { keycloakifyBuildDirPath } = params;
11
11
 
12
12
  return pathJoin(keycloakifyBuildDirPath, "src", "main", "resources", "META-INF", "keycloak-themes.json");
@@ -15,13 +15,13 @@ export function getMetaInfKeycloakThemesJsonPath(params: { keycloakifyBuildDirPa
15
15
  export function readMetaInfKeycloakThemes(params: { keycloakifyBuildDirPath: string }): MetaInfKeycloakTheme {
16
16
  const { keycloakifyBuildDirPath } = params;
17
17
 
18
- return JSON.parse(fs.readFileSync(getMetaInfKeycloakThemesJsonPath({ keycloakifyBuildDirPath })).toString("utf8")) as MetaInfKeycloakTheme;
18
+ return JSON.parse(fs.readFileSync(getMetaInfKeycloakThemesJsonFilePath({ keycloakifyBuildDirPath })).toString("utf8")) as MetaInfKeycloakTheme;
19
19
  }
20
20
 
21
21
  export function writeMetaInfKeycloakThemes(params: { keycloakifyBuildDirPath: string; metaInfKeycloakThemes: MetaInfKeycloakTheme }) {
22
22
  const { keycloakifyBuildDirPath, metaInfKeycloakThemes } = params;
23
23
 
24
- const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonPath({ keycloakifyBuildDirPath });
24
+ const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonFilePath({ keycloakifyBuildDirPath });
25
25
 
26
26
  {
27
27
  const dirPath = pathDirname(metaInfKeycloakThemesJsonPath);
@@ -2,15 +2,19 @@ import { readBuildOptions } from "./shared/buildOptions";
2
2
  import type { CliCommandOptions as CliCommandOptions_common } from "./main";
3
3
  import { promptKeycloakVersion } from "./shared/promptKeycloakVersion";
4
4
  import { readMetaInfKeycloakThemes } from "./shared/metaInfKeycloakThemes";
5
- import { accountV1ThemeName } from "./shared/constants";
5
+ import { accountV1ThemeName, skipBuildJarsEnvName } from "./shared/constants";
6
6
  import { SemVer } from "./tools/SemVer";
7
7
  import type { KeycloakVersionRange } from "./shared/KeycloakVersionRange";
8
8
  import { getJarFileBasename } from "./shared/getJarFileBasename";
9
9
  import { assert, type Equals } from "tsafe/assert";
10
10
  import * as fs from "fs";
11
- import { join as pathJoin, posix as pathPosix } from "path";
11
+ import { join as pathJoin, relative as pathRelative, sep as pathSep, posix as pathPosix } from "path";
12
12
  import * as child_process from "child_process";
13
13
  import chalk from "chalk";
14
+ import chokidar from "chokidar";
15
+ import { waitForDebounceFactory } from "powerhooks/tools/waitForDebounce";
16
+ import { getThemeSrcDirPath } from "./shared/getThemeSrcDirPath";
17
+ import { Deferred } from "evt/tools/Deferred";
14
18
 
15
19
  export type CliCommandOptions = CliCommandOptions_common & {
16
20
  port: number;
@@ -91,13 +95,15 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
91
95
  };
92
96
  }
93
97
 
94
- console.log("On which version of Keycloak do you want to test your theme?");
98
+ console.log(chalk.cyan("On which version of Keycloak do you want to test your theme?"));
95
99
 
96
100
  const { keycloakVersion } = await promptKeycloakVersion({
97
101
  "startingFromMajor": 17,
98
102
  "cacheDirPath": buildOptions.cacheDirPath
99
103
  });
100
104
 
105
+ console.log(`→ ${keycloakVersion}`);
106
+
101
107
  const keycloakMajorNumber = SemVer.parse(keycloakVersion).major;
102
108
 
103
109
  if (doesImplementAccountTheme && keycloakMajorNumber === 22) {
@@ -149,6 +155,8 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
149
155
 
150
156
  const { jarFileBasename } = getJarFileBasename({ keycloakVersionRange });
151
157
 
158
+ console.log(`Using Keycloak ${chalk.bold(jarFileBasename)}`);
159
+
152
160
  const mountTargets = buildOptions.themeNames
153
161
  .map(themeName => {
154
162
  const themeEntry = metaInfKeycloakThemes.themes.find(({ name }) => name === themeName);
@@ -182,10 +190,10 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
182
190
  const containerName = "keycloak-keycloakify";
183
191
 
184
192
  try {
185
- child_process.execSync(`docker rm ${containerName}`, { "stdio": "ignore" });
193
+ child_process.execSync(`docker rm --force ${containerName}`, { "stdio": "ignore" });
186
194
  } catch {}
187
195
 
188
- const child = child_process.spawn(
196
+ const spawnParams = [
189
197
  "docker",
190
198
  [
191
199
  "run",
@@ -203,12 +211,18 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
203
211
  {
204
212
  "cwd": buildOptions.keycloakifyBuildDirPath
205
213
  }
206
- );
214
+ ] as const;
215
+
216
+ const child = child_process.spawn(...spawnParams);
207
217
 
208
218
  child.stdout.on("data", data => process.stdout.write(data));
209
219
 
210
220
  child.stderr.on("data", data => process.stderr.write(data));
211
221
 
222
+ child.on("exit", process.exit);
223
+
224
+ const { themeSrcDirPath } = getThemeSrcDirPath({ "reactAppRootDirPath": buildOptions.reactAppRootDirPath });
225
+
212
226
  {
213
227
  const handler = async (data: Buffer) => {
214
228
  if (!data.toString("utf8").includes("Listening on: http://0.0.0.0:8080")) {
@@ -224,7 +238,12 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
224
238
  "",
225
239
  `${chalk.green("Your theme is accessible at:")}`,
226
240
  `${chalk.green("➜")} ${chalk.cyan.bold("https://test.keycloakify.dev/")}`,
227
- ""
241
+ "",
242
+ `Keycloak Admin console: ${chalk.cyan.bold(`http://localhost:${cliCommandOptions.port}`)}`,
243
+ `- user: ${chalk.cyan.bold("admin")}`,
244
+ `- password: ${chalk.cyan.bold("admin")}`,
245
+ "",
246
+ `Watching for changes in ${chalk.bold(`.${pathSep}${pathRelative(process.cwd(), themeSrcDirPath)}`)} ...`
228
247
  ].join("\n")
229
248
  );
230
249
  };
@@ -232,5 +251,59 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
232
251
  child.stdout.on("data", handler);
233
252
  }
234
253
 
235
- child.on("exit", process.exit);
254
+ {
255
+ const { waitForDebounce } = waitForDebounceFactory({ "delay": 400 });
256
+
257
+ chokidar.watch(themeSrcDirPath, { "ignoreInitial": true }).on("all", async (...eventArgs) => {
258
+ console.log({ eventArgs });
259
+
260
+ await waitForDebounce();
261
+
262
+ console.log(chalk.cyan("Detected changes in the theme. Rebuilding ..."));
263
+
264
+ const dViteBuildDone = new Deferred<void>();
265
+
266
+ {
267
+ const child = child_process.spawn("npx", ["vite", "build"], {
268
+ "cwd": buildOptions.reactAppRootDirPath,
269
+ "env": process.env
270
+ });
271
+
272
+ child.stdout.on("data", data => process.stdout.write(data));
273
+
274
+ child.stderr.on("data", data => process.stderr.write(data));
275
+
276
+ child.on("exit", code => {
277
+ if (code === 0) {
278
+ dViteBuildDone.resolve();
279
+ }
280
+ });
281
+ }
282
+
283
+ await dViteBuildDone.pr;
284
+
285
+ {
286
+ const child = child_process.spawn("npx", ["keycloakify", "build"], {
287
+ "cwd": buildOptions.reactAppRootDirPath,
288
+ "env": {
289
+ ...process.env,
290
+ [skipBuildJarsEnvName]: "true"
291
+ }
292
+ });
293
+
294
+ child.stdout.on("data", data => process.stdout.write(data));
295
+
296
+ child.stderr.on("data", data => process.stderr.write(data));
297
+
298
+ child.on("exit", code => {
299
+ if (code !== 0) {
300
+ console.log(chalk.yellow("Theme not updated, build failed"));
301
+ return;
302
+ }
303
+
304
+ console.log(chalk.green("Rebuild done"));
305
+ });
306
+ }
307
+ });
308
+ }
236
309
  }
@@ -1,9 +1,10 @@
1
1
  import * as child_process from "child_process";
2
2
  import { join as pathJoin, resolve as pathResolve, sep as pathSep } from "path";
3
3
  import { assert } from "tsafe/assert";
4
+ import * as fs from "fs";
4
5
 
5
- export function getNpmWorkspaceRootDirPath(params: { reactAppRootDirPath: string }) {
6
- const { reactAppRootDirPath } = params;
6
+ export function getNpmWorkspaceRootDirPath(params: { reactAppRootDirPath: string; dependencyExpected: string }) {
7
+ const { reactAppRootDirPath, dependencyExpected } = params;
7
8
 
8
9
  const npmWorkspaceRootDirPath = (function callee(depth: number): string {
9
10
  const cwd = pathResolve(pathJoin(...[reactAppRootDirPath, ...Array(depth).fill("..")]));
@@ -20,6 +21,38 @@ export function getNpmWorkspaceRootDirPath(params: { reactAppRootDirPath: string
20
21
  throw error;
21
22
  }
22
23
 
24
+ const { isExpectedDependencyFound } = (() => {
25
+ const packageJsonFilePath = pathJoin(cwd, "package.json");
26
+
27
+ assert(fs.existsSync(packageJsonFilePath));
28
+
29
+ const parsedPackageJson = JSON.parse(fs.readFileSync(packageJsonFilePath).toString("utf8"));
30
+
31
+ let isExpectedDependencyFound = false;
32
+
33
+ for (const dependenciesOrDevDependencies of ["dependencies", "devDependencies"] as const) {
34
+ const dependencies = parsedPackageJson[dependenciesOrDevDependencies];
35
+
36
+ if (dependencies === undefined) {
37
+ continue;
38
+ }
39
+
40
+ assert(dependencies instanceof Object);
41
+
42
+ if (dependencies[dependencyExpected] === undefined) {
43
+ continue;
44
+ }
45
+
46
+ isExpectedDependencyFound = true;
47
+ }
48
+
49
+ return { isExpectedDependencyFound };
50
+ })();
51
+
52
+ if (!isExpectedDependencyFound) {
53
+ return callee(depth + 1);
54
+ }
55
+
23
56
  return cwd;
24
57
  })(0);
25
58
 
@@ -133,7 +133,10 @@ function readBuildOptions(params) {
133
133
  }
134
134
  return (0, path_1.join)(reactAppRootDirPath, resolvedViteConfig.buildDir);
135
135
  })();
136
- var npmWorkspaceRootDirPath = (0, getNpmWorkspaceRootDirPath_1.getNpmWorkspaceRootDirPath)({ reactAppRootDirPath: reactAppRootDirPath }).npmWorkspaceRootDirPath;
136
+ var npmWorkspaceRootDirPath = (0, getNpmWorkspaceRootDirPath_1.getNpmWorkspaceRootDirPath)({
137
+ reactAppRootDirPath: reactAppRootDirPath,
138
+ "dependencyExpected": "keycloakify"
139
+ }).npmWorkspaceRootDirPath;
137
140
  return {
138
141
  "bundler": resolvedViteConfig !== undefined ? "vite" : "webpack",
139
142
  "themeVersion": (_b = (_a = process.env.KEYCLOAKIFY_THEME_VERSION) !== null && _a !== void 0 ? _a : parsedPackageJson.version) !== null && _b !== void 0 ? _b : "0.0.0",
@@ -228,7 +231,7 @@ exports.readBuildOptions = readBuildOptions;
228
231
  "use strict";
229
232
 
230
233
  Object.defineProperty(exports, "__esModule", ({ value: true }));
231
- exports.accountThemePageIds = exports.loginThemePageIds = exports.vitePluginSubScriptEnvNames = exports.accountV1ThemeName = exports.themeTypes = exports.basenameOfTheKeycloakifyResourcesDir = exports.lastKeycloakVersionWithAccountV1 = exports.resources_common = exports.keycloak_resources = exports.nameOfTheGlobal = void 0;
234
+ exports.accountThemePageIds = exports.loginThemePageIds = exports.skipBuildJarsEnvName = exports.vitePluginSubScriptEnvNames = exports.accountV1ThemeName = exports.themeTypes = exports.basenameOfTheKeycloakifyResourcesDir = exports.lastKeycloakVersionWithAccountV1 = exports.resources_common = exports.keycloak_resources = exports.nameOfTheGlobal = void 0;
232
235
  exports.nameOfTheGlobal = "kcContext";
233
236
  exports.keycloak_resources = "keycloak-resources";
234
237
  exports.resources_common = "resources-common";
@@ -240,6 +243,7 @@ exports.vitePluginSubScriptEnvNames = {
240
243
  "runPostBuildScript": "KEYCLOAKIFY_RUN_POST_BUILD_SCRIPT",
241
244
  "resolveViteConfig": "KEYCLOAKIFY_RESOLVE_VITE_CONFIG"
242
245
  };
246
+ exports.skipBuildJarsEnvName = "KEYCLOAKIFY_SKIP_BUILD_JAR";
243
247
  exports.loginThemePageIds = [
244
248
  "login.ftl",
245
249
  "login-username.ftl",
@@ -1973,13 +1977,25 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
1973
1977
  }
1974
1978
  return to.concat(ar || Array.prototype.slice.call(from));
1975
1979
  };
1980
+ var __values = (this && this.__values) || function(o) {
1981
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
1982
+ if (m) return m.call(o);
1983
+ if (o && typeof o.length === "number") return {
1984
+ next: function () {
1985
+ if (o && i >= o.length) o = void 0;
1986
+ return { value: o && o[i++], done: !o };
1987
+ }
1988
+ };
1989
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
1990
+ };
1976
1991
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1977
1992
  exports.getNpmWorkspaceRootDirPath = void 0;
1978
1993
  var child_process = __importStar(__nccwpck_require__(2081));
1979
1994
  var path_1 = __nccwpck_require__(1017);
1980
1995
  var assert_1 = __nccwpck_require__(8078);
1996
+ var fs = __importStar(__nccwpck_require__(7147));
1981
1997
  function getNpmWorkspaceRootDirPath(params) {
1982
- var reactAppRootDirPath = params.reactAppRootDirPath;
1998
+ var reactAppRootDirPath = params.reactAppRootDirPath, dependencyExpected = params.dependencyExpected;
1983
1999
  var npmWorkspaceRootDirPath = (function callee(depth) {
1984
2000
  var cwd = (0, path_1.resolve)(path_1.join.apply(void 0, __spreadArray([], __read(__spreadArray([reactAppRootDirPath], __read(Array(depth).fill("..")), false)), false)));
1985
2001
  try {
@@ -1992,6 +2008,38 @@ function getNpmWorkspaceRootDirPath(params) {
1992
2008
  }
1993
2009
  throw error;
1994
2010
  }
2011
+ var isExpectedDependencyFound = (function () {
2012
+ var e_1, _a;
2013
+ var packageJsonFilePath = (0, path_1.join)(cwd, "package.json");
2014
+ (0, assert_1.assert)(fs.existsSync(packageJsonFilePath));
2015
+ var parsedPackageJson = JSON.parse(fs.readFileSync(packageJsonFilePath).toString("utf8"));
2016
+ var isExpectedDependencyFound = false;
2017
+ try {
2018
+ for (var _b = __values(["dependencies", "devDependencies"]), _c = _b.next(); !_c.done; _c = _b.next()) {
2019
+ var dependenciesOrDevDependencies = _c.value;
2020
+ var dependencies = parsedPackageJson[dependenciesOrDevDependencies];
2021
+ if (dependencies === undefined) {
2022
+ continue;
2023
+ }
2024
+ (0, assert_1.assert)(dependencies instanceof Object);
2025
+ if (dependencies[dependencyExpected] === undefined) {
2026
+ continue;
2027
+ }
2028
+ isExpectedDependencyFound = true;
2029
+ }
2030
+ }
2031
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2032
+ finally {
2033
+ try {
2034
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
2035
+ }
2036
+ finally { if (e_1) throw e_1.error; }
2037
+ }
2038
+ return { isExpectedDependencyFound: isExpectedDependencyFound };
2039
+ })().isExpectedDependencyFound;
2040
+ if (!isExpectedDependencyFound) {
2041
+ return callee(depth + 1);
2042
+ }
1995
2043
  return cwd;
1996
2044
  })(0);
1997
2045
  return { npmWorkspaceRootDirPath: npmWorkspaceRootDirPath };