keycloakify 7.16.0-rc.1 → 8.0.0-rc.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 (145) hide show
  1. package/README.md +59 -3
  2. package/account/Template.js +5 -3
  3. package/account/Template.js.map +1 -1
  4. package/account/kcContext/kcContextMocks.js +0 -4
  5. package/account/kcContext/kcContextMocks.js.map +1 -1
  6. package/bin/copy-keycloak-resources-to-public.js +3 -2
  7. package/bin/copy-keycloak-resources-to-public.js.map +1 -1
  8. package/bin/download-builtin-keycloak-theme.d.ts +1 -1
  9. package/bin/download-builtin-keycloak-theme.js +84 -11
  10. package/bin/download-builtin-keycloak-theme.js.map +1 -1
  11. package/bin/initialize-email-theme.js +6 -5
  12. package/bin/initialize-email-theme.js.map +1 -1
  13. package/bin/keycloakify/BuildOptions.d.ts +18 -36
  14. package/bin/keycloakify/BuildOptions.js +71 -145
  15. package/bin/keycloakify/BuildOptions.js.map +1 -1
  16. package/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +0 -12
  17. package/bin/keycloakify/generateFtl/generateFtl.d.ts +5 -25
  18. package/bin/keycloakify/generateFtl/generateFtl.js +7 -11
  19. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  20. package/bin/keycloakify/{generateJavaStackFiles/generateJavaStackFiles.d.ts → generateJavaStackFiles.d.ts} +3 -4
  21. package/bin/keycloakify/generateJavaStackFiles.js +103 -0
  22. package/bin/keycloakify/generateJavaStackFiles.js.map +1 -0
  23. package/bin/keycloakify/generateStartKeycloakTestingContainer.js +1 -5
  24. package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
  25. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +5 -1
  26. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js +24 -6
  27. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
  28. package/bin/keycloakify/generateTheme/generateTheme.d.ts +8 -28
  29. package/bin/keycloakify/generateTheme/generateTheme.js +22 -33
  30. package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
  31. package/bin/keycloakify/generateTheme/readFieldNameUsage.js +1 -2
  32. package/bin/keycloakify/generateTheme/readFieldNameUsage.js.map +1 -1
  33. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.d.ts +17 -0
  34. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.js +172 -0
  35. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.js.map +1 -0
  36. package/bin/keycloakify/keycloakify.js +17 -17
  37. package/bin/keycloakify/keycloakify.js.map +1 -1
  38. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.d.ts +0 -11
  39. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.js +6 -27
  40. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.js.map +1 -1
  41. package/bin/keycloakify/replacers/replaceImportsInCssCode.js +1 -7
  42. package/bin/keycloakify/replacers/replaceImportsInCssCode.js.map +1 -1
  43. package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.d.ts +3 -13
  44. package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.js +5 -12
  45. package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.js.map +1 -1
  46. package/bin/tools/downloadAndUnzip.d.ts +13 -2
  47. package/bin/tools/downloadAndUnzip.js +81 -15
  48. package/bin/tools/downloadAndUnzip.js.map +1 -1
  49. package/bin/tools/transformCodebase.d.ts +1 -0
  50. package/bin/tools/transformCodebase.js +6 -5
  51. package/bin/tools/transformCodebase.js.map +1 -1
  52. package/bin/tools/unzip.d.ts +2 -1
  53. package/bin/tools/unzip.js +129 -11
  54. package/bin/tools/unzip.js.map +1 -1
  55. package/lib/usePrepareTemplate.d.ts +0 -5
  56. package/lib/usePrepareTemplate.js +4 -10
  57. package/lib/usePrepareTemplate.js.map +1 -1
  58. package/login/Template.js +5 -6
  59. package/login/Template.js.map +1 -1
  60. package/login/kcContext/KcContext.d.ts +1 -1
  61. package/login/kcContext/kcContextMocks.js +1 -5
  62. package/login/kcContext/kcContextMocks.js.map +1 -1
  63. package/login/pages/Login.js +16 -20
  64. package/login/pages/Login.js.map +1 -1
  65. package/login/pages/LoginOtp.js +1 -2
  66. package/login/pages/LoginOtp.js.map +1 -1
  67. package/package.json +11 -77
  68. package/src/account/Template.tsx +5 -3
  69. package/src/account/kcContext/kcContextMocks.ts +0 -4
  70. package/src/bin/copy-keycloak-resources-to-public.ts +3 -2
  71. package/src/bin/download-builtin-keycloak-theme.ts +71 -14
  72. package/src/bin/initialize-email-theme.ts +6 -4
  73. package/src/bin/keycloakify/BuildOptions.ts +99 -192
  74. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +0 -12
  75. package/src/bin/keycloakify/generateFtl/generateFtl.ts +16 -45
  76. package/src/bin/keycloakify/generateJavaStackFiles.ts +84 -0
  77. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +1 -6
  78. package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +30 -6
  79. package/src/bin/keycloakify/generateTheme/generateTheme.ts +34 -69
  80. package/src/bin/keycloakify/generateTheme/readFieldNameUsage.ts +1 -4
  81. package/src/bin/keycloakify/generateTheme/readStaticResourcesUsage.ts +83 -0
  82. package/src/bin/keycloakify/keycloakify.ts +2 -1
  83. package/src/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.ts +9 -51
  84. package/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts +1 -9
  85. package/src/bin/keycloakify/replacers/replaceImportsInInlineCssCode.ts +5 -29
  86. package/src/bin/tools/downloadAndUnzip.ts +99 -15
  87. package/src/bin/tools/transformCodebase.ts +7 -6
  88. package/src/bin/tools/unzip.ts +57 -8
  89. package/src/lib/usePrepareTemplate.ts +13 -24
  90. package/src/login/Template.tsx +5 -6
  91. package/src/login/kcContext/KcContext.ts +1 -1
  92. package/src/login/kcContext/kcContextMocks.ts +1 -5
  93. package/src/login/pages/Login.tsx +31 -34
  94. package/src/login/pages/LoginOtp.tsx +1 -2
  95. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +0 -33
  96. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +0 -76
  97. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +0 -25
  98. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +0 -50
  99. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +0 -424
  100. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +0 -51
  101. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +0 -51
  102. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +0 -91
  103. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +0 -157
  104. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +0 -258
  105. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +0 -515
  106. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +0 -56
  107. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +0 -95
  108. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +0 -34
  109. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +0 -75
  110. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +0 -38
  111. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +0 -93
  112. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +0 -125
  113. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +0 -121
  114. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +0 -115
  115. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +0 -1320
  116. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +0 -64
  117. package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js +0 -298
  118. package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js.map +0 -1
  119. package/bin/keycloakify/generateJavaStackFiles/index.d.ts +0 -1
  120. package/bin/keycloakify/generateJavaStackFiles/index.js +0 -18
  121. package/bin/keycloakify/generateJavaStackFiles/index.js.map +0 -1
  122. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +0 -33
  123. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +0 -76
  124. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +0 -25
  125. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +0 -50
  126. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +0 -424
  127. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +0 -51
  128. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +0 -51
  129. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +0 -91
  130. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +0 -157
  131. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +0 -258
  132. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +0 -515
  133. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +0 -56
  134. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +0 -95
  135. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +0 -34
  136. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +0 -75
  137. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +0 -38
  138. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +0 -93
  139. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +0 -125
  140. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +0 -121
  141. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +0 -115
  142. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +0 -1320
  143. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +0 -64
  144. package/src/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.ts +0 -249
  145. package/src/bin/keycloakify/generateJavaStackFiles/index.ts +0 -1
@@ -4,228 +4,135 @@ import { parse as urlParse } from "url";
4
4
  import { typeGuard } from "tsafe/typeGuard";
5
5
  import { symToStr } from "tsafe/symToStr";
6
6
  import { bundlers, getParsedPackageJson, type Bundler } from "./parsedPackageJson";
7
- import * as fs from "fs";
8
7
  import { join as pathJoin, sep as pathSep } from "path";
9
8
  import parseArgv from "minimist";
10
9
 
11
10
  /** Consolidated build option gathered form CLI arguments and config in package.json */
12
- export type BuildOptions = BuildOptions.Standalone | BuildOptions.ExternalAssets;
13
-
14
- export namespace BuildOptions {
15
- export type Common = {
16
- isSilent: boolean;
17
- themeVersion: string;
18
- themeName: string;
19
- extraThemeNames: string[];
20
- extraThemeProperties: string[] | undefined;
21
- groupId: string;
22
- artifactId: string;
23
- bundler: Bundler;
24
- keycloakVersionDefaultAssets: string;
25
- /** Directory of your built react project. Defaults to {cwd}/build */
26
- reactAppBuildDirPath: string;
27
- /** Directory that keycloakify outputs to. Defaults to {cwd}/build_keycloak */
28
- keycloakifyBuildDirPath: string;
29
- };
30
-
31
- export type Standalone = Common & {
32
- isStandalone: true;
33
- urlPathname: string | undefined;
34
- };
35
-
36
- export type ExternalAssets = ExternalAssets.SameDomain | ExternalAssets.DifferentDomains;
37
-
38
- export namespace ExternalAssets {
39
- export type CommonExternalAssets = Common & {
40
- isStandalone: false;
41
- };
42
-
43
- export type SameDomain = CommonExternalAssets & {
44
- areAppAndKeycloakServerSharingSameDomain: true;
45
- };
46
-
47
- export type DifferentDomains = CommonExternalAssets & {
48
- areAppAndKeycloakServerSharingSameDomain: false;
49
- urlOrigin: string;
50
- urlPathname: string | undefined;
51
- };
52
- }
53
- }
11
+ export type BuildOptions = {
12
+ isSilent: boolean;
13
+ themeVersion: string;
14
+ themeName: string;
15
+ extraThemeNames: string[];
16
+ extraThemeProperties: string[] | undefined;
17
+ groupId: string;
18
+ artifactId: string;
19
+ bundler: Bundler;
20
+ keycloakVersionDefaultAssets: string;
21
+ /** Directory of your built react project. Defaults to {cwd}/build */
22
+ reactAppBuildDirPath: string;
23
+ /** Directory that keycloakify outputs to. Defaults to {cwd}/build_keycloak */
24
+ keycloakifyBuildDirPath: string;
25
+ /** If your app is hosted under a subpath, it's the case in CRA if you have "homepage": "https://example.com/my-app" in your package.json
26
+ * In this case the urlPathname will be "/my-app/" */
27
+ urlPathname: string | undefined;
28
+ };
54
29
 
55
30
  export function readBuildOptions(params: { projectDirPath: string; processArgv: string[] }): BuildOptions {
56
31
  const { projectDirPath, processArgv } = params;
57
32
 
58
- const { isExternalAssetsCliParamProvided, isSilentCliParamProvided } = (() => {
33
+ const { isSilentCliParamProvided } = (() => {
59
34
  const argv = parseArgv(processArgv);
60
35
 
61
36
  return {
62
- "isSilentCliParamProvided": typeof argv["silent"] === "boolean" ? argv["silent"] : false,
63
- "isExternalAssetsCliParamProvided": typeof argv["external-assets"] === "boolean" ? argv["external-assets"] : false
37
+ "isSilentCliParamProvided": typeof argv["silent"] === "boolean" ? argv["silent"] : false
64
38
  };
65
39
  })();
66
40
 
67
41
  const parsedPackageJson = getParsedPackageJson({ projectDirPath });
68
42
 
69
- const url = (() => {
70
- const { homepage } = parsedPackageJson;
43
+ const { name, keycloakify = {}, version, homepage } = parsedPackageJson;
71
44
 
72
- let url: URL | undefined = undefined;
45
+ const { extraThemeProperties, groupId, artifactId, bundler, keycloakVersionDefaultAssets, extraThemeNames = [] } = keycloakify ?? {};
73
46
 
74
- if (homepage !== undefined) {
75
- url = new URL(homepage);
76
- }
47
+ const themeName =
48
+ keycloakify.themeName ??
49
+ name
50
+ .replace(/^@(.*)/, "$1")
51
+ .split("/")
52
+ .join("-");
77
53
 
78
- const CNAME = (() => {
79
- const cnameFilePath = pathJoin(projectDirPath, "public", "CNAME");
54
+ return {
55
+ themeName,
56
+ extraThemeNames,
57
+ "bundler": (() => {
58
+ const { KEYCLOAKIFY_BUNDLER } = process.env;
80
59
 
81
- if (!fs.existsSync(cnameFilePath)) {
82
- return undefined;
60
+ assert(
61
+ typeGuard<Bundler | undefined>(KEYCLOAKIFY_BUNDLER, [undefined, ...id<readonly string[]>(bundlers)].includes(KEYCLOAKIFY_BUNDLER)),
62
+ `${symToStr({ KEYCLOAKIFY_BUNDLER })} should be one of ${bundlers.join(", ")}`
63
+ );
64
+
65
+ return KEYCLOAKIFY_BUNDLER ?? bundler ?? "keycloakify";
66
+ })(),
67
+ "artifactId": process.env.KEYCLOAKIFY_ARTIFACT_ID ?? artifactId ?? `${themeName}-keycloak-theme`,
68
+ "groupId": (() => {
69
+ const fallbackGroupId = `${themeName}.keycloak`;
70
+
71
+ return (
72
+ process.env.KEYCLOAKIFY_GROUP_ID ??
73
+ groupId ??
74
+ (!homepage
75
+ ? fallbackGroupId
76
+ : urlParse(homepage)
77
+ .host?.replace(/:[0-9]+$/, "")
78
+ ?.split(".")
79
+ .reverse()
80
+ .join(".") ?? fallbackGroupId) + ".keycloak"
81
+ );
82
+ })(),
83
+ "themeVersion": process.env.KEYCLOAKIFY_THEME_VERSION ?? process.env.KEYCLOAKIFY_VERSION ?? version ?? "0.0.0",
84
+ extraThemeProperties,
85
+ "isSilent": isSilentCliParamProvided,
86
+ "keycloakVersionDefaultAssets": keycloakVersionDefaultAssets ?? "11.0.3",
87
+ "reactAppBuildDirPath": (() => {
88
+ let { reactAppBuildDirPath = undefined } = parsedPackageJson.keycloakify ?? {};
89
+
90
+ if (reactAppBuildDirPath === undefined) {
91
+ return pathJoin(projectDirPath, "build");
83
92
  }
84
93
 
85
- return fs.readFileSync(cnameFilePath).toString("utf8");
86
- })();
94
+ if (pathSep === "\\") {
95
+ reactAppBuildDirPath = reactAppBuildDirPath.replace(/\//g, pathSep);
96
+ }
87
97
 
88
- if (CNAME !== undefined) {
89
- url = new URL(`https://${CNAME.replace(/\s+$/, "")}`);
90
- }
98
+ if (reactAppBuildDirPath.startsWith(`.${pathSep}`)) {
99
+ return pathJoin(projectDirPath, reactAppBuildDirPath);
100
+ }
91
101
 
92
- if (url === undefined) {
93
- return undefined;
94
- }
102
+ return reactAppBuildDirPath;
103
+ })(),
104
+ "keycloakifyBuildDirPath": (() => {
105
+ let { keycloakifyBuildDirPath = undefined } = parsedPackageJson.keycloakify ?? {};
95
106
 
96
- return {
97
- "origin": url.origin,
98
- "pathname": (() => {
99
- const out = url.pathname.replace(/([^/])$/, "$1/");
107
+ if (keycloakifyBuildDirPath === undefined) {
108
+ return pathJoin(projectDirPath, "build_keycloak");
109
+ }
100
110
 
101
- return out === "/" ? undefined : out;
102
- })()
103
- };
104
- })();
111
+ if (pathSep === "\\") {
112
+ keycloakifyBuildDirPath = keycloakifyBuildDirPath.replace(/\//g, pathSep);
113
+ }
105
114
 
106
- const common: BuildOptions.Common = (() => {
107
- const { name, keycloakify = {}, version, homepage } = parsedPackageJson;
115
+ if (keycloakifyBuildDirPath.startsWith(`.${pathSep}`)) {
116
+ return pathJoin(projectDirPath, keycloakifyBuildDirPath);
117
+ }
108
118
 
109
- const { extraThemeProperties, groupId, artifactId, bundler, keycloakVersionDefaultAssets, extraThemeNames = [] } = keycloakify ?? {};
119
+ return keycloakifyBuildDirPath;
120
+ })(),
121
+ "urlPathname": (() => {
122
+ const { homepage } = parsedPackageJson;
110
123
 
111
- const themeName =
112
- keycloakify.themeName ??
113
- name
114
- .replace(/^@(.*)/, "$1")
115
- .split("/")
116
- .join("-");
124
+ let url: URL | undefined = undefined;
117
125
 
118
- return {
119
- themeName,
120
- extraThemeNames,
121
- "bundler": (() => {
122
- const { KEYCLOAKIFY_BUNDLER } = process.env;
123
-
124
- assert(
125
- typeGuard<Bundler | undefined>(
126
- KEYCLOAKIFY_BUNDLER,
127
- [undefined, ...id<readonly string[]>(bundlers)].includes(KEYCLOAKIFY_BUNDLER)
128
- ),
129
- `${symToStr({ KEYCLOAKIFY_BUNDLER })} should be one of ${bundlers.join(", ")}`
130
- );
131
-
132
- return KEYCLOAKIFY_BUNDLER ?? bundler ?? "keycloakify";
133
- })(),
134
- "artifactId": process.env.KEYCLOAKIFY_ARTIFACT_ID ?? artifactId ?? `${themeName}-keycloak-theme`,
135
- "groupId": (() => {
136
- const fallbackGroupId = `${themeName}.keycloak`;
137
-
138
- return (
139
- process.env.KEYCLOAKIFY_GROUP_ID ??
140
- groupId ??
141
- (!homepage
142
- ? fallbackGroupId
143
- : urlParse(homepage)
144
- .host?.replace(/:[0-9]+$/, "")
145
- ?.split(".")
146
- .reverse()
147
- .join(".") ?? fallbackGroupId) + ".keycloak"
148
- );
149
- })(),
150
- "themeVersion": process.env.KEYCLOAKIFY_THEME_VERSION ?? process.env.KEYCLOAKIFY_VERSION ?? version ?? "0.0.0",
151
- extraThemeProperties,
152
- "isSilent": isSilentCliParamProvided,
153
- "keycloakVersionDefaultAssets": keycloakVersionDefaultAssets ?? "11.0.3",
154
- "reactAppBuildDirPath": (() => {
155
- let { reactAppBuildDirPath = undefined } = parsedPackageJson.keycloakify ?? {};
156
-
157
- if (reactAppBuildDirPath === undefined) {
158
- return pathJoin(projectDirPath, "build");
159
- }
160
-
161
- if (pathSep === "\\") {
162
- reactAppBuildDirPath = reactAppBuildDirPath.replace(/\//g, pathSep);
163
- }
164
-
165
- if (reactAppBuildDirPath.startsWith(`.${pathSep}`)) {
166
- return pathJoin(projectDirPath, reactAppBuildDirPath);
167
- }
168
-
169
- return reactAppBuildDirPath;
170
- })(),
171
- "keycloakifyBuildDirPath": (() => {
172
- let { keycloakifyBuildDirPath = undefined } = parsedPackageJson.keycloakify ?? {};
173
-
174
- if (keycloakifyBuildDirPath === undefined) {
175
- return pathJoin(projectDirPath, "build_keycloak");
176
- }
177
-
178
- if (pathSep === "\\") {
179
- keycloakifyBuildDirPath = keycloakifyBuildDirPath.replace(/\//g, pathSep);
180
- }
181
-
182
- if (keycloakifyBuildDirPath.startsWith(`.${pathSep}`)) {
183
- return pathJoin(projectDirPath, keycloakifyBuildDirPath);
184
- }
185
-
186
- return keycloakifyBuildDirPath;
187
- })()
188
- };
189
- })();
126
+ if (homepage !== undefined) {
127
+ url = new URL(homepage);
128
+ }
190
129
 
191
- if (isExternalAssetsCliParamProvided) {
192
- const commonExternalAssets = id<BuildOptions.ExternalAssets.CommonExternalAssets>({
193
- ...common,
194
- "isStandalone": false
195
- });
196
-
197
- if (parsedPackageJson.keycloakify?.areAppAndKeycloakServerSharingSameDomain) {
198
- return id<BuildOptions.ExternalAssets.SameDomain>({
199
- ...commonExternalAssets,
200
- "areAppAndKeycloakServerSharingSameDomain": true
201
- });
202
- } else {
203
- assert(
204
- url !== undefined,
205
- [
206
- "Can't compile in external assets mode if we don't know where",
207
- "the app will be hosted.",
208
- "You should provide a homepage field in the package.json (or create a",
209
- "public/CNAME file.",
210
- "Alternatively, if your app and the Keycloak server are on the same domain, ",
211
- "eg https://example.com is your app and https://example.com/auth is the keycloak",
212
- 'admin UI, you can set "keycloakify": { "areAppAndKeycloakServerSharingSameDomain": true }',
213
- "in your package.json"
214
- ].join(" ")
215
- );
130
+ if (url === undefined) {
131
+ return undefined;
132
+ }
216
133
 
217
- return id<BuildOptions.ExternalAssets.DifferentDomains>({
218
- ...commonExternalAssets,
219
- "areAppAndKeycloakServerSharingSameDomain": false,
220
- "urlOrigin": url.origin,
221
- "urlPathname": url.pathname
222
- });
223
- }
224
- }
225
-
226
- return id<BuildOptions.Standalone>({
227
- ...common,
228
- "isStandalone": true,
229
- "urlPathname": url?.pathname
230
- });
134
+ const out = url.pathname.replace(/([^/])$/, "$1/");
135
+ return out === "/" ? undefined : out;
136
+ })()
137
+ };
231
138
  }
@@ -483,18 +483,6 @@
483
483
  <#local out_seq += ["/*If you need '" + key + "' on " + pageId + ", please submit an issue to the Keycloakify repo*/"]>
484
484
  <#continue>
485
485
  </#if>
486
-
487
- <#if key == "attemptedUsername" && are_same_path(path, ["auth"])>
488
-
489
- <#attempt>
490
- <#-- https://github.com/keycloak/keycloak/blob/3a2bf0c04bcde185e497aaa32d0bb7ab7520cf4a/themes/src/main/resources/theme/base/login/template.ftl#L63 -->
491
- <#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())>
492
- <#continue>
493
- </#if>
494
- <#recover>
495
- </#attempt>
496
-
497
- </#if>
498
486
 
499
487
  <#attempt>
500
488
  <#if !object[key]??>
@@ -13,39 +13,11 @@ export const themeTypes = ["login", "account"] as const;
13
13
 
14
14
  export type ThemeType = (typeof themeTypes)[number];
15
15
 
16
- export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.ExternalAssets;
17
-
18
- export namespace BuildOptionsLike {
19
- export type Common = {
20
- themeName: string;
21
- themeVersion: string;
22
- };
23
-
24
- export type Standalone = Common & {
25
- isStandalone: true;
26
- urlPathname: string | undefined;
27
- };
28
-
29
- export type ExternalAssets = ExternalAssets.SameDomain | ExternalAssets.DifferentDomains;
30
-
31
- export namespace ExternalAssets {
32
- export type CommonExternalAssets = {
33
- isStandalone: false;
34
- };
35
-
36
- export type SameDomain = Common &
37
- CommonExternalAssets & {
38
- areAppAndKeycloakServerSharingSameDomain: true;
39
- };
40
-
41
- export type DifferentDomains = Common &
42
- CommonExternalAssets & {
43
- areAppAndKeycloakServerSharingSameDomain: false;
44
- urlOrigin: string;
45
- urlPathname: string | undefined;
46
- };
47
- }
48
- }
16
+ export type BuildOptionsLike = {
17
+ themeName: string;
18
+ themeVersion: string;
19
+ urlPathname: string | undefined;
20
+ };
49
21
 
50
22
  assert<BuildOptions extends BuildOptionsLike ? true : false>();
51
23
 
@@ -63,22 +35,23 @@ export function generateFtlFilesCodeFactory(params: {
63
35
  const $ = cheerio.load(indexHtmlCode);
64
36
 
65
37
  fix_imports_statements: {
66
- if (!buildOptions.isStandalone && buildOptions.areAppAndKeycloakServerSharingSameDomain) {
67
- break fix_imports_statements;
68
- }
69
-
70
38
  $("script:not([src])").each((...[, element]) => {
71
- const { fixedJsCode } = replaceImportsFromStaticInJsCode({
72
- "jsCode": $(element).html()!,
73
- buildOptions
74
- });
39
+ const jsCode = $(element).html();
40
+
41
+ assert(jsCode !== null);
42
+
43
+ const { fixedJsCode } = replaceImportsFromStaticInJsCode({ jsCode });
75
44
 
76
45
  $(element).text(fixedJsCode);
77
46
  });
78
47
 
79
48
  $("style").each((...[, element]) => {
49
+ const cssCode = $(element).html();
50
+
51
+ assert(cssCode !== null);
52
+
80
53
  const { fixedCssCode } = replaceImportsInInlineCssCode({
81
- "cssCode": $(element).html()!,
54
+ cssCode,
82
55
  buildOptions
83
56
  });
84
57
 
@@ -100,9 +73,7 @@ export function generateFtlFilesCodeFactory(params: {
100
73
 
101
74
  $(element).attr(
102
75
  attrName,
103
- buildOptions.isStandalone
104
- ? href.replace(new RegExp(`^${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`), "${url.resourcesPath}/build/")
105
- : href.replace(/^\//, `${buildOptions.urlOrigin}/`)
76
+ href.replace(new RegExp(`^${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`), "${url.resourcesPath}/build/")
106
77
  );
107
78
  })
108
79
  );
@@ -0,0 +1,84 @@
1
+ import * as fs from "fs";
2
+ import { join as pathJoin, dirname as pathDirname } from "path";
3
+ import { assert } from "tsafe/assert";
4
+ import type { BuildOptions } from "./BuildOptions";
5
+ import type { ThemeType } from "./generateFtl";
6
+
7
+ export type BuildOptionsLike = {
8
+ themeName: string;
9
+ extraThemeNames: string[];
10
+ groupId: string;
11
+ artifactId: string;
12
+ themeVersion: string;
13
+ };
14
+
15
+ assert<BuildOptions extends BuildOptionsLike ? true : false>();
16
+
17
+ export function generateJavaStackFiles(params: {
18
+ keycloakThemeBuildingDirPath: string;
19
+ implementedThemeTypes: Record<ThemeType | "email", boolean>;
20
+ buildOptions: BuildOptionsLike;
21
+ }): {
22
+ jarFilePath: string;
23
+ } {
24
+ const {
25
+ buildOptions: { groupId, themeName, extraThemeNames, themeVersion, artifactId },
26
+ keycloakThemeBuildingDirPath,
27
+ implementedThemeTypes
28
+ } = params;
29
+
30
+ {
31
+ const { pomFileCode } = (function generatePomFileCode(): {
32
+ pomFileCode: string;
33
+ } {
34
+ const pomFileCode = [
35
+ `<?xml version="1.0"?>`,
36
+ `<project xmlns="http://maven.apache.org/POM/4.0.0"`,
37
+ ` xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"`,
38
+ ` xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">`,
39
+ ` <modelVersion>4.0.0</modelVersion>`,
40
+ ` <groupId>${groupId}</groupId>`,
41
+ ` <artifactId>${artifactId}</artifactId>`,
42
+ ` <version>${themeVersion}</version>`,
43
+ ` <name>${artifactId}</name>`,
44
+ ` <description />`,
45
+ `</project>`
46
+ ].join("\n");
47
+
48
+ return { pomFileCode };
49
+ })();
50
+
51
+ fs.writeFileSync(pathJoin(keycloakThemeBuildingDirPath, "pom.xml"), Buffer.from(pomFileCode, "utf8"));
52
+ }
53
+
54
+ {
55
+ const themeManifestFilePath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "META-INF", "keycloak-themes.json");
56
+
57
+ try {
58
+ fs.mkdirSync(pathDirname(themeManifestFilePath));
59
+ } catch {}
60
+
61
+ fs.writeFileSync(
62
+ themeManifestFilePath,
63
+ Buffer.from(
64
+ JSON.stringify(
65
+ {
66
+ "themes": [themeName, ...extraThemeNames].map(themeName => ({
67
+ "name": themeName,
68
+ "types": Object.entries(implementedThemeTypes)
69
+ .filter(([, isImplemented]) => isImplemented)
70
+ .map(([themeType]) => themeType)
71
+ }))
72
+ },
73
+ null,
74
+ 2
75
+ ),
76
+ "utf8"
77
+ )
78
+ );
79
+ }
80
+
81
+ return {
82
+ "jarFilePath": pathJoin(keycloakThemeBuildingDirPath, "target", `${artifactId}-${themeVersion}.jar`)
83
+ };
84
+ }
@@ -1,7 +1,6 @@
1
1
  import * as fs from "fs";
2
2
  import { join as pathJoin } from "path";
3
3
  import { assert } from "tsafe/assert";
4
- import { Reflect } from "tsafe/Reflect";
5
4
  import type { BuildOptions } from "./BuildOptions";
6
5
 
7
6
  export type BuildOptionsLike = {
@@ -9,11 +8,7 @@ export type BuildOptionsLike = {
9
8
  extraThemeNames: string[];
10
9
  };
11
10
 
12
- {
13
- const buildOptions = Reflect<BuildOptions>();
14
-
15
- assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
16
- }
11
+ assert<BuildOptions extends BuildOptionsLike ? true : false>();
17
12
 
18
13
  generateStartKeycloakTestingContainer.basename = "start_keycloak_testing_container.sh";
19
14
 
@@ -13,13 +13,17 @@ import * as crypto from "crypto";
13
13
  export async function downloadKeycloakStaticResources(
14
14
  // prettier-ignore
15
15
  params: {
16
+ projectDirPath: string;
16
17
  themeType: ThemeType;
17
18
  themeDirPath: string;
18
- isSilent: boolean;
19
19
  keycloakVersion: string;
20
+ usedResources: {
21
+ resourcesCommonFilePaths: string[];
22
+ resourcesFilePaths: string[];
23
+ } | undefined
20
24
  }
21
25
  ) {
22
- const { themeType, isSilent, themeDirPath, keycloakVersion } = params;
26
+ const { projectDirPath, themeType, themeDirPath, keycloakVersion, usedResources } = params;
23
27
 
24
28
  const tmpDirPath = pathJoin(
25
29
  themeDirPath,
@@ -28,19 +32,39 @@ export async function downloadKeycloakStaticResources(
28
32
  );
29
33
 
30
34
  await downloadBuiltinKeycloakTheme({
35
+ projectDirPath,
31
36
  keycloakVersion,
32
- "destDirPath": tmpDirPath,
33
- isSilent
37
+ "destDirPath": tmpDirPath
34
38
  });
35
39
 
36
40
  transformCodebase({
37
41
  "srcDirPath": pathJoin(tmpDirPath, "keycloak", themeType, "resources"),
38
- "destDirPath": pathJoin(themeDirPath, pathRelative(basenameOfKeycloakDirInPublicDir, resourcesDirPathRelativeToPublicDir))
42
+ "destDirPath": pathJoin(themeDirPath, pathRelative(basenameOfKeycloakDirInPublicDir, resourcesDirPathRelativeToPublicDir)),
43
+ "transformSourceCode":
44
+ usedResources === undefined
45
+ ? undefined
46
+ : ({ fileRelativePath, sourceCode }) => {
47
+ if (!usedResources.resourcesFilePaths.includes(fileRelativePath)) {
48
+ return undefined;
49
+ }
50
+
51
+ return { "modifiedSourceCode": sourceCode };
52
+ }
39
53
  });
40
54
 
41
55
  transformCodebase({
42
56
  "srcDirPath": pathJoin(tmpDirPath, "keycloak", "common", "resources"),
43
- "destDirPath": pathJoin(themeDirPath, pathRelative(basenameOfKeycloakDirInPublicDir, resourcesCommonDirPathRelativeToPublicDir))
57
+ "destDirPath": pathJoin(themeDirPath, pathRelative(basenameOfKeycloakDirInPublicDir, resourcesCommonDirPathRelativeToPublicDir)),
58
+ "transformSourceCode":
59
+ usedResources === undefined
60
+ ? undefined
61
+ : ({ fileRelativePath, sourceCode }) => {
62
+ if (!usedResources.resourcesCommonFilePaths.includes(fileRelativePath)) {
63
+ return undefined;
64
+ }
65
+
66
+ return { "modifiedSourceCode": sourceCode };
67
+ }
44
68
  });
45
69
 
46
70
  fs.rmSync(tmpDirPath, { "recursive": true, "force": true });