keycloakify 11.5.4 → 11.6.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.
- package/bin/153.index.js +81 -28
- package/bin/356.index.js +48 -25
- package/bin/{573.index.js → 880.index.js} +155 -9
- package/bin/main.js +5 -4
- package/bin/tools/createObjectThatThrowsIfAccessed.d.ts +21 -0
- package/package.json +5 -2
- package/src/bin/keycloakify/generateResources/generateResources.ts +162 -6
- package/src/bin/main.ts +4 -3
- package/src/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts +63 -24
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-22.json +2201 -0
- package/src/bin/start-keycloak/start-keycloak.ts +131 -36
- package/src/bin/tools/createObjectThatThrowsIfAccessed.ts +90 -0
@@ -40,6 +40,7 @@ import { escapeStringForPropertiesFile } from "../../tools/escapeStringForProper
|
|
40
40
|
import * as child_process from "child_process";
|
41
41
|
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
42
42
|
import propertiesParser from "properties-parser";
|
43
|
+
import { createObjectThatThrowsIfAccessed } from "../../tools/createObjectThatThrowsIfAccessed";
|
43
44
|
|
44
45
|
export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
|
45
46
|
BuildContextLike_generateMessageProperties & {
|
@@ -256,15 +257,17 @@ export async function generateResources(params: {
|
|
256
257
|
writeMessagePropertiesFiles;
|
257
258
|
}
|
258
259
|
|
259
|
-
|
260
|
+
bring_in_account_spa_messages: {
|
260
261
|
if (!isSpa) {
|
261
|
-
break
|
262
|
+
break bring_in_account_spa_messages;
|
262
263
|
}
|
263
264
|
|
264
|
-
|
265
|
+
if (themeType !== "account") {
|
266
|
+
break bring_in_account_spa_messages;
|
267
|
+
}
|
265
268
|
|
266
269
|
const accountUiDirPath = child_process
|
267
|
-
.execSync(`npm list @keycloakify/keycloak
|
270
|
+
.execSync(`npm list @keycloakify/keycloak-account-ui --parseable`, {
|
268
271
|
cwd: pathDirname(buildContext.packageJsonFilePath)
|
269
272
|
})
|
270
273
|
.toString("utf8")
|
@@ -279,7 +282,7 @@ export async function generateResources(params: {
|
|
279
282
|
}
|
280
283
|
|
281
284
|
const messagesDirPath_dest = pathJoin(
|
282
|
-
getThemeTypeDirPath({ themeName, themeType }),
|
285
|
+
getThemeTypeDirPath({ themeName, themeType: "account" }),
|
283
286
|
"messages"
|
284
287
|
);
|
285
288
|
|
@@ -291,7 +294,7 @@ export async function generateResources(params: {
|
|
291
294
|
apply_theme_changes: {
|
292
295
|
const messagesDirPath_theme = pathJoin(
|
293
296
|
buildContext.themeSrcDirPath,
|
294
|
-
|
297
|
+
"account",
|
295
298
|
"messages"
|
296
299
|
);
|
297
300
|
|
@@ -339,6 +342,159 @@ export async function generateResources(params: {
|
|
339
342
|
);
|
340
343
|
}
|
341
344
|
|
345
|
+
bring_in_admin_messages: {
|
346
|
+
if (themeType !== "admin") {
|
347
|
+
break bring_in_admin_messages;
|
348
|
+
}
|
349
|
+
|
350
|
+
const messagesDirPath_theme = pathJoin(
|
351
|
+
buildContext.themeSrcDirPath,
|
352
|
+
"admin",
|
353
|
+
"i18n"
|
354
|
+
);
|
355
|
+
|
356
|
+
assert(
|
357
|
+
fs.existsSync(messagesDirPath_theme),
|
358
|
+
`${messagesDirPath_theme} is supposed to exist`
|
359
|
+
);
|
360
|
+
|
361
|
+
const propertiesByLang: Record<
|
362
|
+
string,
|
363
|
+
{
|
364
|
+
base: Buffer;
|
365
|
+
override: Buffer | undefined;
|
366
|
+
overrideByThemeName: Record<string, Buffer>;
|
367
|
+
}
|
368
|
+
> = {};
|
369
|
+
|
370
|
+
fs.readdirSync(messagesDirPath_theme).forEach(basename => {
|
371
|
+
type ParsedBasename = { lang: string } & (
|
372
|
+
| {
|
373
|
+
isOverride: false;
|
374
|
+
}
|
375
|
+
| {
|
376
|
+
isOverride: true;
|
377
|
+
themeName: string | undefined;
|
378
|
+
}
|
379
|
+
);
|
380
|
+
|
381
|
+
const parsedBasename = ((): ParsedBasename | undefined => {
|
382
|
+
const match = basename.match(/^messages_([^.]+)\.properties$/);
|
383
|
+
|
384
|
+
if (match === null) {
|
385
|
+
return undefined;
|
386
|
+
}
|
387
|
+
|
388
|
+
const discriminator = match[1];
|
389
|
+
|
390
|
+
const split = discriminator.split("_override");
|
391
|
+
|
392
|
+
if (split.length === 1) {
|
393
|
+
return {
|
394
|
+
lang: discriminator,
|
395
|
+
isOverride: false
|
396
|
+
};
|
397
|
+
}
|
398
|
+
|
399
|
+
assert(split.length === 2);
|
400
|
+
|
401
|
+
if (split[1] === "") {
|
402
|
+
return {
|
403
|
+
lang: split[0],
|
404
|
+
isOverride: true,
|
405
|
+
themeName: undefined
|
406
|
+
};
|
407
|
+
}
|
408
|
+
|
409
|
+
const match2 = split[1].match(/^_(.+)$/);
|
410
|
+
|
411
|
+
assert(match2 !== null);
|
412
|
+
|
413
|
+
return {
|
414
|
+
lang: split[0],
|
415
|
+
isOverride: true,
|
416
|
+
themeName: match2[1]
|
417
|
+
};
|
418
|
+
})();
|
419
|
+
|
420
|
+
if (parsedBasename === undefined) {
|
421
|
+
return;
|
422
|
+
}
|
423
|
+
|
424
|
+
propertiesByLang[parsedBasename.lang] ??= {
|
425
|
+
base: createObjectThatThrowsIfAccessed<Buffer>({
|
426
|
+
debugMessage: `No base ${parsedBasename.lang} translation for admin theme`
|
427
|
+
}),
|
428
|
+
override: undefined,
|
429
|
+
overrideByThemeName: {}
|
430
|
+
};
|
431
|
+
|
432
|
+
const buffer = fs.readFileSync(pathJoin(messagesDirPath_theme, basename));
|
433
|
+
|
434
|
+
if (parsedBasename.isOverride === false) {
|
435
|
+
propertiesByLang[parsedBasename.lang].base = buffer;
|
436
|
+
return;
|
437
|
+
}
|
438
|
+
|
439
|
+
if (parsedBasename.themeName === undefined) {
|
440
|
+
propertiesByLang[parsedBasename.lang].override = buffer;
|
441
|
+
return;
|
442
|
+
}
|
443
|
+
|
444
|
+
propertiesByLang[parsedBasename.lang].overrideByThemeName[
|
445
|
+
parsedBasename.themeName
|
446
|
+
] = buffer;
|
447
|
+
});
|
448
|
+
|
449
|
+
writeMessagePropertiesFilesByThemeType.admin = ({
|
450
|
+
messageDirPath,
|
451
|
+
themeName
|
452
|
+
}) => {
|
453
|
+
if (!fs.existsSync(messageDirPath)) {
|
454
|
+
fs.mkdirSync(messageDirPath, { recursive: true });
|
455
|
+
}
|
456
|
+
|
457
|
+
Object.entries(propertiesByLang).forEach(
|
458
|
+
([lang, { base, override, overrideByThemeName }]) => {
|
459
|
+
(languageTags ??= []).push(lang);
|
460
|
+
|
461
|
+
const messages = propertiesParser.parse(base.toString("utf8"));
|
462
|
+
|
463
|
+
if (override !== undefined) {
|
464
|
+
const overrideMessages = propertiesParser.parse(
|
465
|
+
override.toString("utf8")
|
466
|
+
);
|
467
|
+
|
468
|
+
Object.entries(overrideMessages).forEach(
|
469
|
+
([key, value]) => (messages[key] = value)
|
470
|
+
);
|
471
|
+
}
|
472
|
+
|
473
|
+
if (themeName in overrideByThemeName) {
|
474
|
+
const overrideMessages = propertiesParser.parse(
|
475
|
+
overrideByThemeName[themeName].toString("utf8")
|
476
|
+
);
|
477
|
+
|
478
|
+
Object.entries(overrideMessages).forEach(
|
479
|
+
([key, value]) => (messages[key] = value)
|
480
|
+
);
|
481
|
+
}
|
482
|
+
|
483
|
+
const editor = propertiesParser.createEditor();
|
484
|
+
|
485
|
+
Object.entries(messages).forEach(([key, value]) => {
|
486
|
+
editor.set(key, value);
|
487
|
+
});
|
488
|
+
|
489
|
+
fs.writeFileSync(
|
490
|
+
pathJoin(messageDirPath, `messages_${lang}.properties`),
|
491
|
+
Buffer.from(editor.toString(), "utf8")
|
492
|
+
);
|
493
|
+
}
|
494
|
+
);
|
495
|
+
};
|
496
|
+
}
|
497
|
+
|
342
498
|
keycloak_static_resources: {
|
343
499
|
if (isSpa) {
|
344
500
|
break keycloak_static_resources;
|
package/src/bin/main.ts
CHANGED
@@ -259,11 +259,12 @@ program
|
|
259
259
|
.option({
|
260
260
|
key: "file",
|
261
261
|
name: (() => {
|
262
|
-
const
|
262
|
+
const long = "file";
|
263
|
+
const short = "f";
|
263
264
|
|
264
|
-
optionsKeys.push(
|
265
|
+
optionsKeys.push(long, short);
|
265
266
|
|
266
|
-
return
|
267
|
+
return { long, short };
|
267
268
|
})(),
|
268
269
|
description: [
|
269
270
|
"Relative path of the file relative to the directory of your keycloak theme source",
|
@@ -32,38 +32,20 @@ export async function getUiModuleFileSourceCodeReadyToBeCopied(params: {
|
|
32
32
|
await fsPr.readFile(pathJoin(uiModuleDirPath, KEYCLOAK_THEME, fileRelativePath))
|
33
33
|
).toString("utf8");
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
}
|
40
|
-
|
41
|
-
return [`/**`, ...lines.map(line => ` * ${line}`), ` */`].join("\n");
|
42
|
-
}
|
43
|
-
|
44
|
-
if (fileRelativePath.endsWith(".html")) {
|
45
|
-
return [`<!--`, ...lines.map(line => ` ${line}`), `-->`].join("\n");
|
46
|
-
}
|
47
|
-
|
48
|
-
return undefined;
|
49
|
-
};
|
50
|
-
|
51
|
-
const comment = toComment(
|
52
|
-
isForEjection
|
35
|
+
sourceCode = addCommentToSourceCode({
|
36
|
+
sourceCode,
|
37
|
+
fileRelativePath,
|
38
|
+
commentLines: isForEjection
|
53
39
|
? [`This file was ejected from ${uiModuleName} version ${uiModuleVersion}.`]
|
54
40
|
: [
|
55
41
|
`WARNING: Before modifying this file run the following command:`,
|
56
42
|
``,
|
57
|
-
`$ npx keycloakify eject-file --file ${fileRelativePath.split(pathSep).join("/")}`,
|
43
|
+
`$ npx keycloakify eject-file --file '${fileRelativePath.split(pathSep).join("/")}'`,
|
58
44
|
``,
|
59
45
|
`This file comes from ${uiModuleName} version ${uiModuleVersion}.`,
|
60
46
|
`This file has been copied over to your repo by your postinstall script: \`npx keycloakify postinstall\``
|
61
47
|
]
|
62
|
-
);
|
63
|
-
|
64
|
-
if (comment !== undefined) {
|
65
|
-
sourceCode = [comment, ``, sourceCode].join("\n");
|
66
|
-
}
|
48
|
+
});
|
67
49
|
|
68
50
|
const destFilePath = pathJoin(buildContext.themeSrcDirPath, fileRelativePath);
|
69
51
|
|
@@ -80,3 +62,60 @@ export async function getUiModuleFileSourceCodeReadyToBeCopied(params: {
|
|
80
62
|
|
81
63
|
return Buffer.from(sourceCode, "utf8");
|
82
64
|
}
|
65
|
+
|
66
|
+
function addCommentToSourceCode(params: {
|
67
|
+
sourceCode: string;
|
68
|
+
fileRelativePath: string;
|
69
|
+
commentLines: string[];
|
70
|
+
}): string {
|
71
|
+
const { sourceCode, fileRelativePath, commentLines } = params;
|
72
|
+
|
73
|
+
const toResult = (comment: string) => {
|
74
|
+
return [comment, ``, sourceCode].join("\n");
|
75
|
+
};
|
76
|
+
|
77
|
+
for (const ext of [".ts", ".tsx", ".css", ".less", ".sass", ".js", ".jsx"]) {
|
78
|
+
if (!fileRelativePath.endsWith(ext)) {
|
79
|
+
continue;
|
80
|
+
}
|
81
|
+
|
82
|
+
return toResult(
|
83
|
+
[`/**`, ...commentLines.map(line => ` * ${line}`), ` */`].join("\n")
|
84
|
+
);
|
85
|
+
}
|
86
|
+
|
87
|
+
if (fileRelativePath.endsWith(".properties")) {
|
88
|
+
return toResult(commentLines.map(line => `# ${line}`).join("\n"));
|
89
|
+
}
|
90
|
+
|
91
|
+
if (fileRelativePath.endsWith(".html") || fileRelativePath.endsWith(".svg")) {
|
92
|
+
const comment = [
|
93
|
+
`<!--`,
|
94
|
+
...commentLines.map(
|
95
|
+
line =>
|
96
|
+
` ${line.replace("--file", "-f").replace("Before modifying", "Before modifying or replacing")}`
|
97
|
+
),
|
98
|
+
`-->`
|
99
|
+
].join("\n");
|
100
|
+
|
101
|
+
if (fileRelativePath.endsWith(".html") && sourceCode.trim().startsWith("<!")) {
|
102
|
+
const [first, ...rest] = sourceCode.split(">");
|
103
|
+
|
104
|
+
const last = rest.join(">");
|
105
|
+
|
106
|
+
return [`${first}>`, comment, last].join("\n");
|
107
|
+
}
|
108
|
+
|
109
|
+
if (fileRelativePath.endsWith(".svg") && sourceCode.trim().startsWith("<?")) {
|
110
|
+
const [first, ...rest] = sourceCode.split("?>");
|
111
|
+
|
112
|
+
const last = rest.join("?>");
|
113
|
+
|
114
|
+
return [`${first}?>`, comment, last].join("\n");
|
115
|
+
}
|
116
|
+
|
117
|
+
return toResult(comment);
|
118
|
+
}
|
119
|
+
|
120
|
+
return sourceCode;
|
121
|
+
}
|