mirror of
https://github.com/keycloak/keycloak.git
synced 2025-12-16 12:05:49 -06:00
Add timeout option for keycloak-admin-client
Closes #42644 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
@@ -19,6 +19,8 @@ import { WhoAmI } from "./resources/whoAmI.js";
|
||||
import { Credentials, getToken } from "./utils/auth.js";
|
||||
import { defaultBaseUrl, defaultRealm } from "./utils/constants.js";
|
||||
|
||||
export type RequestOptions = Omit<RequestInit, "signal">;
|
||||
|
||||
export interface TokenProvider {
|
||||
getAccessToken: () => Promise<string | undefined>;
|
||||
}
|
||||
@@ -26,8 +28,9 @@ export interface TokenProvider {
|
||||
export interface ConnectionConfig {
|
||||
baseUrl?: string;
|
||||
realmName?: string;
|
||||
requestOptions?: RequestInit;
|
||||
requestOptions?: RequestOptions;
|
||||
requestArgOptions?: Pick<RequestArgs, "catchNotFound">;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export class KeycloakAdminClient {
|
||||
@@ -56,14 +59,16 @@ export class KeycloakAdminClient {
|
||||
public scope?: string;
|
||||
public accessToken?: string;
|
||||
public refreshToken?: string;
|
||||
public timeout?: number;
|
||||
|
||||
#requestOptions?: RequestInit;
|
||||
#requestOptions?: RequestOptions;
|
||||
#globalRequestArgOptions?: Pick<RequestArgs, "catchNotFound">;
|
||||
#tokenProvider?: TokenProvider;
|
||||
|
||||
constructor(connectionConfig?: ConnectionConfig) {
|
||||
this.baseUrl = connectionConfig?.baseUrl || defaultBaseUrl;
|
||||
this.realmName = connectionConfig?.realmName || defaultRealm;
|
||||
this.timeout = connectionConfig?.timeout;
|
||||
this.#requestOptions = connectionConfig?.requestOptions;
|
||||
this.#globalRequestArgOptions = connectionConfig?.requestArgOptions;
|
||||
|
||||
@@ -93,7 +98,10 @@ export class KeycloakAdminClient {
|
||||
realmName: this.realmName,
|
||||
scope: this.scope,
|
||||
credentials,
|
||||
requestOptions: this.#requestOptions,
|
||||
requestOptions: {
|
||||
...this.#requestOptions,
|
||||
...(this.timeout ? { signal: AbortSignal.timeout(this.timeout) } : {}),
|
||||
},
|
||||
});
|
||||
this.accessToken = accessToken;
|
||||
this.refreshToken = refreshToken;
|
||||
|
||||
@@ -248,6 +248,9 @@ export class Agent {
|
||||
...requestOptions,
|
||||
headers: requestHeaders,
|
||||
method,
|
||||
...(this.#client.timeout
|
||||
? { signal: AbortSignal.timeout(this.#client.timeout) }
|
||||
: {}),
|
||||
});
|
||||
|
||||
// now we get the response of the http request
|
||||
|
||||
53
js/libs/keycloak-admin-client/test/timeout.spec.ts
Normal file
53
js/libs/keycloak-admin-client/test/timeout.spec.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { expect } from "chai";
|
||||
import { KeycloakAdminClient } from "../src/client.js";
|
||||
import { credentials } from "./constants.js";
|
||||
import { Server, createServer } from "node:http";
|
||||
|
||||
describe("Timeout", () => {
|
||||
let server: Server;
|
||||
|
||||
before(async () => {
|
||||
server = createServer((req, res) => {
|
||||
res.writeHead(200, { "Content-Type": "text/plain" });
|
||||
setTimeout(() => res.end("Hello, world!\n"), 1500);
|
||||
});
|
||||
server.listen(8888, "localhost");
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await server[Symbol.asyncDispose]();
|
||||
});
|
||||
|
||||
void it("create without timeout", async () => {
|
||||
const client = new KeycloakAdminClient({
|
||||
baseUrl: "http://localhost:8888",
|
||||
});
|
||||
|
||||
try {
|
||||
await client.auth(credentials);
|
||||
} catch (error) {
|
||||
expect(error).to.be.an("Error");
|
||||
expect((error as Error).message).to.contain("Unexpected token 'H'");
|
||||
return;
|
||||
}
|
||||
expect.fail(null, null, "auth did not fail");
|
||||
});
|
||||
|
||||
void it("create with timeout", async () => {
|
||||
const client = new KeycloakAdminClient({
|
||||
baseUrl: "http://localhost:8888",
|
||||
timeout: 1000,
|
||||
});
|
||||
|
||||
try {
|
||||
await client.auth(credentials);
|
||||
} catch (error) {
|
||||
expect(error).to.be.an("DOMException");
|
||||
expect((error as DOMException).message).to.contain(
|
||||
"The operation was aborted due to timeout",
|
||||
);
|
||||
return;
|
||||
}
|
||||
expect.fail(null, null, "auth did not fail");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user