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.
Files changed (27) hide show
  1. package/bin/{682.index.js → 153.index.js} +219 -24
  2. package/bin/main.js +1 -1
  3. package/bin/start-keycloak/realmConfig/{ParsedRealmJson.d.ts → ParsedRealmJson/ParsedRealmJson.d.ts} +2 -3
  4. package/bin/start-keycloak/realmConfig/ParsedRealmJson/index.d.ts +3 -0
  5. package/bin/start-keycloak/realmConfig/ParsedRealmJson/readRealmJsonFile.d.ts +4 -0
  6. package/bin/start-keycloak/realmConfig/ParsedRealmJson/writeRealmJsonFile.d.ts +6 -0
  7. package/bin/start-keycloak/realmConfig/defaultConfig/defaultConfig.d.ts +1 -4
  8. package/bin/tools/Stringifyable.d.ts +13 -0
  9. package/bin/tools/canonicalStringify.d.ts +5 -0
  10. package/package.json +14 -4
  11. package/src/bin/start-keycloak/realmConfig/{ParsedRealmJson.ts → ParsedRealmJson/ParsedRealmJson.ts} +1 -19
  12. package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/index.ts +3 -0
  13. package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/readRealmJsonFile.ts +20 -0
  14. package/src/bin/start-keycloak/realmConfig/ParsedRealmJson/writeRealmJsonFile.ts +29 -0
  15. package/src/bin/start-keycloak/realmConfig/defaultConfig/defaultConfig.ts +3 -4
  16. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-18.json +51 -33
  17. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-19.json +48 -30
  18. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-20.json +50 -32
  19. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-21.json +29 -11
  20. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-23.json +25 -7
  21. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-24.json +26 -8
  22. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-25.json +26 -8
  23. package/src/bin/start-keycloak/realmConfig/defaultConfig/realm-kc-26.json +11 -11
  24. package/src/bin/start-keycloak/realmConfig/prepareRealmConfig.ts +1 -1
  25. package/src/bin/start-keycloak/realmConfig/realmConfig.ts +15 -19
  26. package/src/bin/tools/Stringifyable.ts +99 -0
  27. 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
+ }