keycloakify 9.4.0-rc.0 → 9.4.0-rc.10

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 (66) hide show
  1. package/PUBLIC_URL.d.ts +5 -0
  2. package/PUBLIC_URL.js +15 -0
  3. package/PUBLIC_URL.js.map +1 -0
  4. package/account/kcContext/createGetKcContext.js +7 -4
  5. package/account/kcContext/createGetKcContext.js.map +1 -1
  6. package/account/kcContext/kcContextMocks.js +3 -5
  7. package/account/kcContext/kcContextMocks.js.map +1 -1
  8. package/bin/copy-keycloak-resources-to-public.js +1 -4
  9. package/bin/copy-keycloak-resources-to-public.js.map +1 -1
  10. package/bin/download-builtin-keycloak-theme.js +109 -55
  11. package/bin/download-builtin-keycloak-theme.js.map +1 -1
  12. package/bin/initialize-email-theme.js +2 -4
  13. package/bin/initialize-email-theme.js.map +1 -1
  14. package/bin/keycloakify/buildOptions/buildOptions.d.ts +0 -1
  15. package/bin/keycloakify/buildOptions/buildOptions.js +14 -5
  16. package/bin/keycloakify/buildOptions/buildOptions.js.map +1 -1
  17. package/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +8 -0
  18. package/bin/keycloakify/generateFtl/generateFtl.js +2 -1
  19. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  20. package/bin/keycloakify/generateStartKeycloakTestingContainer.js +0 -1
  21. package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
  22. package/bin/keycloakify/keycloakify.js +6 -6
  23. package/bin/keycloakify/keycloakify.js.map +1 -1
  24. package/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.js +0 -5
  25. package/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.js.map +1 -1
  26. package/bin/tools/downloadAndUnzip.js +108 -24
  27. package/bin/tools/downloadAndUnzip.js.map +1 -1
  28. package/bin/tools/transformCodebase.js +5 -5
  29. package/bin/tools/transformCodebase.js.map +1 -1
  30. package/lib/BASE_URL.d.ts +10 -0
  31. package/lib/BASE_URL.js +38 -0
  32. package/lib/BASE_URL.js.map +1 -0
  33. package/lib/isStorybook.d.ts +1 -0
  34. package/lib/isStorybook.js +3 -0
  35. package/lib/isStorybook.js.map +1 -0
  36. package/lib/keycloakJsAdapter.d.ts +4 -0
  37. package/lib/keycloakJsAdapter.js +4 -0
  38. package/lib/keycloakJsAdapter.js.map +1 -1
  39. package/login/kcContext/createGetKcContext.js +7 -4
  40. package/login/kcContext/createGetKcContext.js.map +1 -1
  41. package/login/kcContext/kcContextMocks.js +3 -5
  42. package/login/kcContext/kcContextMocks.js.map +1 -1
  43. package/package.json +16 -6
  44. package/src/PUBLIC_URL.ts +21 -0
  45. package/src/account/kcContext/createGetKcContext.ts +8 -5
  46. package/src/account/kcContext/kcContextMocks.ts +3 -5
  47. package/src/bin/copy-keycloak-resources-to-public.ts +1 -6
  48. package/src/bin/download-builtin-keycloak-theme.ts +110 -57
  49. package/src/bin/initialize-email-theme.ts +1 -4
  50. package/src/bin/keycloakify/buildOptions/buildOptions.ts +18 -7
  51. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +8 -0
  52. package/src/bin/keycloakify/generateFtl/generateFtl.ts +3 -2
  53. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +0 -1
  54. package/src/bin/keycloakify/keycloakify.ts +8 -6
  55. package/src/bin/keycloakify/replacers/replaceImportsInJsCode/webpack.ts +0 -14
  56. package/src/bin/tools/downloadAndUnzip.ts +77 -15
  57. package/src/bin/tools/transformCodebase.ts +6 -5
  58. package/src/lib/BASE_URL.ts +44 -0
  59. package/src/lib/isStorybook.ts +3 -0
  60. package/src/lib/keycloakJsAdapter.ts +4 -0
  61. package/src/login/kcContext/createGetKcContext.ts +8 -5
  62. package/src/login/kcContext/kcContextMocks.ts +3 -5
  63. package/bin/tools/pathJoin.d.ts +0 -1
  64. package/bin/tools/pathJoin.js +0 -15
  65. package/bin/tools/pathJoin.js.map +0 -1
  66. package/src/bin/tools/pathJoin.ts +0 -6
@@ -2,12 +2,13 @@ import { exec as execCallback } from "child_process";
2
2
  import { createHash } from "crypto";
3
3
  import { mkdir, readFile, stat, writeFile, unlink } from "fs/promises";
4
4
  import fetch, { type FetchOptions } from "make-fetch-happen";
5
- import { dirname as pathDirname, join as pathJoin, resolve as pathResolve, sep as pathSep } from "path";
5
+ import { dirname as pathDirname, join as pathJoin, resolve as pathResolve, sep as pathSep, basename as pathBasename } from "path";
6
6
  import { assert } from "tsafe/assert";
7
7
  import { promisify } from "util";
8
8
  import { transformCodebase } from "./transformCodebase";
9
9
  import { unzip, zip } from "./unzip";
10
10
  import { rm } from "../tools/fs.rm";
11
+ import * as child_process from "child_process";
11
12
 
12
13
  const exec = promisify(execCallback);
13
14
 
@@ -188,10 +189,31 @@ export async function downloadAndUnzip(
188
189
  const zipFilePath = pathJoin(cacheDirPath, `${zipFileBasename}.zip`);
189
190
  const extractDirPath = pathJoin(cacheDirPath, `tmp_unzip_${zipFileBasename}`);
190
191
 
191
- if (!(await exists(zipFilePath))) {
192
+ download_zip_and_transform: {
193
+ if (await exists(zipFilePath)) {
194
+ break download_zip_and_transform;
195
+ }
196
+
192
197
  const opts = await getFetchOptions();
193
- const response = await fetch(url, opts);
198
+
199
+ const { response, isFromRemoteCache } = await (async () => {
200
+ const response = await fetch(`https://github.com/keycloakify/keycloakify/releases/download/v0.0.1/${pathBasename(zipFilePath)}`, opts);
201
+
202
+ if (response.status === 200) {
203
+ return {
204
+ response,
205
+ "isFromRemoteCache": true
206
+ };
207
+ }
208
+
209
+ return {
210
+ "response": await fetch(url, opts),
211
+ "isFromRemoteCache": false
212
+ };
213
+ })();
214
+
194
215
  await mkdir(pathDirname(zipFilePath), { "recursive": true });
216
+
195
217
  /**
196
218
  * The correct way to fix this is to upgrade node-fetch beyond 3.2.5
197
219
  * (see https://github.com/node-fetch/node-fetch/issues/1295#issuecomment-1144061991.)
@@ -201,26 +223,66 @@ export async function downloadAndUnzip(
201
223
  */
202
224
  response.body?.setMaxListeners(Number.MAX_VALUE);
203
225
  assert(typeof response.body !== "undefined" && response.body != null);
226
+
204
227
  await writeFile(zipFilePath, response.body);
205
228
 
206
- if (specificDirsToExtract !== undefined || preCacheTransform !== undefined) {
207
- await unzip(zipFilePath, extractDirPath, specificDirsToExtract);
229
+ if (isFromRemoteCache) {
230
+ break download_zip_and_transform;
231
+ }
208
232
 
209
- try {
210
- await preCacheTransform?.action({
211
- "destDirPath": extractDirPath
212
- });
213
- } catch (error) {
214
- await Promise.all([rm(extractDirPath, { "recursive": true }), unlink(zipFilePath)]);
233
+ if (specificDirsToExtract === undefined && preCacheTransform === undefined) {
234
+ break download_zip_and_transform;
235
+ }
236
+
237
+ await unzip(zipFilePath, extractDirPath, specificDirsToExtract);
238
+
239
+ try {
240
+ await preCacheTransform?.action({
241
+ "destDirPath": extractDirPath
242
+ });
243
+ } catch (error) {
244
+ await Promise.all([rm(extractDirPath, { "recursive": true }), unlink(zipFilePath)]);
245
+
246
+ throw error;
247
+ }
248
+
249
+ await unlink(zipFilePath);
250
+
251
+ await zip(extractDirPath, zipFilePath);
215
252
 
216
- throw error;
253
+ await rm(extractDirPath, { "recursive": true });
254
+
255
+ upload_to_remot_cache_if_admin: {
256
+ const githubToken = process.env["KEYCLOAKIFY_ADMIN_GITHUB_PERSONAL_ACCESS_TOKEN"];
257
+
258
+ if (githubToken === undefined) {
259
+ break upload_to_remot_cache_if_admin;
217
260
  }
218
261
 
219
- await unlink(zipFilePath);
262
+ console.log("uploading to remote cache");
220
263
 
221
- await zip(extractDirPath, zipFilePath);
264
+ try {
265
+ child_process.execSync(`which putasset`);
266
+ } catch {
267
+ child_process.execSync(`npm install -g putasset`);
268
+ }
222
269
 
223
- await rm(extractDirPath, { "recursive": true });
270
+ try {
271
+ child_process.execFileSync("putasset", [
272
+ "--owner",
273
+ "keycloakify",
274
+ "--repo",
275
+ "keycloakify",
276
+ "--tag",
277
+ "v0.0.1",
278
+ "--filename",
279
+ zipFilePath,
280
+ "--token",
281
+ githubToken
282
+ ]);
283
+ } catch {
284
+ console.log("upload failed, asset probably already exists in remote cache");
285
+ }
224
286
  }
225
287
  }
226
288
 
@@ -17,13 +17,14 @@ type TransformSourceCode = (params: { sourceCode: Buffer; filePath: string; file
17
17
  * */
18
18
  export function transformCodebase(params: { srcDirPath: string; destDirPath: string; transformSourceCode?: TransformSourceCode }) {
19
19
  const { srcDirPath, transformSourceCode } = params;
20
- let { destDirPath } = params;
21
20
 
22
- const isTargetSameAsSource = path.relative(srcDirPath, destDirPath) === "";
21
+ const isTargetSameAsSource = path.relative(srcDirPath, params.destDirPath) === "";
23
22
 
24
- if (isTargetSameAsSource) {
25
- destDirPath = path.join(srcDirPath, "..", "tmp_xOsPdkPsTdzPs34sOkHs");
26
- }
23
+ const destDirPath = isTargetSameAsSource ? path.join(srcDirPath, "..", "tmp_xOsPdkPsTdzPs34sOkHs") : params.destDirPath;
24
+
25
+ fs.mkdirSync(destDirPath, {
26
+ "recursive": true
27
+ });
27
28
 
28
29
  for (const fileRelativePath of crawl({ "dirPath": srcDirPath, "returnedPathsType": "relative to dirPath" })) {
29
30
  const filePath = path.join(srcDirPath, fileRelativePath);
@@ -0,0 +1,44 @@
1
+ import { assert } from "tsafe/assert";
2
+
3
+ /**
4
+ * WARNING: Internal use only!!
5
+ * THIS DOES NOT WORK IN KEYCLOAK! It's only for resolving mock assets.
6
+ * This is just a way to know what's the base url that works
7
+ * both in webpack and vite.
8
+ * You can see this as a polyfill that return `import.meta.env.BASE_URL` when in Vite
9
+ * and when in Webpack returns the base url in the same format as vite does meaning
10
+ * "/" if hosted at root or "/foo/" when hosted under a subpath (always start and ends with a "/").
11
+ */
12
+ export const BASE_URL = (() => {
13
+ vite: {
14
+ let BASE_URL: string;
15
+
16
+ try {
17
+ // @ts-expect-error
18
+ BASE_URL = import.meta.env.BASE_URL;
19
+
20
+ assert(typeof BASE_URL === "string");
21
+ } catch {
22
+ break vite;
23
+ }
24
+
25
+ return BASE_URL;
26
+ }
27
+
28
+ webpack: {
29
+ let BASE_URL: string;
30
+
31
+ try {
32
+ // @ts-expect-error
33
+ BASE_URL = process.env.PUBLIC_URL;
34
+
35
+ assert(typeof BASE_URL === "string");
36
+ } catch {
37
+ break webpack;
38
+ }
39
+
40
+ return BASE_URL === "" ? "/" : `${BASE_URL}/`;
41
+ }
42
+
43
+ throw new Error("Bundler not supported");
44
+ })();
@@ -0,0 +1,3 @@
1
+ import { BASE_URL } from "./BASE_URL";
2
+
3
+ export const isStorybook = BASE_URL.startsWith(".");
@@ -36,6 +36,10 @@ export declare namespace keycloak_js {
36
36
  }
37
37
 
38
38
  /**
39
+ * @deprecated: This will be removed in the next major version.
40
+ * If you use this, please copy paste the code into your project.
41
+ * Better yet migrate away from keycloak-js and use https://docs.oidc-spa.dev instead.
42
+ *
39
43
  * NOTE: This is just a slightly modified version of the default adapter in keycloak-js
40
44
  * The goal here is just to be able to inject search param in url before keycloak redirect.
41
45
  * Our use case for it is to pass over the login screen the states of useGlobalState
@@ -2,14 +2,13 @@ import type { KcContext, Attribute } from "./KcContext";
2
2
  import { kcContextMocks, kcContextCommonMock } from "./kcContextMocks";
3
3
  import type { DeepPartial } from "keycloakify/tools/DeepPartial";
4
4
  import { deepAssign } from "keycloakify/tools/deepAssign";
5
+ import { isStorybook } from "keycloakify/lib/isStorybook";
5
6
  import { id } from "tsafe/id";
6
7
  import { exclude } from "tsafe/exclude";
7
8
  import { assert } from "tsafe/assert";
8
9
  import type { ExtendKcContext } from "./getKcContextFromWindow";
9
10
  import { getKcContextFromWindow } from "./getKcContextFromWindow";
10
- import { pathJoin } from "keycloakify/bin/tools/pathJoin";
11
11
  import { symToStr } from "tsafe/symToStr";
12
- import { resources_common } from "keycloakify/bin/constants";
13
12
 
14
13
  export function createGetKcContext<KcContextExtension extends { pageId: string } = never>(params?: {
15
14
  mockData?: readonly DeepPartial<ExtendKcContext<KcContextExtension>>[];
@@ -31,7 +30,13 @@ export function createGetKcContext<KcContextExtension extends { pageId: string }
31
30
  if (mockPageId !== undefined && realKcContext === undefined) {
32
31
  //TODO maybe trow if no mock fo custom page
33
32
 
34
- console.log(`%cKeycloakify: ${symToStr({ mockPageId })} set to ${mockPageId}.`, "background: red; color: yellow; font-size: medium");
33
+ warn_that_mock_is_enbaled: {
34
+ if (isStorybook) {
35
+ break warn_that_mock_is_enbaled;
36
+ }
37
+
38
+ console.log(`%cKeycloakify: ${symToStr({ mockPageId })} set to ${mockPageId}.`, "background: red; color: yellow; font-size: medium");
39
+ }
35
40
 
36
41
  const kcContextDefaultMock = kcContextMocks.find(({ pageId }) => pageId === mockPageId);
37
42
 
@@ -147,8 +152,6 @@ export function createGetKcContext<KcContextExtension extends { pageId: string }
147
152
  return { "kcContext": undefined as any };
148
153
  }
149
154
 
150
- realKcContext.url.resourcesCommonPath = pathJoin(realKcContext.url.resourcesPath, resources_common);
151
-
152
155
  return { "kcContext": realKcContext as any };
153
156
  }
154
157
 
@@ -1,10 +1,10 @@
1
1
  import "minimal-polyfills/Object.fromEntries";
2
2
  import type { KcContext, Attribute } from "./KcContext";
3
3
  import { resources_common, keycloak_resources } from "keycloakify/bin/constants";
4
- import { pathJoin } from "keycloakify/bin/tools/pathJoin";
5
4
  import { id } from "tsafe/id";
6
5
  import { assert, type Equals } from "tsafe/assert";
7
6
  import type { LoginThemePageId } from "keycloakify/bin/keycloakify/generateFtl";
7
+ import { BASE_URL } from "keycloakify/lib/BASE_URL";
8
8
 
9
9
  const attributes: Attribute[] = [
10
10
  {
@@ -100,9 +100,7 @@ const attributes: Attribute[] = [
100
100
 
101
101
  const attributesByName = Object.fromEntries(attributes.map(attribute => [attribute.name, attribute])) as any;
102
102
 
103
- const PUBLIC_URL = (typeof process !== "object" ? undefined : process.env?.["PUBLIC_URL"]) || "/";
104
-
105
- const resourcesPath = pathJoin(PUBLIC_URL, keycloak_resources, "login", "resources");
103
+ const resourcesPath = `${BASE_URL}${keycloak_resources}/login/resources`;
106
104
 
107
105
  export const kcContextCommonMock: KcContext.Common = {
108
106
  "themeVersion": "0.0.0",
@@ -112,7 +110,7 @@ export const kcContextCommonMock: KcContext.Common = {
112
110
  "url": {
113
111
  "loginAction": "#",
114
112
  resourcesPath,
115
- "resourcesCommonPath": pathJoin(resourcesPath, resources_common),
113
+ "resourcesCommonPath": `${resourcesPath}/${resources_common}`,
116
114
  "loginRestartFlowUrl": "/auth/realms/myrealm/login-actions/restart?client_id=account&tab_id=HoAx28ja4xg",
117
115
  "loginUrl": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg"
118
116
  },
@@ -1 +0,0 @@
1
- export declare function pathJoin(...path: string[]): string;
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pathJoin = void 0;
4
- function pathJoin() {
5
- var path = [];
6
- for (var _i = 0; _i < arguments.length; _i++) {
7
- path[_i] = arguments[_i];
8
- }
9
- return path
10
- .map(function (part, i) { return (i === 0 ? part : part.replace(/^\/+/, "")); })
11
- .map(function (part, i) { return (i === path.length - 1 ? part : part.replace(/\/+$/, "")); })
12
- .join(typeof process !== "undefined" && process.platform === "win32" ? "\\" : "/");
13
- }
14
- exports.pathJoin = pathJoin;
15
- //# sourceMappingURL=pathJoin.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pathJoin.js","sourceRoot":"","sources":["../../src/bin/tools/pathJoin.ts"],"names":[],"mappings":";;;AAAA,SAAgB,QAAQ;IAAC,cAAiB;SAAjB,UAAiB,EAAjB,qBAAiB,EAAjB,IAAiB;QAAjB,yBAAiB;;IACtC,OAAO,IAAI;SACN,GAAG,CAAC,UAAC,IAAI,EAAE,CAAC,IAAK,OAAA,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAA3C,CAA2C,CAAC;SAC7D,GAAG,CAAC,UAAC,IAAI,EAAE,CAAC,IAAK,OAAA,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAzD,CAAyD,CAAC;SAC3E,IAAI,CAAC,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC3F,CAAC;AALD,4BAKC"}
@@ -1,6 +0,0 @@
1
- export function pathJoin(...path: string[]): string {
2
- return path
3
- .map((part, i) => (i === 0 ? part : part.replace(/^\/+/, "")))
4
- .map((part, i) => (i === path.length - 1 ? part : part.replace(/\/+$/, "")))
5
- .join(typeof process !== "undefined" && process.platform === "win32" ? "\\" : "/");
6
- }