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