keycloakify 7.16.0-rc.1 → 8.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +3 -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/generateFtl.d.ts +5 -25
  17. package/bin/keycloakify/generateFtl/generateFtl.js +7 -11
  18. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  19. package/bin/keycloakify/{generateJavaStackFiles/generateJavaStackFiles.d.ts → generateJavaStackFiles.d.ts} +3 -4
  20. package/bin/keycloakify/generateJavaStackFiles.js +103 -0
  21. package/bin/keycloakify/generateJavaStackFiles.js.map +1 -0
  22. package/bin/keycloakify/generateStartKeycloakTestingContainer.js +1 -5
  23. package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
  24. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +5 -1
  25. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js +24 -6
  26. package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
  27. package/bin/keycloakify/generateTheme/generateTheme.d.ts +8 -28
  28. package/bin/keycloakify/generateTheme/generateTheme.js +22 -33
  29. package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
  30. package/bin/keycloakify/generateTheme/readFieldNameUsage.js +1 -2
  31. package/bin/keycloakify/generateTheme/readFieldNameUsage.js.map +1 -1
  32. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.d.ts +17 -0
  33. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.js +172 -0
  34. package/bin/keycloakify/generateTheme/readStaticResourcesUsage.js.map +1 -0
  35. package/bin/keycloakify/keycloakify.js +17 -17
  36. package/bin/keycloakify/keycloakify.js.map +1 -1
  37. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.d.ts +0 -11
  38. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.js +6 -27
  39. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.js.map +1 -1
  40. package/bin/keycloakify/replacers/replaceImportsInCssCode.js +1 -7
  41. package/bin/keycloakify/replacers/replaceImportsInCssCode.js.map +1 -1
  42. package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.d.ts +3 -13
  43. package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.js +5 -12
  44. package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.js.map +1 -1
  45. package/bin/tools/downloadAndUnzip.d.ts +13 -2
  46. package/bin/tools/downloadAndUnzip.js +81 -15
  47. package/bin/tools/downloadAndUnzip.js.map +1 -1
  48. package/bin/tools/transformCodebase.d.ts +1 -0
  49. package/bin/tools/transformCodebase.js +6 -5
  50. package/bin/tools/transformCodebase.js.map +1 -1
  51. package/bin/tools/unzip.d.ts +2 -1
  52. package/bin/tools/unzip.js +129 -11
  53. package/bin/tools/unzip.js.map +1 -1
  54. package/lib/usePrepareTemplate.d.ts +0 -5
  55. package/lib/usePrepareTemplate.js +4 -10
  56. package/lib/usePrepareTemplate.js.map +1 -1
  57. package/login/Template.js +5 -6
  58. package/login/Template.js.map +1 -1
  59. package/login/kcContext/KcContext.d.ts +1 -1
  60. package/login/kcContext/kcContextMocks.js +1 -5
  61. package/login/kcContext/kcContextMocks.js.map +1 -1
  62. package/login/pages/Login.js +16 -20
  63. package/login/pages/Login.js.map +1 -1
  64. package/login/pages/LoginOtp.js +1 -2
  65. package/login/pages/LoginOtp.js.map +1 -1
  66. package/package.json +11 -77
  67. package/src/account/Template.tsx +5 -3
  68. package/src/account/kcContext/kcContextMocks.ts +0 -4
  69. package/src/bin/copy-keycloak-resources-to-public.ts +3 -2
  70. package/src/bin/download-builtin-keycloak-theme.ts +71 -14
  71. package/src/bin/initialize-email-theme.ts +6 -4
  72. package/src/bin/keycloakify/BuildOptions.ts +99 -192
  73. package/src/bin/keycloakify/generateFtl/generateFtl.ts +16 -45
  74. package/src/bin/keycloakify/generateJavaStackFiles.ts +84 -0
  75. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +1 -6
  76. package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +30 -6
  77. package/src/bin/keycloakify/generateTheme/generateTheme.ts +34 -69
  78. package/src/bin/keycloakify/generateTheme/readFieldNameUsage.ts +1 -4
  79. package/src/bin/keycloakify/generateTheme/readStaticResourcesUsage.ts +83 -0
  80. package/src/bin/keycloakify/keycloakify.ts +2 -1
  81. package/src/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.ts +9 -51
  82. package/src/bin/keycloakify/replacers/replaceImportsInCssCode.ts +1 -9
  83. package/src/bin/keycloakify/replacers/replaceImportsInInlineCssCode.ts +5 -29
  84. package/src/bin/tools/downloadAndUnzip.ts +99 -15
  85. package/src/bin/tools/transformCodebase.ts +7 -6
  86. package/src/bin/tools/unzip.ts +57 -8
  87. package/src/lib/usePrepareTemplate.ts +13 -24
  88. package/src/login/Template.tsx +5 -6
  89. package/src/login/kcContext/KcContext.ts +1 -1
  90. package/src/login/kcContext/kcContextMocks.ts +1 -5
  91. package/src/login/pages/Login.tsx +31 -34
  92. package/src/login/pages/LoginOtp.tsx +1 -2
  93. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +0 -33
  94. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +0 -76
  95. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +0 -25
  96. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +0 -50
  97. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +0 -424
  98. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +0 -51
  99. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +0 -51
  100. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +0 -91
  101. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +0 -157
  102. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +0 -258
  103. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +0 -515
  104. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +0 -56
  105. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +0 -95
  106. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +0 -34
  107. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +0 -75
  108. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +0 -38
  109. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +0 -93
  110. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +0 -125
  111. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +0 -121
  112. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +0 -115
  113. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +0 -1320
  114. package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +0 -64
  115. package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js +0 -298
  116. package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js.map +0 -1
  117. package/bin/keycloakify/generateJavaStackFiles/index.d.ts +0 -1
  118. package/bin/keycloakify/generateJavaStackFiles/index.js +0 -18
  119. package/bin/keycloakify/generateJavaStackFiles/index.js.map +0 -1
  120. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +0 -33
  121. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +0 -76
  122. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +0 -25
  123. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +0 -50
  124. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +0 -424
  125. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +0 -51
  126. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +0 -51
  127. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +0 -91
  128. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +0 -157
  129. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +0 -258
  130. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +0 -515
  131. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +0 -56
  132. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +0 -95
  133. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +0 -34
  134. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +0 -75
  135. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +0 -38
  136. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +0 -93
  137. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +0 -125
  138. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +0 -121
  139. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +0 -115
  140. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +0 -1320
  141. package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +0 -64
  142. package/src/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.ts +0 -249
  143. 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
  }
@@ -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 });