@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
JavaScript
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==