Configuration
Advanced configuration options for the TypeScript SDK including retry policies, interceptors, and custom transports.
Configuration
The AvnologyId client can be customized extensively for different deployment scenarios -- server-side services, browser SPAs, edge functions, and test environments.
Basic configuration
import { AvnologyId } from "@avnology/sdk-typescript";
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
timeout: 15000,
retries: 2,
});Retry policy
The SDK retries requests on transient failures (network errors, 429 rate limits, 502/503/504 server errors). Each retry uses exponential backoff with jitter.
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
// Retry configuration
retries: 5, // Max retry attempts (default: 3)
retryDelay: 500, // Initial delay in ms (default: 1000)
retryMaxDelay: 30000, // Maximum delay cap in ms (default: 30000)
retryStatusCodes: [429, 502, 503, 504], // HTTP codes to retry (default)
});Retry behavior by error type
| Error | Retried | Notes |
|---|---|---|
| Network timeout | yes | Retried up to retries times |
| Connection refused | yes | Retried with exponential backoff |
| HTTP 429 (Rate Limit) | yes | Waits for Retry-After header duration |
| HTTP 502/503/504 | yes | Server errors, retried with backoff |
| HTTP 400 (Bad Request) | no | Client error, not retried |
| HTTP 401 (Unauthorized) | no | Token may be refreshed, then retried once |
| HTTP 403 (Forbidden) | no | Permission denied, not retried |
| HTTP 404 (Not Found) | no | Resource missing, not retried |
| HTTP 409 (Conflict) | no | Conflict, not retried |
| HTTP 422 (Validation) | no | Validation error, not retried |
Token management
Automatic token refresh
When autoRefresh is enabled (the default), the SDK automatically refreshes expired access tokens using the refresh token before making API calls.
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
autoRefresh: true, // default
// Called each time tokens are refreshed
onTokenRefresh: (tokens) => {
console.log("New access token:", tokens.accessToken);
console.log("New refresh token:", tokens.refreshToken);
// Persist tokens to storage
localStorage.setItem("tokens", JSON.stringify(tokens));
},
});Manual token management
For full control over token lifecycle, disable auto-refresh and manage tokens yourself.
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
autoRefresh: false,
});
// Set tokens explicitly
client.setTokens({
accessToken: "eyJ...",
refreshToken: "rt_...",
expiresAt: new Date("2026-04-09T12:00:00Z"),
});
// Manually refresh when needed
const newTokens = await client.oauth.refreshToken({
refreshToken: "rt_...",
});
client.setTokens(newTokens);Session cookie mode
For browser applications using HTTP-only session cookies (no explicit tokens), configure the client to include credentials.
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
credentials: "include", // Send cookies with every request
autoRefresh: false, // Cookies are managed by the browser
});Custom fetch
Override the global fetch to add logging, custom headers, or use a different HTTP client.
import { AvnologyId } from "@avnology/sdk-typescript";
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
fetch: async (input, init) => {
console.log(`[Avnology] ${init?.method ?? "GET"} ${input}`);
const start = performance.now();
const response = await globalThis.fetch(input, init);
const duration = performance.now() - start;
console.log(`[Avnology] ${response.status} in ${duration.toFixed(0)}ms`);
return response;
},
});Request interceptors
Add headers or transform requests before they are sent.
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
headers: {
"X-Request-Source": "my-app",
"X-Correlation-Id": () => crypto.randomUUID(), // Dynamic header
},
// Transform every request
onRequest: (request) => {
request.headers.set("X-Trace-Id", getTraceId());
return request;
},
// Transform every response
onResponse: (response) => {
const rateLimit = response.headers.get("RateLimit-Remaining");
if (rateLimit && parseInt(rateLimit) < 10) {
console.warn("Approaching rate limit:", rateLimit, "remaining");
}
return response;
},
});Error handling
Global error handler
Register a global error handler for logging or telemetry.
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
onError: (error) => {
// Send to error tracking service
Sentry.captureException(error, {
tags: {
errorCode: error.code,
statusCode: error.statusCode,
},
});
},
});Per-request abort
Cancel individual requests using AbortController.
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const users = await client.admin.listUsers({
pageSize: 100,
signal: controller.signal,
});
} catch (error) {
if (error.name === "AbortError") {
console.log("Request was cancelled");
}
}Environment-specific configuration
Server-side (Node.js / Bun / Deno)
const client = new AvnologyId({
baseUrl: process.env.AVNOLOGY_BASE_URL!,
clientId: process.env.AVNOLOGY_CLIENT_ID!,
clientSecret: process.env.AVNOLOGY_CLIENT_SECRET!,
timeout: 10000,
retries: 3,
});Browser SPA
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
credentials: "include",
timeout: 30000,
autoRefresh: true,
onTokenRefresh: (tokens) => {
sessionStorage.setItem("avnology_tokens", JSON.stringify(tokens));
},
});Edge function (Cloudflare Workers)
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const client = new AvnologyId({
baseUrl: env.AVNOLOGY_BASE_URL,
apiKey: env.AVNOLOGY_API_KEY,
timeout: 5000, // Edge functions have strict time limits
retries: 1,
});
const session = await client.getSession();
return new Response(JSON.stringify(session));
},
};Testing
import { AvnologyId, createMockClient } from "@avnology/sdk-typescript/testing";
const mockClient = createMockClient({
baseUrl: "http://localhost:4455",
// All methods return mock data by default
// Override specific methods:
overrides: {
login: async () => ({
id: "session_test",
identity: { id: "user_test", email: "[email protected]" },
expiresAt: new Date("2099-01-01").toISOString(),
}),
},
});See also
- TypeScript SDK index -- Installation and quick start
- Error types -- Error class hierarchy
- Testing guide -- Testing patterns and mocks