keycloakify 11.5.4 → 11.6.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.
- package/bin/153.index.js +81 -28
- package/bin/{805.index.js → 174.index.js} +111 -2
- package/bin/{356.index.js → 300.index.js} +67 -29
- package/bin/{33.index.js → 568.index.js} +2 -113
- package/bin/615.index.js +1009 -0
- package/bin/653.index.js +53 -135
- package/bin/735.index.js +53 -24
- package/bin/854.index.js +1 -1
- package/bin/{573.index.js → 880.index.js} +155 -9
- package/bin/921.index.js +1 -1
- package/bin/initialize-admin-theme.d.ts +4 -0
- package/bin/main.js +22 -9
- package/bin/shared/addPostinstallScriptIfNotPresent.d.ts +10 -0
- package/bin/shared/customHandler.d.ts +1 -1
- package/bin/shared/customHandler.js.map +1 -1
- package/bin/tools/createObjectThatThrowsIfAccessed.d.ts +21 -0
- package/bin/tools/npmInstall.d.ts +1 -1
- package/package.json +13 -5
- package/src/bin/initialize-account-theme/initializeAccountTheme_singlePage.ts +3 -1
- package/src/bin/initialize-admin-theme.ts +146 -0
- package/src/bin/keycloakify/generateResources/generateResources.ts +162 -6
- package/src/bin/main.ts +19 -4
- package/src/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts +63 -24
- package/src/bin/postinstall/installUiModulesPeerDependencies.ts +1 -1
- package/src/bin/postinstall/uiModuleMeta.ts +7 -1
- package/src/bin/shared/addPostinstallScriptIfNotPresent.ts +70 -0
- package/src/bin/shared/customHandler.ts +1 -0
- 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
- package/src/bin/tools/npmInstall.ts +46 -9
@@ -142,15 +142,96 @@ export async function command(params: {
|
|
142
142
|
].join("\n")
|
143
143
|
);
|
144
144
|
|
145
|
-
const
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
145
|
+
const tag_userSelected = await (async () => {
|
146
|
+
let tag: string;
|
147
|
+
|
148
|
+
let latestMajorTags_copy = [...latestMajorTags];
|
149
|
+
|
150
|
+
while (true) {
|
151
|
+
const { value } = await cliSelect<string>({
|
152
|
+
values: latestMajorTags_copy
|
153
|
+
}).catch(() => {
|
154
|
+
process.exit(-1);
|
155
|
+
});
|
156
|
+
|
157
|
+
tag = value;
|
158
|
+
|
159
|
+
{
|
160
|
+
const doImplementAccountMpa =
|
161
|
+
buildContext.implementedThemeTypes.account.isImplemented &&
|
162
|
+
buildContext.implementedThemeTypes.account.type === "Multi-Page";
|
163
|
+
|
164
|
+
if (doImplementAccountMpa && tag.startsWith("22.")) {
|
165
|
+
console.log(
|
166
|
+
chalk.yellow(
|
167
|
+
`You are implementing a Multi-Page Account theme. Keycloak 22 is not supported, select another version`
|
168
|
+
)
|
169
|
+
);
|
170
|
+
latestMajorTags_copy = latestMajorTags_copy.filter(
|
171
|
+
tag => !tag.startsWith("22.")
|
172
|
+
);
|
173
|
+
continue;
|
174
|
+
}
|
175
|
+
}
|
150
176
|
|
151
|
-
|
177
|
+
const readMajor = (tag: string) => {
|
178
|
+
const major = parseInt(tag.split(".")[0]);
|
179
|
+
assert(!isNaN(major));
|
180
|
+
return major;
|
181
|
+
};
|
152
182
|
|
153
|
-
|
183
|
+
{
|
184
|
+
const major = readMajor(tag);
|
185
|
+
|
186
|
+
const doImplementAdminTheme =
|
187
|
+
buildContext.implementedThemeTypes.admin.isImplemented;
|
188
|
+
|
189
|
+
const getIsSupported = (major: number) => major >= 23;
|
190
|
+
|
191
|
+
if (doImplementAdminTheme && !getIsSupported(major)) {
|
192
|
+
console.log(
|
193
|
+
chalk.yellow(
|
194
|
+
`You are implementing an Admin theme. Only Keycloak 23 and later are supported, select another version`
|
195
|
+
)
|
196
|
+
);
|
197
|
+
latestMajorTags_copy = latestMajorTags_copy.filter(tag =>
|
198
|
+
getIsSupported(readMajor(tag))
|
199
|
+
);
|
200
|
+
continue;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
{
|
205
|
+
const doImplementAccountSpa =
|
206
|
+
buildContext.implementedThemeTypes.account.isImplemented &&
|
207
|
+
buildContext.implementedThemeTypes.account.type === "Single-Page";
|
208
|
+
|
209
|
+
const major = readMajor(tag);
|
210
|
+
|
211
|
+
const getIsSupported = (major: number) => major >= 19;
|
212
|
+
|
213
|
+
if (doImplementAccountSpa && !getIsSupported(major)) {
|
214
|
+
console.log(
|
215
|
+
chalk.yellow(
|
216
|
+
`You are implementing a Single-Page Account theme. Only Keycloak 19 and later are supported, select another version`
|
217
|
+
)
|
218
|
+
);
|
219
|
+
latestMajorTags_copy = latestMajorTags_copy.filter(tag =>
|
220
|
+
getIsSupported(readMajor(tag))
|
221
|
+
);
|
222
|
+
continue;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
break;
|
227
|
+
}
|
228
|
+
|
229
|
+
return tag;
|
230
|
+
})();
|
231
|
+
|
232
|
+
console.log(`→ ${tag_userSelected}`);
|
233
|
+
|
234
|
+
return { dockerImageTag: tag_userSelected };
|
154
235
|
})();
|
155
236
|
|
156
237
|
const keycloakMajorVersionNumber = (() => {
|
@@ -623,42 +704,56 @@ export async function command(params: {
|
|
623
704
|
}
|
624
705
|
)
|
625
706
|
.on("all", async (...[, filePath]) => {
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
buildContext.implementedThemeTypes.account.type === "Single-Page";
|
630
|
-
|
631
|
-
if (!doImplementAccountSpa) {
|
632
|
-
break ignore_account_spa;
|
707
|
+
ignore_path_covered_by_hmr: {
|
708
|
+
if (filePath.endsWith(".properties")) {
|
709
|
+
break ignore_path_covered_by_hmr;
|
633
710
|
}
|
634
711
|
|
635
|
-
if (
|
636
|
-
|
637
|
-
dirPath: pathJoin(buildContext.themeSrcDirPath, "account"),
|
638
|
-
filePath
|
639
|
-
})
|
640
|
-
) {
|
641
|
-
break ignore_account_spa;
|
712
|
+
if (!doStartDevServer) {
|
713
|
+
break ignore_path_covered_by_hmr;
|
642
714
|
}
|
643
715
|
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
716
|
+
ignore_account_spa: {
|
717
|
+
const doImplementAccountSpa =
|
718
|
+
buildContext.implementedThemeTypes.account.isImplemented &&
|
719
|
+
buildContext.implementedThemeTypes.account.type ===
|
720
|
+
"Single-Page";
|
721
|
+
|
722
|
+
if (!doImplementAccountSpa) {
|
723
|
+
break ignore_account_spa;
|
724
|
+
}
|
725
|
+
|
726
|
+
if (
|
727
|
+
!isInside({
|
728
|
+
dirPath: pathJoin(
|
729
|
+
buildContext.themeSrcDirPath,
|
730
|
+
"account"
|
731
|
+
),
|
732
|
+
filePath
|
733
|
+
})
|
734
|
+
) {
|
735
|
+
break ignore_account_spa;
|
736
|
+
}
|
737
|
+
|
738
|
+
return;
|
650
739
|
}
|
651
740
|
|
652
|
-
|
653
|
-
!
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
741
|
+
ignore_admin: {
|
742
|
+
if (!buildContext.implementedThemeTypes.admin.isImplemented) {
|
743
|
+
break ignore_admin;
|
744
|
+
}
|
745
|
+
|
746
|
+
if (
|
747
|
+
!isInside({
|
748
|
+
dirPath: pathJoin(buildContext.themeSrcDirPath, "admin"),
|
749
|
+
filePath
|
750
|
+
})
|
751
|
+
) {
|
752
|
+
break ignore_admin;
|
753
|
+
}
|
754
|
+
|
755
|
+
return;
|
659
756
|
}
|
660
|
-
|
661
|
-
return;
|
662
757
|
}
|
663
758
|
|
664
759
|
console.log(`Detected changes in ${filePath}`);
|
@@ -0,0 +1,90 @@
|
|
1
|
+
const keyIsTrapped = "isTrapped_zSskDe9d";
|
2
|
+
|
3
|
+
export class AccessError extends Error {
|
4
|
+
constructor(message: string) {
|
5
|
+
super(message);
|
6
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
export function createObjectThatThrowsIfAccessed<T extends object>(params?: {
|
11
|
+
debugMessage?: string;
|
12
|
+
isPropertyWhitelisted?: (prop: string | number | symbol) => boolean;
|
13
|
+
}): T {
|
14
|
+
const { debugMessage = "", isPropertyWhitelisted = () => false } = params ?? {};
|
15
|
+
|
16
|
+
const get: NonNullable<ProxyHandler<T>["get"]> = (...args) => {
|
17
|
+
const [, prop] = args;
|
18
|
+
|
19
|
+
if (isPropertyWhitelisted(prop)) {
|
20
|
+
return Reflect.get(...args);
|
21
|
+
}
|
22
|
+
|
23
|
+
if (prop === keyIsTrapped) {
|
24
|
+
return true;
|
25
|
+
}
|
26
|
+
|
27
|
+
throw new AccessError(`Cannot access ${String(prop)} yet ${debugMessage}`);
|
28
|
+
};
|
29
|
+
|
30
|
+
const trappedObject = new Proxy<T>({} as any, {
|
31
|
+
get,
|
32
|
+
set: get
|
33
|
+
});
|
34
|
+
|
35
|
+
return trappedObject;
|
36
|
+
}
|
37
|
+
|
38
|
+
export function createObjectThatThrowsIfAccessedFactory(params: {
|
39
|
+
isPropertyWhitelisted?: (prop: string | number | symbol) => boolean;
|
40
|
+
}) {
|
41
|
+
const { isPropertyWhitelisted } = params;
|
42
|
+
|
43
|
+
return {
|
44
|
+
createObjectThatThrowsIfAccessed: <T extends object>(params?: {
|
45
|
+
debugMessage?: string;
|
46
|
+
}) => {
|
47
|
+
const { debugMessage } = params ?? {};
|
48
|
+
|
49
|
+
return createObjectThatThrowsIfAccessed<T>({
|
50
|
+
debugMessage,
|
51
|
+
isPropertyWhitelisted
|
52
|
+
});
|
53
|
+
}
|
54
|
+
};
|
55
|
+
}
|
56
|
+
|
57
|
+
export function isObjectThatThrowIfAccessed(obj: object) {
|
58
|
+
return (obj as any)[keyIsTrapped] === true;
|
59
|
+
}
|
60
|
+
|
61
|
+
export const THROW_IF_ACCESSED = {
|
62
|
+
__brand: "THROW_IF_ACCESSED"
|
63
|
+
};
|
64
|
+
|
65
|
+
export function createObjectWithSomePropertiesThatThrowIfAccessed<
|
66
|
+
T extends Record<string, unknown>
|
67
|
+
>(obj: { [K in keyof T]: T[K] | typeof THROW_IF_ACCESSED }, debugMessage?: string): T {
|
68
|
+
return Object.defineProperties(
|
69
|
+
obj,
|
70
|
+
Object.fromEntries(
|
71
|
+
Object.entries(obj)
|
72
|
+
.filter(([, value]) => value === THROW_IF_ACCESSED)
|
73
|
+
.map(([key]) => {
|
74
|
+
const getAndSet = () => {
|
75
|
+
throw new AccessError(
|
76
|
+
`Cannot access ${key} yet ${debugMessage ?? ""}`
|
77
|
+
);
|
78
|
+
};
|
79
|
+
|
80
|
+
const pd = {
|
81
|
+
get: getAndSet,
|
82
|
+
set: getAndSet,
|
83
|
+
enumerable: true
|
84
|
+
};
|
85
|
+
|
86
|
+
return [key, pd];
|
87
|
+
})
|
88
|
+
)
|
89
|
+
) as any;
|
90
|
+
}
|
@@ -9,8 +9,9 @@ import { objectKeys } from "tsafe/objectKeys";
|
|
9
9
|
import { getAbsoluteAndInOsFormatPath } from "./getAbsoluteAndInOsFormatPath";
|
10
10
|
import { exclude } from "tsafe/exclude";
|
11
11
|
import { rmSync } from "./fs.rmSync";
|
12
|
+
import { Deferred } from "evt/tools/Deferred";
|
12
13
|
|
13
|
-
export function npmInstall(params: { packageJsonDirPath: string }) {
|
14
|
+
export async function npmInstall(params: { packageJsonDirPath: string }) {
|
14
15
|
const { packageJsonDirPath } = params;
|
15
16
|
|
16
17
|
const packageManagerBinName = (() => {
|
@@ -68,7 +69,7 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
|
68
69
|
|
69
70
|
console.log(chalk.green("Installing in a way that won't break the links..."));
|
70
71
|
|
71
|
-
installWithoutBreakingLinks({
|
72
|
+
await installWithoutBreakingLinks({
|
72
73
|
packageJsonDirPath,
|
73
74
|
garronejLinkInfos
|
74
75
|
});
|
@@ -77,9 +78,9 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
|
77
78
|
}
|
78
79
|
|
79
80
|
try {
|
80
|
-
|
81
|
-
|
82
|
-
|
81
|
+
await runPackageManagerInstall({
|
82
|
+
packageManagerBinName,
|
83
|
+
cwd: packageJsonDirPath
|
83
84
|
});
|
84
85
|
} catch {
|
85
86
|
console.log(
|
@@ -90,6 +91,42 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
|
90
91
|
}
|
91
92
|
}
|
92
93
|
|
94
|
+
async function runPackageManagerInstall(params: {
|
95
|
+
packageManagerBinName: string;
|
96
|
+
cwd: string;
|
97
|
+
}) {
|
98
|
+
const { packageManagerBinName, cwd } = params;
|
99
|
+
|
100
|
+
const dCompleted = new Deferred<void>();
|
101
|
+
|
102
|
+
const child = child_process.spawn(packageManagerBinName, ["install"], {
|
103
|
+
cwd,
|
104
|
+
env: process.env,
|
105
|
+
shell: true
|
106
|
+
});
|
107
|
+
|
108
|
+
child.stdout.on("data", data => process.stdout.write(data));
|
109
|
+
|
110
|
+
child.stderr.on("data", data => {
|
111
|
+
if (data.toString("utf8").includes("has unmet peer dependency")) {
|
112
|
+
return;
|
113
|
+
}
|
114
|
+
|
115
|
+
process.stderr.write(data);
|
116
|
+
});
|
117
|
+
|
118
|
+
child.on("exit", code => {
|
119
|
+
if (code !== 0) {
|
120
|
+
dCompleted.reject(new Error(`Failed with code ${code}`));
|
121
|
+
return;
|
122
|
+
}
|
123
|
+
|
124
|
+
dCompleted.resolve();
|
125
|
+
});
|
126
|
+
|
127
|
+
await dCompleted.pr;
|
128
|
+
}
|
129
|
+
|
93
130
|
function getGarronejLinkInfos(params: {
|
94
131
|
packageJsonDirPath: string;
|
95
132
|
}): { linkedModuleNames: string[]; yarnHomeDirPath: string } | undefined {
|
@@ -180,7 +217,7 @@ function getGarronejLinkInfos(params: {
|
|
180
217
|
return { linkedModuleNames, yarnHomeDirPath };
|
181
218
|
}
|
182
219
|
|
183
|
-
function installWithoutBreakingLinks(params: {
|
220
|
+
async function installWithoutBreakingLinks(params: {
|
184
221
|
packageJsonDirPath: string;
|
185
222
|
garronejLinkInfos: Exclude<ReturnType<typeof getGarronejLinkInfos>, undefined>;
|
186
223
|
}) {
|
@@ -261,9 +298,9 @@ function installWithoutBreakingLinks(params: {
|
|
261
298
|
pathJoin(tmpProjectDirPath, YARN_LOCK)
|
262
299
|
);
|
263
300
|
|
264
|
-
|
265
|
-
|
266
|
-
|
301
|
+
await runPackageManagerInstall({
|
302
|
+
packageManagerBinName: "yarn",
|
303
|
+
cwd: tmpProjectDirPath
|
267
304
|
});
|
268
305
|
|
269
306
|
// NOTE: Moving the modules from the tmp project to the actual project
|