mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
Add timeout option for keycloak-admin-client
Closes #42644 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
94ee6d81fb
commit
40eb51f10c
@ -19,6 +19,8 @@ import { WhoAmI } from "./resources/whoAmI.js";
|
|||||||
import { Credentials, getToken } from "./utils/auth.js";
|
import { Credentials, getToken } from "./utils/auth.js";
|
||||||
import { defaultBaseUrl, defaultRealm } from "./utils/constants.js";
|
import { defaultBaseUrl, defaultRealm } from "./utils/constants.js";
|
||||||
|
|
||||||
|
export type RequestOptions = Omit<RequestInit, "signal">;
|
||||||
|
|
||||||
export interface TokenProvider {
|
export interface TokenProvider {
|
||||||
getAccessToken: () => Promise<string | undefined>;
|
getAccessToken: () => Promise<string | undefined>;
|
||||||
}
|
}
|
||||||
@ -26,8 +28,9 @@ export interface TokenProvider {
|
|||||||
export interface ConnectionConfig {
|
export interface ConnectionConfig {
|
||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
realmName?: string;
|
realmName?: string;
|
||||||
requestOptions?: RequestInit;
|
requestOptions?: RequestOptions;
|
||||||
requestArgOptions?: Pick<RequestArgs, "catchNotFound">;
|
requestArgOptions?: Pick<RequestArgs, "catchNotFound">;
|
||||||
|
timeout?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KeycloakAdminClient {
|
export class KeycloakAdminClient {
|
||||||
@ -56,14 +59,16 @@ export class KeycloakAdminClient {
|
|||||||
public scope?: string;
|
public scope?: string;
|
||||||
public accessToken?: string;
|
public accessToken?: string;
|
||||||
public refreshToken?: string;
|
public refreshToken?: string;
|
||||||
|
public timeout?: number;
|
||||||
|
|
||||||
#requestOptions?: RequestInit;
|
#requestOptions?: RequestOptions;
|
||||||
#globalRequestArgOptions?: Pick<RequestArgs, "catchNotFound">;
|
#globalRequestArgOptions?: Pick<RequestArgs, "catchNotFound">;
|
||||||
#tokenProvider?: TokenProvider;
|
#tokenProvider?: TokenProvider;
|
||||||
|
|
||||||
constructor(connectionConfig?: ConnectionConfig) {
|
constructor(connectionConfig?: ConnectionConfig) {
|
||||||
this.baseUrl = connectionConfig?.baseUrl || defaultBaseUrl;
|
this.baseUrl = connectionConfig?.baseUrl || defaultBaseUrl;
|
||||||
this.realmName = connectionConfig?.realmName || defaultRealm;
|
this.realmName = connectionConfig?.realmName || defaultRealm;
|
||||||
|
this.timeout = connectionConfig?.timeout;
|
||||||
this.#requestOptions = connectionConfig?.requestOptions;
|
this.#requestOptions = connectionConfig?.requestOptions;
|
||||||
this.#globalRequestArgOptions = connectionConfig?.requestArgOptions;
|
this.#globalRequestArgOptions = connectionConfig?.requestArgOptions;
|
||||||
|
|
||||||
@ -93,7 +98,10 @@ export class KeycloakAdminClient {
|
|||||||
realmName: this.realmName,
|
realmName: this.realmName,
|
||||||
scope: this.scope,
|
scope: this.scope,
|
||||||
credentials,
|
credentials,
|
||||||
requestOptions: this.#requestOptions,
|
requestOptions: {
|
||||||
|
...this.#requestOptions,
|
||||||
|
...(this.timeout ? { signal: AbortSignal.timeout(this.timeout) } : {}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
this.refreshToken = refreshToken;
|
this.refreshToken = refreshToken;
|
||||||
|
|||||||
@ -248,6 +248,9 @@ export class Agent {
|
|||||||
...requestOptions,
|
...requestOptions,
|
||||||
headers: requestHeaders,
|
headers: requestHeaders,
|
||||||
method,
|
method,
|
||||||
|
...(this.#client.timeout
|
||||||
|
? { signal: AbortSignal.timeout(this.#client.timeout) }
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// now we get the response of the http request
|
// 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");
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user