UNPKG

@riddance/aws-host

Version:

This is `@riddance/aws-host`, a TypeScript AWS Lambda host adapter for the Riddance serverless framework. It provides AWS-specific implementations for HTTP, event, timer, and context handling in Lambda functions by providing Lambda entry points that trans

161 lines 23.5 kB
import { fetchOK, missing, thrownHasStatus } from '@riddance/fetch'; import { SignatureV4 } from '@smithy/signature-v4'; import { createHash, createHmac, randomUUID } from 'node:crypto'; import { brotliCompress } from 'node:zlib'; export class SnsEventTransport { #attributes; #env; #baseUrl; #baseArn; constructor(client, context, account) { this.#attributes = asMessageAttributes(client); this.#env = context.env; const region = context.env.AWS_REGION ?? 'us-east-1'; this.#baseUrl = `https://sns.${region}.amazonaws.com`; const prefix = context.env.AWS_LAMBDA_FUNCTION_NAME?.slice(0, -(context.meta?.packageName.length ?? 0) - (context.meta?.fileName.length ?? 0) - 2) ?? 'AWS_LAMBDA_FUNCTION_NAME-missing'; this.#baseArn = `arn:aws:sns:${region}:${account}:${prefix}-`; } async sendEvent(topic, type, subject, data, messageId, signal) { try { const { message, additionalAttributes } = await prepareMessage(data, this.#attributes); await awsFetchOK(this.#env, this.#baseUrl, { headers: { 'content-type': 'application/x-www-form-urlencoded', 'x-amz-date': new Date().toISOString(), }, method: 'POST', body: new URLSearchParams({ Version: '2010-03-31', Action: 'Publish', TopicArn: `${this.#baseArn}${topic}-${type}`, Message: message ?? 'null', Subject: subject, MessageId: messageId ?? randomUUID().replaceAll('-', ''), Type: type, ...this.#attributes, ...additionalAttributes, }).toString(), signal, }, 'Error publishing SNS message.', { topic, type, data }); } catch (e) { if (thrownHasStatus(e, 404)) { return; } throw e; } } } async function prepareMessage(data, baseAttributes) { if (!data) { return {}; } const jsonMessage = JSON.stringify(data); if (jsonMessage.length < 8192) { return { message: jsonMessage }; } return { message: await compressMessage(jsonMessage), additionalAttributes: asMessageAttributes({ 'content-encoding': 'br' }, baseAttributes), }; } async function compressMessage(jsonMessage) { const compressed = await brotliCompressAsync(jsonMessage); return compressed.toString('base64'); } function brotliCompressAsync(data) { return new Promise((resolve, reject) => { brotliCompress(Buffer.from(data, 'utf8'), (err, result) => { if (err) { reject(err); return; } resolve(result); }); }); } function asMessageAttributes(obj, existingAttributes) { const baseIndex = existingAttributes ? Object.keys(existingAttributes).length / 3 + 1 : 1; return Object.fromEntries(Object.entries(obj) .filter(withoutUndefinedValue) .flatMap(([k, v], ix) => [ [`MessageAttributes.entry.${baseIndex + ix}.Name`, k], [ `MessageAttributes.entry.${baseIndex + ix}.Value.DataType`, typeof v === 'number' ? 'Number' : 'String', ], [`MessageAttributes.entry.${baseIndex + ix}.Value.StringValue`, v.toString()], ])); } function withoutUndefinedValue(kvp) { return kvp[1] !== undefined; } async function awsFetchOK(env, url, init, errorMessage, errorData) { return fetchOK(url, { ...init, headers: await awsHeaders(env, 'sns', url, init?.method ?? 'GET', init?.headers ?? {}, init?.body ?? ''), }, errorMessage, errorData); } async function awsHeaders(env, service, url, method, headers, body) { const signer = new SignatureV4({ service, region: env.AWS_REGION ?? 'us-east-1', sha256: AwsHash, credentials: { accessKeyId: env.AWS_ACCESS_KEY_ID ?? missing('AWS_ACCESS_KEY_ID'), secretAccessKey: env.AWS_SECRET_ACCESS_KEY ?? missing('AWS_SECRET_ACCESS_KEY'), sessionToken: env.AWS_SESSION_TOKEN, }, }); const uri = new URL(url); const query = {}; uri.searchParams.forEach((value, key) => { query[key] = value; }); const signed = await signer.sign({ method, protocol: 'https:', hostname: uri.hostname, path: uri.pathname, query, headers: { host: uri.hostname, ...headers, }, body, }); return signed.headers; } class AwsHash { #secret; #hash; constructor(secret) { this.#secret = secret; this.#hash = makeHash(this.#secret); } digest() { return Promise.resolve(this.#hash.digest()); } reset() { this.#hash = makeHash(this.#secret); } update(chunk) { this.#hash.update(new Uint8Array(Buffer.from(chunk))); } } function makeHash(secret) { return secret ? createHmac('sha256', castSourceData(secret)) : createHash('sha256'); } function castSourceData(data) { if (Buffer.isBuffer(data)) { return data; } if (typeof data === 'string') { return Buffer.from(data); } if (ArrayBuffer.isView(data)) { return Buffer.from(data.buffer, data.byteOffset, data.byteLength); } return Buffer.from(data); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBR25FLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQWEsTUFBTSxhQUFhLENBQUE7QUFDM0UsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUcxQyxNQUFNLE9BQU8saUJBQWlCO0lBQ2pCLFdBQVcsQ0FBMkI7SUFDdEMsSUFBSSxDQUFzQjtJQUMxQixRQUFRLENBQVE7SUFDaEIsUUFBUSxDQUFRO0lBRXpCLFlBQ0ksTUFBa0IsRUFDbEIsT0FBdUQsRUFDdkQsT0FBZTtRQUVmLElBQUksQ0FBQyxXQUFXLEdBQUcsbUJBQW1CLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDOUMsSUFBSSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFBO1FBQ3ZCLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxJQUFJLFdBQVcsQ0FBQTtRQUNwRCxJQUFJLENBQUMsUUFBUSxHQUFHLGVBQWUsTUFBTSxnQkFBZ0IsQ0FBQTtRQUNyRCxNQUFNLE1BQU0sR0FDUixPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixFQUFFLEtBQUssQ0FDdkMsQ0FBQyxFQUNELENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUN0RixJQUFJLGtDQUFrQyxDQUFBO1FBQzNDLElBQUksQ0FBQyxRQUFRLEdBQUcsZUFBZSxNQUFNLElBQUks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SyxRQUFRLEVBQUUsQ0FBQztRQUMzQixPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDNUIsQ0FBQztJQUNELElBQUksV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ3JFLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7QUFDNUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGZldGNoT0ssIG1pc3NpbmcsIHRocm93bkhhc1N0YXR1cyB9IGZyb20gJ0ByaWRkYW5jZS9mZXRjaCdcbmltcG9ydCB7IEV2ZW50VHJhbnNwb3J0LCB0eXBlIENsaWVudEluZm8gfSBmcm9tICdAcmlkZGFuY2UvaG9zdC9jb250ZXh0J1xuaW1wb3J0IHR5cGUgeyBNZXRhZGF0YSB9IGZyb20gJ0ByaWRkYW5jZS9ob3N0L3JlZ2lzdHJ5J1xuaW1wb3J0IHsgU2lnbmF0dXJlVjQgfSBmcm9tICdAc21pdGh5L3NpZ25hdHVyZS12NCdcbmltcG9ydCB7IGNyZWF0ZUhhc2gsIGNyZWF0ZUhtYWMsIHJhbmRvbVVVSUQsIHR5cGUgSGFzaCB9IGZyb20gJ25vZGU6Y3J5cHRvJ1xuaW1wb3J0IHsgYnJvdGxpQ29tcHJlc3MgfSBmcm9tICdub2RlOnpsaWInXG5pbXBvcnQgdHlwZSB7IEVudmlyb25tZW50LCBKc29uIH0gZnJvbSAnLi4vY29udGV4dC5qcydcblxuZXhwb3J0IGNsYXNzIFNuc0V2ZW50VHJhbnNwb3J0IGltcGxlbWVudHMgRXZlbnRUcmFuc3BvcnQge1xuICAgIHJlYWRvbmx5ICNhdHRyaWJ1dGVzOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9XG4gICAgcmVhZG9ubHkgI2VudjogUGFydGlhbDxFbnZpcm9ubWVudD5cbiAgICByZWFkb25seSAjYmFzZVVybDogc3RyaW5nXG4gICAgcmVhZG9ubHkgI2Jhc2VBcm46IHN0cmluZ1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIGNsaWVudDogQ2xpZW50SW5mbyxcbiAgICAgICAgY29udGV4dDogeyBlbnY6IFBhcnRpYWw8RW52aXJvbm1lbnQ+OyBtZXRhPzogTWV0YWRhdGEgfSxcbiAgICAgICAgYWNjb3VudDogc3RyaW5nLFxuICAgICkge1xuICAgICAgICB0aGlzLiNhdHRyaWJ1dGVzID0gYXNNZXNzYWdlQXR0cmlidXRlcyhjbGllbnQpXG4gICAgICAgIHRoaXMuI2VudiA9IGNvbnRleHQuZW52XG4gICAgICAgIGNvbnN0IHJlZ2lvbiA9IGNvbnRleHQuZW52LkFXU19SRUdJT04gPz8gJ3VzLWVhc3QtMSdcbiAgICAgICAgdGhpcy4jYmFzZVVybCA9IGBodHRwczovL3Nucy4ke3JlZ2lvbn0uYW1hem9uYXdzLmNvbWBcbiAgICAgICAgY29uc3QgcHJlZml4ID1cbiAgICAgICAgICAgIGNvbnRleHQuZW52LkFXU19MQU1CREFfRlVOQ1RJT05fTkFNRT8uc2xpY2UoXG4gICAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgICAtKGNvbnRleHQubWV0YT8ucGFja2FnZU5hbWUubGVuZ3RoID8/IDApIC0gKGNvbnRleHQubWV0YT8uZmlsZU5hbWUubGVuZ3RoID8/IDApIC0gMixcbiAgICAgICAgICAgICkgPz8gJ0FXU19MQU1CREFfRlVOQ1RJT05fTkFNRS1taXNzaW5nJ1xuICAgICAgICB0aGlzLiNiYXNlQXJuID0gYGFybjphd3M6c25zOiR7cmVnaW9ufToke2FjY291bnR9OiR7cHJlZml4fS1gXG4gICAgfVxuXG4gICAgYXN5bmMgc2VuZEV2ZW50KFxuICAgICAgICB0b3BpYzogc3RyaW5nLFxuICAgICAgICB0eXBlOiBzdHJpbmcsXG4gICAgICAgIHN1YmplY3Q6IHN0cmluZyxcbiAgICAgICAgZGF0YTpcbiAgICAgICAgICAgIHwge1xuICAgICAgICAgICAgICAgICAgcmVhZG9ubHkgW2tleTogc3RyaW5nXTogSnNvblxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB8IHVuZGVmaW5lZCxcbiAgICAgICAgbWVzc2FnZUlkOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgICAgIHNpZ25hbDogQWJvcnRTaWduYWwsXG4gICAgKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCB7IG1lc3NhZ2UsIGFkZGl0aW9uYWxBdHRyaWJ1dGVzIH0gPSBhd2FpdCBwcmVwYXJlTWVzc2FnZShkYXRhLCB0aGlzLiNhdHRyaWJ1dGVzKVxuXG4gICAgICAgICAgICBhd2FpdCBhd3NGZXRjaE9LKFxuICAgICAgICAgICAgICAgIHRoaXMuI2VudixcbiAgICAgICAgICAgICAgICB0aGlzLiNiYXNlVXJsLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgJ2NvbnRlbnQtdHlwZSc6ICdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ3gtYW16LWRhdGUnOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICAgICAgICBib2R5OiBuZXcgVVJMU2VhcmNoUGFyYW1zKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb246ICcyMDEwLTAzLTMxJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIEFjdGlvbjogJ1B1Ymxpc2gnLFxuICAgICAgICAgICAgICAgICAgICAgICAgVG9waWNBcm46IGAke3RoaXMuI2Jhc2VBcm59JHt0b3BpY30tJHt0eXBlfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICBNZXNzYWdlOiBtZXNzYWdlID8/ICdudWxsJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIFN1YmplY3Q6IHN1YmplY3QsXG4gICAgICAgICAgICAgICAgICAgICAgICBNZXNzYWdlSWQ6IG1lc3NhZ2VJZCA/PyByYW5kb21VVUlEKCkucmVwbGFjZUFsbCgnLScsICcnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFR5cGU6IHR5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAuLi50aGlzLiNhdHRyaWJ1dGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgLi4uYWRkaXRpb25hbEF0dHJpYnV0ZXMsXG4gICAgICAgICAgICAgICAgICAgIH0pLnRvU3RyaW5nKCksXG4gICAgICAgICAgICAgICAgICAgIHNpZ25hbCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICdFcnJvciBwdWJsaXNoaW5nIFNOUyBtZXNzYWdlLicsXG4gICAgICAgICAgICAgICAgeyB0b3BpYywgdHlwZSwgZGF0YSB9LFxuICAgICAgICAgICAgKVxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAodGhyb3duSGFzU3RhdHVzKGUsIDQwNCkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRocm93IGVcbiAgICAgICAgfVxuICAgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcHJlcGFyZU1lc3NhZ2UoXG4gICAgZGF0YTpcbiAgICAgICAgfCB7XG4gICAgICAgICAgICAgIHJlYWRvbmx5IFtrZXk6IHN0cmluZ106IEpzb25cbiAgICAgICAgICB9XG4gICAgICAgIHwgdW5kZWZpbmVkLFxuICAgIGJhc2VBdHRyaWJ1dGVzOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9LFxuKSB7XG4gICAgaWYgKCFkYXRhKSB7XG4gICAgICAgIHJldHVybiB7fVxuICAgIH1cbiAgICBjb25zdCBqc29uTWVzc2FnZSA9IEpTT04uc3RyaW5naWZ5KGRhdGEpXG4gICAgaWYgKGpzb25NZXNzYWdlLmxlbmd0aCA8IDgxOTIpIHtcbiAgICAgICAgcmV0dXJuIHsgbWVzc2FnZToganNvbk1lc3NhZ2UgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAgIG1lc3NhZ2U6IGF3YWl0IGNvbXByZXNzTWVzc2FnZShqc29uTWVzc2FnZSksXG4gICAgICAgIGFkZGl0aW9uYWxBdHRyaWJ1dGVzOiBhc01lc3NhZ2VBdHRyaWJ1dGVzKHsgJ2NvbnRlbnQtZW5jb2RpbmcnOiAnYnInIH0sIGJhc2VBdHRyaWJ1dGVzKSxcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNvbXByZXNzTWVzc2FnZShqc29uTWVzc2FnZTogc3RyaW5nKSB7XG4gICAgY29uc3QgY29tcHJlc3NlZCA9IGF3YWl0IGJyb3RsaUNvbXByZXNzQXN5bmMoanNvbk1lc3NhZ2UpXG4gICAgcmV0dXJuIGNvbXByZXNzZWQudG9TdHJpbmcoJ2Jhc2U2NCcpXG59XG5cbmZ1bmN0aW9uIGJyb3RsaUNvbXByZXNzQXN5bmMoZGF0YTogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBicm90bGlDb21wcmVzcyhCdWZmZXIuZnJvbShkYXRhLCAndXRmOCcpLCAoZXJyLCByZXN1bHQpID0+IHtcbiAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICByZWplY3QoZXJyKVxuICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzb2x2ZShyZXN1bHQpXG4gICAgICAgIH0pXG4gICAgfSlcbn1cblxuZnVuY3Rpb24gYXNNZXNzYWdlQXR0cmlidXRlcyhcbiAgICBvYmo6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgbnVtYmVyIHwgdW5kZWZpbmVkIH0sXG4gICAgZXhpc3RpbmdBdHRyaWJ1dGVzPzogeyBba2V5OiBzdHJpbmddOiB1bmtub3duIH0sXG4pIHtcbiAgICBjb25zdCBiYXNlSW5kZXggPSBleGlzdGluZ0F0dHJpYnV0ZXMgPyBPYmplY3Qua2V5cyhleGlzdGluZ0F0dHJpYnV0ZXMpLmxlbmd0aCAvIDMgKyAxIDogMVxuICAgIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgIE9iamVjdC5lbnRyaWVzKG9iailcbiAgICAgICAgICAgIC5maWx0ZXIod2l0aG91dFVuZGVmaW5lZFZhbHVlKVxuICAgICAgICAgICAgLmZsYXRNYXAoKFtrLCB2XSwgaXgpID0+IFtcbiAgICAgICAgICAgICAgICBbYE1lc3NhZ2VBdHRyaWJ1dGVzLmVudHJ5LiR7YmFzZUluZGV4ICsgaXh9Lk5hbWVgLCBrXSxcbiAgICAgICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAgICAgIGBNZXNzYWdlQXR0cmlidXRlcy5lbnRyeS4ke2Jhc2VJbmRleCArIGl4fS5WYWx1ZS5EYXRhVHlwZWAsXG4gICAgICAgICAgICAgICAgICAgIHR5cGVvZiB2ID09PSAnbnVtYmVyJyA/ICdOdW1iZXInIDogJ1N0cmluZycsXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBbYE1lc3NhZ2VBdHRyaWJ1dGVzLmVudHJ5LiR7YmFzZUluZGV4ICsgaXh9LlZhbHVlLlN0cmluZ1ZhbHVlYCwgdi50b1N0cmluZygpXSxcbiAgICAgICAgICAgIF0pLFxuICAgIClcbn1cblxuZnVuY3Rpb24gd2l0aG91dFVuZGVmaW5lZFZhbHVlKFxuICAgIGt2cDogW3N0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgdW5kZWZpbmVkXSxcbik6IGt2cCBpcyBbc3RyaW5nLCBzdHJpbmcgfCBudW1iZXJdIHtcbiAgICByZXR1cm4ga3ZwWzFdICE9PSB1bmRlZmluZWRcbn1cblxudHlwZSBSZXF1ZXN0SW5pdCA9IHtcbiAgICBtZXRob2Q6IHN0cmluZ1xuICAgIGhlYWRlcnM/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9XG4gICAgYm9keT86IHN0cmluZ1xuICAgIHNpZ25hbDogQWJvcnRTaWduYWxcbn1cblxuYXN5bmMgZnVuY3Rpb24gYXdzRmV0Y2hPSyhcbiAgICBlbnY6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH0sXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgaW5pdDogUmVxdWVzdEluaXQgfCB1bmRlZmluZWQsXG4gICAgZXJyb3JNZXNzYWdlOiBzdHJpbmcsXG4gICAgZXJyb3JEYXRhPzoge1xuICAgICAgICBba2V5OiBzdHJpbmddOiB1bmtub3duXG4gICAgfSxcbikge1xuICAgIHJldHVybiBmZXRjaE9LKFxuICAgICAgICB1cmwsXG4gICAgICAgIHtcbiAgICAgICAgICAgIC4uLmluaXQsXG4gICAgICAgICAgICBoZWFkZXJzOiBhd2FpdCBhd3NIZWFkZXJzKFxuICAgICAgICAgICAgICAgIGVudixcbiAgICAgICAgICAgICAgICAnc25zJyxcbiAgICAgICAgICAgICAgICB1cmwsXG4gICAgICAgICAgICAgICAgaW5pdD8ubWV0aG9kID8/ICdHRVQnLFxuICAgICAgICAgICAgICAgIGluaXQ/LmhlYWRlcnMgPz8ge30sXG4gICAgICAgICAgICAgICAgaW5pdD8uYm9keSA/PyAnJyxcbiAgICAgICAgICAgICksXG4gICAgICAgIH0sXG4gICAgICAgIGVycm9yTWVzc2FnZSxcbiAgICAgICAgZXJyb3JEYXRhLFxuICAgIClcbn1cblxuYXN5bmMgZnVuY3Rpb24gYXdzSGVhZGVycyhcbiAgICBlbnY6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH0sXG4gICAgc2VydmljZTogc3RyaW5nLFxuICAgIHVybDogc3RyaW5nLFxuICAgIG1ldGhvZDogc3RyaW5nLFxuICAgIGhlYWRlcnM6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0sXG4gICAgYm9keTogc3RyaW5nLFxuKSB7XG4gICAgY29uc3Qgc2lnbmVyID0gbmV3IFNpZ25hdHVyZVY0KHtcbiAgICAgICAgc2VydmljZSxcbiAgICAgICAgcmVnaW9uOiBlbnYuQVdTX1JFR0lPTiA/PyAndXMtZWFzdC0xJyxcbiAgICAgICAgc2hhMjU2OiBBd3NIYXNoLFxuICAgICAgICBjcmVkZW50aWFsczoge1xuICAgICAgICAgICAgYWNjZXNzS2V5SWQ6IGVudi5BV1NfQUNDRVNTX0tFWV9JRCA/PyBtaXNzaW5nKCdBV1NfQUNDRVNTX0tFWV9JRCcpLFxuICAgICAgICAgICAgc2VjcmV0QWNjZXNzS2V5OiBlbnYuQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZID8/IG1pc3NpbmcoJ0FXU19TRUNSRVRfQUNDRVNTX0tFWScpLFxuICAgICAgICAgICAgc2Vzc2lvblRva2VuOiBlbnYuQVdTX1NFU1NJT05fVE9LRU4sXG4gICAgICAgIH0sXG4gICAgfSlcbiAgICBjb25zdCB1cmkgPSBuZXcgVVJMKHVybClcbiAgICBjb25zdCBxdWVyeTogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfSA9IHt9XG4gICAgdXJpLnNlYXJjaFBhcmFtcy5mb3JFYWNoKCh2YWx1ZSwga2V5KSA9PiB7XG4gICAgICAgIHF1ZXJ5W2tleV0gPSB2YWx1ZVxuICAgIH0pXG4gICAgY29uc3Qgc2lnbmVkID0gYXdhaXQgc2lnbmVyLnNpZ24oe1xuICAgICAgICBtZXRob2QsXG4gICAgICAgIHByb3RvY29sOiAnaHR0cHM6JyxcbiAgICAgICAgaG9zdG5hbWU6IHVyaS5ob3N0bmFtZSxcbiAgICAgICAgcGF0aDogdXJpLnBhdGhuYW1lLFxuICAgICAgICBxdWVyeSxcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgaG9zdDogdXJpLmhvc3RuYW1lLFxuICAgICAgICAgICAgLi4uaGVhZGVycyxcbiAgICAgICAgfSxcbiAgICAgICAgYm9keSxcbiAgICB9KVxuICAgIHJldHVybiBzaWduZWQuaGVhZGVyc1xufVxuXG50eXBlIFNvdXJjZURhdGEgPSBzdHJpbmcgfCBBcnJheUJ1ZmZlciB8IEFycmF5QnVmZmVyVmlld1xuXG5jbGFzcyBBd3NIYXNoIHtcbiAgICByZWFkb25seSAjc2VjcmV0PzogU291cmNlRGF0YVxuICAgICNoYXNoOiBIYXNoIHwgUmV0dXJuVHlwZTx0eXBlb2YgY3JlYXRlSG1hYz5cblxuICAgIGNvbnN0cnVjdG9yKHNlY3JldD86IFNvdXJjZURhdGEpIHtcbiAgICAgICAgdGhpcy4jc2VjcmV0ID0gc2VjcmV0XG4gICAgICAgIHRoaXMuI2hhc2ggPSBtYWtlSGFzaCh0aGlzLiNzZWNyZXQpXG4gICAgfVxuXG4gICAgZGlnZXN0KCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMuI2hhc2guZGlnZXN0KCkpXG4gICAgfVxuXG4gICAgcmVzZXQoKSB7XG4gICAgICAgIHRoaXMuI2hhc2ggPSBtYWtlSGFzaCh0aGlzLiNzZWNyZXQpXG4gICAgfVxuXG4gICAgdXBkYXRlKGNodW5rOiBVaW50OEFycmF5KSB7XG4gICAgICAgIHRoaXMuI2hhc2gudXBkYXRlKG5ldyBVaW50OEFycmF5KEJ1ZmZlci5mcm9tKGNodW5rKSkpXG4gICAgfVxufVxuXG5mdW5jdGlvbiBtYWtlSGFzaChzZWNyZXQ/OiBTb3VyY2VEYXRhKSB7XG4gICAgcmV0dXJuIHNlY3JldCA/IGNyZWF0ZUhtYWMoJ3NoYTI1NicsIGNhc3RTb3VyY2VEYXRhKHNlY3JldCkpIDogY3JlYXRlSGFzaCgnc2hhMjU2Jylcbn1cblxuZnVuY3Rpb24gY2FzdFNvdXJjZURhdGEoZGF0YTogU291cmNlRGF0YSkge1xuICAgIGlmIChCdWZmZXIuaXNCdWZmZXIoZGF0YSkpIHtcbiAgICAgICAgcmV0dXJuIGRhdGFcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJykge1xuICAgICAgICByZXR1cm4gQnVmZmVyLmZyb20oZGF0YSlcbiAgICB9XG4gICAgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhkYXRhKSkge1xuICAgICAgICByZXR1cm4gQnVmZmVyLmZyb20oZGF0YS5idWZmZXIsIGRhdGEuYnl0ZU9mZnNldCwgZGF0YS5ieXRlTGVuZ3RoKVxuICAgIH1cbiAgICByZXR1cm4gQnVmZmVyLmZyb20oZGF0YSlcbn1cbiJdfQ==