UNPKG

@rudderstack/integrations-lib

Version:

A comprehensive TypeScript library providing shared utilities, SDKs, and tools for RudderStack integrations and destinations.

281 lines 36.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AxiosClient = void 0; /* eslint-disable require-await */ const axios_1 = __importDefault(require("axios")); const http_1 = __importDefault(require("http")); const https_1 = __importDefault(require("https")); const constants_1 = require("../../constants"); const utils_1 = require("../../utils"); // Allowed labels for timing metrics const TIMING_METRIC_LABELS = [ 'feature', 'destType', 'endpointPath', 'requestMethod', 'module', 'workspaceId', 'destinationId', 'implementation', 'sourceId', ]; // Allowed labels for counter metrics const COUNTER_METRIC_LABELS = [ 'feature', 'destType', 'endpointPath', 'success', 'statusCode', 'requestMethod', 'module', 'workspaceId', 'destinationId', 'implementation', 'sourceId', ]; /** * Filters labels to only include allowed keys * @param allLabels - The complete set of labels * @param allowedLabels - Array of allowed label keys * @returns Filtered labels object */ function filterMetricLabels(allLabels, allowedLabels) { return allowedLabels.reduce((filteredLabels, key) => { if (allLabels[key] !== undefined) { return { ...filteredLabels, [key]: allLabels[key] }; } return filteredLabels; }, {}); } /** * A wrapper around axios to make http requests * * @class AxiosClient * @classdesc * The `AxiosClient` class is a wrapper around the axios library that provides a simplified interface for making HTTP requests. It handles various types of errors and provides a consistent response format. * * @param {AxiosRequestConfig} options - The default options for the http client * * @example * const axiosClient = new AxiosClient({ timeout: 1000 * 10 }); * const response = await axiosClient.post("https://example.com", { foo: "bar" }); * if (response.type === "success") { * console.log(response.statusCode); * console.log(response.responseBody); * } else if (response.type === "application-error") { * console.log(response.statusCode); * console.log(response.message); * console.log(response.responseBody); * } else if (response.type === "client-error") { * console.log(response.statusCode); * console.log(response.message); * } */ class AxiosClient { constructor(options, observabilityConfig) { const defaultOptions = { timeout: 1000 * 10, // `withCredentials` indicates whether or not cross-site Access-Control requests should be made using credentials withCredentials: false, // `responseEncoding` indicates encoding to use for decoding responses (Node.js only), responseEncoding: 'utf8', // `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed, maxBodyLength: 1000 * 1000 * 10, // `maxRedirects` defines the maximum number of redirects to follow in node.js, maxRedirects: 5, // `httpAgent` and `httpsAgent` define a custom agent to be used when performing http httpAgent: new http_1.default.Agent({ keepAlive: true }), // and https requests, respectively, in node.js. This allows options to be added like `keepAlive` that are not enabled by default. httpsAgent: new https_1.default.Agent({ keepAlive: true }), }; this.options = { ...defaultOptions, ...options }; this.instance = axios_1.default.create(this.options); // Merge with default config to eliminate null checks const defaultObservabilityConfig = { logger: undefined, statsClient: undefined, defaultStatTags: {}, }; this.observabilityConfig = { ...defaultObservabilityConfig, ...observabilityConfig }; } async makeRequest(config, responseParser) { const startTimestamp = new Date(); // Extract metadata for logging/metrics const method = config.method?.toUpperCase() || 'UNKNOWN'; const url = config.url || 'unknown'; const body = config.data || undefined; const statTags = { ...this.observabilityConfig.defaultStatTags, requestMethod: method, endpointPath: 'default', ...config.statTags, }; const metadataMetricTags = { ...(this.observabilityConfig.defaultStatTags?.metadata || {}), ...(config.statTags?.metadata || {}), }; // Optional request logging const requestLogParams = { requestDetails: { method: method || 'undefined', url: url || 'undefined', body: body || 'undefined', }, metadata: statTags.metadata || {}, }; this.observabilityConfig.logger?.requestLog(`[HTTP] ${method} ${url} request`, requestLogParams); try { const requestConfig = config; const response = await this.instance.request(requestConfig); const { status, data, headers } = response; // Optional response logging const responseLogParams = { responseDetails: { status: status || 0, body: data || 'undefined', headers: headers || 'undefined', }, metadata: statTags.metadata || {}, }; this.observabilityConfig.logger?.responseLog(`[HTTP] ${method} ${url} response`, responseLogParams); // Optional success metrics const allLabels = { ...metadataMetricTags, ...statTags, statusCode: status }; const timingLabels = filterMetricLabels(allLabels, TIMING_METRIC_LABELS); this.observabilityConfig.statsClient?.timing('outgoing_request_latency', startTimestamp, timingLabels); const counterLabels = filterMetricLabels(allLabels, COUNTER_METRIC_LABELS); this.observabilityConfig.statsClient?.counter('outgoing_request_count', 1, counterLabels); if (responseParser) { try { const parsedData = responseParser(data); return { type: 'success', statusCode: status, responseBody: parsedData, headers, }; } catch (error) { const unknownError = error; return { type: 'client-error', // @ts-expect-error: Error has status statusCode: unknownError.status || 500, message: `Failed to parse response data: ${unknownError.message}`, }; } } return { type: 'success', statusCode: status, responseBody: data, headers }; } catch (error) { // Determine status code for error metrics let errorStatusCode = 500; // Default to 500 for network/unknown errors if (axios_1.default.isAxiosError(error)) { const axiosError = error; if (axiosError.response) { errorStatusCode = axiosError.response.status; } } // Optional error logging this.observabilityConfig.logger?.error?.(`[HTTP] ${method} ${url} error`, { error: error.message, statTags: { ...statTags, statusCode: errorStatusCode }, }); // Optional error metrics const allErrorLabels = { ...metadataMetricTags, ...statTags, statusCode: errorStatusCode }; const timingLabels = filterMetricLabels(allErrorLabels, TIMING_METRIC_LABELS); this.observabilityConfig.statsClient?.timing('outgoing_request_latency', startTimestamp, timingLabels); const counterLabels = filterMetricLabels(allErrorLabels, COUNTER_METRIC_LABELS); this.observabilityConfig.statsClient?.counter('outgoing_request_count', 1, counterLabels); if (axios_1.default.isAxiosError(error)) { const axiosError = error; if (axiosError.response) { const { response } = axiosError; return { type: 'application-error', statusCode: response.status, message: response.statusText, responseBody: response.data, headers: response.headers, }; } if (axiosError.code) { const resp = constants_1.NETWORK_STATUS_ERR_MAP[axiosError.code]; if (!resp) { return { type: 'client-error', statusCode: 500, message: `Unknown Error:${axiosError.message}`, }; } return { type: 'client-error', statusCode: resp.status, message: resp.message, }; } } const unknownError = error; const status = 500; const message = unknownError.message || 'Unknown Error'; return { type: 'client-error', statusCode: status, message }; } } async get(url, options, responseParser) { let config = { method: 'get', url, }; if ((0, utils_1.isNotEmpty)(options)) { config = { ...config, ...options }; } return this.makeRequest(config, responseParser); } async post(url, data, options, responseParser) { let config = { method: 'post', url, data, }; if ((0, utils_1.isNotEmpty)(options)) { config = { ...config, ...options }; } return this.makeRequest(config, responseParser); } async put(url, data, options, responseParser) { let config = { method: 'put', url, data, }; if ((0, utils_1.isNotEmpty)(options)) { config = { ...config, ...options }; } return this.makeRequest(config, responseParser); } async patch(url, data, options, responseParser) { let config = { method: 'patch', url, data, }; if ((0, utils_1.isNotEmpty)(options)) { config = { ...config, ...options }; } return this.makeRequest(config, responseParser); } async delete(url, options, responseParser) { let config = { method: 'delete', url, }; if ((0, utils_1.isNotEmpty)(options)) { config = { ...config, ...options }; } return this.makeRequest(config, responseParser); } } exports.AxiosClient = AxiosClient; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXhpb3NfY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL25ldHdvcmsvY2xpZW50cy9heGlvc19jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsa0NBQWtDO0FBQ2xDLGtEQUF5RDtBQUN6RCxnREFBd0I7QUFDeEIsa0RBQTBCO0FBQzFCLCtDQUF5RDtBQVd6RCx1Q0FBeUM7QUFFekMsb0NBQW9DO0FBQ3BDLE1BQU0sb0JBQW9CLEdBQUc7SUFDM0IsU0FBUztJQUNULFVBQVU7SUFDVixjQUFjO0lBQ2QsZUFBZTtJQUNmLFFBQVE7SUFDUixhQUFhO0lBQ2IsZUFBZTtJQUNmLGdCQUFnQjtJQUNoQixVQUFVO0NBQ1gsQ0FBQztBQUVGLHFDQUFxQztBQUNyQyxNQUFNLHFCQUFxQixHQUFHO0lBQzVCLFNBQVM7SUFDVCxVQUFVO0lBQ1YsY0FBYztJQUNkLFNBQVM7SUFDVCxZQUFZO0lBQ1osZUFBZTtJQUNmLFFBQVE7SUFDUixhQUFhO0lBQ2IsZUFBZTtJQUNmLGdCQUFnQjtJQUNoQixVQUFVO0NBQ1gsQ0FBQztBQUVGOzs7OztHQUtHO0FBQ0gsU0FBUyxrQkFBa0IsQ0FDekIsU0FBa0MsRUFDbEMsYUFBdUI7SUFFdkIsT0FBTyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUMsY0FBdUMsRUFBRSxHQUFXLEVBQUUsRUFBRTtRQUNuRixJQUFJLFNBQVMsQ0FBQyxHQUFHLENBQUMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNqQyxPQUFPLEVBQUUsR0FBRyxjQUFjLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxTQUFTLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN0RCxDQUFDO1FBQ0QsT0FBTyxjQUFjLENBQUM7SUFDeEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ1QsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCRztBQUNILE1BQWEsV0FBVztJQU90QixZQUFZLE9B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Q3JELENBQUM7Q0FHRjtBQTlRRCxrQ0E4UUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSByZXF1aXJlLWF3YWl0ICovXG5pbXBvcnQgYXhpb3MsIHsgQXhpb3NFcnJvciwgQXhpb3NJbnN0YW5jZSB9IGZyb20gJ2F4aW9zJztcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCB7IE5FVFdPUktfU1RBVFVTX0VSUl9NQVAgfSBmcm9tICcuLi8uLi9jb25zdGFudHMnO1xuaW1wb3J0IHtcbiAgQXBpUmVzcG9uc2UsXG4gIEh0dHBDbGllbnQsXG4gIFJlc3BvbnNlUGFyc2VyLFxuICBBeGlvc0NsaWVudE9ic2VydmFiaWxpdHlDb25maWcsXG4gIFN0YXRUYWdzLFxuICBSZXF1ZXN0TG9nUGFyYW1zLFxuICBSZXNwb25zZUxvZ1BhcmFtcyxcbiAgUmVxdWVzdENvbmZpZyxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBpc05vdEVtcHR5IH0gZnJvbSAnLi4vLi4vdXRpbHMnO1xuXG4vLyBBbGxvd2VkIGxhYmVscyBmb3IgdGltaW5nIG1ldHJpY3NcbmNvbnN0IFRJTUlOR19NRVRSSUNfTEFCRUxTID0gW1xuICAnZmVhdHVyZScsXG4gICdkZXN0VHlwZScsXG4gICdlbmRwb2ludFBhdGgnLFxuICAncmVxdWVzdE1ldGhvZCcsXG4gICdtb2R1bGUnLFxuICAnd29ya3NwYWNlSWQnLFxuICAnZGVzdGluYXRpb25JZCcsXG4gICdpbXBsZW1lbnRhdGlvbicsXG4gICdzb3VyY2VJZCcsXG5dO1xuXG4vLyBBbGxvd2VkIGxhYmVscyBmb3IgY291bnRlciBtZXRyaWNzXG5jb25zdCBDT1VOVEVSX01FVFJJQ19MQUJFTFMgPSBbXG4gICdmZWF0dXJlJyxcbiAgJ2Rlc3RUeXBlJyxcbiAgJ2VuZHBvaW50UGF0aCcsXG4gICdzdWNjZXNzJyxcbiAgJ3N0YXR1c0NvZGUnLFxuICAncmVxdWVzdE1ldGhvZCcsXG4gICdtb2R1bGUnLFxuICAnd29ya3NwYWNlSWQnLFxuICAnZGVzdGluYXRpb25JZCcsXG4gICdpbXBsZW1lbnRhdGlvbicsXG4gICdzb3VyY2VJZCcsXG5dO1xuXG4vKipcbiAqIEZpbHRlcnMgbGFiZWxzIHRvIG9ubHkgaW5jbHVkZSBhbGxvd2VkIGtleXNcbiAqIEBwYXJhbSBhbGxMYWJlbHMgLSBUaGUgY29tcGxldGUgc2V0IG9mIGxhYmVsc1xuICogQHBhcmFtIGFsbG93ZWRMYWJlbHMgLSBBcnJheSBvZiBhbGxvd2VkIGxhYmVsIGtleXNcbiAqIEByZXR1cm5zIEZpbHRlcmVkIGxhYmVscyBvYmplY3RcbiAqL1xuZnVuY3Rpb24gZmlsdGVyTWV0cmljTGFiZWxzKFxuICBhbGxMYWJlbHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBhbGxvd2VkTGFiZWxzOiBzdHJpbmdbXSxcbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgcmV0dXJuIGFsbG93ZWRMYWJlbHMucmVkdWNlKChmaWx0ZXJlZExhYmVsczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGtleTogc3RyaW5nKSA9PiB7XG4gICAgaWYgKGFsbExhYmVsc1trZXldICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB7IC4uLmZpbHRlcmVkTGFiZWxzLCBba2V5XTogYWxsTGFiZWxzW2tleV0gfTtcbiAgICB9XG4gICAgcmV0dXJuIGZpbHRlcmVkTGFiZWxzO1xuICB9LCB7fSk7XG59XG5cbi8qKlxuICogQSB3cmFwcGVyIGFyb3VuZCBheGlvcyB0byBtYWtlIGh0dHAgcmVxdWVzdHNcbiAqXG4gKiBAY2xhc3MgQXhpb3NDbGllbnRcbiAqIEBjbGFzc2Rlc2NcbiAqIFRoZSBgQXhpb3NDbGllbnRgIGNsYXNzIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIGF4aW9zIGxpYnJhcnkgdGhhdCBwcm92aWRlcyBhIHNpbXBsaWZpZWQgaW50ZXJmYWNlIGZvciBtYWtpbmcgSFRUUCByZXF1ZXN0cy4gSXQgaGFuZGxlcyB2YXJpb3VzIHR5cGVzIG9mIGVycm9ycyBhbmQgcHJvdmlkZXMgYSBjb25zaXN0ZW50IHJlc3BvbnNlIGZvcm1hdC5cbiAqXG4gKiBAcGFyYW0ge0F4aW9zUmVxdWVzdENvbmZpZ30gb3B0aW9ucyAtIFRoZSBkZWZhdWx0IG9wdGlvbnMgZm9yIHRoZSBodHRwIGNsaWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBheGlvc0NsaWVudCA9IG5ldyBBeGlvc0NsaWVudCh7IHRpbWVvdXQ6IDEwMDAgKiAxMCB9KTtcbiAqIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgYXhpb3NDbGllbnQucG9zdChcImh0dHBzOi8vZXhhbXBsZS5jb21cIiwgeyBmb286IFwiYmFyXCIgfSk7XG4gKiBpZiAocmVzcG9uc2UudHlwZSA9PT0gXCJzdWNjZXNzXCIpIHtcbiAqICAgY29uc29sZS5sb2cocmVzcG9uc2Uuc3RhdHVzQ29kZSk7XG4gKiAgIGNvbnNvbGUubG9nKHJlc3BvbnNlLnJlc3BvbnNlQm9keSk7XG4gKiB9IGVsc2UgaWYgKHJlc3BvbnNlLnR5cGUgPT09IFwiYXBwbGljYXRpb24tZXJyb3JcIikge1xuICogICBjb25zb2xlLmxvZyhyZXNwb25zZS5zdGF0dXNDb2RlKTtcbiAqICAgY29uc29sZS5sb2cocmVzcG9uc2UubWVzc2FnZSk7XG4gKiAgIGNvbnNvbGUubG9nKHJlc3BvbnNlLnJlc3BvbnNlQm9keSk7XG4gKiB9IGVsc2UgaWYgKHJlc3BvbnNlLnR5cGUgPT09IFwiY2xpZW50LWVycm9yXCIpIHtcbiAqICAgY29uc29sZS5sb2cocmVzcG9uc2Uuc3RhdHVzQ29kZSk7XG4gKiAgIGNvbnNvbGUubG9nKHJlc3BvbnNlLm1lc3NhZ2UpO1xuICogfVxuICovXG5leHBvcnQgY2xhc3MgQXhpb3NDbGllbnQgaW1wbGVtZW50cyBIdHRwQ2xpZW50IHtcbiAgcHJpdmF0ZSBvcHRpb25zOiBSZXF1ZXN0Q29uZmlnO1xuXG4gIHByaXZhdGUgaW5zdGFuY2U6IEF4aW9zSW5zdGFuY2U7XG5cbiAgcHJpdmF0ZSBvYnNlcnZhYmlsaXR5Q29uZmlnOiBBeGlvc0NsaWVudE9ic2VydmFiaWxpdHlDb25maWc7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9ucz86IFJlcXVlc3RDb25maWcsIG9ic2VydmFiaWxpdHlDb25maWc/OiBBeGlvc0NsaWVudE9ic2VydmFiaWxpdHlDb25maWcpIHtcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IHtcbiAgICAgIHRpbWVvdXQ6IDEwMDAgKiAxMCxcbiAgICAgIC8vIGB3aXRoQ3JlZGVudGlhbHNgIGluZGljYXRlcyB3aGV0aGVyIG9yIG5vdCBjcm9zcy1zaXRlIEFjY2Vzcy1Db250cm9sIHJlcXVlc3RzIHNob3VsZCBiZSBtYWRlIHVzaW5nIGNyZWRlbnRpYWxzXG4gICAgICB3aXRoQ3JlZGVudGlhbHM6IGZhbHNlLFxuICAgICAgLy8gYHJlc3BvbnNlRW5jb2RpbmdgIGluZGljYXRlcyBlbmNvZGluZyB0byB1c2UgZm9yIGRlY29kaW5nIHJlc3BvbnNlcyAoTm9kZS5qcyBvbmx5KSxcbiAgICAgIHJlc3BvbnNlRW5jb2Rpbmc6ICd1dGY4JyxcbiAgICAgIC8vIGBtYXhCb2R5TGVuZ3RoYCAoTm9kZSBvbmx5IG9wdGlvbikgZGVmaW5lcyB0aGUgbWF4IHNpemUgb2YgdGhlIGh0dHAgcmVxdWVzdCBjb250ZW50IGluIGJ5dGVzIGFsbG93ZWQsXG4gICAgICBtYXhCb2R5TGVuZ3RoOiAxMDAwICogMTAwMCAqIDEwLFxuICAgICAgLy8gYG1heFJlZGlyZWN0c2AgZGVmaW5lcyB0aGUgbWF4aW11bSBudW1iZXIgb2YgcmVkaXJlY3RzIHRvIGZvbGxvdyBpbiBub2RlLmpzLFxuICAgICAgbWF4UmVkaXJlY3RzOiA1LFxuICAgICAgLy8gYGh0dHBBZ2VudGAgYW5kIGBodHRwc0FnZW50YCBkZWZpbmUgYSBjdXN0b20gYWdlbnQgdG8gYmUgdXNlZCB3aGVuIHBlcmZvcm1pbmcgaHR0cFxuICAgICAgaHR0cEFnZW50OiBuZXcgaHR0cC5BZ2VudCh7IGtlZXBBbGl2ZTogdHJ1ZSB9KSxcbiAgICAgIC8vIGFuZCBodHRwcyByZXF1ZXN0cywgcmVzcGVjdGl2ZWx5LCBpbiBub2RlLmpzLiBUaGlzIGFsbG93cyBvcHRpb25zIHRvIGJlIGFkZGVkIGxpa2UgYGtlZXBBbGl2ZWAgdGhhdCBhcmUgbm90IGVuYWJsZWQgYnkgZGVmYXVsdC5cbiAgICAgIGh0dHBzQWdlbnQ6IG5ldyBodHRwcy5BZ2VudCh7IGtlZXBBbGl2ZTogdHJ1ZSB9KSxcbiAgICB9O1xuICAgIHRoaXMub3B0aW9ucyA9IHsgLi4uZGVmYXVsdE9wdGlvbnMsIC4uLm9wdGlvbnMgfTtcbiAgICB0aGlzLmluc3RhbmNlID0gYXhpb3MuY3JlYXRlKHRoaXMub3B0aW9ucyk7XG5cbiAgICAvLyBNZXJnZSB3aXRoIGRlZmF1bHQgY29uZmlnIHRvIGVsaW1pbmF0ZSBudWxsIGNoZWNrc1xuICAgIGNvbnN0IGRlZmF1bHRPYnNlcnZhYmlsaXR5Q29uZmlnOiBBeGlvc0NsaWVudE9ic2VydmFiaWxpdHlDb25maWcgPSB7XG4gICAgICBsb2dnZXI6IHVuZGVmaW5lZCxcbiAgICAgIHN0YXRzQ2xpZW50OiB1bmRlZmluZWQsXG4gICAgICBkZWZhdWx0U3RhdFRhZ3M6IHt9LFxuICAgIH07XG4gICAgdGhpcy5vYnNlcnZhYmlsaXR5Q29uZmlnID0geyAuLi5kZWZhdWx0T2JzZXJ2YWJpbGl0eUNvbmZpZywgLi4ub2JzZXJ2YWJpbGl0eUNvbmZpZyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBtYWtlUmVxdWVzdDxUPihcbiAgICBjb25maWc6IFJlcXVlc3RDb25maWcsXG4gICAgcmVzcG9uc2VQYXJzZXI/OiBSZXNwb25zZVBhcnNlcjxUPixcbiAgKTogUHJvbWlzZTxBcGlSZXNwb25zZTxUPj4ge1xuICAgIGNvbnN0IHN0YXJ0VGltZXN0YW1wID0gbmV3IERhdGUoKTtcbiAgICAvLyBFeHRyYWN0IG1ldGFkYXRhIGZvciBsb2dnaW5nL21ldHJpY3NcbiAgICBjb25zdCBtZXRob2QgPSBjb25maWcubWV0aG9kPy50b1VwcGVyQ2FzZSgpIHx8ICdVTktOT1dOJztcbiAgICBjb25zdCB1cmwgPSBjb25maWcudXJsIHx8ICd1bmtub3duJztcbiAgICBjb25zdCBib2R5ID0gY29uZmlnLmRhdGEgfHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IHN0YXRUYWdzOiBTdGF0VGFncyA9IHtcbiAgICAgIC4uLnRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5kZWZhdWx0U3RhdFRhZ3MsXG4gICAgICByZXF1ZXN0TWV0aG9kOiBtZXRob2QsXG4gICAgICBlbmRwb2ludFBhdGg6ICdkZWZhdWx0JyxcbiAgICAgIC4uLmNvbmZpZy5zdGF0VGFncyxcbiAgICB9O1xuXG4gICAgY29uc3QgbWV0YWRhdGFNZXRyaWNUYWdzID0ge1xuICAgICAgLi4uKHRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5kZWZhdWx0U3RhdFRhZ3M/Lm1ldGFkYXRhIHx8IHt9KSxcbiAgICAgIC4uLihjb25maWcuc3RhdFRhZ3M/Lm1ldGFkYXRhIHx8IHt9KSxcbiAgICB9O1xuXG4gICAgLy8gT3B0aW9uYWwgcmVxdWVzdCBsb2dnaW5nXG4gICAgY29uc3QgcmVxdWVzdExvZ1BhcmFtczogUmVxdWVzdExvZ1BhcmFtcyA9IHtcbiAgICAgIHJlcXVlc3REZXRhaWxzOiB7XG4gICAgICAgIG1ldGhvZDogbWV0aG9kIHx8ICd1bmRlZmluZWQnLFxuICAgICAgICB1cmw6IHVybCB8fCAndW5kZWZpbmVkJyxcbiAgICAgICAgYm9keTogYm9keSB8fCAndW5kZWZpbmVkJyxcbiAgICAgIH0sXG4gICAgICBtZXRhZGF0YTogc3RhdFRhZ3MubWV0YWRhdGEgfHwge30sXG4gICAgfTtcbiAgICB0aGlzLm9ic2VydmFiaWxpdHlDb25maWcubG9nZ2VyPy5yZXF1ZXN0TG9nKFxuICAgICAgYFtIVFRQXSAke21ldGhvZH0gJHt1cmx9IHJlcXVlc3RgLFxuICAgICAgcmVxdWVzdExvZ1BhcmFtcyxcbiAgICApO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcXVlc3RDb25maWcgPSBjb25maWc7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuaW5zdGFuY2UucmVxdWVzdChyZXF1ZXN0Q29uZmlnKTtcbiAgICAgIGNvbnN0IHsgc3RhdHVzLCBkYXRhLCBoZWFkZXJzIH0gPSByZXNwb25zZTtcblxuICAgICAgLy8gT3B0aW9uYWwgcmVzcG9uc2UgbG9nZ2luZ1xuICAgICAgY29uc3QgcmVzcG9uc2VMb2dQYXJhbXM6IFJlc3BvbnNlTG9nUGFyYW1zID0ge1xuICAgICAgICByZXNwb25zZURldGFpbHM6IHtcbiAgICAgICAgICBzdGF0dXM6IHN0YXR1cyB8fCAwLFxuICAgICAgICAgIGJvZHk6IGRhdGEgfHwgJ3VuZGVmaW5lZCcsXG4gICAgICAgICAgaGVhZGVyczogaGVhZGVycyB8fCAndW5kZWZpbmVkJyxcbiAgICAgICAgfSxcbiAgICAgICAgbWV0YWRhdGE6IHN0YXRUYWdzLm1ldGFkYXRhIHx8IHt9LFxuICAgICAgfTtcbiAgICAgIHRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5sb2dnZXI/LnJlc3BvbnNlTG9nKFxuICAgICAgICBgW0hUVFBdICR7bWV0aG9kfSAke3VybH0gcmVzcG9uc2VgLFxuICAgICAgICByZXNwb25zZUxvZ1BhcmFtcyxcbiAgICAgICk7XG5cbiAgICAgIC8vIE9wdGlvbmFsIHN1Y2Nlc3MgbWV0cmljc1xuICAgICAgY29uc3QgYWxsTGFiZWxzID0geyAuLi5tZXRhZGF0YU1ldHJpY1RhZ3MsIC4uLnN0YXRUYWdzLCBzdGF0dXNDb2RlOiBzdGF0dXMgfTtcblxuICAgICAgY29uc3QgdGltaW5nTGFiZWxzID0gZmlsdGVyTWV0cmljTGFiZWxzKGFsbExhYmVscywgVElNSU5HX01FVFJJQ19MQUJFTFMpO1xuICAgICAgdGhpcy5vYnNlcnZhYmlsaXR5Q29uZmlnLnN0YXRzQ2xpZW50Py50aW1pbmcoXG4gICAgICAgICdvdXRnb2luZ19yZXF1ZXN0X2xhdGVuY3knLFxuICAgICAgICBzdGFydFRpbWVzdGFtcCxcbiAgICAgICAgdGltaW5nTGFiZWxzLFxuICAgICAgKTtcblxuICAgICAgY29uc3QgY291bnRlckxhYmVscyA9IGZpbHRlck1ldHJpY0xhYmVscyhhbGxMYWJlbHMsIENPVU5URVJfTUVUUklDX0xBQkVMUyk7XG4gICAgICB0aGlzLm9ic2VydmFiaWxpdHlDb25maWcuc3RhdHNDbGllbnQ/LmNvdW50ZXIoJ291dGdvaW5nX3JlcXVlc3RfY291bnQnLCAxLCBjb3VudGVyTGFiZWxzKTtcblxuICAgICAgaWYgKHJlc3BvbnNlUGFyc2VyKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcGFyc2VkRGF0YSA9IHJlc3BvbnNlUGFyc2VyKGRhdGEpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0eXBlOiAnc3VjY2VzcycsXG4gICAgICAgICAgICBzdGF0dXNDb2RlOiBzdGF0dXMsXG4gICAgICAgICAgICByZXNwb25zZUJvZHk6IHBhcnNlZERhdGEsXG4gICAgICAgICAgICBoZWFkZXJzLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc3QgdW5rbm93bkVycm9yID0gZXJyb3IgYXMgRXJyb3I7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHR5cGU6ICdjbGllbnQtZXJyb3InLFxuICAgICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvcjogRXJyb3IgaGFzIHN0YXR1c1xuICAgICAgICAgICAgc3RhdHVzQ29kZTogdW5rbm93bkVycm9yLnN0YXR1cyB8fCA1MDAsXG4gICAgICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIHBhcnNlIHJlc3BvbnNlIGRhdGE6ICR7dW5rbm93bkVycm9yLm1lc3NhZ2V9YCxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4geyB0eXBlOiAnc3VjY2VzcycsIHN0YXR1c0NvZGU6IHN0YXR1cywgcmVzcG9uc2VCb2R5OiBkYXRhLCBoZWFkZXJzIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIERldGVybWluZSBzdGF0dXMgY29kZSBmb3IgZXJyb3IgbWV0cmljc1xuICAgICAgbGV0IGVycm9yU3RhdHVzQ29kZSA9IDUwMDsgLy8gRGVmYXVsdCB0byA1MDAgZm9yIG5ldHdvcmsvdW5rbm93biBlcnJvcnNcbiAgICAgIGlmIChheGlvcy5pc0F4aW9zRXJyb3IoZXJyb3IpKSB7XG4gICAgICAgIGNvbnN0IGF4aW9zRXJyb3IgPSBlcnJvciBhcyBBeGlvc0Vycm9yO1xuICAgICAgICBpZiAoYXhpb3NFcnJvci5yZXNwb25zZSkge1xuICAgICAgICAgIGVycm9yU3RhdHVzQ29kZSA9IGF4aW9zRXJyb3IucmVzcG9uc2Uuc3RhdHVzO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIE9wdGlvbmFsIGVycm9yIGxvZ2dpbmdcbiAgICAgIHRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5sb2dnZXI/LmVycm9yPy4oYFtIVFRQXSAke21ldGhvZH0gJHt1cmx9IGVycm9yYCwge1xuICAgICAgICBlcnJvcjogKGVycm9yIGFzIEVycm9yKS5tZXNzYWdlLFxuICAgICAgICBzdGF0VGFnczogeyAuLi5zdGF0VGFncywgc3RhdHVzQ29kZTogZXJyb3JTdGF0dXNDb2RlIH0sXG4gICAgICB9KTtcblxuICAgICAgLy8gT3B0aW9uYWwgZXJyb3IgbWV0cmljc1xuICAgICAgY29uc3QgYWxsRXJyb3JMYWJlbHMgPSB7IC4uLm1ldGFkYXRhTWV0cmljVGFncywgLi4uc3RhdFRhZ3MsIHN0YXR1c0NvZGU6IGVycm9yU3RhdHVzQ29kZSB9O1xuXG4gICAgICBjb25zdCB0aW1pbmdMYWJlbHMgPSBmaWx0ZXJNZXRyaWNMYWJlbHMoYWxsRXJyb3JMYWJlbHMsIFRJTUlOR19NRVRSSUNfTEFCRUxTKTtcbiAgICAgIHRoaXMub2JzZXJ2YWJpbGl0eUNvbmZpZy5zdGF0c0NsaWVudD8udGltaW5nKFxuICAgICAgICAnb3V0Z29pbmdfcmVxdWVzdF9sYXRlbmN5JyxcbiAgICAgICAgc3RhcnRUaW1lc3RhbXAsXG4gICAgICAgIHRpbWluZ0xhYmVscyxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGNvdW50ZXJMYWJlbHMgPSBmaWx0ZXJNZXRyaWNMYWJlbHMoYWxsRXJyb3JMYWJlbHMsIENPVU5URVJfTUVUUklDX0xBQkVMUyk7XG4gICAgICB0aGlzLm9ic2VydmFiaWxpdHlDb25maWcuc3RhdHNDbGllbnQ/LmNvdW50ZXIoJ291dGdvaW5nX3JlcXVlc3RfY291bnQnLCAxLCBjb3VudGVyTGFiZWxzKTtcblxuICAgICAgaWYgKGF4aW9zLmlzQXhpb3NFcnJvcihlcnJvcikpIHtcbiAgICAgICAgY29uc3QgYXhpb3NFcnJvciA9IGVycm9yIGFzIEF4aW9zRXJyb3I7XG4gICAgICAgIGlmIChheGlvc0Vycm9yLnJlc3BvbnNlKSB7XG4gICAgICAgICAgY29uc3QgeyByZXNwb25zZSB9ID0gYXhpb3NFcnJvcjtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdHlwZTogJ2FwcGxpY2F0aW9uLWVycm9yJyxcbiAgICAgICAgICAgIHN0YXR1c0NvZGU6IHJlc3BvbnNlLnN0YXR1cyxcbiAgICAgICAgICAgIG1lc3NhZ2U6IHJlc3BvbnNlLnN0YXR1c1RleHQsXG4gICAgICAgICAgICByZXNwb25zZUJvZHk6IHJlc3BvbnNlLmRhdGEsXG4gICAgICAgICAgICBoZWFkZXJzOiByZXNwb25zZS5oZWFkZXJzLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGF4aW9zRXJyb3IuY29kZSkge1xuICAgICAgICAgIGNvbnN0IHJlc3AgPSBORVRXT1JLX1NUQVRVU19FUlJfTUFQW2F4aW9zRXJyb3IuY29kZV07XG4gICAgICAgICAgaWYgKCFyZXNwKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICB0eXBlOiAnY2xpZW50LWVycm9yJyxcbiAgICAgICAgICAgICAgc3RhdHVzQ29kZTogNTAwLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBgVW5rbm93biBFcnJvcjoke2F4aW9zRXJyb3IubWVzc2FnZX1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHR5cGU6ICdjbGllbnQtZXJyb3InLFxuICAgICAgICAgICAgc3RhdHVzQ29kZTogcmVzcC5zdGF0dXMsXG4gICAgICAgICAgICBtZXNzYWdlOiByZXNwLm1lc3NhZ2UsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB1bmtub3duRXJyb3IgPSBlcnJvciBhcyBFcnJvcjtcbiAgICAgIGNvbnN0IHN0YXR1cyA9IDUwMDtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSB1bmtub3duRXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBFcnJvcic7XG5cbiAgICAgIHJldHVybiB7IHR5cGU6ICdjbGllbnQtZXJyb3InLCBzdGF0dXNDb2RlOiBzdGF0dXMsIG1lc3NhZ2UgfTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZ2V0PFQ+KFxuICAgIHVybDogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBSZXF1ZXN0Q29uZmlnLFxuICAgIHJlc3BvbnNlUGFyc2VyPzogUmVzcG9uc2VQYXJzZXI8VD4sXG4gICk6IFByb21pc2U8QXBpUmVzcG9uc2U8VD4+IHtcbiAgICBsZXQgY29uZmlnOiBSZXF1ZXN0Q29uZmlnID0ge1xuICAgICAgbWV0aG9kOiAnZ2V0JyxcbiAgICAgIHVybCxcbiAgICB9O1xuICAgIGlmIChpc05vdEVtcHR5KG9wdGlvbnMpKSB7XG4gICAgICBjb25maWcgPSB7IC4uLmNvbmZpZywgLi4ub3B0aW9ucyB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5tYWtlUmVxdWVzdDxUPihjb25maWcsIHJlc3BvbnNlUGFyc2VyKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBwb3N0PFQ+KFxuICAgIHVybDogc3RyaW5nLFxuICAgIGRhdGE/OiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBSZXF1ZXN0Q29uZmlnLFxuICAgIHJlc3BvbnNlUGFyc2VyPzogUmVzcG9uc2VQYXJzZXI8VD4sXG4gICk6IFByb21pc2U8QXBpUmVzcG9uc2U8VD4+IHtcbiAgICBsZXQgY29uZmlnOiBSZXF1ZXN0Q29uZmlnID0ge1xuICAgICAgbWV0aG9kOiAncG9zdCcsXG4gICAgICB1cmwsXG4gICAgICBkYXRhLFxuICAgIH07XG4gICAgaWYgKGlzTm90RW1wdHkob3B0aW9ucykpIHtcbiAgICAgIGNvbmZpZyA9IHsgLi4uY29uZmlnLCAuLi5vcHRpb25zIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLm1ha2VSZXF1ZXN0PFQ+KGNvbmZpZywgcmVzcG9uc2VQYXJzZXIpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHB1dDxUPihcbiAgICB1cmw6IHN0cmluZyxcbiAgICBkYXRhPzogdW5rbm93bixcbiAgICBvcHRpb25zPzogUmVxdWVzdENvbmZpZyxcbiAgICByZXNwb25zZVBhcnNlcj86IFJlc3BvbnNlUGFyc2VyPFQ+LFxuICApOiBQcm9taXNlPEFwaVJlc3BvbnNlPFQ+PiB7XG4gICAgbGV0IGNvbmZpZzogUmVxdWVzdENvbmZpZyA9IHtcbiAgICAgIG1ldGhvZDogJ3B1dCcsXG4gICAgICB1cmwsXG4gICAgICBkYXRhLFxuICAgIH07XG4gICAgaWYgKGlzTm90RW1wdHkob3B0aW9ucykpIHtcbiAgICAgIGNvbmZpZyA9IHsgLi4uY29uZmlnLCAuLi5vcHRpb25zIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLm1ha2VSZXF1ZXN0PFQ+KGNvbmZpZywgcmVzcG9uc2VQYXJzZXIpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHBhdGNoPFQ+KFxuICAgIHVybDogc3RyaW5nLFxuICAgIGRhdGE/OiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBSZXF1ZXN0Q29uZmlnLFxuICAgIHJlc3BvbnNlUGFyc2VyPzogUmVzcG9uc2VQYXJzZXI8VD4sXG4gICk6IFByb21pc2U8QXBpUmVzcG9uc2U8VD4+IHtcbiAgICBsZXQgY29uZmlnOiBSZXF1ZXN0Q29uZmlnID0ge1xuICAgICAgbWV0aG9kOiAncGF0Y2gnLFxuICAgICAgdXJsLFxuICAgICAgZGF0YSxcbiAgICB9O1xuICAgIGlmIChpc05vdEVtcHR5KG9wdGlvbnMpKSB7XG4gICAgICBjb25maWcgPSB7IC4uLmNvbmZpZywgLi4ub3B0aW9ucyB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5tYWtlUmVxdWVzdDxUPihjb25maWcsIHJlc3BvbnNlUGFyc2VyKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBkZWxldGU8VD4oXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFJlcXVlc3RDb25maWcsXG4gICAgcmVzcG9uc2VQYXJzZXI/OiBSZXNwb25zZVBhcnNlcjxUPixcbiAgKTogUHJvbWlzZTxBcGlSZXNwb25zZTxUPj4ge1xuICAgIGxldCBjb25maWc6IFJlcXVlc3RDb25maWcgPSB7XG4gICAgICBtZXRob2Q6ICdkZWxldGUnLFxuICAgICAgdXJsLFxuICAgIH07XG4gICAgaWYgKGlzTm90RW1wdHkob3B0aW9ucykpIHtcbiAgICAgIGNvbmZpZyA9IHsgLi4uY29uZmlnLCAuLi5vcHRpb25zIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLm1ha2VSZXF1ZXN0PFQ+KGNvbmZpZywgcmVzcG9uc2VQYXJzZXIpO1xuICB9XG5cbiAgLy8gQWRkIG90aGVyIEhUVFAgbWV0aG9kcyBhcyBuZWVkZWRcbn1cbiJdfQ==