@keycloak/keycloak-admin-client 22.0.4 → 23.0.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/README.md CHANGED
@@ -220,6 +220,7 @@ Demo code: https://github.com/keycloak/keycloak/blob/main/js/libs/keycloak-admin
220
220
  - Count (`GET /{realm}/groups/count`)
221
221
  - List members (`GET /{realm}/groups/{id}/members`)
222
222
  - Set or create child (`POST /{realm}/groups/{id}/children`)
223
+ - Get children (`GET /{realm}/groups/{id}/children`)
223
224
 
224
225
  ### Group role-mapping
225
226
 
package/lib/client.d.ts CHANGED
@@ -25,6 +25,7 @@ export interface ConnectionConfig {
25
25
  requestArgOptions?: Pick<RequestArgs, "catchNotFound">;
26
26
  }
27
27
  export declare class KeycloakAdminClient {
28
+ #private;
28
29
  users: Users;
29
30
  userStorageProvider: UserStorageProvider;
30
31
  groups: Groups;
@@ -44,9 +45,6 @@ export declare class KeycloakAdminClient {
44
45
  realmName: string;
45
46
  accessToken?: string;
46
47
  refreshToken?: string;
47
- private requestOptions?;
48
- private globalRequestArgOptions?;
49
- private tokenProvider?;
50
48
  constructor(connectionConfig?: ConnectionConfig);
51
49
  auth(credentials: Credentials): Promise<void>;
52
50
  registerTokenProvider(provider: TokenProvider): void;
package/lib/client.js CHANGED
@@ -37,14 +37,14 @@ export class KeycloakAdminClient {
37
37
  realmName;
38
38
  accessToken;
39
39
  refreshToken;
40
- requestOptions;
41
- globalRequestArgOptions;
42
- tokenProvider;
40
+ #requestOptions;
41
+ #globalRequestArgOptions;
42
+ #tokenProvider;
43
43
  constructor(connectionConfig) {
44
44
  this.baseUrl = connectionConfig?.baseUrl || defaultBaseUrl;
45
45
  this.realmName = connectionConfig?.realmName || defaultRealm;
46
- this.requestOptions = connectionConfig?.requestOptions;
47
- this.globalRequestArgOptions = connectionConfig?.requestArgOptions;
46
+ this.#requestOptions = connectionConfig?.requestOptions;
47
+ this.#globalRequestArgOptions = connectionConfig?.requestArgOptions;
48
48
  // Initialize resources
49
49
  this.users = new Users(this);
50
50
  this.userStorageProvider = new UserStorageProvider(this);
@@ -67,31 +67,31 @@ export class KeycloakAdminClient {
67
67
  baseUrl: this.baseUrl,
68
68
  realmName: this.realmName,
69
69
  credentials,
70
- requestOptions: this.requestOptions,
70
+ requestOptions: this.#requestOptions,
71
71
  });
72
72
  this.accessToken = accessToken;
73
73
  this.refreshToken = refreshToken;
74
74
  }
75
75
  registerTokenProvider(provider) {
76
- if (this.tokenProvider) {
76
+ if (this.#tokenProvider) {
77
77
  throw new Error("An existing token provider was already registered.");
78
78
  }
79
- this.tokenProvider = provider;
79
+ this.#tokenProvider = provider;
80
80
  }
81
81
  setAccessToken(token) {
82
82
  this.accessToken = token;
83
83
  }
84
84
  async getAccessToken() {
85
- if (this.tokenProvider) {
86
- return this.tokenProvider.getAccessToken();
85
+ if (this.#tokenProvider) {
86
+ return this.#tokenProvider.getAccessToken();
87
87
  }
88
88
  return this.accessToken;
89
89
  }
90
90
  getRequestOptions() {
91
- return this.requestOptions;
91
+ return this.#requestOptions;
92
92
  }
93
93
  getGlobalRequestArgOptions() {
94
- return this.globalRequestArgOptions;
94
+ return this.#globalRequestArgOptions;
95
95
  }
96
96
  setConfig(connectionConfig) {
97
97
  if (typeof connectionConfig.baseUrl === "string" &&
@@ -102,6 +102,6 @@ export class KeycloakAdminClient {
102
102
  connectionConfig.realmName) {
103
103
  this.realmName = connectionConfig.realmName;
104
104
  }
105
- this.requestOptions = connectionConfig.requestOptions;
105
+ this.#requestOptions = connectionConfig.requestOptions;
106
106
  }
107
107
  }
@@ -15,4 +15,5 @@ export interface ConfigPropertyRepresentation {
15
15
  defaultValue?: any;
16
16
  options?: string[];
17
17
  secret?: boolean;
18
+ required?: boolean;
18
19
  }
@@ -9,4 +9,5 @@ export interface ConfigPropertyRepresentation {
9
9
  defaultValue?: object;
10
10
  options?: string[];
11
11
  secret?: boolean;
12
+ required?: boolean;
12
13
  }
@@ -0,0 +1,6 @@
1
+ export default interface EffectiveMessageBundleRepresentation {
2
+ theme?: string;
3
+ themeType?: string;
4
+ locale?: string;
5
+ source?: boolean;
6
+ }
@@ -5,6 +5,7 @@ export default interface GroupRepresentation {
5
5
  id?: string;
6
6
  name?: string;
7
7
  path?: string;
8
+ subGroupCount?: number;
8
9
  subGroups?: GroupRepresentation[];
9
10
  access?: Record<string, boolean>;
10
11
  attributes?: Record<string, any>;
@@ -16,4 +16,5 @@ export interface KeyMetadataRepresentation {
16
16
  algorithm?: string;
17
17
  publicKey?: string;
18
18
  certificate?: string;
19
+ validTo?: string;
19
20
  }
@@ -4,7 +4,7 @@ export default interface UserProfileConfig {
4
4
  }
5
5
  export interface UserProfileAttribute {
6
6
  name?: string;
7
- validations?: Record<string, Record<string, unknown>>;
7
+ validations?: Record<string, unknown>;
8
8
  validators?: Record<string, unknown>;
9
9
  annotations?: Record<string, unknown>;
10
10
  required?: UserProfileAttributeRequired;
@@ -31,3 +31,22 @@ export interface UserProfileGroup {
31
31
  displayDescription?: string;
32
32
  annotations?: Record<string, unknown>;
33
33
  }
34
+ export interface UserProfileAttributeMetadata {
35
+ name?: string;
36
+ displayName?: string;
37
+ required?: boolean;
38
+ readOnly?: boolean;
39
+ group?: string;
40
+ annotations?: Record<string, unknown>;
41
+ validators?: Record<string, Record<string, unknown>>;
42
+ }
43
+ export interface UserProfileAttributeGroupMetadata {
44
+ name?: string;
45
+ displayHeader?: string;
46
+ displayDescription?: string;
47
+ annotations?: Record<string, unknown>;
48
+ }
49
+ export interface UserProfileMetadata {
50
+ attributes?: UserProfileAttributeMetadata[];
51
+ groups?: UserProfileAttributeGroupMetadata[];
52
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,8 @@
1
- import type UserConsentRepresentation from "./userConsentRepresentation.js";
2
1
  import type CredentialRepresentation from "./credentialRepresentation.js";
3
2
  import type FederatedIdentityRepresentation from "./federatedIdentityRepresentation.js";
4
3
  import type { RequiredActionAlias } from "./requiredActionProviderRepresentation.js";
5
- import type UserProfileConfig from "./userProfileConfig.js";
4
+ import type UserConsentRepresentation from "./userConsentRepresentation.js";
5
+ import type { UserProfileMetadata } from "./userProfileMetadata.js";
6
6
  export default interface UserRepresentation {
7
7
  id?: string;
8
8
  createdTimestamp?: number;
@@ -28,5 +28,5 @@ export default interface UserRepresentation {
28
28
  realmRoles?: string[];
29
29
  self?: string;
30
30
  serviceAccountClientId?: string;
31
- userProfileMetadata?: UserProfileConfig;
31
+ userProfileMetadata?: UserProfileMetadata;
32
32
  }
package/lib/index.d.ts CHANGED
@@ -2,5 +2,5 @@ import { KeycloakAdminClient } from "./client.js";
2
2
  import { RequiredActionAlias } from "./defs/requiredActionProviderRepresentation.js";
3
3
  export declare const requiredAction: typeof RequiredActionAlias;
4
4
  export default KeycloakAdminClient;
5
- export { NetworkError } from "./utils/fetchWithError.js";
5
+ export { NetworkError, fetchWithError } from "./utils/fetchWithError.js";
6
6
  export type { NetworkErrorOptions } from "./utils/fetchWithError.js";
package/lib/index.js CHANGED
@@ -2,4 +2,4 @@ import { KeycloakAdminClient } from "./client.js";
2
2
  import { RequiredActionAlias } from "./defs/requiredActionProviderRepresentation.js";
3
3
  export const requiredAction = RequiredActionAlias;
4
4
  export default KeycloakAdminClient;
5
- export { NetworkError } from "./utils/fetchWithError.js";
5
+ export { NetworkError, fetchWithError } from "./utils/fetchWithError.js";
@@ -18,10 +18,7 @@ export interface RequestArgs {
18
18
  headers?: HeadersInit;
19
19
  }
20
20
  export declare class Agent {
21
- private client;
22
- private basePath;
23
- private getBaseParams?;
24
- private getBaseUrl?;
21
+ #private;
25
22
  constructor({ client, path, getUrlParams, getBaseUrl, }: {
26
23
  client: KeycloakAdminClient;
27
24
  path?: string;
@@ -30,7 +27,5 @@ export declare class Agent {
30
27
  });
31
28
  request({ method, path, urlParamKeys, queryParamKeys, catchNotFound, keyTransform, payloadKey, returnResourceIdInLocationHeader, ignoredKeys, headers, }: RequestArgs): (payload?: any, options?: Pick<RequestArgs, "catchNotFound">) => Promise<any>;
32
29
  updateRequest({ method, path, urlParamKeys, queryParamKeys, catchNotFound, keyTransform, payloadKey, returnResourceIdInLocationHeader, headers, }: RequestArgs): (query?: any, payload?: any) => Promise<any>;
33
- private requestWithParams;
34
- private transformKey;
35
30
  }
36
31
  export {};
@@ -6,19 +6,19 @@ import { stringifyQueryParams } from "../utils/stringifyQueryParams.js";
6
6
  // constants
7
7
  const SLASH = "/";
8
8
  export class Agent {
9
- client;
10
- basePath;
11
- getBaseParams;
12
- getBaseUrl;
9
+ #client;
10
+ #basePath;
11
+ #getBaseParams;
12
+ #getBaseUrl;
13
13
  constructor({ client, path = "/", getUrlParams = () => ({}), getBaseUrl = () => client.baseUrl, }) {
14
- this.client = client;
15
- this.getBaseParams = getUrlParams;
16
- this.getBaseUrl = getBaseUrl;
17
- this.basePath = path;
14
+ this.#client = client;
15
+ this.#getBaseParams = getUrlParams;
16
+ this.#getBaseUrl = getBaseUrl;
17
+ this.#basePath = path;
18
18
  }
19
19
  request({ method, path = "", urlParamKeys = [], queryParamKeys = [], catchNotFound = false, keyTransform, payloadKey, returnResourceIdInLocationHeader, ignoredKeys, headers, }) {
20
20
  return async (payload = {}, options) => {
21
- const baseParams = this.getBaseParams?.() ?? {};
21
+ const baseParams = this.#getBaseParams?.() ?? {};
22
22
  // Filter query parameters by queryParamKeys
23
23
  const queryParams = queryParamKeys.length > 0 ? pick(payload, queryParamKeys) : undefined;
24
24
  // Add filtered payload parameters to base parameters
@@ -33,10 +33,10 @@ export class Agent {
33
33
  }
34
34
  // Transform keys of both payload and queryParams
35
35
  if (keyTransform) {
36
- this.transformKey(payload, keyTransform);
37
- this.transformKey(queryParams, keyTransform);
36
+ this.#transformKey(payload, keyTransform);
37
+ this.#transformKey(queryParams, keyTransform);
38
38
  }
39
- return this.requestWithParams({
39
+ return this.#requestWithParams({
40
40
  method,
41
41
  path,
42
42
  payload,
@@ -44,7 +44,7 @@ export class Agent {
44
44
  queryParams,
45
45
  // catchNotFound precedence: global > local > default
46
46
  catchNotFound,
47
- ...(this.client.getGlobalRequestArgOptions() ?? options ?? {}),
47
+ ...(this.#client.getGlobalRequestArgOptions() ?? options ?? {}),
48
48
  payloadKey,
49
49
  returnResourceIdInLocationHeader,
50
50
  headers,
@@ -53,7 +53,7 @@ export class Agent {
53
53
  }
54
54
  updateRequest({ method, path = "", urlParamKeys = [], queryParamKeys = [], catchNotFound = false, keyTransform, payloadKey, returnResourceIdInLocationHeader, headers, }) {
55
55
  return async (query = {}, payload = {}) => {
56
- const baseParams = this.getBaseParams?.() ?? {};
56
+ const baseParams = this.#getBaseParams?.() ?? {};
57
57
  // Filter query parameters by queryParamKeys
58
58
  const queryParams = queryParamKeys
59
59
  ? pick(query, queryParamKeys)
@@ -66,9 +66,9 @@ export class Agent {
66
66
  };
67
67
  // Transform keys of queryParams
68
68
  if (keyTransform) {
69
- this.transformKey(queryParams, keyTransform);
69
+ this.#transformKey(queryParams, keyTransform);
70
70
  }
71
- return this.requestWithParams({
71
+ return this.#requestWithParams({
72
72
  method,
73
73
  path,
74
74
  payload,
@@ -81,16 +81,16 @@ export class Agent {
81
81
  });
82
82
  };
83
83
  }
84
- async requestWithParams({ method, path, payload, urlParams, queryParams, catchNotFound, payloadKey, returnResourceIdInLocationHeader, headers, }) {
85
- const newPath = urlJoin(this.basePath, path);
84
+ async #requestWithParams({ method, path, payload, urlParams, queryParams, catchNotFound, payloadKey, returnResourceIdInLocationHeader, headers, }) {
85
+ const newPath = urlJoin(this.#basePath, path);
86
86
  // Parse template and replace with values from urlParams
87
87
  const pathTemplate = parseTemplate(newPath);
88
88
  const parsedPath = pathTemplate.expand(urlParams);
89
- const url = new URL(`${this.getBaseUrl?.() ?? ""}${parsedPath}`);
90
- const requestOptions = { ...this.client.getRequestOptions() };
89
+ const url = new URL(`${this.#getBaseUrl?.() ?? ""}${parsedPath}`);
90
+ const requestOptions = { ...this.#client.getRequestOptions() };
91
91
  const requestHeaders = new Headers([
92
92
  ...new Headers(requestOptions.headers).entries(),
93
- ["authorization", `Bearer ${await this.client.getAccessToken()}`],
93
+ ["authorization", `Bearer ${await this.#client.getAccessToken()}`],
94
94
  ["accept", "application/json, text/plain, */*"],
95
95
  ...new Headers(headers).entries(),
96
96
  ]);
@@ -156,7 +156,7 @@ export class Agent {
156
156
  throw err;
157
157
  }
158
158
  }
159
- transformKey(payload, keyMapping) {
159
+ #transformKey(payload, keyMapping) {
160
160
  if (!payload) {
161
161
  return;
162
162
  }
@@ -6,12 +6,21 @@ import type RoleRepresentation from "../defs/roleRepresentation.js";
6
6
  import type { RoleMappingPayload } from "../defs/roleRepresentation.js";
7
7
  import type UserRepresentation from "../defs/userRepresentation.js";
8
8
  import Resource from "./resource.js";
9
- export interface GroupQuery {
9
+ interface Query {
10
+ search?: string;
11
+ exact?: boolean;
12
+ }
13
+ interface PaginatedQuery {
10
14
  first?: number;
11
15
  max?: number;
12
- search?: string;
16
+ }
17
+ interface SummarizedQuery {
13
18
  briefRepresentation?: boolean;
14
19
  }
20
+ export type GroupQuery = Query & PaginatedQuery & SummarizedQuery;
21
+ export type SubGroupQuery = PaginatedQuery & SummarizedQuery & {
22
+ parentId: string;
23
+ };
15
24
  export interface GroupCountQuery {
16
25
  search?: string;
17
26
  top?: boolean;
@@ -19,7 +28,7 @@ export interface GroupCountQuery {
19
28
  export declare class Groups extends Resource<{
20
29
  realm?: string;
21
30
  }> {
22
- find: (payload?: (GroupQuery & {
31
+ find: (payload?: (Query & PaginatedQuery & SummarizedQuery & {
23
32
  realm?: string | undefined;
24
33
  }) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<GroupRepresentation[]>;
25
34
  create: (payload?: (GroupRepresentation & {
@@ -84,6 +93,14 @@ export declare class Groups extends Resource<{
84
93
  } & {
85
94
  realm?: string | undefined;
86
95
  }, payload: GroupRepresentation) => Promise<void>;
96
+ /**
97
+ * Finds all subgroups on the specified parent group matching the provided parameters.
98
+ */
99
+ listSubGroups: (payload?: (PaginatedQuery & SummarizedQuery & {
100
+ parentId: string;
101
+ } & {
102
+ realm?: string | undefined;
103
+ }) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<GroupRepresentation[]>;
87
104
  /**
88
105
  * Members
89
106
  */
@@ -181,3 +198,4 @@ export declare class Groups extends Resource<{
181
198
  }) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<ManagementPermissionReference>;
182
199
  constructor(client: KeycloakAdminClient);
183
200
  }
201
+ export {};
@@ -2,6 +2,7 @@ import Resource from "./resource.js";
2
2
  export class Groups extends Resource {
3
3
  find = this.makeRequest({
4
4
  method: "GET",
5
+ queryParamKeys: ["search", "exact", "briefRepresentation", "first", "max"],
5
6
  });
6
7
  create = this.makeRequest({
7
8
  method: "POST",
@@ -62,6 +63,16 @@ export class Groups extends Resource {
62
63
  path: "/{id}/children",
63
64
  urlParamKeys: ["id"],
64
65
  });
66
+ /**
67
+ * Finds all subgroups on the specified parent group matching the provided parameters.
68
+ */
69
+ listSubGroups = this.makeRequest({
70
+ method: "GET",
71
+ path: "/{parentId}/children",
72
+ urlParamKeys: ["parentId"],
73
+ queryParamKeys: ["first", "max", "briefRepresentation"],
74
+ catchNotFound: true,
75
+ });
65
76
  /**
66
77
  * Members
67
78
  */
@@ -1,7 +1,7 @@
1
1
  import type { KeycloakAdminClient } from "../client.js";
2
2
  import { RequestArgs } from "./agent.js";
3
3
  export default class Resource<ParamType = {}> {
4
- private agent;
4
+ #private;
5
5
  constructor(client: KeycloakAdminClient, settings?: {
6
6
  path?: string;
7
7
  getUrlParams?: () => Record<string, any>;
@@ -1,17 +1,17 @@
1
1
  import { Agent } from "./agent.js";
2
2
  export default class Resource {
3
- agent;
3
+ #agent;
4
4
  constructor(client, settings = {}) {
5
- this.agent = new Agent({
5
+ this.#agent = new Agent({
6
6
  client,
7
7
  ...settings,
8
8
  });
9
9
  }
10
10
  makeRequest = (args) => {
11
- return this.agent.request(args);
11
+ return this.#agent.request(args);
12
12
  };
13
13
  // update request will take three types: query, payload and response
14
14
  makeUpdateRequest = (args) => {
15
- return this.agent.updateRequest(args);
15
+ return this.#agent.updateRequest(args);
16
16
  };
17
17
  }
@@ -1,7 +1,15 @@
1
1
  import Resource from "./resource.js";
2
2
  import type { ServerInfoRepresentation } from "../defs/serverInfoRepesentation.js";
3
3
  import type KeycloakAdminClient from "../index.js";
4
+ import type EffectiveMessageBundleRepresentation from "../defs/effectiveMessageBundleRepresentation.js";
4
5
  export declare class ServerInfo extends Resource {
5
6
  constructor(client: KeycloakAdminClient);
6
7
  find: (payload?: {} | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<ServerInfoRepresentation>;
8
+ findEffectiveMessageBundles: (payload?: {
9
+ realm: string;
10
+ theme?: string | undefined;
11
+ themeType?: string | undefined;
12
+ locale?: string | undefined;
13
+ source?: boolean | undefined;
14
+ } | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<EffectiveMessageBundleRepresentation[]>;
7
15
  }
@@ -2,12 +2,18 @@ import Resource from "./resource.js";
2
2
  export class ServerInfo extends Resource {
3
3
  constructor(client) {
4
4
  super(client, {
5
- path: "/admin/serverinfo",
5
+ path: "/",
6
6
  getBaseUrl: () => client.baseUrl,
7
7
  });
8
8
  }
9
9
  find = this.makeRequest({
10
10
  method: "GET",
11
- path: "/",
11
+ path: "/admin/serverinfo",
12
+ });
13
+ findEffectiveMessageBundles = this.makeRequest({
14
+ method: "GET",
15
+ path: "/resources/{realm}/{themeType}/{locale}",
16
+ urlParamKeys: ["realm", "themeType", "locale"],
17
+ queryParamKeys: ["theme", "source"],
12
18
  });
13
19
  }
@@ -1,15 +1,16 @@
1
- import Resource from "./resource.js";
2
- import type UserRepresentation from "../defs/userRepresentation.js";
3
- import type UserConsentRepresentation from "../defs/userConsentRepresentation.js";
4
- import type UserSessionRepresentation from "../defs/userSessionRepresentation.js";
5
1
  import type { KeycloakAdminClient } from "../client.js";
2
+ import type CredentialRepresentation from "../defs/credentialRepresentation.js";
3
+ import type FederatedIdentityRepresentation from "../defs/federatedIdentityRepresentation.js";
4
+ import type GroupRepresentation from "../defs/groupRepresentation.js";
6
5
  import type MappingsRepresentation from "../defs/mappingsRepresentation.js";
7
6
  import type RoleRepresentation from "../defs/roleRepresentation.js";
8
7
  import type { RoleMappingPayload } from "../defs/roleRepresentation.js";
9
- import type FederatedIdentityRepresentation from "../defs/federatedIdentityRepresentation.js";
10
- import type GroupRepresentation from "../defs/groupRepresentation.js";
11
- import type CredentialRepresentation from "../defs/credentialRepresentation.js";
12
- import type UserProfileConfig from "../defs/userProfileConfig.js";
8
+ import type UserConsentRepresentation from "../defs/userConsentRepresentation.js";
9
+ import type UserProfileConfig from "../defs/userProfileMetadata.js";
10
+ import type { UserProfileMetadata } from "../defs/userProfileMetadata.js";
11
+ import type UserRepresentation from "../defs/userRepresentation.js";
12
+ import type UserSessionRepresentation from "../defs/userSessionRepresentation.js";
13
+ import Resource from "./resource.js";
13
14
  interface SearchQuery {
14
15
  search?: string;
15
16
  }
@@ -66,6 +67,9 @@ export declare class Users extends Resource<{
66
67
  updateProfile: (payload?: (UserProfileConfig & {
67
68
  realm?: string | undefined;
68
69
  }) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<UserProfileConfig>;
70
+ getProfileMetadata: (payload?: {
71
+ realm?: string | undefined;
72
+ } | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<UserProfileMetadata>;
69
73
  /**
70
74
  * role mappings
71
75
  */
@@ -38,6 +38,10 @@ export class Users extends Resource {
38
38
  method: "PUT",
39
39
  path: "/profile",
40
40
  });
41
+ getProfileMetadata = this.makeRequest({
42
+ method: "GET",
43
+ path: "/profile/metadata",
44
+ });
41
45
  /**
42
46
  * role mappings
43
47
  */
@@ -5,7 +5,9 @@ export declare class WhoAmI extends Resource<{
5
5
  realm?: string;
6
6
  }> {
7
7
  constructor(client: KeycloakAdminClient);
8
- find: (payload?: {
8
+ find: (payload?: ({
9
+ currentRealm: string;
10
+ } & {
9
11
  realm?: string | undefined;
10
- } | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<WhoAmIRepresentation>;
12
+ }) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<WhoAmIRepresentation>;
11
13
  }
@@ -12,5 +12,6 @@ export class WhoAmI extends Resource {
12
12
  find = this.makeRequest({
13
13
  method: "GET",
14
14
  path: "/whoami",
15
+ queryParamKeys: ["currentRealm"],
15
16
  });
16
17
  }
@@ -1,15 +1,25 @@
1
1
  export function stringifyQueryParams(params) {
2
- return new URLSearchParams(Object.entries(params).filter((param) => {
3
- const [, value] = param;
4
- if (typeof value === "undefined" || value === null) {
5
- return false;
2
+ const searchParams = new URLSearchParams();
3
+ for (const [key, value] of Object.entries(params)) {
4
+ // Ignore undefined and null values.
5
+ if (value === undefined || value === null) {
6
+ continue;
6
7
  }
8
+ // Ignore empty strings.
7
9
  if (typeof value === "string" && value.length === 0) {
8
- return false;
10
+ continue;
9
11
  }
12
+ // Ignore empty arrays.
10
13
  if (Array.isArray(value) && value.length === 0) {
11
- return false;
14
+ continue;
12
15
  }
13
- return true;
14
- })).toString();
16
+ // Append each entry of an array as a separate parameter, or the value itself otherwise.
17
+ if (Array.isArray(value)) {
18
+ value.forEach((item) => searchParams.append(key, item.toString()));
19
+ }
20
+ else {
21
+ searchParams.append(key, value.toString());
22
+ }
23
+ }
24
+ return searchParams.toString();
15
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keycloak/keycloak-admin-client",
3
- "version": "22.0.4",
3
+ "version": "23.0.0",
4
4
  "description": "A client to interact with Keycloak's Administration API",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -37,12 +37,12 @@
37
37
  "url-template": "^3.1.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@faker-js/faker": "^8.0.2",
41
- "@types/chai": "^4.3.5",
42
- "@types/lodash-es": "^4.17.7",
43
- "@types/mocha": "^10.0.1",
44
- "@types/node": "^20.4.1",
45
- "chai": "^4.3.7",
40
+ "@faker-js/faker": "^8.3.1",
41
+ "@types/chai": "^4.3.11",
42
+ "@types/lodash-es": "^4.17.12",
43
+ "@types/mocha": "^10.0.6",
44
+ "@types/node": "^20.9.4",
45
+ "chai": "^4.3.10",
46
46
  "mocha": "^10.2.0",
47
47
  "ts-node": "^10.9.1"
48
48
  },