UNPKG

fusion-plugin-rpc

Version:

Fetch data on the server and client with an RPC style interface.

234 lines (229 loc) 28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _koaBodyparser = _interopRequireDefault(require("koa-bodyparser")); var _formidable = _interopRequireDefault(require("formidable")); var _fusionCore = require("fusion-core"); var _fusionPluginUniversalEvents = require("fusion-plugin-universal-events"); var _missingHandlerError = _interopRequireDefault(require("./missing-handler-error")); var _responseError = _interopRequireDefault(require("./response-error")); var _tokens = require("./tokens"); var _utils = require("./utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** Copyright (c) 2018 Uber Technologies, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ /* eslint-env node */ const statKey = 'rpc:method'; /* Helper function */ function hasHandler(handlers, method) { return Object.prototype.hasOwnProperty.call(handlers, method); } class RPC { constructor(emitter, handlers, ctx) { if (!ctx || !ctx.headers) { throw new Error('fusion-plugin-rpc requires `ctx`'); } this.ctx = ctx; this.emitter = emitter; this.handlers = handlers; return this; } async request(method, args) { const startTime = ms(); if (!this.ctx) { throw new Error('fusion-plugin-rpc requires `ctx`'); } if (!this.emitter) { throw new Error('fusion-plugin-rpc requires `emitter`'); } const scopedEmitter = this.emitter.from(this.ctx); if (!this.handlers) { throw new Error('fusion-plugin-rpc requires `handlers`'); } if (!hasHandler(this.handlers, method)) { const e = new _missingHandlerError.default(method); if (scopedEmitter) { scopedEmitter.emit('rpc:error', { method, origin: 'server', error: e }); } throw e; } try { const result = await this.handlers[method](args, this.ctx); if (scopedEmitter) { scopedEmitter.emit(statKey, { method, status: 'success', origin: 'server', timing: ms() - startTime }); } return result; } catch (e) { if (scopedEmitter) { scopedEmitter.emit(statKey, { method, error: e, status: 'failure', origin: 'server', timing: ms() - startTime }); } throw e; } } } const pluginFactory = () => (0, _fusionCore.createPlugin)({ deps: { RouteTags: _fusionCore.RouteTagsToken.optional, emitter: _fusionPluginUniversalEvents.UniversalEventsToken, handlers: _tokens.RPCHandlersToken, bodyParserOptions: _tokens.BodyParserOptionsToken.optional, rpcConfig: _tokens.RPCHandlersConfigToken.optional }, provides: deps => { const { emitter, handlers } = deps; const service = { from: (0, _fusionCore.memoize)(ctx => new RPC(emitter, handlers, ctx)) }; return service; }, middleware: deps => { const { emitter, handlers, bodyParserOptions, rpcConfig } = deps; if (!handlers) throw new Error('Missing handlers registered to RPCHandlersToken'); if (!emitter) throw new Error('Missing emitter registered to UniversalEventsToken'); const parseBody = (0, _koaBodyparser.default)(bodyParserOptions); const apiPath = (0, _utils.formatApiPath)(rpcConfig && rpcConfig.apiPath ? rpcConfig.apiPath : 'api'); return async (ctx, next) => { await next(); const routeTags = deps.RouteTags && deps.RouteTags.from(ctx) || {}; const scopedEmitter = emitter.from(ctx); if (ctx.method === 'POST' && ctx.path.startsWith(apiPath)) { const startTime = ms(); // eslint-disable-next-line no-useless-escape const pathMatch = new RegExp(`${apiPath}([^/]+)`, 'i'); const [, method] = ctx.path.match(pathMatch) || []; if (hasHandler(handlers, method)) { routeTags.name = method; let body; try { if (ctx.req && ctx.req.headers && ctx.req.headers['content-type'] && ctx.req.headers['content-type'].indexOf('multipart/form-data') !== -1) { const form = new _formidable.default.IncomingForm(); body = await new Promise((resolve, reject) => { form.parse(ctx.req, (err, fields, files) => { if (err) { reject(err); } resolve({ ...fields, ...files }); }); }); } else { await parseBody(ctx, () => Promise.resolve()); } } catch (e) { ctx.body = { status: 'failure', data: { message: e.message, code: e.type || 'ERR_BAD_BODY', meta: e.meta } }; if (scopedEmitter) { scopedEmitter.emit(statKey, { method, error: e, status: 'failure', origin: 'browser', timing: ms() - startTime }); } // don't try to call handler return; } try { const result = await handlers[method](body || ctx.request.body, ctx); ctx.body = { status: 'success', data: result }; if (scopedEmitter) { scopedEmitter.emit(statKey, { method, status: 'success', origin: 'browser', timing: ms() - startTime }); } } catch (e) { const error = e instanceof _responseError.default ? e : new Error(process.env.NODE_ENV !== "production" ? 'UnknownError - Use ResponseError from fusion-plugin-rpc (or fusion-plugin-rpc-redux-react if you are using React) package for more detailed error messages' : 'Internal Server Error'); ctx.body = { status: 'failure', data: { message: error.message, // @ts-expect-error code: error.code, // @ts-expect-error meta: error.meta } }; if (scopedEmitter) { scopedEmitter.emit(statKey, { method, error: e, status: 'failure', origin: 'browser', timing: ms() - startTime }); } } } else { const e = new _missingHandlerError.default(method); ctx.body = { status: 'failure', data: { message: e.message, code: e.code } }; ctx.status = 404; if (scopedEmitter) { scopedEmitter.emit('rpc:error', { origin: 'browser', method, error: e }); } } } }; } }); /* Helper functions */ function ms() { const [seconds, ns] = process.hrtime(); return Math.round(seconds * 1000 + ns / 1e6); } var _default = true && pluginFactory(); exports.default = _default; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJzdGF0S2V5IiwiaGFzSGFuZGxlciIsImhhbmRsZXJzIiwibWV0aG9kIiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiUlBDIiwiY29uc3RydWN0b3IiLCJlbWl0dGVyIiwiY3R4IiwiaGVhZGVycyIsIkVycm9yIiwicmVxdWVzdCIsImFyZ3MiLCJzdGFydFRpbWUiLCJtcyIsInNjb3BlZEVtaXR0ZXIiLCJmcm9tIiwiZSIsIk1pc3NpbmdIYW5kbGVyRXJyb3IiLCJlbWl0Iiwib3JpZ2luIiwiZXJyb3IiLCJyZXN1bHQiLCJzdGF0dXMiLCJ0aW1pbmciLCJwbHVnaW5GYWN0b3J5IiwiY3JlYXRlUGx1Z2luIiwiZGVwcyIsIlJvdXRlVGFncyIsIlJvdXRlVGFnc1Rva2VuIiwib3B0aW9uYWwiLCJVbml2ZXJzYWxFdmVudHNUb2tlbiIsIlJQQ0hhbmRsZXJzVG9rZW4iLCJib2R5UGFyc2VyT3B0aW9ucyIsIkJvZHlQYXJzZXJPcHRpb25zVG9rZW4iLCJycGNDb25maWciLCJSUENIYW5kbGVyc0NvbmZpZ1Rva2VuIiwicHJvdmlkZXMiLCJzZXJ2aWNlIiwibWVtb2l6ZSIsIm1pZGRsZXdhcmUiLCJwYXJzZUJvZHkiLCJib2R5cGFyc2VyIiwiYXBpUGF0aCIsImZvcm1hdEFwaVBhdGgiLCJuZXh0Iiwicm91dGVUYWdzIiwicGF0aCIsInN0YXJ0c1dpdGgiLCJwYXRoTWF0Y2giLCJSZWdFeHAiLCJtYXRjaCIsIm5hbWUiLCJib2R5IiwicmVxIiwiaW5kZXhPZiIsImZvcm0iLCJmb3JtaWRhYmxlIiwiSW5jb21pbmdGb3JtIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwYXJzZSIsImVyciIsImZpZWxkcyIsImZpbGVzIiwiZGF0YSIsIm1lc3NhZ2UiLCJjb2RlIiwidHlwZSIsIm1ldGEiLCJSZXNwb25zZUVycm9yIiwic2Vjb25kcyIsIm5zIiwicHJvY2VzcyIsImhydGltZSIsIk1hdGgiLCJyb3VuZCJdLCJzb3VyY2VzIjpbInNyYy9zZXJ2ZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqIENvcHlyaWdodCAoYykgMjAxOCBVYmVyIFRlY2hub2xvZ2llcywgSW5jLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqL1xuXG4vKiBlc2xpbnQtZW52IG5vZGUgKi9cblxuaW1wb3J0IGJvZHlwYXJzZXIgZnJvbSAna29hLWJvZHlwYXJzZXInO1xuaW1wb3J0IGZvcm1pZGFibGUgZnJvbSAnZm9ybWlkYWJsZSc7XG5cbmltcG9ydCB7Y3JlYXRlUGx1Z2luLCBtZW1vaXplLCBSb3V0ZVRhZ3NUb2tlbn0gZnJvbSAnZnVzaW9uLWNvcmUnO1xuaW1wb3J0IHR5cGUge0NvbnRleHR9IGZyb20gJ2Z1c2lvbi1jb3JlJztcbmltcG9ydCB7VW5pdmVyc2FsRXZlbnRzVG9rZW59IGZyb20gJ2Z1c2lvbi1wbHVnaW4tdW5pdmVyc2FsLWV2ZW50cyc7XG5pbXBvcnQgdHlwZSB7RmV0Y2h9IGZyb20gJ2Z1c2lvbi10b2tlbnMnO1xuXG5pbXBvcnQgTWlzc2luZ0hhbmRsZXJFcnJvciBmcm9tICcuL21pc3NpbmctaGFuZGxlci1lcnJvcic7XG5pbXBvcnQgUmVzcG9uc2VFcnJvciBmcm9tICcuL3Jlc3BvbnNlLWVycm9yJztcbmltcG9ydCB7XG4gIEJvZHlQYXJzZXJPcHRpb25zVG9rZW4sXG4gIFJQQ0hhbmRsZXJzVG9rZW4sXG4gIFJQQ0hhbmRsZXJzQ29uZmlnVG9rZW4sXG59IGZyb20gJy4vdG9rZW5zJztcbmltcG9ydCB0eXBlIHtIYW5kbGVyVHlwZX0gZnJvbSAnLi90b2tlbnMnO1xuaW1wb3J0IHR5cGUge1JQQ1BsdWdpblR5cGUsIElFbWl0dGVyfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7Zm9ybWF0QXBpUGF0aH0gZnJvbSAnLi91dGlscyc7XG5cbmNvbnN0IHN0YXRLZXkgPSAncnBjOm1ldGhvZCc7XG5cbi8qIEhlbHBlciBmdW5jdGlvbiAqL1xuZnVuY3Rpb24gaGFzSGFuZGxlcihoYW5kbGVyczogSGFuZGxlclR5cGUsIG1ldGhvZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoaGFuZGxlcnMsIG1ldGhvZCk7XG59XG5cbmNsYXNzIFJQQyB7XG4gIGN0eDogQ29udGV4dCB8IHVuZGVmaW5lZCB8IG51bGw7XG4gIGVtaXR0ZXI6IElFbWl0dGVyIHwgdW5kZWZpbmVkIHwgbnVsbDtcbiAgaGFuZGxlcnM6IEhhbmRsZXJUeXBlIHwgdW5kZWZpbmVkIHwgbnVsbDtcbiAgZmV0Y2g6IEZldGNoIHwgdW5kZWZpbmVkIHwgbnVsbDtcblxuICBjb25zdHJ1Y3RvcihlbWl0dGVyOiBJRW1pdHRlciwgaGFuZGxlcnM6IGFueSwgY3R4OiBDb250ZXh0KSB7XG4gICAgaWYgKCFjdHggfHwgIWN0eC5oZWFkZXJzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Z1c2lvbi1wbHVnaW4tcnBjIHJlcXVpcmVzIGBjdHhgJyk7XG4gICAgfVxuICAgIHRoaXMuY3R4ID0gY3R4O1xuICAgIHRoaXMuZW1pdHRlciA9IGVtaXR0ZXI7XG4gICAgdGhpcy5oYW5kbGVycyA9IGhhbmRsZXJzO1xuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBhc3luYyByZXF1ZXN0PFRBcmdzLCBUUmVzdWx0PihtZXRob2Q6IHN0cmluZywgYXJnczogVEFyZ3MpOiBQcm9taXNlPFRSZXN1bHQ+IHtcbiAgICBjb25zdCBzdGFydFRpbWUgPSBtcygpO1xuXG4gICAgaWYgKCF0aGlzLmN0eCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdmdXNpb24tcGx1Z2luLXJwYyByZXF1aXJlcyBgY3R4YCcpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuZW1pdHRlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdmdXNpb24tcGx1Z2luLXJwYyByZXF1aXJlcyBgZW1pdHRlcmAnKTtcbiAgICB9XG4gICAgY29uc3Qgc2NvcGVkRW1pdHRlciA9IHRoaXMuZW1pdHRlci5mcm9tKHRoaXMuY3R4KTtcblxuICAgIGlmICghdGhpcy5oYW5kbGVycykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdmdXNpb24tcGx1Z2luLXJwYyByZXF1aXJlcyBgaGFuZGxlcnNgJyk7XG4gICAgfVxuICAgIGlmICghaGFzSGFuZGxlcih0aGlzLmhhbmRsZXJzLCBtZXRob2QpKSB7XG4gICAgICBjb25zdCBlID0gbmV3IE1pc3NpbmdIYW5kbGVyRXJyb3IobWV0aG9kKTtcbiAgICAgIGlmIChzY29wZWRFbWl0dGVyKSB7XG4gICAgICAgIHNjb3BlZEVtaXR0ZXIuZW1pdCgncnBjOmVycm9yJywge1xuICAgICAgICAgIG1ldGhvZCxcbiAgICAgICAgICBvcmlnaW46ICdzZXJ2ZXInLFxuICAgICAgICAgIGVycm9yOiBlLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHRocm93IGU7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmhhbmRsZXJzW21ldGhvZF0oYXJncywgdGhpcy5jdHgpO1xuICAgICAgaWYgKHNjb3BlZEVtaXR0ZXIpIHtcbiAgICAgICAgc2NvcGVkRW1pdHRlci5lbWl0KHN0YXRLZXksIHtcbiAgICAgICAgICBtZXRob2QsXG4gICAgICAgICAgc3RhdHVzOiAnc3VjY2VzcycsXG4gICAgICAgICAgb3JpZ2luOiAnc2VydmVyJyxcbiAgICAgICAgICB0aW1pbmc6IG1zKCkgLSBzdGFydFRpbWUsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBpZiAoc2NvcGVkRW1pdHRlcikge1xuICAgICAgICBzY29wZWRFbWl0dGVyLmVtaXQoc3RhdEtleSwge1xuICAgICAgICAgIG1ldGhvZCxcbiAgICAgICAgICBlcnJvcjogZSxcbiAgICAgICAgICBzdGF0dXM6ICdmYWlsdXJlJyxcbiAgICAgICAgICBvcmlnaW46ICdzZXJ2ZXInLFxuICAgICAgICAgIHRpbWluZzogbXMoKSAtIHN0YXJ0VGltZSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxufVxuXG5jb25zdCBwbHVnaW5GYWN0b3J5OiAoKSA9PiBSUENQbHVnaW5UeXBlID0gKCkgPT5cbiAgY3JlYXRlUGx1Z2luKHtcbiAgICBkZXBzOiB7XG4gICAgICBSb3V0ZVRhZ3M6IFJvdXRlVGFnc1Rva2VuLm9wdGlvbmFsLFxuICAgICAgZW1pdHRlcjogVW5pdmVyc2FsRXZlbnRzVG9rZW4sXG4gICAgICBoYW5kbGVyczogUlBDSGFuZGxlcnNUb2tlbixcbiAgICAgIGJvZHlQYXJzZXJPcHRpb25zOiBCb2R5UGFyc2VyT3B0aW9uc1Rva2VuLm9wdGlvbmFsLFxuICAgICAgcnBjQ29uZmlnOiBSUENIYW5kbGVyc0NvbmZpZ1Rva2VuLm9wdGlvbmFsLFxuICAgIH0sXG5cbiAgICBwcm92aWRlczogKGRlcHMpID0+IHtcbiAgICAgIGNvbnN0IHtlbWl0dGVyLCBoYW5kbGVyc30gPSBkZXBzO1xuXG4gICAgICBjb25zdCBzZXJ2aWNlID0ge1xuICAgICAgICBmcm9tOiBtZW1vaXplKChjdHgpID0+IG5ldyBSUEMoZW1pdHRlciwgaGFuZGxlcnMsIGN0eCkpLFxuICAgICAgfTtcbiAgICAgIHJldHVybiBzZXJ2aWNlO1xuICAgIH0sXG5cbiAgICBtaWRkbGV3YXJlOiAoZGVwcykgPT4ge1xuICAgICAgY29uc3Qge2VtaXR0ZXIsIGhhbmRsZXJzLCBib2R5UGFyc2VyT3B0aW9ucywgcnBjQ29uZmlnfSA9IGRlcHM7XG4gICAgICBpZiAoIWhhbmRsZXJzKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgaGFuZGxlcnMgcmVnaXN0ZXJlZCB0byBSUENIYW5kbGVyc1Rva2VuJyk7XG4gICAgICBpZiAoIWVtaXR0ZXIpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBlbWl0dGVyIHJlZ2lzdGVyZWQgdG8gVW5pdmVyc2FsRXZlbnRzVG9rZW4nKTtcbiAgICAgIGNvbnN0IHBhcnNlQm9keSA9IGJvZHlwYXJzZXIoYm9keVBhcnNlck9wdGlvbnMpO1xuXG4gICAgICBjb25zdCBhcGlQYXRoID0gZm9ybWF0QXBpUGF0aChcbiAgICAgICAgcnBjQ29uZmlnICYmIHJwY0NvbmZpZy5hcGlQYXRoID8gcnBjQ29uZmlnLmFwaVBhdGggOiAnYXBpJ1xuICAgICAgKTtcblxuICAgICAgcmV0dXJuIGFzeW5jIChjdHgsIG5leHQpID0+IHtcbiAgICAgICAgYXdhaXQgbmV4dCgpO1xuICAgICAgICBjb25zdCByb3V0ZVRhZ3MgPSAoZGVwcy5Sb3V0ZVRhZ3MgJiYgZGVwcy5Sb3V0ZVRhZ3MuZnJvbShjdHgpKSB8fCB7fTtcbiAgICAgICAgY29uc3Qgc2NvcGVkRW1pdHRlciA9IGVtaXR0ZXIuZnJvbShjdHgpO1xuICAgICAgICBpZiAoY3R4Lm1ldGhvZCA9PT0gJ1BPU1QnICYmIGN0eC5wYXRoLnN0YXJ0c1dpdGgoYXBpUGF0aCkpIHtcbiAgICAgICAgICBjb25zdCBzdGFydFRpbWUgPSBtcygpO1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11c2VsZXNzLWVzY2FwZVxuICAgICAgICAgIGNvbnN0IHBhdGhNYXRjaCA9IG5ldyBSZWdFeHAoYCR7YXBpUGF0aH0oW14vXSspYCwgJ2knKTtcbiAgICAgICAgICBjb25zdCBbLCBtZXRob2RdID0gY3R4LnBhdGgubWF0Y2gocGF0aE1hdGNoKSB8fCBbXTtcbiAgICAgICAgICBpZiAoaGFzSGFuZGxlcihoYW5kbGVycywgbWV0aG9kKSkge1xuICAgICAgICAgICAgcm91dGVUYWdzLm5hbWUgPSBtZXRob2Q7XG4gICAgICAgICAgICBsZXQgYm9keTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBjdHgucmVxICYmXG4gICAgICAgICAgICAgICAgY3R4LnJlcS5oZWFkZXJzICYmXG4gICAgICAgICAgICAgICAgY3R4LnJlcS5oZWFkZXJzWydjb250ZW50LXR5cGUnXSAmJlxuICAgICAgICAgICAgICAgIGN0eC5yZXEuaGVhZGVyc1snY29udGVudC10eXBlJ10uaW5kZXhPZihcbiAgICAgICAgICAgICAgICAgICdtdWx0aXBhcnQvZm9ybS1kYXRhJ1xuICAgICAgICAgICAgICAgICkgIT09IC0xXG4gICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZvcm0gPSBuZXcgZm9ybWlkYWJsZS5JbmNvbWluZ0Zvcm0oKTtcbiAgICAgICAgICAgICAgICBib2R5ID0gYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgICAgZm9ybS5wYXJzZShcbiAgICAgICAgICAgICAgICAgICAgY3R4LnJlcSxcbiAgICAgICAgICAgICAgICAgICAgKFxuICAgICAgICAgICAgICAgICAgICAgIGVycixcbiAgICAgICAgICAgICAgICAgICAgICBmaWVsZHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFt4OiBzdHJpbmddOiBhbnk7XG4gICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICBmaWxlc1xuICAgICAgICAgICAgICAgICAgICApID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLmZpZWxkcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLmZpbGVzLFxuICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGF3YWl0IHBhcnNlQm9keShjdHgsICgpID0+IFByb21pc2UucmVzb2x2ZSgpKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICBjdHguYm9keSA9IHtcbiAgICAgICAgICAgICAgICBzdGF0dXM6ICdmYWlsdXJlJyxcbiAgICAgICAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICAgICAgICBtZXNzYWdlOiBlLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICBjb2RlOiBlLnR5cGUgfHwgJ0VSUl9CQURfQk9EWScsXG4gICAgICAgICAgICAgICAgICBtZXRhOiBlLm1ldGEsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgaWYgKHNjb3BlZEVtaXR0ZXIpIHtcbiAgICAgICAgICAgICAgICBzY29wZWRFbWl0dGVyLmVtaXQoc3RhdEtleSwge1xuICAgICAgICAgICAgICAgICAgbWV0aG9kLFxuICAgICAgICAgICAgICAgICAgZXJyb3I6IGUsXG4gICAgICAgICAgICAgICAgICBzdGF0dXM6ICdmYWlsdXJlJyxcbiAgICAgICAgICAgICAgICAgIG9yaWdpbjogJ2Jyb3dzZXInLFxuICAgICAgICAgICAgICAgICAgdGltaW5nOiBtcygpIC0gc3RhcnRUaW1lLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIC8vIGRvbid0IHRyeSB0byBjYWxsIGhhbmRsZXJcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBoYW5kbGVyc1ttZXRob2RdKFxuICAgICAgICAgICAgICAgIGJvZHkgfHwgY3R4LnJlcXVlc3QuYm9keSxcbiAgICAgICAgICAgICAgICBjdHhcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgY3R4LmJvZHkgPSB7XG4gICAgICAgICAgICAgICAgc3RhdHVzOiAnc3VjY2VzcycsXG4gICAgICAgICAgICAgICAgZGF0YTogcmVzdWx0LFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICBpZiAoc2NvcGVkRW1pdHRlcikge1xuICAgICAgICAgICAgICAgIHNjb3BlZEVtaXR0ZXIuZW1pdChzdGF0S2V5LCB7XG4gICAgICAgICAgICAgICAgICBtZXRob2QsXG4gICAgICAgICAgICAgICAgICBzdGF0dXM6ICdzdWNjZXNzJyxcbiAgICAgICAgICAgICAgICAgIG9yaWdpbjogJ2Jyb3dzZXInLFxuICAgICAgICAgICAgICAgICAgdGltaW5nOiBtcygpIC0gc3RhcnRUaW1lLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVycm9yID1cbiAgICAgICAgICAgICAgICBlIGluc3RhbmNlb2YgUmVzcG9uc2VFcnJvclxuICAgICAgICAgICAgICAgICAgPyBlXG4gICAgICAgICAgICAgICAgICA6IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICBfX0RFVl9fXG4gICAgICAgICAgICAgICAgICAgICAgICA/ICdVbmtub3duRXJyb3IgLSBVc2UgUmVzcG9uc2VFcnJvciBmcm9tIGZ1c2lvbi1wbHVnaW4tcnBjIChvciBmdXNpb24tcGx1Z2luLXJwYy1yZWR1eC1yZWFjdCBpZiB5b3UgYXJlIHVzaW5nIFJlYWN0KSBwYWNrYWdlIGZvciBtb3JlIGRldGFpbGVkIGVycm9yIG1lc3NhZ2VzJ1xuICAgICAgICAgICAgICAgICAgICAgICAgOiAnSW50ZXJuYWwgU2VydmVyIEVycm9yJ1xuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICBjdHguYm9keSA9IHtcbiAgICAgICAgICAgICAgICBzdGF0dXM6ICdmYWlsdXJlJyxcbiAgICAgICAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICAgICAgICBtZXNzYWdlOiBlcnJvci5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvclxuICAgICAgICAgICAgICAgICAgY29kZTogZXJyb3IuY29kZSxcbiAgICAgICAgICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICAgICAgICAgICAgICAgIG1ldGE6IGVycm9yLm1ldGEsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgaWYgKHNjb3BlZEVtaXR0ZXIpIHtcbiAgICAgICAgICAgICAgICBzY29wZWRFbWl0dGVyLmVtaXQoc3RhdEtleSwge1xuICAgICAgICAgICAgICAgICAgbWV0aG9kLFxuICAgICAgICAgICAgICAgICAgZXJyb3I6IGUsXG4gICAgICAgICAgICAgICAgICBzdGF0dXM6ICdmYWlsdXJlJyxcbiAgICAgICAgICAgICAgICAgIG9yaWdpbjogJ2Jyb3dzZXInLFxuICAgICAgICAgICAgICAgICAgdGltaW5nOiBtcygpIC0gc3RhcnRUaW1lLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IGUgPSBuZXcgTWlzc2luZ0hhbmRsZXJFcnJvcihtZXRob2QpO1xuICAgICAgICAgICAgY3R4LmJvZHkgPSB7XG4gICAgICAgICAgICAgIHN0YXR1czogJ2ZhaWx1cmUnLFxuICAgICAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZTogZS5tZXNzYWdlLFxuICAgICAgICAgICAgICAgIGNvZGU6IGUuY29kZSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjdHguc3RhdHVzID0gNDA0O1xuICAgICAgICAgICAgaWYgKHNjb3BlZEVtaXR0ZXIpIHtcbiAgICAgICAgICAgICAgc2NvcGVkRW1pdHRlci5lbWl0KCdycGM6ZXJyb3InLCB7XG4gICAgICAgICAgICAgICAgb3JpZ2luOiAnYnJvd3NlcicsXG4gICAgICAgICAgICAgICAgbWV0aG9kLFxuICAgICAgICAgICAgICAgIGVycm9yOiBlLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfSxcbiAgfSk7XG5cbi8qIEhlbHBlciBmdW5jdGlvbnMgKi9cbmZ1bmN0aW9uIG1zKCkge1xuICBjb25zdCBbc2Vjb25kcywgbnNdID0gcHJvY2Vzcy5ocnRpbWUoKTtcbiAgcmV0dXJuIE1hdGgucm91bmQoc2Vjb25kcyAqIDEwMDAgKyBucyAvIDFlNik7XG59XG5cbmV4cG9ydCBkZWZhdWx0IF9fTk9ERV9fICYmIChwbHVnaW5GYWN0b3J5KCkgYXMgYW55IGFzIFJQQ1BsdWdpblR5cGUpO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFTQTtBQUNBO0FBRUE7QUFFQTtBQUdBO0FBQ0E7QUFDQTtBQU9BO0FBQXNDO0FBMUJ0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBcUJBLE1BQU1BLE9BQU8sR0FBRyxZQUFZOztBQUU1QjtBQUNBLFNBQVNDLFVBQVUsQ0FBQ0MsUUFBcUIsRUFBRUMsTUFBYyxFQUFXO0VBQ2xFLE9BQU9DLE1BQU0sQ0FBQ0MsU0FBUyxDQUFDQyxjQUFjLENBQUNDLElBQUksQ0FBQ0wsUUFBUSxFQUFFQyxNQUFNLENBQUM7QUFDL0Q7QUFFQSxNQUFNSyxHQUFHLENBQUM7RUFNUkMsV0FBVyxDQUFDQyxPQUFpQixFQUFFUixRQUFhLEVBQUVTLEdBQVksRUFBRTtJQUMxRCxJQUFJLENBQUNBLEdBQUcsSUFBSSxDQUFDQSxHQUFHLENBQUNDLE9BQU8sRUFBRTtNQUN4QixNQUFNLElB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