@data-client/rest
Version:
Quickly define typed REST resources and endpoints
236 lines (229 loc) • 31.8 kB
JavaScript
import _objectDestructuringEmpty from "@babel/runtime/helpers/esm/objectDestructuringEmpty";
import _extends from "@babel/runtime/helpers/esm/extends";
import _classPrivateFieldLooseBase from "@babel/runtime/helpers/esm/classPrivateFieldLooseBase";
import _classPrivateFieldLooseKey from "@babel/runtime/helpers/esm/classPrivateFieldLooseKey";
import { Endpoint } from '@data-client/endpoint';
import { pathToRegexp } from 'path-to-regexp';
import extractCollection from './extractCollection.js';
import mapCollection from './mapCollection.js';
import NetworkError from './NetworkError.js';
import { createPaginationSchema } from './paginatedCollections.js';
import paramsToString from './paramsToString.js';
import { getUrlBase, getUrlTokens, isPojo } from './RestHelpers.js';
/** Simplifies endpoint definitions that follow REST patterns
*
* @see https://dataclient.io/rest/api/RestEndpoint
*/
var _hasBody = /*#__PURE__*/_classPrivateFieldLooseKey("hasBody");
export default class RestEndpoint extends Endpoint {
constructor(options) {
var _options$fetch;
super((_options$fetch = options.fetch) != null ? _options$fetch : async function (...args) {
const urlParams = _classPrivateFieldLooseBase(this, _hasBody)[_hasBody] && args.length < 2 ? {} : args[0] || {};
const body = _classPrivateFieldLooseBase(this, _hasBody)[_hasBody] ? args[args.length - 1] : undefined;
return this.fetchResponse(this.url(urlParams), await this.getRequestInit(body)).then(response => this.parseResponse(response)).then(res => this.process(res, ...args));
}, options);
// we want to use the prototype chain here
Object.defineProperty(this, _hasBody, {
writable: true,
value: void 0
});
if (!('sideEffect' in this) || 'method' in options && !('sideEffect' in options)) {
this.sideEffect = options.method === 'GET' || options.method === undefined ? undefined : true;
}
if (this.method === undefined) {
this.method = this.sideEffect ? 'POST' : 'GET';
}
if (this.urlPrefix === undefined) {
this.urlPrefix = '';
}
_classPrivateFieldLooseBase(this, _hasBody)[_hasBody] = (!('body' in this) || this.body !== undefined) && !['GET', 'DELETE'].includes(this.method);
Object.defineProperty(this, 'name', {
get() {
// using 'in' to ensure inheritance lookup
if ('__name' in this) return this.__name;
return this.urlPrefix + this.path;
}
});
}
key(...args) {
return `${this.method} ${this.url(_classPrivateFieldLooseBase(this, _hasBody)[_hasBody] && args.length < 2 ? {} : args[0] || {})}`;
}
/** Get the url */
url(urlParams = {}) {
const urlBase = getUrlBase(this.path)(urlParams);
const tokens = getUrlTokens(this.path);
const searchParams = {};
Object.keys(urlParams).forEach(k => {
if (!tokens.has(k)) {
searchParams[k] = urlParams[k];
}
});
if (Object.keys(searchParams).length) {
return `${this.urlPrefix}${urlBase}?${this.searchToString(searchParams)}`;
}
return `${this.urlPrefix}${urlBase}`;
}
/** Encode the url searchParams */
searchToString(searchParams) {
return paramsToString(searchParams);
}
getHeaders(headers) {
return headers;
}
/** Init options for fetch - run at fetch */
async getRequestInit(body) {
const bodyIsPojo = isPojo(body);
if (bodyIsPojo) {
body = JSON.stringify(body);
}
const init = _extends({}, this.requestInit, {
method: this.method,
signal: this.signal,
body
});
if (!body || bodyIsPojo) {
init.headers = _extends({
// default to application/json but allow user explicit overrides
'Content-Type': 'application/json'
}, init.headers);
}
init.headers = await this.getHeaders(init.headers);
return init;
}
/** Perform network request and resolve with HTTP Response */
fetchResponse(input, init) {
return fetch(input, init).then(response => {
if (!response.ok) {
throw new NetworkError(response);
}
return response;
}).catch(error => {
// ensure CORS, network down, and parse errors are still caught by NetworkErrorBoundary
if (error instanceof TypeError) {
error.status = 500;
}
throw error;
});
}
parseResponse(response) {
var _response$headers$get;
// this should not have any content to read
if (response.status === 204) return Promise.resolve(null);
if (!((_response$headers$get = response.headers.get('content-type')) != null && _response$headers$get.includes('json'))) {
return response.text().then(text => {
// string or 'not set' schema, are valid
// when overriding process they might handle other cases, so we don't want to block on our logic
if (['string', 'undefined'].includes(typeof this.schema) || this.schema === null || this.process !== RestEndpoint.prototype.process) return text;
const error = new NetworkError(response);
error.status = 404;
error.message = `Unexpected text response for schema ${this.schema}`;
// custom dev-only messages for more detailed cause
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
var _response$headers$get2;
if (!((_response$headers$get2 = response.headers.get('content-type')) != null && _response$headers$get2.includes('html') || text.startsWith('<!doctype html>'))) {
if (tryParse(text) !== undefined) {
error.message = `"content-type" header does not include "json", but JSON response found.
See https://www.rfc-editor.org/rfc/rfc4627 for information on JSON responses
Using parsed JSON.
If text content was expected see https://dataclient.io/rest/api/RestEndpoint#parseResponse`;
}
} else {
error.message = `Unexpected html response for schema ${this.schema}
This likely means no API endpoint was configured for this request, resulting in an HTML fallback.
Response (first 300 characters): ${text.substring(0, 300)}`;
}
}
throw error;
});
}
return response.json().catch(error => {
error.status = 400;
throw error;
});
}
process(value) {
return value;
}
errorPolicy(error) {
return error.status >= 500 ? 'soft' : undefined;
}
get pathRegex() {
return pathToRegexp(this.path);
}
testKey(key) {
const prefix = this.method + ' ' + this.urlPrefix;
if (!key.startsWith(prefix)) return false;
let lastQuestion = key.lastIndexOf('?');
if (lastQuestion === -1) lastQuestion = undefined;
return this.pathRegex.test(key.substring(prefix.length, lastQuestion));
}
extend(options) {
// make a constructor/prototype based off this
// extend from it and init with options sent
class E extends this.constructor {}
Object.assign(E.prototype, this);
return new E(// fetch get overridden by function prototype, so we must set it explicitly every time
_extends({
fetch: this.fetch
}, options));
}
paginated(removeCursor) {
if (typeof removeCursor === 'string') {
const fieldName = removeCursor;
removeCursor = _ref => {
let params = _extends({}, (_objectDestructuringEmpty(_ref), _ref));
delete params[fieldName];
return [params];
};
}
let found = false;
const createPaginatedSchema = collection => {
found = true;
return createPaginationSchema(removeCursor, collection);
};
const newSchema = mapCollection(this.schema, createPaginatedSchema);
if (!found) throw new Error('Missing Collection');
const sup = this;
return this.extend({
schema: newSchema,
key(...args) {
return sup.key.call(this, ...removeCursor(...args));
},
name: this.name + '.getPage'
});
}
get getPage() {
return this.paginated(this.paginationField);
}
get push() {
return this.extend({
method: 'POST',
schema: extractCollection(this.schema, s => s.push),
name: this.name + '.create'
});
}
get unshift() {
return this.extend({
method: 'POST',
schema: extractCollection(this.schema, s => s.unshift),
name: this.name + '.create'
});
}
get assign() {
return this.extend({
method: 'POST',
schema: extractCollection(this.schema, s => s.assign),
name: this.name + '.create'
});
}
}
const tryParse = input => {
try {
return JSON.parse(input);
} catch (e) {
return undefined;
}
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJFbmRwb2ludCIsInBhdGhUb1JlZ2V4cCIsImV4dHJhY3RDb2xsZWN0aW9uIiwibWFwQ29sbGVjdGlvbiIsIk5ldHdvcmtFcnJvciIsImNyZWF0ZVBhZ2luYXRpb25TY2hlbWEiLCJwYXJhbXNUb1N0cmluZyIsImdldFVybEJhc2UiLCJnZXRVcmxUb2tlbnMiLCJpc1Bvam8iLCJfaGFzQm9keSIsIl9jbGFzc1ByaXZhdGVGaWVsZExvb3NlS2V5IiwiUmVzdEVuZHBvaW50IiwiY29uc3RydWN0b3IiLCJvcHRpb25zIiwiX29wdGlvbnMkZmV0Y2giLCJmZXRjaCIsImFyZ3MiLCJ1cmxQYXJhbXMiLCJfY2xhc3NQcml2YXRlRmllbGRMb29zZUJhc2UiLCJsZW5ndGgiLCJib2R5IiwidW5kZWZpbmVkIiwiZmV0Y2hSZXNwb25zZSIsInVybCIsImdldFJlcXVlc3RJbml0IiwidGhlbiIsInJlc3BvbnNlIiwicGFyc2VSZXNwb25zZSIsInJlcyIsInByb2Nlc3MiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsIndyaXRhYmxlIiwidmFsdWUiLCJzaWRlRWZmZWN0IiwibWV0aG9kIiwidXJsUHJlZml4IiwiaW5jbHVkZXMiLCJnZXQiLCJfX25hbWUiLCJwYXRoIiwia2V5IiwidXJsQmFzZSIsInRva2VucyIsInNlYXJjaFBhcmFtcyIsImtleXMiLCJmb3JFYWNoIiwiayIsImhhcyIsInNlYXJjaFRvU3RyaW5nIiwiZ2V0SGVhZGVycyIsImhlYWRlcnMiLCJib2R5SXNQb2pvIiwiSlNPTiIsInN0cmluZ2lmeSIsImluaXQiLCJfZXh0ZW5kcyIsInJlcXVlc3RJbml0Iiwic2lnbmFsIiwiaW5wdXQiLCJvayIsImNhdGNoIiwiZXJyb3IiLCJUeXBlRXJyb3IiLCJzdGF0dXMiLCJfcmVzcG9uc2UkaGVhZGVycyRnZXQiLCJQcm9taXNlIiwicmVzb2x2ZSIsInRleHQiLCJzY2hlbWEiLCJwcm90b3R5cGUiLCJtZXNzYWdlIiwiZW52IiwiTk9ERV9FTlYiLCJfcmVzcG9uc2UkaGVhZGVycyRnZXQyIiwic3RhcnRzV2l0aCIsInRyeVBhcnNlIiwic3Vic3RyaW5nIiwianNvbiIsImVycm9yUG9saWN5IiwicGF0aFJlZ2V4IiwidGVzdEtleSIsInByZWZpeCIsImxhc3RRdWVzdGlvbiIsImxhc3RJbmRleE9mIiwidGVzdCIsImV4dGVuZCIsIkUiLCJhc3NpZ24iLCJwYWdpbmF0ZWQiLCJyZW1vdmVDdXJzb3IiLCJmaWVsZE5hbWUiLCJfcmVmIiwicGFyYW1zIiwiX29iamVjdERlc3RydWN0dXJpbmdFbXB0eSIsImZvdW5kIiwiY3JlYXRlUGFnaW5hdGVkU2NoZW1hIiwiY29sbGVjdGlvbiIsIm5ld1NjaGVtYSIsIkVycm9yIiwic3VwIiwiY2FsbCIsIm5hbWUiLCJnZXRQYWdlIiwicGFnaW5hdGlvbkZpZWxkIiwicHVzaCIsInMiLCJ1bnNoaWZ0IiwicGFyc2UiLCJlIl0sInNvdXJjZXMiOlsiLi4vc3JjL1Jlc3RFbmRwb2ludC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBFbmRwb2ludCB9IGZyb20gJ0BkYXRhLWNsaWVudC9lbmRwb2ludCc7XG5pbXBvcnQgeyBwYXRoVG9SZWdleHAgfSBmcm9tICdwYXRoLXRvLXJlZ2V4cCc7XG5cbmltcG9ydCBleHRyYWN0Q29sbGVjdGlvbiBmcm9tICcuL2V4dHJhY3RDb2xsZWN0aW9uLmpzJztcbmltcG9ydCBtYXBDb2xsZWN0aW9uIGZyb20gJy4vbWFwQ29sbGVjdGlvbi5qcyc7XG5pbXBvcnQgTmV0d29ya0Vycm9yIGZyb20gJy4vTmV0d29ya0Vycm9yLmpzJztcbmltcG9ydCB7IGNyZWF0ZVBhZ2luYXRpb25TY2hlbWEgfSBmcm9tICcuL3BhZ2luYXRlZENvbGxlY3Rpb25zLmpzJztcbmltcG9ydCBwYXJhbXNUb1N0cmluZyBmcm9tICcuL3BhcmFtc1RvU3RyaW5nLmpzJztcbmltcG9ydCB7IGdldFVybEJhc2UsIGdldFVybFRva2VucywgaXNQb2pvIH0gZnJvbSAnLi9SZXN0SGVscGVycy5qcyc7XG5cbi8qKiBTaW1wbGlmaWVzIGVuZHBvaW50IGRlZmluaXRpb25zIHRoYXQgZm9sbG93IFJFU1QgcGF0dGVybnNcbiAqXG4gKiBAc2VlIGh0dHBzOi8vZGF0YWNsaWVudC5pby9yZXN0L2FwaS9SZXN0RW5kcG9pbnRcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUmVzdEVuZHBvaW50IGV4dGVuZHMgRW5kcG9pbnQge1xuICAjaGFzQm9keTtcbiAgY29uc3RydWN0b3Iob3B0aW9ucykge1xuICAgIHN1cGVyKFxuICAgICAgb3B0aW9ucy5mZXRjaCA/P1xuICAgICAgICBhc3luYyBmdW5jdGlvbiAoLi4uYXJncykge1xuICAgICAgICAgIGNvbnN0IHVybFBhcmFtcyA9XG4gICAgICAgICAgICB0aGlzLiNoYXNCb2R5ICYmIGFyZ3MubGVuZ3RoIDwgMiA/IHt9IDogYXJnc1swXSB8fCB7fTtcbiAgICAgICAgICBjb25zdCBib2R5ID0gdGhpcy4jaGFzQm9keSA/IGFyZ3NbYXJncy5sZW5ndGggLSAxXSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICByZXR1cm4gdGhpcy5mZXRjaFJlc3BvbnNlKFxuICAgICAgICAgICAgdGhpcy51cmwodXJsUGFyYW1zKSxcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZ2V0UmVxdWVzdEluaXQoYm9keSksXG4gICAgICAgICAgKVxuICAgICAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4gdGhpcy5wYXJzZVJlc3BvbnNlKHJlc3BvbnNlKSlcbiAgICAgICAgICAgIC50aGVuKHJlcyA9PiB0aGlzLnByb2Nlc3MocmVzLCAuLi5hcmdzKSk7XG4gICAgICAgIH0sXG4gICAgICBvcHRpb25zLFxuICAgICk7XG4gICAgLy8gd2Ugd2FudCB0byB1c2UgdGhlIHByb3RvdHlwZSBjaGFpbiBoZXJlXG4gICAgaWYgKFxuICAgICAgISgnc2lkZUVmZmVjdCcgaW4gdGhpcykgfHxcbiAgICAgICgnbWV0aG9kJyBpbiBvcHRpb25zICYmICEoJ3NpZGVFZmZlY3QnIGluIG9wdGlvbnMpKVxuICAgICkge1xuICAgICAgdGhpcy5zaWRlRWZmZWN0ID1cbiAgICAgICAgb3B0aW9ucy5tZXRob2QgPT09ICdHRVQnIHx8IG9wdGlvbnMubWV0aG9kID09PSB1bmRlZmluZWQgP1xuICAgICAgICAgIHVuZGVmaW5lZFxuICAgICAgICA6IHRydWU7XG4gICAgfVxuICAgIGlmICh0aGlzLm1ldGhvZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLm1ldGhvZCA9IHRoaXMuc2lkZUVmZmVjdCA/ICdQT1NUJyA6ICdHRVQnO1xuICAgIH1cbiAgICBpZiAodGhpcy51cmxQcmVmaXggPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy51cmxQcmVmaXggPSAnJztcbiAgICB9XG4gICAgdGhpcy4jaGFzQm9keSA9XG4gICAgICAoISgnYm9keScgaW4gdGhpcykgfHwgdGhpcy5ib2R5ICE9PSB1bmRlZmluZWQpICYmXG4gICAgICAhWydHRVQnLCAnREVMRVRFJ10uaW5jbHVkZXModGhpcy5tZXRob2QpO1xuXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICduYW1lJywge1xuICAgICAgZ2V0KCkge1xuICAgICAgICAvLyB1c2luZyAnaW4nIHRvIGVuc3VyZSBpbmhlcml0YW5jZSBsb29rdXBcbiAgICAgICAgaWYgKCdfX25hbWUnIGluIHRoaXMpIHJldHVybiB0aGlzLl9fbmFtZTtcbiAgICAgICAgcmV0dXJuIHRoaXMudXJsUHJlZml4ICsgdGhpcy5wYXRoO1xuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIGtleSguLi5hcmdzKSB7XG4gICAgcmV0dXJuIGAke3RoaXMubWV0aG9kfSAke3RoaXMudXJsKFxuICAgICAgdGhpcy4jaGFzQm9keSAmJiBhcmdzLmxlbmd0aCA8IDIgPyB7fSA6IGFyZ3NbMF0gfHwge30sXG4gICAgKX1gO1xuICB9XG5cbiAgLyoqIEdldCB0aGUgdXJsICovXG4gIHVybCh1cmxQYXJhbXMgPSB7fSkge1xuICAgIGNvbnN0IHVybEJhc2UgPSBnZXRVcmxCYXNlKHRoaXMucGF0aCkodXJsUGFyYW1zKTtcbiAgICBjb25zdCB0b2tlbnMgPSBnZXRVcmxUb2tlbnModGhpcy5wYXRoKTtcbiAgICBjb25zdCBzZWFyY2hQYXJhbXMgPSB7fTtcbiAgICBPYmplY3Qua2V5cyh1cmxQYXJhbXMpLmZvckVhY2goayA9PiB7XG4gICAgICBpZiAoIXRva2Vucy5oYXMoaykpIHtcbiAgICAgICAgc2VhcmNoUGFyYW1zW2tdID0gdXJsUGFyYW1zW2tdO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChPYmplY3Qua2V5cyhzZWFyY2hQYXJhbXMpLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIGAke3RoaXMudXJsUHJlZml4fSR7dXJsQmFzZX0/JHt0aGlzLnNlYXJjaFRvU3RyaW5nKHNlYXJjaFBhcmFtcyl9YDtcbiAgICB9XG4gICAgcmV0dXJuIGAke3RoaXMudXJsUHJlZml4fSR7dXJsQmFzZX1gO1xuICB9XG5cbiAgLyoqIEVuY29kZSB0aGUgdXJsIHNlYXJjaFBhcmFtcyAqL1xuICBzZWFyY2hUb1N0cmluZyhzZWFyY2hQYXJhbXMpIHtcbiAgICByZXR1cm4gcGFyYW1zVG9TdHJpbmcoc2VhcmNoUGFyYW1zKTtcbiAgfVxuXG4gIGdldEhlYWRlcnMoaGVhZGVycykge1xuICAgIHJldHVybiBoZWFkZXJzO1xuICB9XG5cbiAgLyoqIEluaXQgb3B0aW9ucyBmb3IgZmV0Y2ggLSBydW4gYXQgZmV0Y2ggKi9cbiAgYXN5bmMgZ2V0UmVxdWVzdEluaXQoYm9keSkge1xuICAgIGNvbnN0IGJvZHlJc1Bvam8gPSBpc1Bvam8oYm9keSk7XG4gICAgaWYgKGJvZHlJc1Bvam8pIHtcbiAgICAgIGJvZHkgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcbiAgICB9XG4gICAgY29uc3QgaW5pdCA9IHtcbiAgICAgIC4uLnRoaXMucmVxdWVzdEluaXQsXG4gICAgICBtZXRob2Q6IHRoaXMubWV0aG9kLFxuICAgICAgc2lnbmFsOiB0aGlzLnNpZ25hbCxcbiAgICAgIGJvZHksXG4gICAgfTtcbiAgICBpZiAoIWJvZHkgfHwgYm9keUlzUG9qbykge1xuICAgICAgaW5pdC5oZWFkZXJzID0ge1xuICAgICAgICAvLyBkZWZhdWx0IHRvIGFwcGxpY2F0aW9uL2pzb24gYnV0IGFsbG93IHVzZXIgZXhwbGljaXQgb3ZlcnJpZGVzXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIC4uLmluaXQuaGVhZGVycyxcbiAgICAgIH07XG4gICAgfVxuICAgIGluaXQuaGVhZGVycyA9IGF3YWl0IHRoaXMuZ2V0SGVhZGVycyhpbml0LmhlYWRlcnMpO1xuICAgIHJldHVybiBpbml0O1xuICB9XG5cbiAgLyoqIFBlcmZvcm0gbmV0d29yayByZXF1ZXN0IGFuZCByZXNvbHZlIHdpdGggSFRUUCBSZXNwb25zZSAqL1xuICBmZXRjaFJlc3BvbnNlKGlucHV0LCBpbml0KSB7XG4gICAgcmV0dXJuIGZldGNoKGlucHV0LCBpbml0KVxuICAgICAgLnRoZW4ocmVzcG9uc2UgPT4ge1xuICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IE5ldHdvcmtFcnJvcihyZXNwb25zZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIC8vIGVuc3VyZSBDT1JTLCBuZXR3b3JrIGRvd24sIGFuZCBwYXJzZSBlcnJvcnMgYXJlIHN0aWxsIGNhdWdodCBieSBOZXR3b3JrRXJyb3JCb3VuZGFyeVxuICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBUeXBlRXJyb3IpIHtcbiAgICAgICAgICBlcnJvci5zdGF0dXMgPSA1MDA7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9KTtcbiAgfVxuXG4gIHBhcnNlUmVzcG9uc2UocmVzcG9uc2UpIHtcbiAgICAvLyB0aGlzIHNob3VsZCBub3QgaGF2ZSBhbnkgY29udGVudCB0byByZWFkXG4gICAgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gMjA0KSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG51bGwpO1xuICAgIGlmICghcmVzcG9uc2UuaGVhZGVycy5nZXQoJ2NvbnRlbnQtdHlwZScpPy5pbmNsdWRlcygnanNvbicpKSB7XG4gICAgICByZXR1cm4gcmVzcG9uc2UudGV4dCgpLnRoZW4odGV4dCA9PiB7XG4gICAgICAgIC8vIHN0cmluZyBvciAnbm90IHNldCcgc2NoZW1hLCBhcmUgdmFsaWRcbiAgICAgICAgLy8gd2hlbiBvdmVycmlkaW5nIHByb2Nlc3MgdGhleSBtaWdodCBoYW5kbGUgb3RoZXIgY2FzZXMsIHNvIHdlIGRvbid0IHdhbnQgdG8gYmxvY2sgb24gb3VyIGxvZ2ljXG4gICAgICAgIGlmIChcbiAgICAgICAgICBbJ3N0cmluZycsICd1bmRlZmluZWQnXS5pbmNsdWRlcyh0eXBlb2YgdGhpcy5zY2hlbWEpIHx8XG4gICAgICAgICAgdGhpcy5zY2hlbWEgPT09IG51bGwgfHxcbiAgICAgICAgICB0aGlzLnByb2Nlc3MgIT09IFJlc3RFbmRwb2ludC5wcm90b3R5cGUucHJvY2Vzc1xuICAgICAgICApXG4gICAgICAgICAgcmV0dXJuIHRleHQ7XG5cbiAgICAgICAgY29uc3QgZXJyb3IgPSBuZXcgTmV0d29ya0Vycm9yKHJlc3BvbnNlKTtcbiAgICAgICAgZXJyb3Iuc3RhdHVzID0gNDA0O1xuICAgICAgICBlcnJvci5tZXNzYWdlID0gYFVuZXhwZWN0ZWQgdGV4dCByZXNwb25zZSBmb3Igc2NoZW1hICR7dGhpcy5zY2hlbWF9YDtcbiAgICAgICAgLy8gY3VzdG9tIGRldi1vbmx5IG1lc3NhZ2VzIGZvciBtb3JlIGRldGFpbGVkIGNhdXNlXG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBlbHNlICovXG4gICAgICAgIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgIShcbiAgICAgICAgICAgICAgcmVzcG9uc2UuaGVhZGVycy5nZXQoJ2NvbnRlbnQtdHlwZScpPy5pbmNsdWRlcygnaHRtbCcpIHx8XG4gICAgICAgICAgICAgIHRleHQuc3RhcnRzV2l0aCgnPCFkb2N0eXBlIGh0bWw+JylcbiAgICAgICAgICAgIClcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIGlmICh0cnlQYXJzZSh0ZXh0KSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIGVycm9yLm1lc3NhZ2UgPSBgXCJjb250ZW50LXR5cGVcIiBoZWFkZXIgZG9lcyBub3QgaW5jbHVkZSBcImpzb25cIiwgYnV0IEpTT04gcmVzcG9uc2UgZm91bmQuXG5TZWUgaHR0cHM6Ly93d3cucmZjLWVkaXRvci5vcmcvcmZjL3JmYzQ2MjcgZm9yIGluZm9ybWF0aW9uIG9uIEpTT04gcmVzcG9uc2VzXG5cblVzaW5nIHBhcnNlZCBKU09OLlxuSWYgdGV4dCBjb250ZW50IHdhcyBleHBlY3RlZCBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL1Jlc3RFbmRwb2ludCNwYXJzZVJlc3BvbnNlYDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZXJyb3IubWVzc2FnZSA9IGBVbmV4cGVjdGVkIGh0bWwgcmVzcG9uc2UgZm9yIHNjaGVtYSAke3RoaXMuc2NoZW1hfVxuVGhpcyBsaWtlbHkgbWVhbnMgbm8gQVBJIGVuZHBvaW50IHdhcyBjb25maWd1cmVkIGZvciB0aGlzIHJlcXVlc3QsIHJlc3VsdGluZyBpbiBhbiBIVE1MIGZhbGxiYWNrLlxuXG5SZXNwb25zZSAoZmlyc3QgMzAwIGNoYXJhY3RlcnMpOiAke3RleHQuc3Vic3RyaW5nKDAsIDMwMCl9YDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3BvbnNlLmpzb24oKS5jYXRjaChlcnJvciA9PiB7XG4gICAgICBlcnJvci5zdGF0dXMgPSA0MDA7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9KTtcbiAgfVxuXG4gIHByb2Nlc3ModmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICBlcnJvclBvbGljeShlcnJvcikge1xuICAgIHJldHVybiBlcnJvci5zdGF0dXMgPj0gNTAwID8gJ3NvZnQnIDogdW5kZWZpbmVkO1xuICB9XG5cbiAgZ2V0IHBhdGhSZWdleCgpIHtcbiAgICByZXR1cm4gcGF0aFRvUmVnZXhwKHRoaXMucGF0aCk7XG4gIH1cblxuICB0ZXN0S2V5KGtleSkge1xuICAgIGNvbnN0IHByZWZpeCA9IHRoaXMubWV0aG9kICsgJyAnICsgdGhpcy51cmxQcmVmaXg7XG4gICAgaWYgKCFrZXkuc3RhcnRzV2l0aChwcmVmaXgpKSByZXR1cm4gZmFsc2U7XG4gICAgbGV0IGxhc3RRdWVzdGlvbiA9IGtleS5sYXN0SW5kZXhPZignPycpO1xuICAgIGlmIChsYXN0UXVlc3Rpb24gPT09IC0xKSBsYXN0UXVlc3Rpb24gPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHRoaXMucGF0aFJlZ2V4LnRlc3Qoa2V5LnN1YnN0cmluZyhwcmVmaXgubGVuZ3RoLCBsYXN0UXVlc3Rpb24pKTtcbiAgfVxuXG4gIGV4dGVuZChvcHRpb25zKSB7XG4gICAgLy8gbWFrZSBhIGNvbnN0cnVjdG9yL3Byb3RvdHlwZSBiYXNlZCBvZmYgdGhpc1xuICAgIC8vIGV4dGVuZCBmcm9tIGl0IGFuZCBpbml0IHdpdGggb3B0aW9ucyBzZW50XG4gICAgY2xhc3MgRSBleHRlbmRzIHRoaXMuY29uc3RydWN0b3Ige31cblxuICAgIE9iamVjdC5hc3NpZ24oRS5wcm90b3R5cGUsIHRoaXMpO1xuXG4gICAgcmV0dXJuIG5ldyBFKFxuICAgICAgLy8gIGZldGNoIGdldCBvdmVycmlkZGVuIGJ5IGZ1bmN0aW9uIHByb3RvdHlwZSwgc28gd2UgbXVzdCBzZXQgaXQgZXhwbGljaXRseSBldmVyeSB0aW1lXG4gICAgICB7IGZldGNoOiB0aGlzLmZldGNoLCAuLi5vcHRpb25zIH0sXG4gICAgKTtcbiAgfVxuXG4gIHBhZ2luYXRlZChyZW1vdmVDdXJzb3IpIHtcbiAgICBpZiAodHlwZW9mIHJlbW92ZUN1cnNvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGNvbnN0IGZpZWxkTmFtZSA9IHJlbW92ZUN1cnNvcjtcbiAgICAgIHJlbW92ZUN1cnNvciA9ICh7IC4uLnBhcmFtcyB9KSA9PiB7XG4gICAgICAgIGRlbGV0ZSBwYXJhbXNbZmllbGROYW1lXTtcbiAgICAgICAgcmV0dXJuIFtwYXJhbXNdO1xuICAgICAgfTtcbiAgICB9XG4gICAgbGV0IGZvdW5kID0gZmFsc2U7XG4gICAgY29uc3QgY3JlYXRlUGFnaW5hdGVkU2NoZW1hID0gY29sbGVjdGlvbiA9PiB7XG4gICAgICBmb3VuZCA9IHRydWU7XG4gICAgICByZXR1cm4gY3JlYXRlUGFnaW5hdGlvblNjaGVtYShyZW1vdmVDdXJzb3IsIGNvbGxlY3Rpb24pO1xuICAgIH07XG4gICAgY29uc3QgbmV3U2NoZW1hID0gbWFwQ29sbGVjdGlvbih0aGlzLnNjaGVtYSwgY3JlYXRlUGFnaW5hdGVkU2NoZW1hKTtcblxuICAgIGlmICghZm91bmQpIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBDb2xsZWN0aW9uJyk7XG4gICAgY29uc3Qgc3VwID0gdGhpcztcblxuICAgIHJldHVybiB0aGlzLmV4dGVuZCh7XG4gICAgICBzY2hlbWE6IG5ld1NjaGVtYSxcbiAgICAgIGtleSguLi5hcmdzKSB7XG4gICAgICAgIHJldHVybiBzdXAua2V5LmNhbGwodGhpcywgLi4ucmVtb3ZlQ3Vyc29yKC4uLmFyZ3MpKTtcbiAgICAgIH0sXG4gICAgICBuYW1lOiB0aGlzLm5hbWUgKyAnLmdldFBhZ2UnLFxuICAgIH0pO1xuICB9XG5cbiAgZ2V0IGdldFBhZ2UoKSB7XG4gICAgcmV0dXJuIHRoaXMucGFnaW5hdGVkKHRoaXMucGFnaW5hdGlvbkZpZWxkKTtcbiAgfVxuXG4gIGdldCBwdXNoKCkge1xuICAgIHJldHVybiB0aGlzLmV4dGVuZCh7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIHNjaGVtYTogZXh0cmFjdENvbGxlY3Rpb24odGhpcy5zY2hlbWEsIHMgPT4gcy5wdXNoKSxcbiAgICAgIG5hbWU6IHRoaXMubmFtZSArICcuY3JlYXRlJyxcbiAgICB9KTtcbiAgfVxuXG4gIGdldCB1bnNoaWZ0KCkge1xuICAgIHJldHVybiB0aGlzLmV4dGVuZCh7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIHNjaGVtYTogZXh0cmFjdENvbGxlY3Rpb24odGhpcy5zY2hlbWEsIHMgPT4gcy51bnNoaWZ0KSxcbiAgICAgIG5hbWU6IHRoaXMubmFtZSArICcuY3JlYXRlJyxcbiAgICB9KTtcbiAgfVxuXG4gIGdldCBhc3NpZ24oKSB7XG4gICAgcmV0dXJuIHRoaXMuZXh0ZW5kKHtcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgc2NoZW1hOiBleHRyYWN0Q29sbGVjdGlvbih0aGlzLnNjaGVtYSwgcyA9PiBzLmFzc2lnbiksXG4gICAgICBuYW1lOiB0aGlzLm5hbWUgKyAnLmNyZWF0ZScsXG4gICAgfSk7XG4gIH1cbn1cblxuY29uc3QgdHJ5UGFyc2UgPSBpbnB1dCA9PiB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIEpTT04ucGFyc2UoaW5wdXQpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufTtcbiJdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLFNBQVNBLFFBQVEsUUFBUSx1QkFBdUI7QUFDaEQsU0FBU0MsWUFBWSxRQUFRLGdCQUFnQjtBQUU3QyxPQUFPQyxpQkFBaUIsTUFBTSx3QkFBd0I7QUFDdEQsT0FBT0MsYUFBYSxNQUFNLG9CQUFvQjtBQUM5QyxPQUFPQyxZQUFZLE1BQU0sbUJBQW1CO0FBQzVDLFNBQVNDLHNCQUFzQixRQUFRLDJCQUEyQjtBQUNsRSxPQUFPQyxjQUFjLE1BQU0scUJBQXFCO0FBQ2hELFNBQVNDLFVBQVUsRUFBRUMsWUFBWSxFQUFFQyxNQUFNLFFBQVEsa0JBQWtCOztBQUVuRTtBQUNBO0FBQ0E7QUFD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