@go-to-k/cdkd 0.290.16 → 0.290.18
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/{asg-provider-CvkcE8rH.js → asg-provider-Di5-tD3l.js} +3 -3
- package/dist/{asg-provider-CvkcE8rH.js.map → asg-provider-Di5-tD3l.js.map} +1 -1
- package/dist/aws-client-defaults-BoIxyCir.js +574 -0
- package/dist/aws-client-defaults-BoIxyCir.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-B91NMqm1.js → deploy-engine-DuiVEV9B.js} +1750 -133
- package/dist/deploy-engine-DuiVEV9B.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-U03H43s7.js → program-BcdccZA8.js} +388 -568
- package/dist/{program-U03H43s7.js.map → program-BcdccZA8.js.map} +1 -1
- package/dist/{version-1FTpsWNc.js → version-Da2VV388.js} +2 -2
- package/dist/{version-1FTpsWNc.js.map → version-Da2VV388.js.map} +1 -1
- package/package.json +1 -1
- package/dist/aws-client-defaults-D-iYiIJ6.js +0 -218
- package/dist/aws-client-defaults-D-iYiIJ6.js.map +0 -1
- package/dist/deploy-engine-B91NMqm1.js.map +0 -1
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* back on that path.
|
|
9
9
|
*/
|
|
10
10
|
function getCdkdVersion() {
|
|
11
|
-
return "0.290.
|
|
11
|
+
return "0.290.18";
|
|
12
12
|
}
|
|
13
13
|
/** The two spellings commander registers for `.version()`. */
|
|
14
14
|
const VERSION_FLAGS = /* @__PURE__ */ new Set(["--version", "-V"]);
|
|
@@ -41,4 +41,4 @@ function isVersionOnlyInvocation(userArgs) {
|
|
|
41
41
|
|
|
42
42
|
//#endregion
|
|
43
43
|
export { isVersionOnlyInvocation as n, getCdkdVersion as t };
|
|
44
|
-
//# sourceMappingURL=version-
|
|
44
|
+
//# sourceMappingURL=version-Da2VV388.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-
|
|
1
|
+
{"version":3,"file":"version-Da2VV388.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Injected at build time by tsdown `define` from package.json (see the\n// `define` block in vite.config.ts). It does NOT exist under vitest or under\n// `node --experimental-strip-types`, where the define never runs, so every\n// read must go through the `typeof` guard below.\ndeclare const __CDKD_VERSION__: string;\n\n/** Dev sentinel reported when the build-time define has not run. */\nexport const DEV_VERSION_SENTINEL = '0.0.0-dev';\n\n/**\n * The build-time cdkd version, with a dev fallback for non-built contexts.\n *\n * This module deliberately has NO imports. `src/cli/index.ts` reads the\n * version on a fast path that must not pull the command tree (see\n * `isVersionOnlyInvocation`), and any import here would put a module graph\n * back on that path.\n */\nexport function getCdkdVersion(): string {\n return typeof __CDKD_VERSION__ === 'string' ? __CDKD_VERSION__ : DEV_VERSION_SENTINEL;\n}\n\n/** The two spellings commander registers for `.version()`. */\nconst VERSION_FLAGS = new Set(['--version', '-V']);\n\n/**\n * True when the whole invocation is nothing but a version flag.\n *\n * Deliberately narrower than \"the argv contains a version flag\", and the\n * reason is CONSERVATISM rather than a known disagreement. Measured against\n * commander 12.1.0 on 2026-08-25, every multi-token shape tried still printed\n * the version and exited 0 — `cdkd -c --version`, `cdkd deploy -c --version`,\n * `cdkd --profile -V` — so commander gives a standalone version flag priority\n * and does not consume it as an option value. An earlier draft of this comment\n * asserted the opposite; it was wrong, and a review measured it.\n *\n * The narrow rule is still the right one, for two reasons that survive that\n * correction. It does not DEPEND on that precedence, which is commander's\n * behaviour rather than cdkd's and can change across a major; and a wider rule\n * would be a second spelling of commander's parse, which is the class of bug\n * where two predicates answer one question and disagree at an edge nobody\n * enumerated. A single-token argv has no such edge — there is no subcommand to\n * route to and no option that could be consuming it.\n *\n * Everything this refuses falls through to the full commander parse with its\n * behaviour unchanged, so the cost of refusing too much is only that those\n * invocations stay slow.\n */\nexport function isVersionOnlyInvocation(userArgs: readonly string[]): boolean {\n return userArgs.length === 1 && VERSION_FLAGS.has(userArgs[0] as string);\n}\n"],"mappings":";;;;;;;;;AAiBA,SAAgB,iBAAyB;CACvC;AACF;;AAGA,MAAM,gCAAgB,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;AAyBjD,SAAgB,wBAAwB,UAAsC;CAC5E,OAAO,SAAS,WAAW,KAAK,cAAc,IAAI,SAAS,EAAY;AACzE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@go-to-k/cdkd",
|
|
3
|
-
"version": "0.290.
|
|
3
|
+
"version": "0.290.18",
|
|
4
4
|
"description": "Drop-in CDK CLI for existing CDK apps - up to 15x faster deploys via direct AWS SDK calls instead of CloudFormation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import { defaultProvider } from "@aws-sdk/credential-provider-node";
|
|
2
|
-
import { NodeHttpHandler } from "@smithy/node-http-handler";
|
|
3
|
-
import { Agent } from "node:http";
|
|
4
|
-
import { Agent as Agent$1 } from "node:https";
|
|
5
|
-
import { Agent as Agent$2 } from "agent-base";
|
|
6
|
-
import { HttpProxyAgent } from "http-proxy-agent";
|
|
7
|
-
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
8
|
-
import { getProxyForUrl } from "proxy-from-env";
|
|
9
|
-
|
|
10
|
-
//#region src/utils/proxy-routing-agent.ts
|
|
11
|
-
/**
|
|
12
|
-
* An `http.Agent` that routes each request through the environment's proxy, or
|
|
13
|
-
* direct, according to `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY`.
|
|
14
|
-
*
|
|
15
|
-
* WHY A ROUTING AGENT AND NOT A PLAIN PROXY AGENT
|
|
16
|
-
*
|
|
17
|
-
* `NodeHttpHandler` picks its agent by PROTOCOL alone — `httpsAgent` for an
|
|
18
|
-
* `https:` request, `httpAgent` otherwise — and never consults the request's
|
|
19
|
-
* host. `https-proxy-agent` does not read `NO_PROXY` either. So a statically
|
|
20
|
-
* chosen proxy agent cannot express "this host is exempt", which is the whole
|
|
21
|
-
* of what `NO_PROXY` means. Deciding per REQUEST is the only place the host is
|
|
22
|
-
* known, and `agent-base` gives us that hook: when `connect()` returns an
|
|
23
|
-
* `http.Agent` rather than a socket, the base class delegates the request to it
|
|
24
|
-
* via `socket.addRequest(req, connectOpts)`.
|
|
25
|
-
*
|
|
26
|
-
* That delegation is also why the INNER agents carry `keepAlive` rather than
|
|
27
|
-
* this one: the sockets pool on whichever agent `connect()` hands back, so a
|
|
28
|
-
* `keepAlive` set only here would never be consulted.
|
|
29
|
-
*
|
|
30
|
-
* WHY THE INNER CACHE IS PER INSTANCE
|
|
31
|
-
*
|
|
32
|
-
* Node's `Agent.prototype.destroy()` walks `[this.freeSockets, this.sockets]`,
|
|
33
|
-
* and the second is the ACTIVE set — it aborts in-flight requests, not just
|
|
34
|
-
* idle sockets. `NodeHttpHandler.destroy()` forwards to `httpAgent` and
|
|
35
|
-
* `httpsAgent` unconditionally, external instances included, and cdkd destroys
|
|
36
|
-
* clients mid-run (`deploy` drops the STS client right after
|
|
37
|
-
* `GetCallerIdentity`). A module-global inner cache would therefore let one
|
|
38
|
-
* client's teardown kill another client's live request. Each `AwsClients`
|
|
39
|
-
* client gets its own routing agent, so the cache is scoped to `this` and
|
|
40
|
-
* {@link destroy} forwards to the inner agents — without that forwarding the
|
|
41
|
-
* tunneled sockets would outlive the client and keep the process alive.
|
|
42
|
-
*
|
|
43
|
-
* The cost of not sharing is duplicate CONNECT + TLS handshakes where two
|
|
44
|
-
* clients talk to the same host. Pooling is per host either way, so sharing
|
|
45
|
-
* could never remove the FIRST handshake to each distinct AWS endpoint, and
|
|
46
|
-
* most runtime traffic goes through the per-service `AwsClients` singleton, so
|
|
47
|
-
* the duplicates are few. This is also what the SDK already does: it builds a
|
|
48
|
-
* `keepAlive` agent per client on the unproxied path.
|
|
49
|
-
*/
|
|
50
|
-
/**
|
|
51
|
-
* Applied to every inner agent.
|
|
52
|
-
*
|
|
53
|
-
* The SDK sets these itself, but ONLY when it is handed a plain option bag —
|
|
54
|
-
* an external `Agent` instance is passed through untouched
|
|
55
|
-
* (`@smithy/node-http-handler`'s `NodeHttpHandler` constructor). Since a
|
|
56
|
-
* routing agent IS such an instance, omitting them would silently drop
|
|
57
|
-
* connection reuse for every proxied run, and a concurrent deploy would
|
|
58
|
-
* renegotiate TLS per request.
|
|
59
|
-
*/
|
|
60
|
-
const INNER_AGENT_OPTIONS = {
|
|
61
|
-
keepAlive: true,
|
|
62
|
-
maxSockets: 50
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Build the absolute URL `getProxyForUrl` needs from what `connect()` is given.
|
|
66
|
-
*
|
|
67
|
-
* An IPv6 literal is bracketed, or the `host:port` join produces a string no
|
|
68
|
-
* URL parser accepts (`https://::1:443`) and `NO_PROXY` could never match an
|
|
69
|
-
* IPv6 entry. Unreachable with AWS hostnames; handled because the alternative
|
|
70
|
-
* is a silent wrong answer rather than an error.
|
|
71
|
-
*/
|
|
72
|
-
function requestUrl(options) {
|
|
73
|
-
const secure = options.secureEndpoint;
|
|
74
|
-
const rawHost = options.host ?? "localhost";
|
|
75
|
-
const host = rawHost.includes(":") && !rawHost.startsWith("[") ? `[${rawHost}]` : rawHost;
|
|
76
|
-
const port = options.port ?? (secure ? 443 : 80);
|
|
77
|
-
return `${secure ? "https" : "http"}://${host}:${port}`;
|
|
78
|
-
}
|
|
79
|
-
var ProxyRoutingAgent = class extends Agent$2 {
|
|
80
|
-
/**
|
|
81
|
-
* Inner agents by `<scheme>|<proxy url or "direct">`.
|
|
82
|
-
*
|
|
83
|
-
* Keyed on the proxy URL and not merely on "proxied or not" because
|
|
84
|
-
* `NO_PROXY` is not the only thing that varies per host: `HTTP_PROXY` and
|
|
85
|
-
* `HTTPS_PROXY` may name different proxies, and a single agent bound to one
|
|
86
|
-
* of them would quietly send the other scheme's traffic to the wrong place.
|
|
87
|
-
*/
|
|
88
|
-
innerAgents = /* @__PURE__ */ new Map();
|
|
89
|
-
connect(_req, options) {
|
|
90
|
-
const secure = options.secureEndpoint;
|
|
91
|
-
const proxyUrl = getProxyForUrl(requestUrl(options));
|
|
92
|
-
const key = `${secure ? "https" : "http"}|${proxyUrl || "direct"}`;
|
|
93
|
-
const cached = this.innerAgents.get(key);
|
|
94
|
-
if (cached) return cached;
|
|
95
|
-
const agent = createInnerAgent(secure, proxyUrl);
|
|
96
|
-
this.innerAgents.set(key, agent);
|
|
97
|
-
return agent;
|
|
98
|
-
}
|
|
99
|
-
destroy() {
|
|
100
|
-
for (const agent of this.innerAgents.values()) agent.destroy();
|
|
101
|
-
this.innerAgents.clear();
|
|
102
|
-
super.destroy();
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
function createInnerAgent(secure, proxyUrl) {
|
|
106
|
-
if (!proxyUrl) return secure ? new Agent$1(INNER_AGENT_OPTIONS) : new Agent(INNER_AGENT_OPTIONS);
|
|
107
|
-
return secure ? new HttpsProxyAgent(proxyUrl, INNER_AGENT_OPTIONS) : new HttpProxyAgent(proxyUrl, INNER_AGENT_OPTIONS);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
//#endregion
|
|
111
|
-
//#region src/utils/aws-client-defaults.ts
|
|
112
|
-
/**
|
|
113
|
-
* Client config every AWS SDK client in cdkd must be built with.
|
|
114
|
-
*
|
|
115
|
-
* WHY THIS EXISTS
|
|
116
|
-
*
|
|
117
|
-
* The AWS SDK for JavaScript v3 does NOT read `HTTPS_PROXY` / `HTTP_PROXY` the
|
|
118
|
-
* way botocore (the AWS CLI) and Go's `net/http` do. Its own guide says a proxy
|
|
119
|
-
* is supplied "through a third-party HTTP agent" by whoever constructs the
|
|
120
|
-
* client — so on a machine whose only egress is a corporate proxy, an SDK call
|
|
121
|
-
* dials out directly and fails, typically as
|
|
122
|
-
* `CredentialsProviderError: self-signed certificate in certificate chain`
|
|
123
|
-
* because the direct route is what the network intercepts (issue #2388).
|
|
124
|
-
*
|
|
125
|
-
* Node 24's `NODE_USE_ENV_PROXY=1` is not a way out: it rewires the GLOBAL
|
|
126
|
-
* agent, and every SDK client builds its own.
|
|
127
|
-
*
|
|
128
|
-
* WHY THE CREDENTIAL CHAIN IS INJECTED TOO
|
|
129
|
-
*
|
|
130
|
-
* A client's `requestHandler` does not reach every credential hop:
|
|
131
|
-
*
|
|
132
|
-
* - STS (`role_arn` profiles, web identity) reads `requestHandler` off
|
|
133
|
-
* `parentClientConfig`, so it INHERITS ours. Nothing to do.
|
|
134
|
-
* - `@aws-sdk/credential-provider-sso` builds its portal client from
|
|
135
|
-
* `clientConfig` alone, coalescing only `logger`, `region` and
|
|
136
|
-
* `userAgentAppId` from the caller. `@aws-sdk/token-providers` does the same
|
|
137
|
-
* for the SSO-OIDC refresh. So an SSO profile fails at
|
|
138
|
-
* `resolveSSOCredentials` — BEFORE any service call — unless the chain is
|
|
139
|
-
* constructed here with the handler threaded through `clientConfig`.
|
|
140
|
-
* - IMDS (`@smithy/credential-provider-imds`) and ECS container credentials
|
|
141
|
-
* (`@aws-sdk/credential-provider-http`) call `node:http` / build their own
|
|
142
|
-
* handler, so they bypass a proxy on their own and need no special casing.
|
|
143
|
-
*
|
|
144
|
-
* The chain is therefore built per call. `defaultProvider` MEMOIZES resolved
|
|
145
|
-
* credentials inside the chain instance, so one shared instance would hand a
|
|
146
|
-
* client configured for profile A the credentials of profile B. Per call costs
|
|
147
|
-
* nothing relative to today, since each client already builds its own chain.
|
|
148
|
-
*
|
|
149
|
-
* `clientConfig` carries `requestHandler` and NOTHING else — a `region` there
|
|
150
|
-
* would override the SSO portal's own region — and `profile` is passed
|
|
151
|
-
* ALONGSIDE it, because the built-in chain sees a profile through the client
|
|
152
|
-
* config while an injected chain does not.
|
|
153
|
-
*
|
|
154
|
-
* SPREAD THIS FIRST, SITE-SPECIFIC CONFIG SECOND
|
|
155
|
-
*
|
|
156
|
-
* `new S3Client({ ...awsClientDefaults({ profile }), region, ...(creds && { credentials: creds }) })`
|
|
157
|
-
*
|
|
158
|
-
* A site that supplies its own `credentials` must keep them — `config-loader`'s
|
|
159
|
-
* default-bucket probe reuses the STS client's resolved provider on purpose, so
|
|
160
|
-
* that the bucket it probes is checked as the identity the name was derived
|
|
161
|
-
* from. That provider already carries the handler, because the STS client it
|
|
162
|
-
* came from was built through this helper.
|
|
163
|
-
*/
|
|
164
|
-
/**
|
|
165
|
-
* The proxy variables, in the order `proxy-from-env` itself reads them.
|
|
166
|
-
*
|
|
167
|
-
* Only their PRESENCE is decided here. Which one applies to a given request —
|
|
168
|
-
* and whether `NO_PROXY` exempts it — is `getProxyForUrl`'s job, per request,
|
|
169
|
-
* inside {@link ProxyRoutingAgent}. Deciding it here instead would collapse
|
|
170
|
-
* `HTTP_PROXY` and `HTTPS_PROXY` into one answer and send `http://` traffic to
|
|
171
|
-
* an HTTPS proxy.
|
|
172
|
-
*/
|
|
173
|
-
const PROXY_ENV_VARS = [
|
|
174
|
-
"HTTPS_PROXY",
|
|
175
|
-
"https_proxy",
|
|
176
|
-
"HTTP_PROXY",
|
|
177
|
-
"http_proxy",
|
|
178
|
-
"ALL_PROXY",
|
|
179
|
-
"all_proxy"
|
|
180
|
-
];
|
|
181
|
-
let proxyConfigured;
|
|
182
|
-
function isProxyConfigured() {
|
|
183
|
-
if (proxyConfigured === void 0) {
|
|
184
|
-
let configured = false;
|
|
185
|
-
for (const name of PROXY_ENV_VARS) {
|
|
186
|
-
const value = process.env[name];
|
|
187
|
-
if (value === void 0 || value === "") continue;
|
|
188
|
-
if (value.trim() === "") throw new Error(`${name} is set to whitespace only. Set it to a proxy URL (e.g. http://proxy.example:8080) or unset it.`);
|
|
189
|
-
configured = true;
|
|
190
|
-
}
|
|
191
|
-
proxyConfigured = configured;
|
|
192
|
-
}
|
|
193
|
-
return proxyConfigured;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Returns `{}` when no proxy is configured, which keeps the unproxied path
|
|
197
|
-
* byte-identical to what the SDK builds on its own and makes this a no-op for
|
|
198
|
-
* every existing user.
|
|
199
|
-
*/
|
|
200
|
-
function awsClientDefaults(options = {}) {
|
|
201
|
-
if (!isProxyConfigured()) return {};
|
|
202
|
-
const agent = new ProxyRoutingAgent();
|
|
203
|
-
const requestHandler = new NodeHttpHandler({
|
|
204
|
-
httpAgent: agent,
|
|
205
|
-
httpsAgent: agent
|
|
206
|
-
});
|
|
207
|
-
return {
|
|
208
|
-
requestHandler,
|
|
209
|
-
credentials: defaultProvider({
|
|
210
|
-
...options.profile !== void 0 && options.profile !== "" && { profile: options.profile },
|
|
211
|
-
clientConfig: { requestHandler }
|
|
212
|
-
})
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
//#endregion
|
|
217
|
-
export { awsClientDefaults as t };
|
|
218
|
-
//# sourceMappingURL=aws-client-defaults-D-iYiIJ6.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"aws-client-defaults-D-iYiIJ6.js","names":["Agent","HttpsAgent","HttpAgent"],"sources":["../src/utils/proxy-routing-agent.ts","../src/utils/aws-client-defaults.ts"],"sourcesContent":["/**\n * An `http.Agent` that routes each request through the environment's proxy, or\n * direct, according to `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY`.\n *\n * WHY A ROUTING AGENT AND NOT A PLAIN PROXY AGENT\n *\n * `NodeHttpHandler` picks its agent by PROTOCOL alone — `httpsAgent` for an\n * `https:` request, `httpAgent` otherwise — and never consults the request's\n * host. `https-proxy-agent` does not read `NO_PROXY` either. So a statically\n * chosen proxy agent cannot express \"this host is exempt\", which is the whole\n * of what `NO_PROXY` means. Deciding per REQUEST is the only place the host is\n * known, and `agent-base` gives us that hook: when `connect()` returns an\n * `http.Agent` rather than a socket, the base class delegates the request to it\n * via `socket.addRequest(req, connectOpts)`.\n *\n * That delegation is also why the INNER agents carry `keepAlive` rather than\n * this one: the sockets pool on whichever agent `connect()` hands back, so a\n * `keepAlive` set only here would never be consulted.\n *\n * WHY THE INNER CACHE IS PER INSTANCE\n *\n * Node's `Agent.prototype.destroy()` walks `[this.freeSockets, this.sockets]`,\n * and the second is the ACTIVE set — it aborts in-flight requests, not just\n * idle sockets. `NodeHttpHandler.destroy()` forwards to `httpAgent` and\n * `httpsAgent` unconditionally, external instances included, and cdkd destroys\n * clients mid-run (`deploy` drops the STS client right after\n * `GetCallerIdentity`). A module-global inner cache would therefore let one\n * client's teardown kill another client's live request. Each `AwsClients`\n * client gets its own routing agent, so the cache is scoped to `this` and\n * {@link destroy} forwards to the inner agents — without that forwarding the\n * tunneled sockets would outlive the client and keep the process alive.\n *\n * The cost of not sharing is duplicate CONNECT + TLS handshakes where two\n * clients talk to the same host. Pooling is per host either way, so sharing\n * could never remove the FIRST handshake to each distinct AWS endpoint, and\n * most runtime traffic goes through the per-service `AwsClients` singleton, so\n * the duplicates are few. This is also what the SDK already does: it builds a\n * `keepAlive` agent per client on the unproxied path.\n */\n\nimport { Agent as HttpAgent } from 'node:http';\nimport type { ClientRequest } from 'node:http';\nimport { Agent as HttpsAgent } from 'node:https';\nimport { Agent, type AgentConnectOpts } from 'agent-base';\nimport { HttpProxyAgent } from 'http-proxy-agent';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\nimport { getProxyForUrl } from 'proxy-from-env';\n\n/**\n * Applied to every inner agent.\n *\n * The SDK sets these itself, but ONLY when it is handed a plain option bag —\n * an external `Agent` instance is passed through untouched\n * (`@smithy/node-http-handler`'s `NodeHttpHandler` constructor). Since a\n * routing agent IS such an instance, omitting them would silently drop\n * connection reuse for every proxied run, and a concurrent deploy would\n * renegotiate TLS per request.\n */\nconst INNER_AGENT_OPTIONS = { keepAlive: true, maxSockets: 50 } as const;\n\n/**\n * Build the absolute URL `getProxyForUrl` needs from what `connect()` is given.\n *\n * An IPv6 literal is bracketed, or the `host:port` join produces a string no\n * URL parser accepts (`https://::1:443`) and `NO_PROXY` could never match an\n * IPv6 entry. Unreachable with AWS hostnames; handled because the alternative\n * is a silent wrong answer rather than an error.\n */\nfunction requestUrl(options: AgentConnectOpts): string {\n const secure = options.secureEndpoint;\n const rawHost = options.host ?? 'localhost';\n const host = rawHost.includes(':') && !rawHost.startsWith('[') ? `[${rawHost}]` : rawHost;\n const port = options.port ?? (secure ? 443 : 80);\n return `${secure ? 'https' : 'http'}://${host}:${port}`;\n}\n\nexport class ProxyRoutingAgent extends Agent {\n /**\n * Inner agents by `<scheme>|<proxy url or \"direct\">`.\n *\n * Keyed on the proxy URL and not merely on \"proxied or not\" because\n * `NO_PROXY` is not the only thing that varies per host: `HTTP_PROXY` and\n * `HTTPS_PROXY` may name different proxies, and a single agent bound to one\n * of them would quietly send the other scheme's traffic to the wrong place.\n */\n private readonly innerAgents = new Map<string, HttpAgent>();\n\n connect(_req: ClientRequest, options: AgentConnectOpts): HttpAgent {\n const secure = options.secureEndpoint;\n const proxyUrl = getProxyForUrl(requestUrl(options));\n const key = `${secure ? 'https' : 'http'}|${proxyUrl || 'direct'}`;\n\n const cached = this.innerAgents.get(key);\n if (cached) return cached;\n\n const agent = createInnerAgent(secure, proxyUrl);\n this.innerAgents.set(key, agent);\n return agent;\n }\n\n override destroy(): void {\n for (const agent of this.innerAgents.values()) {\n agent.destroy();\n }\n this.innerAgents.clear();\n super.destroy();\n }\n}\n\nfunction createInnerAgent(secure: boolean, proxyUrl: string): HttpAgent {\n if (!proxyUrl) {\n // No proxy for this host — `NO_PROXY` matched, or no proxy variable is set\n // for this scheme. A plain agent keeps the request byte-identical to the\n // unproxied path.\n return secure ? new HttpsAgent(INNER_AGENT_OPTIONS) : new HttpAgent(INNER_AGENT_OPTIONS);\n }\n // `HttpsProxyAgent` opens a CONNECT tunnel and upgrades it to TLS, so the\n // origin's own certificate is what gets validated; `HttpProxyAgent` rewrites\n // the request line for a plain `http:` origin. Which one applies is decided\n // by the ORIGIN's scheme, not the proxy's — a plain `http://` proxy serves\n // both.\n return secure\n ? new HttpsProxyAgent<string>(proxyUrl, INNER_AGENT_OPTIONS)\n : new HttpProxyAgent<string>(proxyUrl, INNER_AGENT_OPTIONS);\n}\n","/**\n * Client config every AWS SDK client in cdkd must be built with.\n *\n * WHY THIS EXISTS\n *\n * The AWS SDK for JavaScript v3 does NOT read `HTTPS_PROXY` / `HTTP_PROXY` the\n * way botocore (the AWS CLI) and Go's `net/http` do. Its own guide says a proxy\n * is supplied \"through a third-party HTTP agent\" by whoever constructs the\n * client — so on a machine whose only egress is a corporate proxy, an SDK call\n * dials out directly and fails, typically as\n * `CredentialsProviderError: self-signed certificate in certificate chain`\n * because the direct route is what the network intercepts (issue #2388).\n *\n * Node 24's `NODE_USE_ENV_PROXY=1` is not a way out: it rewires the GLOBAL\n * agent, and every SDK client builds its own.\n *\n * WHY THE CREDENTIAL CHAIN IS INJECTED TOO\n *\n * A client's `requestHandler` does not reach every credential hop:\n *\n * - STS (`role_arn` profiles, web identity) reads `requestHandler` off\n * `parentClientConfig`, so it INHERITS ours. Nothing to do.\n * - `@aws-sdk/credential-provider-sso` builds its portal client from\n * `clientConfig` alone, coalescing only `logger`, `region` and\n * `userAgentAppId` from the caller. `@aws-sdk/token-providers` does the same\n * for the SSO-OIDC refresh. So an SSO profile fails at\n * `resolveSSOCredentials` — BEFORE any service call — unless the chain is\n * constructed here with the handler threaded through `clientConfig`.\n * - IMDS (`@smithy/credential-provider-imds`) and ECS container credentials\n * (`@aws-sdk/credential-provider-http`) call `node:http` / build their own\n * handler, so they bypass a proxy on their own and need no special casing.\n *\n * The chain is therefore built per call. `defaultProvider` MEMOIZES resolved\n * credentials inside the chain instance, so one shared instance would hand a\n * client configured for profile A the credentials of profile B. Per call costs\n * nothing relative to today, since each client already builds its own chain.\n *\n * `clientConfig` carries `requestHandler` and NOTHING else — a `region` there\n * would override the SSO portal's own region — and `profile` is passed\n * ALONGSIDE it, because the built-in chain sees a profile through the client\n * config while an injected chain does not.\n *\n * SPREAD THIS FIRST, SITE-SPECIFIC CONFIG SECOND\n *\n * `new S3Client({ ...awsClientDefaults({ profile }), region, ...(creds && { credentials: creds }) })`\n *\n * A site that supplies its own `credentials` must keep them — `config-loader`'s\n * default-bucket probe reuses the STS client's resolved provider on purpose, so\n * that the bucket it probes is checked as the identity the name was derived\n * from. That provider already carries the handler, because the STS client it\n * came from was built through this helper.\n */\n\nimport { defaultProvider } from '@aws-sdk/credential-provider-node';\nimport { NodeHttpHandler } from '@smithy/node-http-handler';\n// The `.ts` spelling below is REQUIRED, not a slip.\n//\n// `scripts/audit-provider-coverage.ts` imports `src/utils/aws-clients.ts`\n// directly and runs under `node`'s native type stripping, which resolves\n// relative specifiers LITERALLY — it does not rewrite `.js` to `.ts` the way\n// TypeScript does at emit time. The constraint is TRANSITIVE: it binds every\n// module reachable from `aws-clients.ts`, this one included, so a `./foo.js`\n// import ANYWHERE in that closure breaks `vp run audit:coverage:check` in CI.\n// `tsconfig.json`'s `rewriteRelativeImportExtensions` is what emits the `.ts`\n// spelling as `.js`, and `tests/unit/utils/aws-clients-region-fold.test.ts`\n// fences the whole closure by resolving it the way `node` would.\nimport { ProxyRoutingAgent } from './proxy-routing-agent.ts';\n\nexport interface AwsClientDefaultsOptions {\n /** The profile the calling site was configured with, if any. */\n profile?: string | undefined;\n}\n\n/**\n * A partial AWS SDK client config. Empty when no proxy is configured.\n *\n * `credentials` is derived from `defaultProvider` rather than imported from\n * `@smithy/types` so that naming the type costs no new dependency.\n */\nexport interface AwsClientDefaults {\n requestHandler?: NodeHttpHandler;\n credentials?: ReturnType<typeof defaultProvider>;\n}\n\n/**\n * The proxy variables, in the order `proxy-from-env` itself reads them.\n *\n * Only their PRESENCE is decided here. Which one applies to a given request —\n * and whether `NO_PROXY` exempts it — is `getProxyForUrl`'s job, per request,\n * inside {@link ProxyRoutingAgent}. Deciding it here instead would collapse\n * `HTTP_PROXY` and `HTTPS_PROXY` into one answer and send `http://` traffic to\n * an HTTPS proxy.\n */\nexport const PROXY_ENV_VARS = [\n 'HTTPS_PROXY',\n 'https_proxy',\n 'HTTP_PROXY',\n 'http_proxy',\n 'ALL_PROXY',\n 'all_proxy',\n] as const;\n\nlet proxyConfigured: boolean | undefined;\n\nfunction isProxyConfigured(): boolean {\n // Read lazily and memoize only the PARSE RESULT, so module import order\n // cannot freeze an answer before the CLI has finished setting up, and so a\n // test can control the environment through `resetAwsClientDefaults()`.\n if (proxyConfigured === undefined) {\n // Every spelling is examined before the answer is decided. A `.some()` here\n // short-circuited at the first VALID variable, so `HTTPS_PROXY=http://ok`\n // beside a typo'd `http_proxy=' '` never reached the guard below -- and\n // the typo then resurfaced per request as exactly the unnamed URL-parse\n // error the guard exists to pre-empt.\n let configured = false;\n for (const name of PROXY_ENV_VARS) {\n const value = process.env[name];\n if (value === undefined || value === '') continue;\n if (value.trim() === '') {\n // Whitespace-only is a typo, not a configuration. Treating it as SET\n // fails later with a URL-parse error naming neither the variable nor\n // cdkd; treating it as UNSET is worse still, because the run then goes\n // direct and fails with the certificate error this whole change exists\n // to remove -- with no hint that the variable was the cause.\n //\n // A plain `Error` rather than `CdkdError`: importing the error module\n // would add a `.js` relative import to the closure reachable from\n // `aws-clients.ts`, which is the constraint the header above describes.\n throw new Error(\n `${name} is set to whitespace only. Set it to a proxy URL ` +\n `(e.g. http://proxy.example:8080) or unset it.`\n );\n }\n configured = true;\n }\n proxyConfigured = configured;\n }\n return proxyConfigured;\n}\n\n/**\n * Returns `{}` when no proxy is configured, which keeps the unproxied path\n * byte-identical to what the SDK builds on its own and makes this a no-op for\n * every existing user.\n */\nexport function awsClientDefaults(options: AwsClientDefaultsOptions = {}): AwsClientDefaults {\n if (!isProxyConfigured()) return {};\n\n // A FRESH agent per call. `NodeHttpHandler.destroy()` destroys `httpAgent`\n // and `httpsAgent` unconditionally, and Node's `Agent.destroy()` aborts\n // ACTIVE sockets, so a shared agent would let one client's teardown kill\n // another client's in-flight request. See `proxy-routing-agent.ts`.\n const agent = new ProxyRoutingAgent();\n const requestHandler = new NodeHttpHandler({ httpAgent: agent, httpsAgent: agent });\n\n return {\n requestHandler,\n credentials: defaultProvider({\n ...(options.profile !== undefined && options.profile !== '' && { profile: options.profile }),\n clientConfig: { requestHandler },\n }),\n };\n}\n\n/** Drop the memoized environment read. Test seam; mirrors `resetAwsClients()`. */\nexport function resetAwsClientDefaults(): void {\n proxyConfigured = undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DA,MAAM,sBAAsB;CAAE,WAAW;CAAM,YAAY;AAAG;;;;;;;;;AAU9D,SAAS,WAAW,SAAmC;CACrD,MAAM,SAAS,QAAQ;CACvB,MAAM,UAAU,QAAQ,QAAQ;CAChC,MAAM,OAAO,QAAQ,SAAS,GAAG,KAAK,CAAC,QAAQ,WAAW,GAAG,IAAI,IAAI,QAAQ,KAAK;CAClF,MAAM,OAAO,QAAQ,SAAS,SAAS,MAAM;CAC7C,OAAO,GAAG,SAAS,UAAU,OAAO,KAAK,KAAK,GAAG;AACnD;AAEA,IAAa,oBAAb,cAAuCA,QAAM;;;;;;;;;CAS3C,AAAiB,8BAAc,IAAI,IAAuB;CAE1D,QAAQ,MAAqB,SAAsC;EACjE,MAAM,SAAS,QAAQ;EACvB,MAAM,WAAW,eAAe,WAAW,OAAO,CAAC;EACnD,MAAM,MAAM,GAAG,SAAS,UAAU,OAAO,GAAG,YAAY;EAExD,MAAM,SAAS,KAAK,YAAY,IAAI,GAAG;EACvC,IAAI,QAAQ,OAAO;EAEnB,MAAM,QAAQ,iBAAiB,QAAQ,QAAQ;EAC/C,KAAK,YAAY,IAAI,KAAK,KAAK;EAC/B,OAAO;CACT;CAEA,AAAS,UAAgB;EACvB,KAAK,MAAM,SAAS,KAAK,YAAY,OAAO,GAC1C,MAAM,QAAQ;EAEhB,KAAK,YAAY,MAAM;EACvB,MAAM,QAAQ;CAChB;AACF;AAEA,SAAS,iBAAiB,QAAiB,UAA6B;CACtE,IAAI,CAAC,UAIH,OAAO,SAAS,IAAIC,QAAW,mBAAmB,IAAI,IAAIC,MAAU,mBAAmB;CAOzF,OAAO,SACH,IAAI,gBAAwB,UAAU,mBAAmB,IACzD,IAAI,eAAuB,UAAU,mBAAmB;AAC9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,IAAI;AAEJ,SAAS,oBAA6B;CAIpC,IAAI,oBAAoB,QAAW;EAMjC,IAAI,aAAa;EACjB,KAAK,MAAM,QAAQ,gBAAgB;GACjC,MAAM,QAAQ,QAAQ,IAAI;GAC1B,IAAI,UAAU,UAAa,UAAU,IAAI;GACzC,IAAI,MAAM,KAAK,MAAM,IAUnB,MAAM,IAAI,MACR,GAAG,KAAK,gGAEV;GAEF,aAAa;EACf;EACA,kBAAkB;CACpB;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,kBAAkB,UAAoC,CAAC,GAAsB;CAC3F,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC;CAMlC,MAAM,QAAQ,IAAI,kBAAkB;CACpC,MAAM,iBAAiB,IAAI,gBAAgB;EAAE,WAAW;EAAO,YAAY;CAAM,CAAC;CAElF,OAAO;EACL;EACA,aAAa,gBAAgB;GAC3B,GAAI,QAAQ,YAAY,UAAa,QAAQ,YAAY,MAAM,EAAE,SAAS,QAAQ,QAAQ;GAC1F,cAAc,EAAE,eAAe;EACjC,CAAC;CACH;AACF"}
|