Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 50x 50x 50x 50x 50x 1x 49x 1x 48x 50x 50x 50x 3x 50x 58x 58x 58x 116x 58x | // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
// SPDX-License-Identifier: Apache-2.0
/**
* @module MCP/imf/utils
* @description Configuration-resolution and URL utilities for the IMF SDMX client.
*/
import type { IMFClientOptions } from './types.js';
import { DEFAULT_IMF_API_BASE_URL, DEFAULT_IMF_API_TIMEOUT_MS } from './config.js';
/**
* Resolve the IMF base URL and per-request timeout from constructor options
* and environment variables.
* @param options - Client constructor options (may be empty `{}`).
* @returns Resolved `base` URL string and `timeout` in milliseconds.
* @internal
*/
export function readBaseAndTimeout(options: IMFClientOptions): { base: string; timeout: number } {
const envBase = process.env['IMF_API_BASE_URL'];
const envTimeout = process.env['IMF_API_TIMEOUT_MS'];
const parsedEnvTimeout =
envTimeout !== undefined && envTimeout !== '' ? Number.parseInt(envTimeout, 10) : Number.NaN;
const base =
options.apiBaseUrl ?? (envBase && envBase !== '' ? envBase : DEFAULT_IMF_API_BASE_URL);
let timeout: number;
if (
options.timeoutMs !== undefined &&
Number.isFinite(options.timeoutMs) &&
options.timeoutMs > 0
) {
timeout = options.timeoutMs;
} else if (Number.isFinite(parsedEnvTimeout) && parsedEnvTimeout > 0) {
timeout = parsedEnvTimeout;
} else {
timeout = DEFAULT_IMF_API_TIMEOUT_MS;
}
return { base, timeout };
}
/**
* Strip trailing slashes without using a regex, so the CodeQL polynomial-
* ReDoS detector has nothing to flag. Single linear pass from the right.
* @param s - Input URL or path string.
* @returns The string with all trailing `/` characters removed.
* @internal
*/
export function stripTrailingSlashes(s: string): string {
let end = s.length;
while (end > 0 && s.charCodeAt(end - 1) === 47) {
end -= 1;
}
return end === s.length ? s : s.slice(0, end);
}
/**
* Read IMF Azure-APIM subscription keys from the environment, in priority
* order (primary, then secondary). Empty / unset / duplicate keys are
* filtered out so the returned array is `[]` only when no key is set at all.
*
* @returns Ordered list of candidate API keys (length 0–2).
*/
export function readImfSubscriptionKeysFromEnv(): readonly string[] {
const candidates = [process.env['IMF_API_PRIMARY_KEY'], process.env['IMF_API_SECONDARY_KEY']];
const keys: string[] = [];
for (const k of candidates) {
if (typeof k === 'string' && k.length > 0 && !keys.includes(k)) keys.push(k);
}
return keys;
}
|