Files
personal_site/frontend/node_modules/@aws-amplify/backend-deployer/lib/cdk_deployer.js
T

212 lines
27 KiB
JavaScript

import process from 'node:process';
import { AmplifyError, AmplifyFault, CDKContextKey, } from '@aws-amplify/platform-core';
import path from 'path';
import { MemoryContext, StackSelectionStrategy, } from '@aws-cdk/toolkit-lib';
import { tsImport } from 'tsx/esm/api';
import { CloudAssembly } from 'aws-cdk-lib/cx-api';
import { pathToFileURL } from 'url';
import { AssetStaging } from 'aws-cdk-lib/core';
import { Worker } from 'node:worker_threads';
/**
* Invokes CDK command via execa
*/
export class CDKDeployer {
cdkErrorMapper;
backendLocator;
packageManagerController;
cdkToolkit;
ioHost;
absoluteCloudAssemblyLocation = path.resolve(process.cwd(), '.amplify/artifacts/cdk.out');
/**
* Instantiates instance of CDKDeployer
*/
constructor(cdkErrorMapper, backendLocator, packageManagerController, cdkToolkit, ioHost) {
this.cdkErrorMapper = cdkErrorMapper;
this.backendLocator = backendLocator;
this.packageManagerController = packageManagerController;
this.cdkToolkit = cdkToolkit;
this.ioHost = ioHost;
}
/**
* Invokes cdk deploy API
*/
deploy = async (backendId, deployProps) => {
// Hack?? CDK uses global asset cache that is not cleared if assets are
// changing within the same process (which now happens with CDK Toolkit APIs)
// See https://github.com/aws/aws-cdk-cli/issues/236
AssetStaging.clearAssetHashCache();
const cx = await this.getCdkCloudAssembly(backendId, deployProps?.secretLastUpdated?.getTime());
// Initiate synth for the cloud executable and send a message for display.
const synthStartTime = Date.now();
let synthAssembly, synthError = undefined;
await this.ioHost.notify({
message: `Backend synthesis started`,
code: 'SYNTH_STARTED',
action: 'amplify',
time: new Date(),
level: 'info',
data: undefined,
});
try {
synthAssembly = await this.cdkToolkit.synth(cx, {
stacks: {
strategy: StackSelectionStrategy.ALL_STACKS,
},
});
}
catch (error) {
synthError = error;
}
const synthTimeSeconds = Math.floor((Date.now() - synthStartTime) / 10) / 100;
await this.ioHost.notify({
message: `Backend synthesized in ${synthTimeSeconds} seconds`,
code: 'SYNTH_FINISHED',
action: 'amplify',
time: new Date(),
level: 'result',
data: undefined,
});
// Typescript compilation. For type related errors, we prefer to show errors from TS to customers rather than synth
const typeCheckStartTime = Date.now();
await this.ioHost.notify({
message: `Backend type checks started`,
code: 'TS_STARTED',
action: 'amplify',
time: new Date(),
level: 'info',
data: undefined,
});
if (deployProps?.validateAppSources) {
try {
await this.compileProject(path.dirname(this.backendLocator.locate()));
}
catch (typeError) {
if (synthError &&
AmplifyError.isAmplifyError(typeError) &&
typeError.name === 'FunctionEnvVarFileNotGeneratedError') {
// synth has failed and we don't have auto generated function environment definition files. This
// resulted in the exception caught here, which is not very useful for the customers.
// We instead throw the synth error for customers to fix what caused the synth to fail.
throw this.cdkErrorMapper.getAmplifyError(synthError, backendId.type);
}
throw typeError;
}
finally {
const typeCheckTimeSeconds = Math.floor((Date.now() - typeCheckStartTime) / 10) / 100;
await this.ioHost.notify({
message: `Type checks completed in ${typeCheckTimeSeconds} seconds`,
code: 'TS_FINISHED',
action: 'amplify',
time: new Date(),
level: 'result',
data: undefined,
});
}
}
// If typescript compilation was successful but synth had failed, we throw synth error
if (synthError) {
throw this.cdkErrorMapper.getAmplifyError(synthError, backendId.type);
}
// Perform actual deployment. CFN or hotswap
const deployStartTime = Date.now();
try {
await this.cdkToolkit.deploy(synthAssembly, {
stacks: {
strategy: StackSelectionStrategy.ALL_STACKS,
},
deploymentMethod: backendId.type === 'sandbox'
? { method: 'hotswap', fallback: { method: 'direct' } }
: { method: 'direct' },
});
}
catch (error) {
await this.ioHost.notify({
message: 'Deployment failed',
code: 'DEPLOY_FAILED',
action: 'amplify',
time: new Date(),
level: 'error',
data: undefined,
});
throw this.cdkErrorMapper.getAmplifyError(error, backendId.type);
}
finally {
await synthAssembly?.dispose();
}
return {
deploymentTimes: {
synthesisTime: synthTimeSeconds,
totalTime: synthTimeSeconds +
Math.floor((Date.now() - deployStartTime) / 10) / 100,
},
};
};
/**
* Invokes cdk destroy API
*/
destroy = async (backendId) => {
const deploymentStartTime = Date.now();
try {
await this.cdkToolkit.destroy(await this.getCdkCloudAssembly(backendId), {
stacks: {
strategy: StackSelectionStrategy.ALL_STACKS,
},
});
return {
deploymentTimes: {
totalTime: Math.floor((Date.now() - deploymentStartTime) / 10) / 100,
},
};
}
catch (error) {
throw this.cdkErrorMapper.getAmplifyError(error, backendId.type);
}
};
compileProject = (projectDirectory) => {
return new Promise((resolve, reject) => {
const worker = new Worker(new URL('ts_compiler.js', import.meta.url), {
workerData: { projectDirectory },
});
worker.on('message', () => {
// do nothing
});
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new AmplifyFault('TSCompilerWorkerFault', {
message: `Worker stopped with exit code ${code}`,
}));
}
resolve();
});
});
};
/**
* Build cloud executable from dynamically importing the cdk ts file, i.e. backend.ts
*/
getCdkCloudAssembly = (backendId, secretLastUpdated) => {
const contextParams = {};
if (backendId.type === 'sandbox') {
if (secretLastUpdated) {
contextParams['secretLastUpdated'] = secretLastUpdated;
}
}
contextParams[CDKContextKey.BACKEND_NAMESPACE] = backendId.namespace;
contextParams[CDKContextKey.BACKEND_NAME] = backendId.name;
contextParams[CDKContextKey.DEPLOYMENT_TYPE] = backendId.type;
return this.cdkToolkit.fromAssemblyBuilder(async () => {
await tsImport(pathToFileURL(this.backendLocator.locate()).toString(), import.meta.url);
/**
By not having a child process with toolkit lib, the `process.on('beforeExit')` does not execute
on the CDK side resulting in the app not getting synthesized properly. So we send a signal/message
to the same process and catch it in backend package where App is initialized to explicitly perform synth
*/
process.emit('message', 'amplifySynth', undefined);
return new CloudAssembly(this.absoluteCloudAssemblyLocation);
}, {
contextStore: new MemoryContext(contextParams),
outdir: this.absoluteCloudAssemblyLocation,
});
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2RrX2RlcGxveWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2Nka19kZXBsb3llci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFZbkMsT0FBTyxFQUNMLFlBQVksRUFDWixZQUFZLEVBRVosYUFBYSxHQUNkLE1BQU0sNEJBQTRCLENBQUM7QUFDcEMsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sRUFDTCxhQUFhLEVBQ2Isc0JBQXNCLEdBRXZCLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN2QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbkQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUNwQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTdDOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFVSDtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBYkYsNkJBQTZCLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FDM0QsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUNiLDRCQUE0QixDQUM3QixDQUFDO0lBRUY7O09BRUc7SUFDSCxZQUNtQixjQUE4QixFQUM5QixjQUE4QixFQUM5Qix3QkFBa0QsRUFDbEQsVUFBbUIsRUFDbkIsTUFBcUI7UUFKckIsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQUM5Qiw2QkFBd0IsR0FBeEIsd0JBQXdCLENBQTBCO1FBQ2xELGVBQVUsR0FBVixVQUFVLENBQVM7UUFDbkIsV0FBTSxHQUFOLE1BQU0sQ0FBZTtJQUNyQyxDQUFDO0lBRUo7O09BRUc7SUFDSCxNQUFNLEdBQUcsS0FB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WUFDakMsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO2dCQUN0QixhQUFhLENBQUMsbUJBQW1CLENBQUMsR0FBRyxpQkFBaUIsQ0FBQztZQUN6RCxDQUFDO1FBQ0gsQ0FBQztRQUVELGFBQWEsQ0FBQyxhQUFhLENBQUMsaUJBQWlCLENBQUMsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDO1FBQ3JFLGFBQWEsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQztRQUMzRCxhQUFhLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUM7UUFDOUQsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLG1CQUFtQixDQUN4QyxLQUFLLElBQUksRUFBRTtZQUNULE1BQU0sUUFBUSxDQUNaLGFBQWEsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQ3RELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUNoQixDQUFDO1lBRUY7Ozs7ZUFJRztZQUNILE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGNBQWMsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUNuRCxPQUFPLElBQUksYUFBYSxDQUFDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1FBQy9ELENBQUMsRUFDRDtZQUNFLFlBQVksRUFBRSxJQUFJLGFBQWEsQ0FBQyxhQUFhLENBQUM7WUFDOUMsTUFBTSxFQUFFLElBQUksQ0FBQyw2QkFBNkI7U0FDM0MsQ0FDRixDQUFDO0lBQ0osQ0FBQyxDQUFDO0NBQ0giLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcHJvY2VzcyBmcm9tICdub2RlOnByb2Nlc3MnO1xuXG5pbXBvcnQge1xuICBCYWNrZW5kRGVwbG95ZXIsXG4gIERlcGxveVByb3BzLFxufSBmcm9tICcuL2Nka19kZXBsb3llcl9zaW5nbGV0b25fZmFjdG9yeS5qcyc7XG5pbXBvcnQgeyBDZGtFcnJvck1hcHBlciB9IGZyb20gJy4vY2RrX2Vycm9yX21hcHBlci5qcyc7XG5pbXBvcnQge1xuICBBbXBsaWZ5SU9Ib3N0LFxuICBCYWNrZW5kSWRlbnRpZmllcixcbiAgdHlwZSBQYWNrYWdlTWFuYWdlckNvbnRyb2xsZXIsXG59IGZyb20gJ0Bhd3MtYW1wbGlmeS9wbHVnaW4tdHlwZXMnO1xuaW1wb3J0IHtcbiAgQW1wbGlmeUVycm9yLFxuICBBbXBsaWZ5RmF1bHQsXG4gIEJhY2tlbmRMb2NhdG9yLFxuICBDREtDb250ZXh0S2V5LFxufSBmcm9tICdAYXdzLWFtcGxpZnkvcGxhdGZvcm0tY29yZSc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7XG4gIE1lbW9yeUNvbnRleHQsXG4gIFN0YWNrU2VsZWN0aW9uU3RyYXRlZ3ksXG4gIFRvb2xraXQsXG59IGZyb20gJ0Bhd3MtY2RrL3Rvb2xraXQtbGliJztcbmltcG9ydCB7IHRzSW1wb3J0IH0gZnJvbSAndHN4L2VzbS9hcGknO1xuaW1wb3J0IHsgQ2xvdWRBc3NlbWJseSB9IGZyb20gJ2F3cy1jZGstbGliL2N4LWFwaSc7XG5pbXBvcnQgeyBwYXRoVG9GaWxlVVJMIH0gZnJvbSAndXJsJztcbmltcG9ydCB7IEFzc2V0U3RhZ2luZyB9IGZyb20gJ2F3cy1jZGstbGliL2NvcmUnO1xuaW1wb3J0IHsgV29ya2VyIH0gZnJvbSAnbm9kZTp3b3JrZXJfdGhyZWFkcyc7XG5cbi8qKlxuICogSW52b2tlcyBDREsgY29tbWFuZCB2aWEgZXhlY2FcbiAqL1xuZXhwb3J0IGNsYXNzIENES0RlcGxveWVyIGltcGxlbWVudHMgQmFja2VuZERlcGxveWVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBhYnNvbHV0ZUNsb3VkQXNzZW1ibHlMb2NhdGlvbiA9IHBhdGgucmVzb2x2ZShcbiAgICBwcm9jZXNzLmN3ZCgpLFxuICAgICcuYW1wbGlmeS9hcnRpZmFjdHMvY2RrLm91dCcsXG4gICk7XG5cbiAgLyoqXG4gICAqIEluc3RhbnRpYXRlcyBpbnN0YW5jZSBvZiBDREtEZXBsb3llclxuICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBjZGtFcnJvck1hcHBlcjogQ2RrRXJyb3JNYXBwZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBiYWNrZW5kTG9jYXRvcjogQmFja2VuZExvY2F0b3IsXG4gICAgcHJpdmF0ZSByZWFkb25seSBwYWNrYWdlTWFuYWdlckNvbnRyb2xsZXI6IFBhY2thZ2VNYW5hZ2VyQ29udHJvbGxlcixcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNka1Rvb2xraXQ6IFRvb2xraXQsXG4gICAgcHJpdmF0ZSByZWFkb25seSBpb0hvc3Q6IEFtcGxpZnlJT0hvc3QsXG4gICkge31cblxuICAvKipcbiAgICogSW52b2tlcyBjZGsgZGVwbG95IEFQSVxuICAgKi9cbiAgZGVwbG95ID0gYXN5bmMgKGJhY2tlbmRJZDogQmFja2VuZElkZW50aWZpZXIsIGRlcGxveVByb3BzPzogRGVwbG95UHJvcHMpID0+IHtcbiAgICAvLyBIYWNrPz8gQ0RLIHVzZXMgZ2xvYmFsIGFzc2V0IGNhY2hlIHRoYXQgaXMgbm90IGNsZWFyZWQgaWYgYXNzZXRzIGFyZVxuICAgIC8vIGNoYW5naW5nIHdpdGhpbiB0aGUgc2FtZSBwcm9jZXNzICh3aGljaCBub3cgaGFwcGVucyB3aXRoIENESyBUb29sa2l0IEFQSXMpXG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay1jbGkvaXNzdWVzLzIzNlxuICAgIEFzc2V0U3RhZ2luZy5jbGVhckFzc2V0SGFzaENhY2hlKCk7XG5cbiAgICBjb25zdCBjeCA9IGF3YWl0IHRoaXMuZ2V0Q2RrQ2xvdWRBc3NlbWJseShcbiAgICAgIGJhY2tlbmRJZCxcbiAgICAgIGRlcGxveVByb3BzPy5zZWNyZXRMYXN0VXBkYXRlZD8uZ2V0VGltZSgpLFxuICAgICk7XG4gICAgLy8gSW5pdGlhdGUgc3ludGggZm9yIHRoZSBjbG91ZCBleGVjdXRhYmxlIGFuZCBzZW5kIGEgbWVzc2FnZSBmb3IgZGlzcGxheS5cbiAgICBjb25zdCBzeW50aFN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgbGV0IHN5bnRoQXNzZW1ibHksXG4gICAgICBzeW50aEVycm9yOiBFcnJvciB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICBhd2FpdCB0aGlzLmlvSG9zdC5ub3RpZnkoe1xuICAgICAgbWVzc2FnZTogYEJhY2tlbmQgc3ludGhlc2lzIHN0YXJ0ZWRgLFxuICAgICAgY29kZTogJ1NZTlRIX1NUQVJURUQnLFxuICAgICAgYWN0aW9uOiAnYW1wbGlmeScsXG4gICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgbGV2ZWw6ICdpbmZvJyxcbiAgICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIHRyeSB7XG4gICAgICBzeW50aEFzc2VtYmx5ID0gYXdhaXQgdGhpcy5jZGtUb29sa2l0LnN5bnRoKGN4LCB7XG4gICAgICAgIHN0YWNrczoge1xuICAgICAgICAgIHN0cmF0ZWd5OiBTdGFja1NlbGVjdGlvblN0cmF0ZWd5LkFMTF9TVEFDS1MsXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgc3ludGhFcnJvciA9IGVycm9yIGFzIEVycm9yO1xuICAgIH1cblxuICAgIGNvbnN0IHN5bnRoVGltZVNlY29uZHMgPVxuICAgICAgTWF0aC5mbG9vcigoRGF0ZS5ub3coKSAtIHN5bnRoU3RhcnRUaW1lKSAvIDEwKSAvIDEwMDtcblxuICAgIGF3YWl0IHRoaXMuaW9Ib3N0Lm5vdGlmeSh7XG4gICAgICBtZXNzYWdlOiBgQmFja2VuZCBzeW50aGVzaXplZCBpbiAke3N5bnRoVGltZVNlY29uZHN9IHNlY29uZHNgLFxuICAgICAgY29kZTogJ1NZTlRIX0ZJTklTSEVEJyxcbiAgICAgIGFjdGlvbjogJ2FtcGxpZnknLFxuICAgICAgdGltZTogbmV3IERhdGUoKSxcbiAgICAgIGxldmVsOiAncmVzdWx0JyxcbiAgICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIC8vIFR5cGVzY3JpcHQgY29tcGlsYXRpb24uIEZvciB0eXBlIHJlbGF0ZWQgZXJyb3JzLCB3ZSBwcmVmZXIgdG8gc2hvdyBlcnJvcnMgZnJvbSBUUyB0byBjdXN0b21lcnMgcmF0aGVyIHRoYW4gc3ludGhcbiAgICBjb25zdCB0eXBlQ2hlY2tTdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIGF3YWl0IHRoaXMuaW9Ib3N0Lm5vdGlmeSh7XG4gICAgICBtZXNzYWdlOiBgQmFja2VuZCB0eXBlIGNoZWNrcyBzdGFydGVkYCxcbiAgICAgIGNvZGU6ICdUU19TVEFSVEVEJyxcbiAgICAgIGFjdGlvbjogJ2FtcGxpZnknLFxuICAgICAgdGltZTogbmV3IERhdGUoKSxcbiAgICAgIGxldmVsOiAnaW5mbycsXG4gICAgICBkYXRhOiB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICBpZiAoZGVwbG95UHJvcHM/LnZhbGlkYXRlQXBwU291cmNlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5jb21waWxlUHJvamVjdChwYXRoLmRpcm5hbWUodGhpcy5iYWNrZW5kTG9jYXRvci5sb2NhdGUoKSkpO1xuICAgICAgfSBjYXRjaCAodHlwZUVycm9yKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBzeW50aEVycm9yICYmXG4gICAgICAgICAgQW1wbGlmeUVycm9yLmlzQW1wbGlmeUVycm9yKHR5cGVFcnJvcikgJiZcbiAgICAgICAgICB0eXBlRXJyb3IubmFtZSA9PT0gJ0Z1bmN0aW9uRW52VmFyRmlsZU5vdEdlbmVyYXRlZEVycm9yJ1xuICAgICAgICApIHtcbiAgICAgICAgICAvLyBzeW50aCBoYXMgZmFpbGVkIGFuZCB3ZSBkb24ndCBoYXZlIGF1dG8gZ2VuZXJhdGVkIGZ1bmN0aW9uIGVudmlyb25tZW50IGRlZmluaXRpb24gZmlsZXMuIFRoaXNcbiAgICAgICAgICAvLyByZXN1bHRlZCBpbiB0aGUgZXhjZXB0aW9uIGNhdWdodCBoZXJlLCB3aGljaCBpcyBub3QgdmVyeSB1c2VmdWwgZm9yIHRoZSBjdXN0b21lcnMuXG4gICAgICAgICAgLy8gV2UgaW5zdGVhZCB0aHJvdyB0aGUgc3ludGggZXJyb3IgZm9yIGN1c3RvbWVycyB0byBmaXggd2hhdCBjYXVzZWQgdGhlIHN5bnRoIHRvIGZhaWwuXG4gICAgICAgICAgdGhyb3cgdGhpcy5jZGtFcnJvck1hcHBlci5nZXRBbXBsaWZ5RXJyb3Ioc3ludGhFcnJvciwgYmFja2VuZElkLnR5cGUpO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IHR5cGVFcnJvcjtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGNvbnN0IHR5cGVDaGVja1RpbWVTZWNvbmRzID1cbiAgICAgICAgICBNYXRoLmZsb29yKChEYXRlLm5vdygpIC0gdHlwZUNoZWNrU3RhcnRUaW1lKSAvIDEwKSAvIDEwMDtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3Qubm90aWZ5KHtcbiAgICAgICAgICBtZXNzYWdlOiBgVHlwZSBjaGVja3MgY29tcGxldGVkIGluICR7dHlwZUNoZWNrVGltZVNlY29uZHN9IHNlY29uZHNgLFxuICAgICAgICAgIGNvZGU6ICdUU19GSU5JU0hFRCcsXG4gICAgICAgICAgYWN0aW9uOiAnYW1wbGlmeScsXG4gICAgICAgICAgdGltZTogbmV3IERhdGUoKSxcbiAgICAgICAgICBsZXZlbDogJ3Jlc3VsdCcsXG4gICAgICAgICAgZGF0YTogdW5kZWZpbmVkLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJZiB0eXBlc2NyaXB0IGNvbXBpbGF0aW9uIHdhcyBzdWNjZXNzZnVsIGJ1dCBzeW50aCBoYWQgZmFpbGVkLCB3ZSB0aHJvdyBzeW50aCBlcnJvclxuICAgIGlmIChzeW50aEVycm9yKSB7XG4gICAgICB0aHJvdyB0aGlzLmNka0Vycm9yTWFwcGVyLmdldEFtcGxpZnlFcnJvcihzeW50aEVycm9yLCBiYWNrZW5kSWQudHlwZSk7XG4gICAgfVxuXG4gICAgLy8gUGVyZm9ybSBhY3R1YWwgZGVwbG95bWVudC4gQ0ZOIG9yIGhvdHN3YXBcbiAgICBjb25zdCBkZXBsb3lTdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNka1Rvb2xraXQuZGVwbG95KHN5bnRoQXNzZW1ibHkhLCB7XG4gICAgICAgIHN0YWNrczoge1xuICAgICAgICAgIHN0cmF0ZWd5OiBTdGFja1NlbGVjdGlvblN0cmF0ZWd5LkFMTF9TVEFDS1MsXG4gICAgICAgIH0sXG4gICAgICAgIGRlcGxveW1lbnRNZXRob2Q6XG4gICAgICAgICAgYmFja2VuZElkLnR5cGUgPT09ICdzYW5kYm94J1xuICAgICAgICAgICAgPyB7IG1ldGhvZDogJ2hvdHN3YXAnLCBmYWxsYmFjazogeyBtZXRob2Q6ICdkaXJlY3QnIH0gfVxuICAgICAgICAgICAgOiB7IG1ldGhvZDogJ2RpcmVjdCcgfSxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSG9zdC5ub3RpZnkoe1xuICAgICAgICBtZXNzYWdlOiAnRGVwbG95bWVudCBmYWlsZWQnLFxuICAgICAgICBjb2RlOiAnREVQTE9ZX0ZBSUxFRCcsXG4gICAgICAgIGFjdGlvbjogJ2FtcGxpZnknLFxuICAgICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgICBsZXZlbDogJ2Vycm9yJyxcbiAgICAgICAgZGF0YTogdW5kZWZpbmVkLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyB0aGlzLmNka0Vycm9yTWFwcGVyLmdldEFtcGxpZnlFcnJvcihlcnJvciBhcyBFcnJvciwgYmFja2VuZElkLnR5cGUpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCBzeW50aEFzc2VtYmx5Py5kaXNwb3NlKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRlcGxveW1lbnRUaW1lczoge1xuICAgICAgICBzeW50aGVzaXNUaW1lOiBzeW50aFRpbWVTZWNvbmRzLFxuICAgICAgICB0b3RhbFRpbWU6XG4gICAgICAgICAgc3ludGhUaW1lU2Vjb25kcyArXG4gICAgICAgICAgTWF0aC5mbG9vcigoRGF0ZS5ub3coKSAtIGRlcGxveVN0YXJ0VGltZSkgLyAxMCkgLyAxMDAsXG4gICAgICB9LFxuICAgIH07XG4gIH07XG5cbiAgLyoqXG4gICAqIEludm9rZXMgY2RrIGRlc3Ryb3kgQVBJXG4gICAqL1xuICBkZXN0cm95ID0gYXN5bmMgKGJhY2tlbmRJZDogQmFja2VuZElkZW50aWZpZXIpID0+IHtcbiAgICBjb25zdCBkZXBsb3ltZW50U3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5jZGtUb29sa2l0LmRlc3Ryb3koYXdhaXQgdGhpcy5nZXRDZGtDbG91ZEFzc2VtYmx5KGJhY2tlbmRJZCksIHtcbiAgICAgICAgc3RhY2tzOiB7XG4gICAgICAgICAgc3RyYXRlZ3k6IFN0YWNrU2VsZWN0aW9uU3RyYXRlZ3kuQUxMX1NUQUNLUyxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZGVwbG95bWVudFRpbWVzOiB7XG4gICAgICAgICAgdG90YWxUaW1lOiBNYXRoLmZsb29yKChEYXRlLm5vdygpIC0gZGVwbG95bWVudFN0YXJ0VGltZSkgLyAxMCkgLyAxMDAsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyB0aGlzLmNka0Vycm9yTWFwcGVyLmdldEFtcGxpZnlFcnJvcihlcnJvciBhcyBFcnJvciwgYmFja2VuZElkLnR5cGUpO1xuICAgIH1cbiAgfTtcblxuICBjb21waWxlUHJvamVjdCA9IChwcm9qZWN0RGlyZWN0b3J5OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3Qgd29ya2VyID0gbmV3IFdvcmtlcihuZXcgVVJMKCd0c19jb21waWxlci5qcycsIGltcG9ydC5tZXRhLnVybCksIHtcbiAgICAgICAgd29ya2VyRGF0YTogeyBwcm9qZWN0RGlyZWN0b3J5IH0sXG4gICAgICB9KTtcbiAgICAgIHdvcmtlci5vbignbWVzc2FnZScsICgpID0+IHtcbiAgICAgICAgLy8gZG8gbm90aGluZ1xuICAgICAgfSk7XG4gICAgICB3b3JrZXIub24oJ2Vycm9yJywgcmVqZWN0KTtcbiAgICAgIHdvcmtlci5vbignZXhpdCcsIChjb2RlKSA9PiB7XG4gICAgICAgIGlmIChjb2RlICE9PSAwKSB7XG4gICAgICAgICAgcmVqZWN0KFxuICAgICAgICAgICAgbmV3IEFtcGxpZnlGYXVsdCgnVFNDb21waWxlcldvcmtlckZhdWx0Jywge1xuICAgICAgICAgICAgICBtZXNzYWdlOiBgV29ya2VyIHN0b3BwZWQgd2l0aCBleGl0IGNvZGUgJHtjb2RlfWAsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBCdWlsZCBjbG91ZCBleGVjdXRhYmxlIGZyb20gZHluYW1pY2FsbHkgaW1wb3J0aW5nIHRoZSBjZGsgdHMgZmlsZSwgaS5lLiBiYWNrZW5kLnRzXG4gICAqL1xuICBwcml2YXRlIGdldENka0Nsb3VkQXNzZW1ibHkgPSAoXG4gICAgYmFja2VuZElkOiBCYWNrZW5kSWRlbnRpZmllcixcbiAgICBzZWNyZXRMYXN0VXBkYXRlZD86IG51bWJlcixcbiAgKSA9PiB7XG4gICAgY29uc3QgY29udGV4dFBhcmFtczoge1xuICAgICAgW2tleTogc3RyaW5nXTogdW5rbm93bjtcbiAgICB9ID0ge307XG5cbiAgICBpZiAoYmFja2VuZElkLnR5cGUgPT09ICdzYW5kYm94Jykge1xuICAgICAgaWYgKHNlY3JldExhc3RVcGRhdGVkKSB7XG4gICAgICAgIGNvbnRleHRQYXJhbXNbJ3NlY3JldExhc3RVcGRhdGVkJ10gPSBzZWNyZXRMYXN0VXBkYXRlZDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb250ZXh0UGFyYW1zW0NES0NvbnRleHRLZXkuQkFDS0VORF9OQU1FU1BBQ0VdID0gYmFja2VuZElkLm5hbWVzcGFjZTtcbiAgICBjb250ZXh0UGFyYW1zW0NES0NvbnRleHRLZXkuQkFDS0VORF9OQU1FXSA9IGJhY2tlbmRJZC5uYW1lO1xuICAgIGNvbnRleHRQYXJhbXNbQ0RLQ29udGV4dEtleS5ERVBMT1lNRU5UX1RZUEVdID0gYmFja2VuZElkLnR5cGU7XG4gICAgcmV0dXJuIHRoaXMuY2RrVG9vbGtpdC5mcm9tQXNzZW1ibHlCdWlsZGVyKFxuICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCB0c0ltcG9ydChcbiAgICAgICAgICBwYXRoVG9GaWxlVVJMKHRoaXMuYmFja2VuZExvY2F0b3IubG9jYXRlKCkpLnRvU3RyaW5nKCksXG4gICAgICAgICAgaW1wb3J0Lm1ldGEudXJsLFxuICAgICAgICApO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgIEJ5IG5vdCBoYXZpbmcgYSBjaGlsZCBwcm9jZXNzIHdpdGggdG9vbGtpdCBsaWIsIHRoZSBgcHJvY2Vzcy5vbignYmVmb3JlRXhpdCcpYCBkb2VzIG5vdCBleGVjdXRlXG4gICAgICAgICAgb24gdGhlIENESyBzaWRlIHJlc3VsdGluZyBpbiB0aGUgYXBwIG5vdCBnZXR0aW5nIHN5bnRoZXNpemVkIHByb3Blcmx5LiBTbyB3ZSBzZW5kIGEgc2lnbmFsL21lc3NhZ2VcbiAgICAgICAgICB0byB0aGUgc2FtZSBwcm9jZXNzIGFuZCBjYXRjaCBpdCBpbiBiYWNrZW5kIHBhY2thZ2Ugd2hlcmUgQXBwIGlzIGluaXRpYWxpemVkIHRvIGV4cGxpY2l0bHkgcGVyZm9ybSBzeW50aFxuICAgICAgICAgKi9cbiAgICAgICAgcHJvY2Vzcy5lbWl0KCdtZXNzYWdlJywgJ2FtcGxpZnlTeW50aCcsIHVuZGVmaW5lZCk7XG4gICAgICAgIHJldHVybiBuZXcgQ2xvdWRBc3NlbWJseSh0aGlzLmFic29sdXRlQ2xvdWRBc3NlbWJseUxvY2F0aW9uKTtcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGNvbnRleHRTdG9yZTogbmV3IE1lbW9yeUNvbnRleHQoY29udGV4dFBhcmFtcyksXG4gICAgICAgIG91dGRpcjogdGhpcy5hYnNvbHV0ZUNsb3VkQXNzZW1ibHlMb2NhdGlvbixcbiAgICAgIH0sXG4gICAgKTtcbiAgfTtcbn1cbiJdfQ==