@go-to-k/cdkd 0.220.3 → 0.220.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +85 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1553,7 +1553,7 @@ const FLUSH_INTERVAL_MS = 2e3;
|
|
|
1553
1553
|
const FLUSH_EVENT_THRESHOLD = 50;
|
|
1554
1554
|
/** Build-time cdkd version, with a dev fallback for non-built contexts. */
|
|
1555
1555
|
function getCdkdVersion() {
|
|
1556
|
-
return "0.220.
|
|
1556
|
+
return "0.220.4";
|
|
1557
1557
|
}
|
|
1558
1558
|
/**
|
|
1559
1559
|
* Generate a time-sortable unique run id, e.g.
|
|
@@ -1929,6 +1929,18 @@ function recordRunFailed(recorder, stackName, error) {
|
|
|
1929
1929
|
* lock + bounded retry. After exhaustion, the writer logs warn and
|
|
1930
1930
|
* continues; the index becomes stale until the next deploy/destroy
|
|
1931
1931
|
* updates it.
|
|
1932
|
+
*
|
|
1933
|
+
* Cross-region state bucket: like `S3StateBackend` and `LockManager`, the
|
|
1934
|
+
* store tolerates a state bucket that lives in a different AWS region from
|
|
1935
|
+
* the CLI's base region. Before its first S3 operation it resolves the
|
|
1936
|
+
* bucket's actual region via `GetBucketLocation` and, if it differs from
|
|
1937
|
+
* the supplied client's region, builds a private replacement client for
|
|
1938
|
+
* that region (issue #819 — without this, every index write/remove against
|
|
1939
|
+
* a cross-region bucket failed with S3's 301 PermanentRedirect, surfacing
|
|
1940
|
+
* as `Exports index ... failed (non-retryable): ... must be addressed using
|
|
1941
|
+
* the specified endpoint`; the index was silently never maintained
|
|
1942
|
+
* cross-region, although the canonical state.json — written through the
|
|
1943
|
+
* already-region-corrected `S3StateBackend` — stayed correct).
|
|
1932
1944
|
*/
|
|
1933
1945
|
/** Schema version for the exports index file. Separate from state.json's version. */
|
|
1934
1946
|
const EXPORT_INDEX_VERSION = 1;
|
|
@@ -1977,6 +1989,9 @@ var ExportIndexStore = class {
|
|
|
1977
1989
|
* where it actually matters. Reads (`lookup`) remain unsynchronized.
|
|
1978
1990
|
*/
|
|
1979
1991
|
writeChain = Promise.resolve();
|
|
1992
|
+
/** Memoization for the one-time bucket-region resolution (issue #819). */
|
|
1993
|
+
clientResolved = false;
|
|
1994
|
+
resolveInFlight = null;
|
|
1980
1995
|
constructor(s3Client, bucket, prefix, region, stateBackend, opts = {}) {
|
|
1981
1996
|
this.s3Client = s3Client;
|
|
1982
1997
|
this.bucket = bucket;
|
|
@@ -1993,6 +2008,72 @@ var ExportIndexStore = class {
|
|
|
1993
2008
|
return `${this.prefix}/_index/${this.region}/exports.json`;
|
|
1994
2009
|
}
|
|
1995
2010
|
/**
|
|
2011
|
+
* Resolve the state bucket's actual region and, if it differs from the
|
|
2012
|
+
* supplied client's configured region, replace the client reference with
|
|
2013
|
+
* a new S3Client pointed at the bucket's region (issue #819).
|
|
2014
|
+
*
|
|
2015
|
+
* Mirrors `LockManager.ensureClientForBucket()` (issue #803) with the same
|
|
2016
|
+
* two deliberate differences from `S3StateBackend`:
|
|
2017
|
+
*
|
|
2018
|
+
* - The replacement client reuses the original client's resolved
|
|
2019
|
+
* credentials provider, so `--profile` / static credentials carry over
|
|
2020
|
+
* without the four `ExportIndexStore` call sites having to thread client
|
|
2021
|
+
* options.
|
|
2022
|
+
* - The original client is NOT destroyed. It is the shared `AwsClients.s3`
|
|
2023
|
+
* instance that other components (state backend, lock manager) still hold
|
|
2024
|
+
* a reference to.
|
|
2025
|
+
*
|
|
2026
|
+
* `resolveBucketRegion` caches per bucket name for the process lifetime, so
|
|
2027
|
+
* when the state backend / lock manager have already resolved the same
|
|
2028
|
+
* bucket this incurs no additional `GetBucketLocation` call.
|
|
2029
|
+
*
|
|
2030
|
+
* Best-effort: if the supplied client does not expose the SDK
|
|
2031
|
+
* `config.region()` shape (e.g. a hand-rolled test double) the resolution
|
|
2032
|
+
* is skipped and the original client is used unchanged.
|
|
2033
|
+
*/
|
|
2034
|
+
async ensureClientForBucket() {
|
|
2035
|
+
if (this.clientResolved) return;
|
|
2036
|
+
if (this.resolveInFlight) return this.resolveInFlight;
|
|
2037
|
+
this.resolveInFlight = (async () => {
|
|
2038
|
+
try {
|
|
2039
|
+
const config = this.s3Client.config;
|
|
2040
|
+
if (!config || typeof config.region !== "function") {
|
|
2041
|
+
this.clientResolved = true;
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
const currentRegion = await config.region();
|
|
2045
|
+
const fallbackRegion = typeof currentRegion === "string" ? currentRegion : void 0;
|
|
2046
|
+
let probeCredentials;
|
|
2047
|
+
try {
|
|
2048
|
+
if (typeof config.credentials === "function") probeCredentials = await config.credentials();
|
|
2049
|
+
} catch {
|
|
2050
|
+
probeCredentials = void 0;
|
|
2051
|
+
}
|
|
2052
|
+
const bucketRegion = await resolveBucketRegion(this.bucket, {
|
|
2053
|
+
...probeCredentials && { credentials: probeCredentials },
|
|
2054
|
+
...fallbackRegion && { fallbackRegion }
|
|
2055
|
+
});
|
|
2056
|
+
if (bucketRegion !== currentRegion) {
|
|
2057
|
+
this.logger.debug(`State bucket '${this.bucket}' is in '${bucketRegion}' (exports-index client was '${String(currentRegion)}'); building a region-corrected S3 client for index operations.`);
|
|
2058
|
+
this.s3Client = new S3Client({
|
|
2059
|
+
region: bucketRegion,
|
|
2060
|
+
credentials: this.s3Client.config.credentials,
|
|
2061
|
+
logger: {
|
|
2062
|
+
debug: () => {},
|
|
2063
|
+
info: () => {},
|
|
2064
|
+
warn: () => {},
|
|
2065
|
+
error: () => {}
|
|
2066
|
+
}
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
this.clientResolved = true;
|
|
2070
|
+
} finally {
|
|
2071
|
+
this.resolveInFlight = null;
|
|
2072
|
+
}
|
|
2073
|
+
})();
|
|
2074
|
+
return this.resolveInFlight;
|
|
2075
|
+
}
|
|
2076
|
+
/**
|
|
1996
2077
|
* Look up an exported value by name. Returns the cached entry on hit,
|
|
1997
2078
|
* or `undefined` on miss. The caller is responsible for falling back
|
|
1998
2079
|
* to a state.json scan and (if found) patching the index via
|
|
@@ -2113,6 +2194,7 @@ var ExportIndexStore = class {
|
|
|
2113
2194
|
}
|
|
2114
2195
|
}
|
|
2115
2196
|
async readIndexRaw() {
|
|
2197
|
+
await this.ensureClientForBucket();
|
|
2116
2198
|
try {
|
|
2117
2199
|
const response = await this.s3Client.send(new GetObjectCommand({
|
|
2118
2200
|
Bucket: this.bucket,
|
|
@@ -2128,6 +2210,7 @@ var ExportIndexStore = class {
|
|
|
2128
2210
|
}
|
|
2129
2211
|
}
|
|
2130
2212
|
async writeIndex(next, expectedEtag) {
|
|
2213
|
+
await this.ensureClientForBucket();
|
|
2131
2214
|
const body = JSON.stringify(next, null, 2);
|
|
2132
2215
|
return (await this.s3Client.send(new PutObjectCommand({
|
|
2133
2216
|
Bucket: this.bucket,
|
|
@@ -53550,7 +53633,7 @@ function reorderArgs(argv) {
|
|
|
53550
53633
|
async function main() {
|
|
53551
53634
|
installPipeCloseHandler();
|
|
53552
53635
|
const program = new Command();
|
|
53553
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.220.
|
|
53636
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.220.4");
|
|
53554
53637
|
program.addCommand(createBootstrapCommand());
|
|
53555
53638
|
program.addCommand(createSynthCommand());
|
|
53556
53639
|
program.addCommand(createListCommand());
|