keycloakify 11.5.3 → 11.5.4
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/{682.index.js → 153.index.js} +219 -24
- package/bin/main.js +1 -1
- package/bin/start-keycloak/realmConfig/{ParsedRealmJson.d.ts → ParsedRealmJson/ParsedRealmJson.d.ts} +2 -3
- package/bin/start-keycloak/realmConfig/ParsedRealmJson/index.d.ts +3 -0
- package/bin/start-keycloak/realmConfig/ParsedRealmJson/readRealmJsonFile.d.ts +4 -0
- package/bin/start-keycloak/realmConfig/ParsedRealmJson/writeRealmJsonFile.d.ts +6 -0
- package/bin/start-keycloak/realmConfig/defaultConfig/defaultConfig.d.ts +1 -4
- package/bin/tools/Stringifyable.d.ts +13 -0
- package/bin/tools/canonicalStringify.d.ts +5 -0
- package/package.json +14 -4
- package/src/bin/start-keycloak/realmConfig/{ParsedRealmJson.ts → ParsedRealmJson/ParsedRealmJson.ts} +1 -19
- package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/index.ts +3 -0
- package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/readRealmJsonFile.ts +20 -0
- package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/writeRealmJsonFile.ts +29 -0
- package/src/bin/start-keycloak/realmConfig/defaultConfig/defaultConfig.ts +3 -4
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-18.json +51 -33
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-19.json +48 -30
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-20.json +50 -32
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-21.json +29 -11
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-23.json +25 -7
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-24.json +26 -8
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-25.json +26 -8
- package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-26.json +11 -11
- package/src/bin/start-keycloak/realmConfig/prepareRealmConfig.ts +1 -1
- package/src/bin/start-keycloak/realmConfig/realmConfig.ts +15 -19
- package/src/bin/tools/Stringifyable.ts +99 -0
- package/src/bin/tools/canonicalStringify.ts +164 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
import { z } from "zod";
|
2
|
+
import { same } from "evt/tools/inDepth/same";
|
3
|
+
import { assert, type Equals } from "tsafe/assert";
|
4
|
+
import { id } from "tsafe/id";
|
5
|
+
|
6
|
+
export type Stringifyable =
|
7
|
+
| StringifyableAtomic
|
8
|
+
| StringifyableObject
|
9
|
+
| StringifyableArray;
|
10
|
+
|
11
|
+
export type StringifyableAtomic = string | number | boolean | null;
|
12
|
+
|
13
|
+
// NOTE: Use Record<string, Stringifyable>
|
14
|
+
interface StringifyableObject {
|
15
|
+
[key: string]: Stringifyable;
|
16
|
+
}
|
17
|
+
|
18
|
+
// NOTE: Use Stringifyable[]
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
20
|
+
interface StringifyableArray extends Array<Stringifyable> {}
|
21
|
+
|
22
|
+
export const zStringifyableAtomic = (() => {
|
23
|
+
type TargetType = StringifyableAtomic;
|
24
|
+
|
25
|
+
const zTargetType = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
26
|
+
|
27
|
+
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
|
28
|
+
|
29
|
+
return id<z.ZodType<TargetType>>(zTargetType);
|
30
|
+
})();
|
31
|
+
|
32
|
+
export const zStringifyable: z.ZodType<Stringifyable> = z
|
33
|
+
.any()
|
34
|
+
.superRefine((val, ctx) => {
|
35
|
+
const isStringifyable = same(JSON.parse(JSON.stringify(val)), val);
|
36
|
+
if (!isStringifyable) {
|
37
|
+
ctx.addIssue({
|
38
|
+
code: z.ZodIssueCode.custom,
|
39
|
+
message: "Not stringifyable"
|
40
|
+
});
|
41
|
+
}
|
42
|
+
});
|
43
|
+
|
44
|
+
export function getIsAtomic(
|
45
|
+
stringifyable: Stringifyable
|
46
|
+
): stringifyable is StringifyableAtomic {
|
47
|
+
return (
|
48
|
+
["string", "number", "boolean"].includes(typeof stringifyable) ||
|
49
|
+
stringifyable === null
|
50
|
+
);
|
51
|
+
}
|
52
|
+
|
53
|
+
export const { getValueAtPath } = (() => {
|
54
|
+
function getValueAtPath_rec(
|
55
|
+
stringifyable: Stringifyable,
|
56
|
+
path: (string | number)[]
|
57
|
+
): Stringifyable | undefined {
|
58
|
+
if (path.length === 0) {
|
59
|
+
return stringifyable;
|
60
|
+
}
|
61
|
+
|
62
|
+
if (getIsAtomic(stringifyable)) {
|
63
|
+
return undefined;
|
64
|
+
}
|
65
|
+
|
66
|
+
const [first, ...rest] = path;
|
67
|
+
|
68
|
+
let dereferenced: Stringifyable | undefined;
|
69
|
+
|
70
|
+
if (stringifyable instanceof Array) {
|
71
|
+
if (typeof first !== "number") {
|
72
|
+
return undefined;
|
73
|
+
}
|
74
|
+
|
75
|
+
dereferenced = stringifyable[first];
|
76
|
+
} else {
|
77
|
+
if (typeof first !== "string") {
|
78
|
+
return undefined;
|
79
|
+
}
|
80
|
+
|
81
|
+
dereferenced = stringifyable[first];
|
82
|
+
}
|
83
|
+
|
84
|
+
if (dereferenced === undefined) {
|
85
|
+
return undefined;
|
86
|
+
}
|
87
|
+
|
88
|
+
return getValueAtPath_rec(dereferenced, rest);
|
89
|
+
}
|
90
|
+
|
91
|
+
function getValueAtPath(
|
92
|
+
stringifyableObjectOrArray: Record<string, Stringifyable> | Stringifyable[],
|
93
|
+
path: (string | number)[]
|
94
|
+
): Stringifyable | undefined {
|
95
|
+
return getValueAtPath_rec(stringifyableObjectOrArray, path);
|
96
|
+
}
|
97
|
+
|
98
|
+
return { getValueAtPath };
|
99
|
+
})();
|
@@ -0,0 +1,164 @@
|
|
1
|
+
import { getIsAtomic, getValueAtPath, type Stringifyable } from "./Stringifyable";
|
2
|
+
|
3
|
+
export function canonicalStringify(params: {
|
4
|
+
data: Record<string, Stringifyable> | Stringifyable[];
|
5
|
+
referenceData: Record<string, Stringifyable> | Stringifyable[];
|
6
|
+
}): string {
|
7
|
+
const { data, referenceData } = params;
|
8
|
+
|
9
|
+
return JSON.stringify(
|
10
|
+
makeDeterministicCopy({
|
11
|
+
path: [],
|
12
|
+
data,
|
13
|
+
getCanonicalKeys: path => {
|
14
|
+
const referenceValue = (() => {
|
15
|
+
const path_patched: (string | number)[] = [];
|
16
|
+
|
17
|
+
for (let i = 0; i < path.length; i++) {
|
18
|
+
let value_i = getValueAtPath(referenceData, [
|
19
|
+
...path_patched,
|
20
|
+
path[i]
|
21
|
+
]);
|
22
|
+
|
23
|
+
if (value_i !== undefined) {
|
24
|
+
path_patched.push(path[i]);
|
25
|
+
continue;
|
26
|
+
}
|
27
|
+
|
28
|
+
if (typeof path[i] !== "number") {
|
29
|
+
return undefined;
|
30
|
+
}
|
31
|
+
|
32
|
+
value_i = getValueAtPath(referenceData, [...path_patched, 0]);
|
33
|
+
|
34
|
+
if (value_i !== undefined) {
|
35
|
+
path_patched.push(0);
|
36
|
+
continue;
|
37
|
+
}
|
38
|
+
|
39
|
+
return undefined;
|
40
|
+
}
|
41
|
+
|
42
|
+
return getValueAtPath(referenceData, path_patched);
|
43
|
+
})();
|
44
|
+
|
45
|
+
if (referenceValue === undefined) {
|
46
|
+
return undefined;
|
47
|
+
}
|
48
|
+
|
49
|
+
if (getIsAtomic(referenceValue)) {
|
50
|
+
return undefined;
|
51
|
+
}
|
52
|
+
|
53
|
+
if (referenceValue instanceof Array) {
|
54
|
+
return undefined;
|
55
|
+
}
|
56
|
+
|
57
|
+
return Object.keys(referenceValue);
|
58
|
+
}
|
59
|
+
}),
|
60
|
+
null,
|
61
|
+
2
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
function makeDeterministicCopy(params: {
|
66
|
+
path: (string | number)[];
|
67
|
+
data: Stringifyable;
|
68
|
+
getCanonicalKeys: (path: (string | number)[]) => string[] | undefined;
|
69
|
+
}): Stringifyable {
|
70
|
+
const { path, data, getCanonicalKeys } = params;
|
71
|
+
|
72
|
+
if (getIsAtomic(data)) {
|
73
|
+
return data;
|
74
|
+
}
|
75
|
+
|
76
|
+
if (data instanceof Array) {
|
77
|
+
return makeDeterministicCopy_array({
|
78
|
+
path,
|
79
|
+
data,
|
80
|
+
getCanonicalKeys
|
81
|
+
});
|
82
|
+
}
|
83
|
+
|
84
|
+
return makeDeterministicCopy_record({
|
85
|
+
path,
|
86
|
+
data,
|
87
|
+
getCanonicalKeys
|
88
|
+
});
|
89
|
+
}
|
90
|
+
|
91
|
+
function makeDeterministicCopy_record(params: {
|
92
|
+
path: (string | number)[];
|
93
|
+
data: Record<string, Stringifyable>;
|
94
|
+
getCanonicalKeys: (path: (string | number)[]) => string[] | undefined;
|
95
|
+
}): Record<string, Stringifyable> {
|
96
|
+
const { path, data, getCanonicalKeys } = params;
|
97
|
+
|
98
|
+
const keysOfAtomicValues: string[] = [];
|
99
|
+
const keysOfNonAtomicValues: string[] = [];
|
100
|
+
|
101
|
+
for (const [key, value] of Object.entries(data)) {
|
102
|
+
if (getIsAtomic(value)) {
|
103
|
+
keysOfAtomicValues.push(key);
|
104
|
+
} else {
|
105
|
+
keysOfNonAtomicValues.push(key);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
keysOfAtomicValues.sort();
|
110
|
+
keysOfNonAtomicValues.sort();
|
111
|
+
|
112
|
+
const keys = [...keysOfAtomicValues, ...keysOfNonAtomicValues];
|
113
|
+
|
114
|
+
reorder_according_to_canonical: {
|
115
|
+
const canonicalKeys = getCanonicalKeys(path);
|
116
|
+
|
117
|
+
if (canonicalKeys === undefined) {
|
118
|
+
break reorder_according_to_canonical;
|
119
|
+
}
|
120
|
+
|
121
|
+
const keys_toPrepend: string[] = [];
|
122
|
+
|
123
|
+
for (const key of canonicalKeys) {
|
124
|
+
const indexOfKey = keys.indexOf(key);
|
125
|
+
|
126
|
+
if (indexOfKey === -1) {
|
127
|
+
continue;
|
128
|
+
}
|
129
|
+
|
130
|
+
keys.splice(indexOfKey, 1);
|
131
|
+
keys_toPrepend.push(key);
|
132
|
+
}
|
133
|
+
|
134
|
+
keys.unshift(...keys_toPrepend);
|
135
|
+
}
|
136
|
+
|
137
|
+
const result: Record<string, Stringifyable> = {};
|
138
|
+
|
139
|
+
for (const key of keys) {
|
140
|
+
result[key] = makeDeterministicCopy({
|
141
|
+
path: [...path, key],
|
142
|
+
data: data[key],
|
143
|
+
getCanonicalKeys
|
144
|
+
});
|
145
|
+
}
|
146
|
+
|
147
|
+
return result;
|
148
|
+
}
|
149
|
+
|
150
|
+
function makeDeterministicCopy_array(params: {
|
151
|
+
path: (string | number)[];
|
152
|
+
data: Stringifyable[];
|
153
|
+
getCanonicalKeys: (path: (string | number)[]) => string[] | undefined;
|
154
|
+
}): Stringifyable[] {
|
155
|
+
const { path, data, getCanonicalKeys } = params;
|
156
|
+
|
157
|
+
return [...data].map((entry, i) =>
|
158
|
+
makeDeterministicCopy({
|
159
|
+
path: [...path, i],
|
160
|
+
data: entry,
|
161
|
+
getCanonicalKeys
|
162
|
+
})
|
163
|
+
);
|
164
|
+
}
|