Source: common.js

import * as fs from 'fs';
import {APIError, InvalidArgumentException} from "./exception.js";

/**
 * Module-level override for the API base endpoint. Empty means use the
 * region-based default. Set via {@link SetEndpoint}.
 *
 * @private
 * @type {string}
 */
var _endpoint = ''

/**
 * Normalize an image/file input into the value expected by the API. The input
 * may be a cache reference ("ref:..."), a URL, a local file path (which is read
 * and base64-encoded), or an already-base64-encoded/long string.
 *
 * @param {string} str Input value: a "ref:" cache reference, a URL, a local
 *   file path, or a base64-encoded image string.
 * @param {boolean} [allowCache=false] If `true`, a value starting with "ref:"
 *   is returned unchanged as a cache reference.
 * @returns {string} The URL, cache reference, or base64-encoded file contents.
 * @throws {InvalidArgumentException} If the input is neither a valid URL, an
 *   existing file, nor a sufficiently long string to be treated as inline data.
 */
export function ParseInput(str, allowCache=false) {
    if(allowCache && str.slice(0, 4) === 'ref:') {
        return str
    }
    try {
        new URL(str)
        return str
    } catch (e) {}

    if (fs.existsSync(str)) {
        let data = fs.readFileSync(str)
        return Buffer.from(data).toString('base64')
    }

    if(str.length > 100) {
        return str
    }
    throw new InvalidArgumentException('Invalid input image, file not found or malformed URL.')
}

/**
 * Map of supported region codes to their API base URLs.
 *
 * @private
 * @type {Object<string, string>}
 */
const REGION_ENDPOINTS = {
    us: 'https://api2.idanalyzer.com',
    eu: 'https://api2-eu.idanalyzer.com',
}

/**
 * Resolve a request URI into a fully-qualified URL. Absolute URLs are returned
 * unchanged. Otherwise the URI is resolved against the override endpoint set by
 * {@link SetEndpoint}, or, if none is set, against the base URL for the region
 * given by the `IDANALYZER_REGION` environment variable (defaults to "us").
 *
 * @param {string} uri An absolute URL, or a path relative to the API base URL.
 * @returns {string} The fully-qualified request URL.
 * @throws {InvalidArgumentException} If `IDANALYZER_REGION` is set to an unsupported region.
 */
export function GetEndpoint(uri) {
    if (uri.slice(0, 4).toLowerCase() === 'http')
        return uri

    if(_endpoint !== '') {
        let u = new URL(uri, _endpoint)
        return u.href
    }

    let region = (process.env.IDANALYZER_REGION || 'us').toLowerCase()
    if(!(region in REGION_ENDPOINTS)) {
        throw new InvalidArgumentException(`Invalid IDANALYZER_REGION '${region}', valid regions are: us, eu.`)
    }
    return `${REGION_ENDPOINTS[region]}/${uri}`
}

/**
 * Override the API base endpoint for all subsequent requests, bypassing the
 * region-based default. Pass an empty string to clear the override and revert
 * to region-based resolution.
 *
 * @param {string} [endpoint=''] Fully-qualified base URL to use as the API endpoint.
 * @returns {void}
 * @throws {TypeError} If `endpoint` is not a valid URL.
 */
export function SetEndpoint(endpoint='') {
    let i = new URL('', endpoint)
    _endpoint = endpoint
}

/**
 * Inspect a decoded API response and optionally raise on an error payload.
 *
 * @param {Object<string, *>} respJson The decoded JSON response body.
 * @param {boolean} throwError If `true` and the response contains an `error`
 *   object, an {@link APIError} is thrown instead of returning the response.
 * @returns {Object<string, *>} The original response object (when not throwing).
 * @throws {APIError} If `throwError` is `true` and the response contains an error.
 */
export function ApiExceptionHandle(respJson, throwError) {
    if ('error' in respJson && throwError) {
        throw new APIError(respJson['error']['message'], respJson['error']['code'])
    }
    return respJson
}