diff --git a/bin/cdklocal b/bin/cdklocal index b62b7b7..819a6e1 100755 --- a/bin/cdklocal +++ b/bin/cdklocal @@ -28,6 +28,14 @@ const getLocalEndpoint = async () => process.env.AWS_ENDPOINT_URL || `${PROTOCOL var resolvedHostname = undefined; +const runAsyncFunctionAsSync = (asyncFn) => { + return (...args) => { + asyncFn(...args).catch((e) => { + console.error(e); + }); + }; +}; + const getLocalHost = async () => { if (resolvedHostname) { // early exit to not resolve again @@ -204,34 +212,51 @@ const patchCurrentAccount = (SDK) => { }; const patchToolkitInfo = (ToolkitInfo) => { - const { - BUCKET_NAME_OUTPUT, BUCKET_DOMAIN_NAME_OUTPUT - } = require("aws-cdk/lib/api/bootstrap/bootstrap-props"); - - const setBucketUrl = function setBucketUrl(object) { + const setBucketUrl = function setBucketUrl(object, bucket, domain) { + const newBucketUrl = `https://${domain.replace(`${bucket}.`, "")}:${EDGE_PORT}/${bucket}`; Object.defineProperty(object, "bucketUrl", { - async get() { - const bucket = this.requireOutput(BUCKET_NAME_OUTPUT); - const domain = this.requireOutput(BUCKET_DOMAIN_NAME_OUTPUT) || await getLocalHost(); - return `https://${domain.replace(`${bucket}.`, "")}:${EDGE_PORT}/${bucket}`; + get() { + return newBucketUrl; } }); }; + // Pre-fetch the necessary values for the bucket URL + const prefetchBucketUrl = async (object) => { + // Has been observed that the object is not always an instance of ToolkitInfo + if (object && Object.prototype.hasOwnProperty.call(object, "bucketName") && Object.prototype.hasOwnProperty.call(object, "bucketUrl")) { + try { + const bucket = object.bucketName; + const domain = object.bucketUrl.replace("https://", "") || await getLocalHost(); + // When object is ExistingToolkitInfo & the bucketName/bucketUrl attributes are non-null + setBucketUrl(object, bucket, domain); + } catch (e) { + // ToolkitInfo: bucketName/bucketUrl attributes don't exist or if implemented, they throw exceptions + // so the exceptions have to be ignored. + // + // The following is an example of how the bucketName/bucketUrl attributes are implemented in the BootstrapStackNotFoundInfos class: + // I.e.: https://github.com/aws/aws-cdk/blob/87e21d625af86873716734dd5568940d41096c45/packages/aws-cdk/lib/api/toolkit-info.ts#L190-L196 + // + // The following is an example of how the bucketName/bucketUrl attributes are implemented in the ExistingToolkitInfo class: + // I.e.: https://github.com/aws/aws-cdk/blob/87e21d625af86873716734dd5568940d41096c45/packages/aws-cdk/lib/api/toolkit-info.ts#L124-L130 + } + } + }; + // for compatibility with with older versions of CDK - setBucketUrl(ToolkitInfo.prototype); + runAsyncFunctionAsSync(prefetchBucketUrl(ToolkitInfo.prototype)); const cdkLookupFn = ToolkitInfo.lookup; ToolkitInfo.lookup = async (...args) => { const toolkitInfoObject = await cdkLookupFn(...args); - setBucketUrl(toolkitInfoObject); + await prefetchBucketUrl(toolkitInfoObject); return toolkitInfoObject; }; - + const fromStackFn = ToolkitInfo.fromStack; ToolkitInfo.fromStack = (...args) => { const toolkitInfoObject = fromStackFn(...args); - setBucketUrl(toolkitInfoObject); + runAsyncFunctionAsSync(prefetchBucketUrl(toolkitInfoObject)); return toolkitInfoObject; }; };