@go-to-k/cdkd 0.219.2 → 0.219.3
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-B_hrCxRx.js +790 -0
- package/dist/asg-provider-B_hrCxRx.js.map +1 -0
- package/dist/{aws-clients-DWUnLza1.js → aws-clients-pjPwZz1r.js} +2 -18
- package/dist/{aws-clients-DWUnLza1.js.map → aws-clients-pjPwZz1r.js.map} +1 -1
- package/dist/cli.js +5 -786
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-B6CuzOHi.js → deploy-engine-Drw_e42s.js} +13 -1485
- package/dist/deploy-engine-Drw_e42s.js.map +1 -0
- package/dist/import-helpers-wLipXr5g.js +1484 -0
- package/dist/import-helpers-wLipXr5g.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/rolldown-runtime-CjeV3_4I.js +18 -0
- package/package.json +1 -1
- package/dist/deploy-engine-B6CuzOHi.js.map +0 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { B as generateResourceNameWithFallback, E as SynthesisError, F as getLiveRenderer, H as withStackName, M as getLogger, R as applyDefaultNameForFallback, T as StateError, a as assertRegionMatch, b as ProvisioningError, c as AssetError, d as DependencyError, g as MacroExpansionError, h as LockError, i as resolveExplicitPhysicalId, k as normalizeAwsError, n as matchesCdkPath, o as disableInstanceApiTermination, r as normalizeAwsTagsToCfn, s as isTerminationProtectionPropagationError, x as ResourceTimeoutError } from "./import-helpers-wLipXr5g.js";
|
|
2
|
+
import { r as getAwsClients } from "./aws-clients-pjPwZz1r.js";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { DeleteObjectCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
5
5
|
import { CloudControlClient, CreateResourceCommand, DeleteResourceCommand, GetResourceCommand, GetResourceRequestStatusCommand, ListResourcesCommand, UpdateResourceCommand } from "@aws-sdk/client-cloudcontrol";
|
|
6
6
|
import { AttachRolePolicyCommand, CreateRoleCommand, DeleteRoleCommand, DeleteRolePermissionsBoundaryCommand, DeleteRolePolicyCommand, DetachRolePolicyCommand, GetRoleCommand, GetRolePolicyCommand, IAMClient, ListAttachedRolePoliciesCommand, ListInstanceProfilesForRoleCommand, ListRolePoliciesCommand, ListRoleTagsCommand, ListRolesCommand, NoSuchEntityException, PutRolePermissionsBoundaryCommand, PutRolePolicyCommand, RemoveRoleFromInstanceProfileCommand, TagRoleCommand, UntagRoleCommand, UpdateAssumeRolePolicyCommand, UpdateRoleCommand } from "@aws-sdk/client-iam";
|
|
7
7
|
import { PublishCommand, SNSClient } from "@aws-sdk/client-sns";
|
|
8
8
|
import { GetFunctionUrlConfigCommand, InvokeCommand, LambdaClient, UpdateFunctionConfigurationCommand, waitUntilFunctionActiveV2, waitUntilFunctionUpdatedV2 } from "@aws-sdk/client-lambda";
|
|
9
9
|
import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
|
|
10
|
-
import { DescribeAvailabilityZonesCommand, DescribeImagesCommand, DescribeLaunchTemplatesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupsCommand, DescribeSubnetsCommand, DescribeVpcsCommand, DescribeVpnGatewaysCommand, EC2Client
|
|
10
|
+
import { DescribeAvailabilityZonesCommand, DescribeImagesCommand, DescribeLaunchTemplatesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupsCommand, DescribeSubnetsCommand, DescribeVpcsCommand, DescribeVpnGatewaysCommand, EC2Client } from "@aws-sdk/client-ec2";
|
|
11
11
|
import { DescribeTableCommand } from "@aws-sdk/client-dynamodb";
|
|
12
12
|
import { CloudFormationClient, CreateChangeSetCommand, DeleteStackCommand, DescribeChangeSetCommand, GetTemplateCommand, waitUntilChangeSetCreateComplete } from "@aws-sdk/client-cloudformation";
|
|
13
13
|
import { GetRestApiCommand } from "@aws-sdk/client-api-gateway";
|
|
@@ -27,1330 +27,6 @@ import graphlib from "graphlib";
|
|
|
27
27
|
import { DescribeDBClustersCommand, RDSClient } from "@aws-sdk/client-rds";
|
|
28
28
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
29
29
|
|
|
30
|
-
//#region src/provisioning/resource-name.ts
|
|
31
|
-
/**
|
|
32
|
-
* Per-async-context stack name. Resource-name generation reads this so that
|
|
33
|
-
* concurrent deploys (`cdkd deploy --all` runs stacks in parallel up to
|
|
34
|
-
* `--stack-concurrency`) don't fight over a single shared variable.
|
|
35
|
-
*
|
|
36
|
-
* History: this was `let currentStackName: string | undefined` until
|
|
37
|
-
* 2026-05-01. Two parallel `deploy()` calls would each call
|
|
38
|
-
* `setCurrentStackName(...)` and the second would overwrite the first;
|
|
39
|
-
* any IAM Role / SQS Queue / etc. created by the first stack while the
|
|
40
|
-
* second was active would get the second stack's prefix in its physical
|
|
41
|
-
* name, then the second stack's own create attempt for the same logical
|
|
42
|
-
* id would collide ("Role with name X already exists"). Switching to
|
|
43
|
-
* `AsyncLocalStorage` scopes the value to each deploy's async chain.
|
|
44
|
-
*/
|
|
45
|
-
const stackNameStore = new AsyncLocalStorage();
|
|
46
|
-
function withStackName(stackName, fn) {
|
|
47
|
-
return stackNameStore.run(stackName, fn);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Read the current async context's stack name, if any.
|
|
51
|
-
*
|
|
52
|
-
* Returns `undefined` outside any `withStackName` / `setCurrentStackName`
|
|
53
|
-
* scope. Used by the live renderer to scope per-stack in-flight task
|
|
54
|
-
* entries so concurrent deploys don't clobber each other's tasks (same
|
|
55
|
-
* `logicalId` in two stacks would collide on the singleton renderer's
|
|
56
|
-
* task Map without this).
|
|
57
|
-
*/
|
|
58
|
-
function getCurrentStackName() {
|
|
59
|
-
return stackNameStore.getStore();
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Per-async-context "skip the stack-name prefix on user-supplied physical
|
|
63
|
-
* names" flag. Read by `generateResourceName` when its caller passes
|
|
64
|
-
* `userSupplied: true`; auto-generated-name paths
|
|
65
|
-
* (`generateResourceName(logicalId, ...)`) ignore this flag.
|
|
66
|
-
*
|
|
67
|
-
* Scoped via AsyncLocalStorage so that `--stack-concurrency > 1` runs
|
|
68
|
-
* cannot cross-contaminate — each deploy's body is wrapped in its own
|
|
69
|
-
* `withSkipPrefix(...)` scope (the deploy CLI plumbs the resolved
|
|
70
|
-
* `--no-prefix-user-supplied-names` value through here). Default
|
|
71
|
-
* `false` preserves pre-PR behavior when the flag is not set.
|
|
72
|
-
*/
|
|
73
|
-
const skipPrefixStore = new AsyncLocalStorage();
|
|
74
|
-
function withSkipPrefix(skip, fn) {
|
|
75
|
-
return skipPrefixStore.run(skip, fn);
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Read the current async context's skip-prefix flag. Defaults to
|
|
79
|
-
* `false` when no `withSkipPrefix` scope is active.
|
|
80
|
-
*
|
|
81
|
-
* Public for unit tests; `generateResourceName` consumes this
|
|
82
|
-
* internally.
|
|
83
|
-
*/
|
|
84
|
-
function getCurrentSkipPrefix() {
|
|
85
|
-
return skipPrefixStore.getStore() ?? false;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Resource types whose pre-PR #297 code path ran user-supplied
|
|
89
|
-
* physical names through `generateResourceName` (= got the stack-name
|
|
90
|
-
* prefix). These are the only types affected by
|
|
91
|
-
* `--no-prefix-user-supplied-names`; flipping the flag against an
|
|
92
|
-
* existing stack proposes REPLACEMENT on every state resource of
|
|
93
|
-
* one of these types whose `physicalId` is still prefixed.
|
|
94
|
-
*
|
|
95
|
-
* Pattern A providers (Lambda, S3, SNS, SQS, DynamoDB, Logs LogGroup,
|
|
96
|
-
* Events Rule, etc.) historically short-circuited user-supplied names
|
|
97
|
-
* **out** of `generateResourceName` entirely — those types never got
|
|
98
|
-
* the prefix regardless of the flag, so they are NOT included here.
|
|
99
|
-
*
|
|
100
|
-
* Used by the deploy-time pre-flight migration check in
|
|
101
|
-
* `src/cli/commands/prefix-migration-check.ts`. Keep in sync with the
|
|
102
|
-
* Pattern B provider call sites that consume
|
|
103
|
-
* `generateResourceNameWithFallback(...)`.
|
|
104
|
-
*/
|
|
105
|
-
const PATTERN_B_RESOURCE_TYPES = [
|
|
106
|
-
"AWS::IAM::Role",
|
|
107
|
-
"AWS::IAM::User",
|
|
108
|
-
"AWS::IAM::Group",
|
|
109
|
-
"AWS::IAM::InstanceProfile",
|
|
110
|
-
"AWS::IAM::ManagedPolicy",
|
|
111
|
-
"AWS::ElasticLoadBalancingV2::LoadBalancer",
|
|
112
|
-
"AWS::ElasticLoadBalancingV2::TargetGroup"
|
|
113
|
-
];
|
|
114
|
-
/**
|
|
115
|
-
* For each Pattern B resource type, the CFn template `Properties` field
|
|
116
|
-
* the user sets to supply a physical name (`new iam.Role(this, 'X',
|
|
117
|
-
* { roleName: 'my-role' })` → `Properties.RoleName: 'my-role'`).
|
|
118
|
-
*
|
|
119
|
-
* Used by the prefix-migration check to distinguish user-supplied
|
|
120
|
-
* physical names (which the v0.94.0 default flip would actually
|
|
121
|
-
* REPLACE on next deploy) from auto-generated logical-id-fallback
|
|
122
|
-
* names (which keep the prefix in BOTH old and new default — no
|
|
123
|
-
* REPLACE pending). Without this discriminator, the migration
|
|
124
|
-
* check naively flags every prefix-style physicalId regardless of
|
|
125
|
-
* its origin, surfacing a false-positive WARNING on auto-generated
|
|
126
|
-
* names that won't actually be touched.
|
|
127
|
-
*
|
|
128
|
-
* Keep in sync with `PATTERN_B_RESOURCE_TYPES` and with each
|
|
129
|
-
* provider's `Properties[<NameField>]` lookup in
|
|
130
|
-
* `src/provisioning/providers/`.
|
|
131
|
-
*/
|
|
132
|
-
const PATTERN_B_NAME_PROPERTIES = {
|
|
133
|
-
"AWS::IAM::Role": "RoleName",
|
|
134
|
-
"AWS::IAM::User": "UserName",
|
|
135
|
-
"AWS::IAM::Group": "GroupName",
|
|
136
|
-
"AWS::IAM::InstanceProfile": "InstanceProfileName",
|
|
137
|
-
"AWS::IAM::ManagedPolicy": "ManagedPolicyName",
|
|
138
|
-
"AWS::ElasticLoadBalancingV2::LoadBalancer": "Name",
|
|
139
|
-
"AWS::ElasticLoadBalancingV2::TargetGroup": "Name"
|
|
140
|
-
};
|
|
141
|
-
/**
|
|
142
|
-
* Generate a unique resource name from the logical ID.
|
|
143
|
-
*
|
|
144
|
-
* Generates names in CloudFormation-compatible format:
|
|
145
|
-
* `{StackName}-{LogicalId}-{Hash}` (truncated to maxLength).
|
|
146
|
-
*
|
|
147
|
-
* @param name The raw name (from properties or logicalId fallback)
|
|
148
|
-
* @param options Length and character constraints
|
|
149
|
-
* @returns A sanitized, truncated name that fits the constraints
|
|
150
|
-
*/
|
|
151
|
-
function generateResourceName(name, options) {
|
|
152
|
-
const { maxLength, lowercase = false, allowedPattern = /[^a-zA-Z0-9-]/g, userSupplied = false } = options;
|
|
153
|
-
const currentStackName = stackNameStore.getStore();
|
|
154
|
-
const fullName = currentStackName && !(userSupplied && getCurrentSkipPrefix()) ? `${currentStackName}-${name}` : name;
|
|
155
|
-
let sanitized = lowercase ? fullName.toLowerCase() : fullName;
|
|
156
|
-
sanitized = sanitized.replace(allowedPattern, "-");
|
|
157
|
-
sanitized = sanitized.replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
|
|
158
|
-
if (sanitized.length <= maxLength) return sanitized;
|
|
159
|
-
const hash = createHash("sha256").update(fullName).digest("hex").substring(0, 8);
|
|
160
|
-
const maxPrefixLength = maxLength - hash.length - 1;
|
|
161
|
-
return `${sanitized.substring(0, maxPrefixLength).replace(/-+$/, "")}-${hash}`;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Generate a resource name from a user-declared physical name OR
|
|
165
|
-
* fall back to the logical id.
|
|
166
|
-
*
|
|
167
|
-
* Wraps {@link generateResourceName} to express the Pattern B call-site
|
|
168
|
-
* shape (`generateResourceName((properties['Name'] as string | undefined)
|
|
169
|
-
* || logicalId, opts)`) as a single typed helper. The user-supplied
|
|
170
|
-
* branch passes `userSupplied: true`, which makes the per-deploy
|
|
171
|
-
* `withSkipPrefix(true)` flag drop the stack-name prefix on that name.
|
|
172
|
-
* The fallback (logical-id) branch is `userSupplied: false` and keeps
|
|
173
|
-
* the prefix regardless of the flag — auto-generated names rely on
|
|
174
|
-
* the prefix for cross-stack uniqueness.
|
|
175
|
-
*
|
|
176
|
-
* Use at every Pattern B provider call site (currently IAM Role, IAM
|
|
177
|
-
* User, IAM Group, IAM InstanceProfile, ELBv2 LoadBalancer, ELBv2
|
|
178
|
-
* TargetGroup) so the `--no-prefix-user-supplied-names` flag controls
|
|
179
|
-
* those types consistently. Pattern A providers (Lambda, S3, SNS,
|
|
180
|
-
* SQS, DynamoDB, etc.) do NOT need this helper — they already
|
|
181
|
-
* short-circuit the user-supplied name out of the
|
|
182
|
-
* `generateResourceName` call entirely, so the prefix is never
|
|
183
|
-
* applied to user-supplied names regardless of the flag.
|
|
184
|
-
*/
|
|
185
|
-
function generateResourceNameWithFallback(userSuppliedName, logicalId, options) {
|
|
186
|
-
if (userSuppliedName !== void 0 && userSuppliedName !== "") return generateResourceName(userSuppliedName, {
|
|
187
|
-
...options,
|
|
188
|
-
userSupplied: true
|
|
189
|
-
});
|
|
190
|
-
return generateResourceName(logicalId, {
|
|
191
|
-
...options,
|
|
192
|
-
userSupplied: false
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Default name generation rules for CC API fallback.
|
|
197
|
-
*
|
|
198
|
-
* When an SDK provider falls back to CC API, the resource may need a
|
|
199
|
-
* default name that the SDK provider would have generated. This map
|
|
200
|
-
* defines the name property and generation options for each resource type.
|
|
201
|
-
*
|
|
202
|
-
* Format: resourceType → { nameProperty, options, postProcess? }
|
|
203
|
-
*/
|
|
204
|
-
const FALLBACK_NAME_RULES = {
|
|
205
|
-
"AWS::S3::Bucket": {
|
|
206
|
-
nameProperty: "BucketName",
|
|
207
|
-
options: {
|
|
208
|
-
maxLength: 63,
|
|
209
|
-
lowercase: true
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
"AWS::SQS::Queue": {
|
|
213
|
-
nameProperty: "QueueName",
|
|
214
|
-
options: { maxLength: 80 }
|
|
215
|
-
},
|
|
216
|
-
"AWS::SNS::Topic": {
|
|
217
|
-
nameProperty: "TopicName",
|
|
218
|
-
options: { maxLength: 256 }
|
|
219
|
-
},
|
|
220
|
-
"AWS::Lambda::Function": {
|
|
221
|
-
nameProperty: "FunctionName",
|
|
222
|
-
options: { maxLength: 64 }
|
|
223
|
-
},
|
|
224
|
-
"AWS::Lambda::LayerVersion": {
|
|
225
|
-
nameProperty: "LayerName",
|
|
226
|
-
options: { maxLength: 64 }
|
|
227
|
-
},
|
|
228
|
-
"AWS::IAM::Role": {
|
|
229
|
-
nameProperty: "RoleName",
|
|
230
|
-
options: { maxLength: 64 }
|
|
231
|
-
},
|
|
232
|
-
"AWS::IAM::Policy": {
|
|
233
|
-
nameProperty: "PolicyName",
|
|
234
|
-
options: { maxLength: 64 }
|
|
235
|
-
},
|
|
236
|
-
"AWS::IAM::ManagedPolicy": {
|
|
237
|
-
nameProperty: "ManagedPolicyName",
|
|
238
|
-
options: { maxLength: 128 }
|
|
239
|
-
},
|
|
240
|
-
"AWS::IAM::User": {
|
|
241
|
-
nameProperty: "UserName",
|
|
242
|
-
options: { maxLength: 64 }
|
|
243
|
-
},
|
|
244
|
-
"AWS::IAM::Group": {
|
|
245
|
-
nameProperty: "GroupName",
|
|
246
|
-
options: { maxLength: 128 }
|
|
247
|
-
},
|
|
248
|
-
"AWS::IAM::InstanceProfile": {
|
|
249
|
-
nameProperty: "InstanceProfileName",
|
|
250
|
-
options: { maxLength: 128 }
|
|
251
|
-
},
|
|
252
|
-
"AWS::DynamoDB::Table": {
|
|
253
|
-
nameProperty: "TableName",
|
|
254
|
-
options: { maxLength: 255 }
|
|
255
|
-
},
|
|
256
|
-
"AWS::ECR::Repository": {
|
|
257
|
-
nameProperty: "RepositoryName",
|
|
258
|
-
options: {
|
|
259
|
-
maxLength: 256,
|
|
260
|
-
lowercase: true
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
"AWS::ECS::Cluster": {
|
|
264
|
-
nameProperty: "ClusterName",
|
|
265
|
-
options: { maxLength: 255 }
|
|
266
|
-
},
|
|
267
|
-
"AWS::ECS::Service": {
|
|
268
|
-
nameProperty: "ServiceName",
|
|
269
|
-
options: { maxLength: 255 }
|
|
270
|
-
},
|
|
271
|
-
"AWS::Logs::LogGroup": {
|
|
272
|
-
nameProperty: "LogGroupName",
|
|
273
|
-
options: { maxLength: 512 }
|
|
274
|
-
},
|
|
275
|
-
"AWS::CloudWatch::Alarm": {
|
|
276
|
-
nameProperty: "AlarmName",
|
|
277
|
-
options: { maxLength: 256 }
|
|
278
|
-
},
|
|
279
|
-
"AWS::Events::Rule": {
|
|
280
|
-
nameProperty: "Name",
|
|
281
|
-
options: { maxLength: 64 }
|
|
282
|
-
},
|
|
283
|
-
"AWS::Events::EventBus": {
|
|
284
|
-
nameProperty: "Name",
|
|
285
|
-
options: { maxLength: 256 }
|
|
286
|
-
},
|
|
287
|
-
"AWS::Kinesis::Stream": {
|
|
288
|
-
nameProperty: "Name",
|
|
289
|
-
options: { maxLength: 128 }
|
|
290
|
-
},
|
|
291
|
-
"AWS::StepFunctions::StateMachine": {
|
|
292
|
-
nameProperty: "StateMachineName",
|
|
293
|
-
options: { maxLength: 80 }
|
|
294
|
-
},
|
|
295
|
-
"AWS::SecretsManager::Secret": {
|
|
296
|
-
nameProperty: "Name",
|
|
297
|
-
options: {
|
|
298
|
-
maxLength: 512,
|
|
299
|
-
allowedPattern: /[^a-zA-Z0-9-/_]/g
|
|
300
|
-
}
|
|
301
|
-
},
|
|
302
|
-
"AWS::SSM::Parameter": {
|
|
303
|
-
nameProperty: "Name",
|
|
304
|
-
options: { maxLength: 2048 }
|
|
305
|
-
},
|
|
306
|
-
"AWS::Cognito::UserPool": {
|
|
307
|
-
nameProperty: "UserPoolName",
|
|
308
|
-
options: { maxLength: 128 }
|
|
309
|
-
},
|
|
310
|
-
"AWS::ElastiCache::SubnetGroup": {
|
|
311
|
-
nameProperty: "CacheSubnetGroupName",
|
|
312
|
-
options: {
|
|
313
|
-
maxLength: 255,
|
|
314
|
-
lowercase: true
|
|
315
|
-
}
|
|
316
|
-
},
|
|
317
|
-
"AWS::ElastiCache::CacheCluster": {
|
|
318
|
-
nameProperty: "ClusterName",
|
|
319
|
-
options: {
|
|
320
|
-
maxLength: 40,
|
|
321
|
-
lowercase: true
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
"AWS::RDS::DBSubnetGroup": {
|
|
325
|
-
nameProperty: "DBSubnetGroupName",
|
|
326
|
-
options: {
|
|
327
|
-
maxLength: 255,
|
|
328
|
-
lowercase: true
|
|
329
|
-
}
|
|
330
|
-
},
|
|
331
|
-
"AWS::RDS::DBCluster": {
|
|
332
|
-
nameProperty: "DBClusterIdentifier",
|
|
333
|
-
options: {
|
|
334
|
-
maxLength: 63,
|
|
335
|
-
lowercase: true
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
"AWS::RDS::DBInstance": {
|
|
339
|
-
nameProperty: "DBInstanceIdentifier",
|
|
340
|
-
options: {
|
|
341
|
-
maxLength: 63,
|
|
342
|
-
lowercase: true
|
|
343
|
-
}
|
|
344
|
-
},
|
|
345
|
-
"AWS::DocDB::DBSubnetGroup": {
|
|
346
|
-
nameProperty: "DBSubnetGroupName",
|
|
347
|
-
options: {
|
|
348
|
-
maxLength: 255,
|
|
349
|
-
lowercase: true
|
|
350
|
-
}
|
|
351
|
-
},
|
|
352
|
-
"AWS::DocDB::DBCluster": {
|
|
353
|
-
nameProperty: "DBClusterIdentifier",
|
|
354
|
-
options: {
|
|
355
|
-
maxLength: 63,
|
|
356
|
-
lowercase: true
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
"AWS::DocDB::DBInstance": {
|
|
360
|
-
nameProperty: "DBInstanceIdentifier",
|
|
361
|
-
options: {
|
|
362
|
-
maxLength: 63,
|
|
363
|
-
lowercase: true
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
"AWS::Neptune::DBSubnetGroup": {
|
|
367
|
-
nameProperty: "DBSubnetGroupName",
|
|
368
|
-
options: {
|
|
369
|
-
maxLength: 255,
|
|
370
|
-
lowercase: true
|
|
371
|
-
}
|
|
372
|
-
},
|
|
373
|
-
"AWS::Neptune::DBCluster": {
|
|
374
|
-
nameProperty: "DBClusterIdentifier",
|
|
375
|
-
options: {
|
|
376
|
-
maxLength: 63,
|
|
377
|
-
lowercase: true
|
|
378
|
-
}
|
|
379
|
-
},
|
|
380
|
-
"AWS::Neptune::DBInstance": {
|
|
381
|
-
nameProperty: "DBInstanceIdentifier",
|
|
382
|
-
options: {
|
|
383
|
-
maxLength: 63,
|
|
384
|
-
lowercase: true
|
|
385
|
-
}
|
|
386
|
-
},
|
|
387
|
-
"AWS::ElasticLoadBalancingV2::LoadBalancer": {
|
|
388
|
-
nameProperty: "Name",
|
|
389
|
-
options: { maxLength: 32 }
|
|
390
|
-
},
|
|
391
|
-
"AWS::ElasticLoadBalancingV2::TargetGroup": {
|
|
392
|
-
nameProperty: "Name",
|
|
393
|
-
options: { maxLength: 32 }
|
|
394
|
-
},
|
|
395
|
-
"AWS::WAFv2::WebACL": {
|
|
396
|
-
nameProperty: "Name",
|
|
397
|
-
options: { maxLength: 128 }
|
|
398
|
-
},
|
|
399
|
-
"AWS::CodeBuild::Project": {
|
|
400
|
-
nameProperty: "Name",
|
|
401
|
-
options: { maxLength: 255 }
|
|
402
|
-
},
|
|
403
|
-
"AWS::S3Express::DirectoryBucket": {
|
|
404
|
-
nameProperty: "BucketName",
|
|
405
|
-
options: {
|
|
406
|
-
maxLength: 63,
|
|
407
|
-
lowercase: true
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
/**
|
|
412
|
-
* Apply default name generation for CC API fallback.
|
|
413
|
-
*
|
|
414
|
-
* When a resource doesn't have an explicit name property set,
|
|
415
|
-
* generates the same default name that the SDK provider would have created.
|
|
416
|
-
* This ensures consistent naming regardless of whether SDK or CC API handles the resource.
|
|
417
|
-
*
|
|
418
|
-
* @param logicalId Logical ID from the template
|
|
419
|
-
* @param resourceType CloudFormation resource type
|
|
420
|
-
* @param properties Resource properties (will not be mutated)
|
|
421
|
-
* @returns Properties with default name applied if needed, or original properties if no rule exists
|
|
422
|
-
*/
|
|
423
|
-
function applyDefaultNameForFallback(logicalId, resourceType, properties) {
|
|
424
|
-
const rule = FALLBACK_NAME_RULES[resourceType];
|
|
425
|
-
if (!rule) return properties;
|
|
426
|
-
if (properties[rule.nameProperty]) return properties;
|
|
427
|
-
const generatedName = generateResourceName(logicalId, rule.options);
|
|
428
|
-
return {
|
|
429
|
-
...properties,
|
|
430
|
-
[rule.nameProperty]: generatedName
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
//#endregion
|
|
435
|
-
//#region src/utils/live-renderer.ts
|
|
436
|
-
/**
|
|
437
|
-
* Live multi-line progress renderer for the bottom of the terminal.
|
|
438
|
-
*
|
|
439
|
-
* Maintains a "live area" listing in-flight tasks (Creating MyBucket...),
|
|
440
|
-
* redrawn on a spinner timer. Other log output is routed through
|
|
441
|
-
* {@link LiveRenderer.printAbove} so it appears above the live area without
|
|
442
|
-
* disturbing the currently-displayed in-flight tasks.
|
|
443
|
-
*
|
|
444
|
-
* Design notes:
|
|
445
|
-
* - Multiple resources can be in flight concurrently (cdkd uses parallel DAG
|
|
446
|
-
* dispatch), so a single in-place line overwrite is not enough — each
|
|
447
|
-
* in-flight resource is its own line in the live area.
|
|
448
|
-
* - On non-TTY (CI/log-collection), the renderer stays inactive and
|
|
449
|
-
* {@link LiveRenderer.printAbove} falls through to a direct write, so output
|
|
450
|
-
* matches the previous append-only behavior.
|
|
451
|
-
* - In verbose mode (debug level) the caller should not start the renderer:
|
|
452
|
-
* debug logs would interleave too aggressively with the live area.
|
|
453
|
-
*/
|
|
454
|
-
const SPINNER_FRAMES = [
|
|
455
|
-
"⠋",
|
|
456
|
-
"⠙",
|
|
457
|
-
"⠹",
|
|
458
|
-
"⠸",
|
|
459
|
-
"⠼",
|
|
460
|
-
"⠴",
|
|
461
|
-
"⠦",
|
|
462
|
-
"⠧",
|
|
463
|
-
"⠇",
|
|
464
|
-
"⠏"
|
|
465
|
-
];
|
|
466
|
-
const FRAME_INTERVAL_MS = 80;
|
|
467
|
-
const ESC = "\x1B[";
|
|
468
|
-
/**
|
|
469
|
-
* Scope a task `id` to its calling stack so two stacks running in
|
|
470
|
-
* parallel — `cdkd deploy --all` with `--stack-concurrency > 1` — don't
|
|
471
|
-
* collide on the same `logicalId` in the renderer's task Map. Without
|
|
472
|
-
* this, stack B's `addTask('MyQueue', ...)` would overwrite stack A's
|
|
473
|
-
* entry, and stack A's later `removeTask('MyQueue')` would erase
|
|
474
|
-
* stack B's.
|
|
475
|
-
*/
|
|
476
|
-
function scopedKey(id, stackName) {
|
|
477
|
-
return stackName ? `${stackName}:${id}` : id;
|
|
478
|
-
}
|
|
479
|
-
var LiveRenderer = class {
|
|
480
|
-
tasks = /* @__PURE__ */ new Map();
|
|
481
|
-
active = false;
|
|
482
|
-
spinnerIndex = 0;
|
|
483
|
-
interval = null;
|
|
484
|
-
linesDrawn = 0;
|
|
485
|
-
cursorHidden = false;
|
|
486
|
-
exitListener = null;
|
|
487
|
-
stream;
|
|
488
|
-
constructor(stream = process.stdout) {
|
|
489
|
-
this.stream = stream;
|
|
490
|
-
}
|
|
491
|
-
isActive() {
|
|
492
|
-
return this.active;
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Enable the live renderer. No-op if stdout is not a TTY or if
|
|
496
|
-
* `CDKD_NO_LIVE=1`. Returns true if successfully enabled.
|
|
497
|
-
*/
|
|
498
|
-
start() {
|
|
499
|
-
if (this.active) return true;
|
|
500
|
-
if (!this.stream.isTTY) return false;
|
|
501
|
-
if (process.env["CDKD_NO_LIVE"] === "1") return false;
|
|
502
|
-
this.active = true;
|
|
503
|
-
this.hideCursor();
|
|
504
|
-
if (!this.exitListener) {
|
|
505
|
-
this.exitListener = () => this.showCursor();
|
|
506
|
-
process.on("exit", this.exitListener);
|
|
507
|
-
}
|
|
508
|
-
this.interval = setInterval(() => this.draw(), FRAME_INTERVAL_MS);
|
|
509
|
-
if (typeof this.interval.unref === "function") this.interval.unref();
|
|
510
|
-
return true;
|
|
511
|
-
}
|
|
512
|
-
stop() {
|
|
513
|
-
if (!this.active) return;
|
|
514
|
-
if (this.interval) {
|
|
515
|
-
clearInterval(this.interval);
|
|
516
|
-
this.interval = null;
|
|
517
|
-
}
|
|
518
|
-
this.clear();
|
|
519
|
-
this.showCursor();
|
|
520
|
-
if (this.exitListener) {
|
|
521
|
-
process.removeListener("exit", this.exitListener);
|
|
522
|
-
this.exitListener = null;
|
|
523
|
-
}
|
|
524
|
-
this.tasks.clear();
|
|
525
|
-
this.active = false;
|
|
526
|
-
}
|
|
527
|
-
addTask(id, label) {
|
|
528
|
-
const stackName = getCurrentStackName();
|
|
529
|
-
this.tasks.set(scopedKey(id, stackName), {
|
|
530
|
-
label,
|
|
531
|
-
startedAt: Date.now(),
|
|
532
|
-
stackName
|
|
533
|
-
});
|
|
534
|
-
if (this.active) this.draw();
|
|
535
|
-
}
|
|
536
|
-
removeTask(id) {
|
|
537
|
-
const stackName = getCurrentStackName();
|
|
538
|
-
if (!this.tasks.delete(scopedKey(id, stackName))) return;
|
|
539
|
-
if (this.active) this.draw();
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* Replace the label of a previously-added task in place. No-op if the
|
|
543
|
-
* task is not currently tracked (e.g. it already finished). Used by the
|
|
544
|
-
* per-resource deadline wrapper to surface a "[taking longer than
|
|
545
|
-
* expected, Nm+]" suffix without disturbing the elapsed-time counter
|
|
546
|
-
* the renderer tracks via `startedAt`.
|
|
547
|
-
*/
|
|
548
|
-
updateTaskLabel(id, label) {
|
|
549
|
-
const stackName = getCurrentStackName();
|
|
550
|
-
const task = this.tasks.get(scopedKey(id, stackName));
|
|
551
|
-
if (!task) return;
|
|
552
|
-
task.label = label;
|
|
553
|
-
if (this.active) this.draw();
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Print content above the live area. Clears the live area, runs the writer,
|
|
557
|
-
* then redraws the live area. When the renderer is inactive, the writer
|
|
558
|
-
* runs directly so callers can use this unconditionally.
|
|
559
|
-
*/
|
|
560
|
-
printAbove(write) {
|
|
561
|
-
if (!this.active) {
|
|
562
|
-
write();
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
this.clear();
|
|
566
|
-
write();
|
|
567
|
-
this.draw();
|
|
568
|
-
}
|
|
569
|
-
clear() {
|
|
570
|
-
if (this.linesDrawn === 0) return;
|
|
571
|
-
this.stream.write("\r");
|
|
572
|
-
for (let i = 0; i < this.linesDrawn; i++) this.stream.write(`${ESC}1A${ESC}2K`);
|
|
573
|
-
this.linesDrawn = 0;
|
|
574
|
-
}
|
|
575
|
-
draw() {
|
|
576
|
-
if (!this.active) return;
|
|
577
|
-
this.clear();
|
|
578
|
-
if (this.tasks.size === 0) return;
|
|
579
|
-
const frame = SPINNER_FRAMES[this.spinnerIndex % SPINNER_FRAMES.length];
|
|
580
|
-
this.spinnerIndex++;
|
|
581
|
-
const distinctStacks = /* @__PURE__ */ new Set();
|
|
582
|
-
for (const task of this.tasks.values()) distinctStacks.add(task.stackName);
|
|
583
|
-
const showStackPrefix = distinctStacks.size > 1;
|
|
584
|
-
const cols = this.stream.columns ?? 80;
|
|
585
|
-
const lines = [];
|
|
586
|
-
for (const task of this.tasks.values()) {
|
|
587
|
-
const elapsed = ((Date.now() - task.startedAt) / 1e3).toFixed(1);
|
|
588
|
-
const raw = ` ${frame} ${showStackPrefix && task.stackName ? `[${task.stackName}] ` : ""}${task.label} (${elapsed}s)`;
|
|
589
|
-
lines.push(this.truncate(raw, cols));
|
|
590
|
-
}
|
|
591
|
-
this.stream.write(lines.join("\n") + "\n");
|
|
592
|
-
this.linesDrawn = lines.length;
|
|
593
|
-
}
|
|
594
|
-
truncate(s, maxLen) {
|
|
595
|
-
if (s.length <= maxLen) return s;
|
|
596
|
-
if (maxLen <= 1) return "…";
|
|
597
|
-
return s.substring(0, maxLen - 1) + "…";
|
|
598
|
-
}
|
|
599
|
-
hideCursor() {
|
|
600
|
-
if (this.cursorHidden) return;
|
|
601
|
-
this.stream.write(`${ESC}?25l`);
|
|
602
|
-
this.cursorHidden = true;
|
|
603
|
-
}
|
|
604
|
-
showCursor() {
|
|
605
|
-
if (!this.cursorHidden) return;
|
|
606
|
-
this.stream.write(`${ESC}?25h`);
|
|
607
|
-
this.cursorHidden = false;
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
let globalRenderer = null;
|
|
611
|
-
function getLiveRenderer() {
|
|
612
|
-
if (!globalRenderer) globalRenderer = new LiveRenderer();
|
|
613
|
-
return globalRenderer;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
//#endregion
|
|
617
|
-
//#region src/utils/stack-context.ts
|
|
618
|
-
const outputBufferStore = new AsyncLocalStorage();
|
|
619
|
-
/**
|
|
620
|
-
* Run `fn` with a fresh log buffer scoped to its async chain. Any
|
|
621
|
-
* `logger.info / debug / warn / error` calls inside `fn` (and any
|
|
622
|
-
* `await`s) push into the buffer instead of writing to stdout/stderr.
|
|
623
|
-
* Returns the buffered lines (and either `result` or `error`) so the
|
|
624
|
-
* caller can flush them in one block.
|
|
625
|
-
*/
|
|
626
|
-
async function runStackBuffered(fn) {
|
|
627
|
-
const buffer = { lines: [] };
|
|
628
|
-
return outputBufferStore.run(buffer, async () => {
|
|
629
|
-
try {
|
|
630
|
-
return {
|
|
631
|
-
ok: true,
|
|
632
|
-
result: await fn(),
|
|
633
|
-
lines: buffer.lines
|
|
634
|
-
};
|
|
635
|
-
} catch (error) {
|
|
636
|
-
return {
|
|
637
|
-
ok: false,
|
|
638
|
-
error,
|
|
639
|
-
lines: buffer.lines
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Get the current async context's stack output buffer, or `undefined`
|
|
646
|
-
* if no `runStackBuffered` is active. The logger consults this on every
|
|
647
|
-
* call: present → push to buffer; absent → fall through to live
|
|
648
|
-
* renderer / console.
|
|
649
|
-
*/
|
|
650
|
-
function getCurrentStackOutputBuffer() {
|
|
651
|
-
return outputBufferStore.getStore();
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
//#endregion
|
|
655
|
-
//#region src/utils/logger.ts
|
|
656
|
-
/**
|
|
657
|
-
* ANSI color codes
|
|
658
|
-
*
|
|
659
|
-
* Kept internal — `ConsoleLogger.formatMessage` references these for the
|
|
660
|
-
* verbose/compact mode level prefixes. For inline color wrapping in
|
|
661
|
-
* production code, import from `./colors.js` instead (which lives in a
|
|
662
|
-
* separate module so unit tests that mock `logger.ts` don't strip color
|
|
663
|
-
* helpers as a side effect).
|
|
664
|
-
*/
|
|
665
|
-
const colors = {
|
|
666
|
-
reset: "\x1B[0m",
|
|
667
|
-
bright: "\x1B[1m",
|
|
668
|
-
dim: "\x1B[2m",
|
|
669
|
-
red: "\x1B[31m",
|
|
670
|
-
green: "\x1B[32m",
|
|
671
|
-
yellow: "\x1B[33m",
|
|
672
|
-
blue: "\x1B[34m",
|
|
673
|
-
cyan: "\x1B[36m",
|
|
674
|
-
gray: "\x1B[90m"
|
|
675
|
-
};
|
|
676
|
-
/**
|
|
677
|
-
* Format timestamp
|
|
678
|
-
*/
|
|
679
|
-
function formatTimestamp() {
|
|
680
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Console logger implementation
|
|
684
|
-
*
|
|
685
|
-
* Supports two output modes:
|
|
686
|
-
* - verbose (debug level): timestamps, module prefixes, all details
|
|
687
|
-
* - compact (info level): clean output without timestamps or prefixes
|
|
688
|
-
*/
|
|
689
|
-
var ConsoleLogger = class {
|
|
690
|
-
level;
|
|
691
|
-
useColors;
|
|
692
|
-
constructor(level = "info", useColors = true) {
|
|
693
|
-
this.level = level;
|
|
694
|
-
this.useColors = useColors;
|
|
695
|
-
}
|
|
696
|
-
shouldLog(level) {
|
|
697
|
-
const levels = [
|
|
698
|
-
"debug",
|
|
699
|
-
"info",
|
|
700
|
-
"warn",
|
|
701
|
-
"error"
|
|
702
|
-
];
|
|
703
|
-
const currentLevelIndex = levels.indexOf(this.level);
|
|
704
|
-
return levels.indexOf(level) >= currentLevelIndex;
|
|
705
|
-
}
|
|
706
|
-
formatMessage(level, message, ...args) {
|
|
707
|
-
const formattedArgs = args.length > 0 ? " " + args.map((a) => JSON.stringify(a)).join(" ") : "";
|
|
708
|
-
if (this.level === "debug") {
|
|
709
|
-
const timestamp = formatTimestamp();
|
|
710
|
-
const levelStr = level.toUpperCase().padEnd(5);
|
|
711
|
-
if (this.useColors) {
|
|
712
|
-
const levelColor = {
|
|
713
|
-
debug: colors.gray,
|
|
714
|
-
info: colors.blue,
|
|
715
|
-
warn: colors.yellow,
|
|
716
|
-
error: colors.red
|
|
717
|
-
}[level];
|
|
718
|
-
return `${colors.dim}${timestamp}${colors.reset} ${levelColor}${levelStr}${colors.reset} ${message}${formattedArgs}`;
|
|
719
|
-
}
|
|
720
|
-
return `${timestamp} ${levelStr} ${message}${formattedArgs}`;
|
|
721
|
-
}
|
|
722
|
-
if (this.useColors) {
|
|
723
|
-
if (level === "error") return `${colors.red}${message}${formattedArgs}${colors.reset}`;
|
|
724
|
-
if (level === "warn") return `${colors.yellow}${message}${formattedArgs}${colors.reset}`;
|
|
725
|
-
return `${message}${formattedArgs}`;
|
|
726
|
-
}
|
|
727
|
-
return `${message}${formattedArgs}`;
|
|
728
|
-
}
|
|
729
|
-
/**
|
|
730
|
-
* Route a formatted log line. When a per-stack output buffer is active in
|
|
731
|
-
* the current async context (parallel multi-stack deploy), capture the
|
|
732
|
-
* line into the buffer so it can be flushed as one atomic block when the
|
|
733
|
-
* stack finishes. Otherwise fall through to the live renderer / console
|
|
734
|
-
* as before.
|
|
735
|
-
*/
|
|
736
|
-
emit(level, formatted) {
|
|
737
|
-
const buffer = getCurrentStackOutputBuffer();
|
|
738
|
-
if (buffer) {
|
|
739
|
-
buffer.lines.push(formatted);
|
|
740
|
-
return;
|
|
741
|
-
}
|
|
742
|
-
getLiveRenderer().printAbove(() => {
|
|
743
|
-
if (level === "error") console.error(formatted);
|
|
744
|
-
else if (level === "warn") console.warn(formatted);
|
|
745
|
-
else if (level === "info") console.info(formatted);
|
|
746
|
-
else console.debug(formatted);
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
debug(message, ...args) {
|
|
750
|
-
if (this.shouldLog("debug")) this.emit("debug", this.formatMessage("debug", message, ...args));
|
|
751
|
-
}
|
|
752
|
-
info(message, ...args) {
|
|
753
|
-
if (this.shouldLog("info")) this.emit("info", this.formatMessage("info", message, ...args));
|
|
754
|
-
}
|
|
755
|
-
warn(message, ...args) {
|
|
756
|
-
if (this.shouldLog("warn")) this.emit("warn", this.formatMessage("warn", message, ...args));
|
|
757
|
-
}
|
|
758
|
-
error(message, ...args) {
|
|
759
|
-
if (this.shouldLog("error")) this.emit("error", this.formatMessage("error", message, ...args));
|
|
760
|
-
}
|
|
761
|
-
/**
|
|
762
|
-
* Set log level
|
|
763
|
-
*/
|
|
764
|
-
setLevel(level) {
|
|
765
|
-
this.level = level;
|
|
766
|
-
}
|
|
767
|
-
getLevel() {
|
|
768
|
-
return this.level;
|
|
769
|
-
}
|
|
770
|
-
/**
|
|
771
|
-
* Create a child logger with a prefix
|
|
772
|
-
*
|
|
773
|
-
* In verbose mode, prefix is shown as [Prefix]. In compact mode, prefix is hidden.
|
|
774
|
-
*/
|
|
775
|
-
child(prefix) {
|
|
776
|
-
return new ChildLogger(prefix, this.useColors);
|
|
777
|
-
}
|
|
778
|
-
};
|
|
779
|
-
/**
|
|
780
|
-
* Child logger that always syncs level from global logger
|
|
781
|
-
*/
|
|
782
|
-
var ChildLogger = class extends ConsoleLogger {
|
|
783
|
-
prefix;
|
|
784
|
-
constructor(prefix, useColors) {
|
|
785
|
-
super("info", useColors);
|
|
786
|
-
this.prefix = prefix;
|
|
787
|
-
}
|
|
788
|
-
syncLevel() {
|
|
789
|
-
if (globalLogger) this.setLevel(globalLogger.getLevel());
|
|
790
|
-
}
|
|
791
|
-
debug(message, ...args) {
|
|
792
|
-
this.syncLevel();
|
|
793
|
-
super.debug(`[${this.prefix}] ${message}`, ...args);
|
|
794
|
-
}
|
|
795
|
-
info(message, ...args) {
|
|
796
|
-
this.syncLevel();
|
|
797
|
-
const msg = this.getLevel() === "debug" ? `[${this.prefix}] ${message}` : message;
|
|
798
|
-
super.info(msg, ...args);
|
|
799
|
-
}
|
|
800
|
-
warn(message, ...args) {
|
|
801
|
-
this.syncLevel();
|
|
802
|
-
const msg = this.getLevel() === "debug" ? `[${this.prefix}] ${message}` : message;
|
|
803
|
-
super.warn(msg, ...args);
|
|
804
|
-
}
|
|
805
|
-
error(message, ...args) {
|
|
806
|
-
this.syncLevel();
|
|
807
|
-
const msg = this.getLevel() === "debug" ? `[${this.prefix}] ${message}` : message;
|
|
808
|
-
super.error(msg, ...args);
|
|
809
|
-
}
|
|
810
|
-
};
|
|
811
|
-
/**
|
|
812
|
-
* Global logger instance
|
|
813
|
-
*/
|
|
814
|
-
let globalLogger = null;
|
|
815
|
-
/**
|
|
816
|
-
* Get or create global logger
|
|
817
|
-
*/
|
|
818
|
-
function getLogger() {
|
|
819
|
-
if (!globalLogger) globalLogger = new ConsoleLogger();
|
|
820
|
-
return globalLogger;
|
|
821
|
-
}
|
|
822
|
-
/**
|
|
823
|
-
* Set global logger instance
|
|
824
|
-
*/
|
|
825
|
-
function setLogger(logger) {
|
|
826
|
-
globalLogger = logger;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
//#endregion
|
|
830
|
-
//#region src/utils/error-handler.ts
|
|
831
|
-
/**
|
|
832
|
-
* Base error class for cdkd
|
|
833
|
-
*/
|
|
834
|
-
var CdkdError = class CdkdError extends Error {
|
|
835
|
-
code;
|
|
836
|
-
cause;
|
|
837
|
-
constructor(message, code, cause) {
|
|
838
|
-
super(message);
|
|
839
|
-
this.code = code;
|
|
840
|
-
this.cause = cause;
|
|
841
|
-
this.name = "CdkdError";
|
|
842
|
-
Object.setPrototypeOf(this, CdkdError.prototype);
|
|
843
|
-
}
|
|
844
|
-
};
|
|
845
|
-
/**
|
|
846
|
-
* State management errors
|
|
847
|
-
*/
|
|
848
|
-
var StateError = class StateError extends CdkdError {
|
|
849
|
-
constructor(message, cause) {
|
|
850
|
-
super(message, "STATE_ERROR", cause);
|
|
851
|
-
this.name = "StateError";
|
|
852
|
-
Object.setPrototypeOf(this, StateError.prototype);
|
|
853
|
-
}
|
|
854
|
-
};
|
|
855
|
-
/**
|
|
856
|
-
* Lock acquisition errors
|
|
857
|
-
*/
|
|
858
|
-
var LockError = class LockError extends CdkdError {
|
|
859
|
-
constructor(message, cause) {
|
|
860
|
-
super(message, "LOCK_ERROR", cause);
|
|
861
|
-
this.name = "LockError";
|
|
862
|
-
Object.setPrototypeOf(this, LockError.prototype);
|
|
863
|
-
}
|
|
864
|
-
};
|
|
865
|
-
/**
|
|
866
|
-
* Synthesis errors
|
|
867
|
-
*/
|
|
868
|
-
var SynthesisError = class SynthesisError extends CdkdError {
|
|
869
|
-
constructor(message, cause) {
|
|
870
|
-
super(message, "SYNTHESIS_ERROR", cause);
|
|
871
|
-
this.name = "SynthesisError";
|
|
872
|
-
Object.setPrototypeOf(this, SynthesisError.prototype);
|
|
873
|
-
}
|
|
874
|
-
};
|
|
875
|
-
/**
|
|
876
|
-
* Asset errors
|
|
877
|
-
*/
|
|
878
|
-
var AssetError = class AssetError extends CdkdError {
|
|
879
|
-
constructor(message, cause) {
|
|
880
|
-
super(message, "ASSET_ERROR", cause);
|
|
881
|
-
this.name = "AssetError";
|
|
882
|
-
Object.setPrototypeOf(this, AssetError.prototype);
|
|
883
|
-
}
|
|
884
|
-
};
|
|
885
|
-
/**
|
|
886
|
-
* Local-invoke `docker build` failures.
|
|
887
|
-
*
|
|
888
|
-
* Surfaces the stderr captured from `docker build` so the user can
|
|
889
|
-
* re-run the same command directly to debug Dockerfile syntax errors
|
|
890
|
-
* or missing build context. Used by `src/local/docker-image-builder.ts`
|
|
891
|
-
* (PR 5) for container Lambdas; the parallel `AssetError` covers the
|
|
892
|
-
* `cdkd publish-assets` / `cdkd deploy` build path. Kept distinct from
|
|
893
|
-
* `AssetError` so `cdkd local invoke` failures don't show up under the
|
|
894
|
-
* "asset" error class.
|
|
895
|
-
*/
|
|
896
|
-
var LocalInvokeBuildError = class LocalInvokeBuildError extends CdkdError {
|
|
897
|
-
constructor(message, cause) {
|
|
898
|
-
super(message, "LOCAL_INVOKE_BUILD_ERROR", cause);
|
|
899
|
-
this.name = "LocalInvokeBuildError";
|
|
900
|
-
Object.setPrototypeOf(this, LocalInvokeBuildError.prototype);
|
|
901
|
-
}
|
|
902
|
-
};
|
|
903
|
-
/**
|
|
904
|
-
* Resource provisioning errors
|
|
905
|
-
*/
|
|
906
|
-
var ProvisioningError = class ProvisioningError extends CdkdError {
|
|
907
|
-
resourceType;
|
|
908
|
-
logicalId;
|
|
909
|
-
physicalId;
|
|
910
|
-
constructor(message, resourceType, logicalId, physicalId, cause) {
|
|
911
|
-
super(message, "PROVISIONING_ERROR", cause);
|
|
912
|
-
this.resourceType = resourceType;
|
|
913
|
-
this.logicalId = logicalId;
|
|
914
|
-
this.physicalId = physicalId;
|
|
915
|
-
this.name = "ProvisioningError";
|
|
916
|
-
Object.setPrototypeOf(this, ProvisioningError.prototype);
|
|
917
|
-
}
|
|
918
|
-
};
|
|
919
|
-
/**
|
|
920
|
-
* Resource provisioning timeout errors (per-resource wall-clock deadline).
|
|
921
|
-
*
|
|
922
|
-
* Thrown by `withResourceDeadline` when a single CREATE / UPDATE / DELETE
|
|
923
|
-
* operation exceeds the user-configured `--resource-timeout`. The deploy
|
|
924
|
-
* engine catches this, wraps it in {@link ProvisioningError}, and lets the
|
|
925
|
-
* existing failure path (interrupt siblings → pre-rollback save → rollback
|
|
926
|
-
* unless `--no-rollback`) take over.
|
|
927
|
-
*
|
|
928
|
-
* The message intentionally names the resource, type, region, elapsed time
|
|
929
|
-
* and operation, plus how to override the default. Long-running providers
|
|
930
|
-
* (e.g. Custom Resource: 1h polling cap) self-report their needed budget
|
|
931
|
-
* via `getMinResourceTimeoutMs()`, so the user only needs a per-type
|
|
932
|
-
* override (`--resource-timeout TYPE=DURATION`) when they want to bump a
|
|
933
|
-
* specific non-self-reporting type or shorten a self-reported one.
|
|
934
|
-
*/
|
|
935
|
-
var ResourceTimeoutError = class ResourceTimeoutError extends CdkdError {
|
|
936
|
-
logicalId;
|
|
937
|
-
resourceType;
|
|
938
|
-
region;
|
|
939
|
-
elapsedMs;
|
|
940
|
-
operation;
|
|
941
|
-
timeoutMs;
|
|
942
|
-
constructor(logicalId, resourceType, region, elapsedMs, operation, timeoutMs) {
|
|
943
|
-
const elapsedLabel = formatDuration(elapsedMs);
|
|
944
|
-
const timeoutLabel = formatDuration(timeoutMs);
|
|
945
|
-
super(`Resource ${logicalId} (${resourceType}) in ${region} timed out after ${timeoutLabel} during ${operation} (elapsed ${elapsedLabel}).\nThis may indicate a stuck Cloud Control polling loop, hung Custom Resource, or
|
|
946
|
-
slow ENI provisioning. Re-run with --resource-timeout ${resourceType}=<DURATION>\nto bump the budget for this resource type only, or --verbose to see the
|
|
947
|
-
underlying provider activity.`, "RESOURCE_TIMEOUT");
|
|
948
|
-
this.logicalId = logicalId;
|
|
949
|
-
this.resourceType = resourceType;
|
|
950
|
-
this.region = region;
|
|
951
|
-
this.elapsedMs = elapsedMs;
|
|
952
|
-
this.operation = operation;
|
|
953
|
-
this.timeoutMs = timeoutMs;
|
|
954
|
-
this.name = "ResourceTimeoutError";
|
|
955
|
-
Object.setPrototypeOf(this, ResourceTimeoutError.prototype);
|
|
956
|
-
}
|
|
957
|
-
};
|
|
958
|
-
/**
|
|
959
|
-
* Format a duration in milliseconds as a short human-readable label
|
|
960
|
-
* (`30m`, `1h30m`, `45s`). Used by {@link ResourceTimeoutError} so the
|
|
961
|
-
* error message stays compact.
|
|
962
|
-
*/
|
|
963
|
-
function formatDuration(ms) {
|
|
964
|
-
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
965
|
-
const totalMinutes = Math.round(ms / 6e4);
|
|
966
|
-
if (totalMinutes < 60) return `${totalMinutes}m`;
|
|
967
|
-
const hours = Math.floor(totalMinutes / 60);
|
|
968
|
-
const minutes = totalMinutes % 60;
|
|
969
|
-
return minutes === 0 ? `${hours}h` : `${hours}h${minutes}m`;
|
|
970
|
-
}
|
|
971
|
-
/**
|
|
972
|
-
* Dependency resolution errors
|
|
973
|
-
*/
|
|
974
|
-
var DependencyError = class DependencyError extends CdkdError {
|
|
975
|
-
constructor(message, cause) {
|
|
976
|
-
super(message, "DEPENDENCY_ERROR", cause);
|
|
977
|
-
this.name = "DependencyError";
|
|
978
|
-
Object.setPrototypeOf(this, DependencyError.prototype);
|
|
979
|
-
}
|
|
980
|
-
};
|
|
981
|
-
/**
|
|
982
|
-
* Configuration errors
|
|
983
|
-
*/
|
|
984
|
-
var ConfigError = class ConfigError extends CdkdError {
|
|
985
|
-
constructor(message, cause) {
|
|
986
|
-
super(message, "CONFIG_ERROR", cause);
|
|
987
|
-
this.name = "ConfigError";
|
|
988
|
-
Object.setPrototypeOf(this, ConfigError.prototype);
|
|
989
|
-
}
|
|
990
|
-
};
|
|
991
|
-
/**
|
|
992
|
-
* Signals a partial-failure outcome that should map to exit code 2 (not 1).
|
|
993
|
-
*
|
|
994
|
-
* Used by `cdkd destroy` and `cdkd state destroy` when one or more
|
|
995
|
-
* per-resource deletes failed but the overall command finished its work
|
|
996
|
-
* (state.json is preserved, the rest of the stack was deleted, and the
|
|
997
|
-
* user can re-run to clean up the remaining resources).
|
|
998
|
-
*
|
|
999
|
-
* Exit code conventions:
|
|
1000
|
-
* - 0: command completed successfully, no resources left in error state.
|
|
1001
|
-
* - 1: command-level failure (auth error, bad arguments, synth crash,
|
|
1002
|
-
* unhandled exception). Default for any thrown error.
|
|
1003
|
-
* - 2: partial failure — work completed but some resources are still in
|
|
1004
|
-
* an error state. Re-running typically resolves it. Documented in
|
|
1005
|
-
* README's "Exit codes" section.
|
|
1006
|
-
*
|
|
1007
|
-
* `handleError` recognizes this class via `instanceof` and uses its
|
|
1008
|
-
* `exitCode` instead of the default 1.
|
|
1009
|
-
*/
|
|
1010
|
-
var PartialFailureError = class PartialFailureError extends CdkdError {
|
|
1011
|
-
exitCode = 2;
|
|
1012
|
-
constructor(message, cause) {
|
|
1013
|
-
super(message, "PARTIAL_FAILURE", cause);
|
|
1014
|
-
this.name = "PartialFailureError";
|
|
1015
|
-
Object.setPrototypeOf(this, PartialFailureError.prototype);
|
|
1016
|
-
}
|
|
1017
|
-
};
|
|
1018
|
-
/**
|
|
1019
|
-
* Signals that a provider cannot perform an in-place `update` for a
|
|
1020
|
-
* resource type — most commonly because the AWS resource is structurally
|
|
1021
|
-
* immutable (`AWS::Lambda::LayerVersion`, `AWS::S3Tables::TableBucket` once
|
|
1022
|
-
* created, certain `AWS::EC2::*` sub-resources) or because the provider
|
|
1023
|
-
* surfaces a sub-resource attachment whose only mutation pattern is
|
|
1024
|
-
* delete + add (Lambda permission statements, IAM policy attachments).
|
|
1025
|
-
*
|
|
1026
|
-
* Surfaced through `cdkd drift --revert`, which calls
|
|
1027
|
-
* `provider.update(logicalId, physicalId, type, stateProps, awsProps)` to
|
|
1028
|
-
* push cdkd state values back into AWS for every drifted resource. When a
|
|
1029
|
-
* provider throws this error, the drift command collects it as a
|
|
1030
|
-
* per-resource outcome distinct from a generic AWS update failure: the
|
|
1031
|
-
* fix is to re-deploy with `--replace` (or recreate the resource), not to
|
|
1032
|
-
* retry the update.
|
|
1033
|
-
*
|
|
1034
|
-
* Carries the same `exitCode = 2` as {@link PartialFailureError} so a
|
|
1035
|
-
* drift run that hits one immutable resource is reported as partial-
|
|
1036
|
-
* success rather than fatal — the rest of the drifted resources still
|
|
1037
|
-
* had their `update` invoked, and the user has a clear next step printed
|
|
1038
|
-
* for the unsupported one.
|
|
1039
|
-
*/
|
|
1040
|
-
var ResourceUpdateNotSupportedError = class ResourceUpdateNotSupportedError extends CdkdError {
|
|
1041
|
-
exitCode = 2;
|
|
1042
|
-
resourceType;
|
|
1043
|
-
logicalId;
|
|
1044
|
-
/**
|
|
1045
|
-
* Human-readable hint printed alongside the error. The default is
|
|
1046
|
-
* "use cdkd deploy with --replace, or change the resource definition
|
|
1047
|
-
* to create a new version" — providers are encouraged to override
|
|
1048
|
-
* with a more specific suggestion when one is available (e.g.
|
|
1049
|
-
* Lambda::Permission's "delete + add a new statement").
|
|
1050
|
-
*/
|
|
1051
|
-
suggestion;
|
|
1052
|
-
constructor(resourceType, logicalId, suggestion, cause) {
|
|
1053
|
-
super(`${resourceType} (${logicalId}) cannot be updated in place: ${suggestion ? suggestion : "use cdkd deploy with --replace, or change the resource definition to create a new version"}.`, "RESOURCE_UPDATE_NOT_SUPPORTED", cause);
|
|
1054
|
-
this.resourceType = resourceType;
|
|
1055
|
-
this.logicalId = logicalId;
|
|
1056
|
-
this.suggestion = suggestion;
|
|
1057
|
-
this.name = "ResourceUpdateNotSupportedError";
|
|
1058
|
-
Object.setPrototypeOf(this, ResourceUpdateNotSupportedError.prototype);
|
|
1059
|
-
}
|
|
1060
|
-
};
|
|
1061
|
-
/**
|
|
1062
|
-
* Signals a refusal to destroy a stack whose CDK manifest has
|
|
1063
|
-
* `terminationProtection: true`.
|
|
1064
|
-
*
|
|
1065
|
-
* Surfaced from `cdkd destroy <stack>` / `cdkd destroy --all` BEFORE
|
|
1066
|
-
* any lock acquisition or per-resource delete. In multi-stack runs
|
|
1067
|
-
* (e.g. `--all`) this counts as a per-stack failure and the rest of
|
|
1068
|
-
* the targets continue — the aggregated count is wrapped in
|
|
1069
|
-
* {@link PartialFailureError} so the command exits with code 2.
|
|
1070
|
-
*
|
|
1071
|
-
* The bypass workflow is documented in the message: edit the CDK code
|
|
1072
|
-
* (`new Stack(app, '...', { terminationProtection: false })`),
|
|
1073
|
-
* redeploy, then retry the destroy. A future `--remove-protection`
|
|
1074
|
-
* flag (separate scope) will provide an explicit one-shot bypass.
|
|
1075
|
-
*
|
|
1076
|
-
* Note: `cdkd state destroy` (state-only, no synth) does NOT honor
|
|
1077
|
-
* `terminationProtection` — the flag is a CDK property not persisted
|
|
1078
|
-
* in cdkd's state.json. Use `cdkd destroy` when synth is available.
|
|
1079
|
-
*/
|
|
1080
|
-
var StackTerminationProtectionError = class StackTerminationProtectionError extends CdkdError {
|
|
1081
|
-
stackName;
|
|
1082
|
-
constructor(stackName, cause) {
|
|
1083
|
-
super(`Stack '${stackName}' has terminationProtection: true and cannot be destroyed. Set terminationProtection: false in the CDK code, redeploy, then retry 'cdkd destroy ${stackName}'.`, "STACK_TERMINATION_PROTECTION", cause);
|
|
1084
|
-
this.stackName = stackName;
|
|
1085
|
-
this.name = "StackTerminationProtectionError";
|
|
1086
|
-
Object.setPrototypeOf(this, StackTerminationProtectionError.prototype);
|
|
1087
|
-
}
|
|
1088
|
-
};
|
|
1089
|
-
/**
|
|
1090
|
-
* `cdkd destroy <child>` refused because the named stack is a nested
|
|
1091
|
-
* child of another stack. Mirrors CloudFormation's `you can't directly
|
|
1092
|
-
* destroy a nested stack` semantic — destroying the child without
|
|
1093
|
-
* touching the parent would leave the parent's `AWS::CloudFormation::Stack`
|
|
1094
|
-
* record pointing at non-existent resources, and the parent's next
|
|
1095
|
-
* deploy would silently try to re-create them.
|
|
1096
|
-
*
|
|
1097
|
-
* Detected by reading the loaded state's v6 `parentStack` field — only
|
|
1098
|
-
* state files written by `NestedStackProvider.create` (or by the
|
|
1099
|
-
* recursive `cdkd import --migrate-from-cloudformation` walk) carry
|
|
1100
|
-
* this field; top-level stacks have `parentStack: undefined` and pass
|
|
1101
|
-
* the guard unchanged.
|
|
1102
|
-
*
|
|
1103
|
-
* Fires from `cdkd destroy` AFTER state load but BEFORE lock
|
|
1104
|
-
* acquisition or any per-resource delete, so the refusal is cheap.
|
|
1105
|
-
* Surfaced as a per-stack failure (wrapped in {@link PartialFailureError},
|
|
1106
|
-
* exit code 2) in multi-stack runs — siblings continue.
|
|
1107
|
-
*
|
|
1108
|
-
* Bypass paths (both intentional escape hatches):
|
|
1109
|
-
*
|
|
1110
|
-
* 1. `cdkd destroy <parent>` — the normal cascading-destroy path; the
|
|
1111
|
-
* parent's reverse-DAG walks into the child via
|
|
1112
|
-
* `NestedStackProvider.delete` and removes both layers atomically.
|
|
1113
|
-
* 2. `cdkd state destroy <child>` — state-only destroy with no parent
|
|
1114
|
-
* coupling check. The state-driven entry point intentionally
|
|
1115
|
-
* bypasses this guard for the same reason `cdkd state destroy`
|
|
1116
|
-
* bypasses `terminationProtection`: it's the "I know what I'm
|
|
1117
|
-
* doing" path for cleaning up state when synth is unavailable or
|
|
1118
|
-
* the user accepts leaving the parent's reference dangling.
|
|
1119
|
-
*/
|
|
1120
|
-
var NestedStackChildDirectDestroyError = class NestedStackChildDirectDestroyError extends CdkdError {
|
|
1121
|
-
stackName;
|
|
1122
|
-
parentStack;
|
|
1123
|
-
parentLogicalId;
|
|
1124
|
-
constructor(stackName, parentStack, parentLogicalId, cause) {
|
|
1125
|
-
const logicalIdSuffix = parentLogicalId ? ` (parent's logical id: ${parentLogicalId})` : "";
|
|
1126
|
-
super(`Stack '${stackName}' is a nested child of '${parentStack}'${logicalIdSuffix}; directly destroying a nested stack is not supported. Either run 'cdkd destroy ${parentStack}' to cascade-delete this child along with its parent, or run 'cdkd state destroy ${stackName}' if you intentionally want to leave the parent's reference dangling (the state-only escape hatch).`, "NESTED_STACK_CHILD_DIRECT_DESTROY", cause);
|
|
1127
|
-
this.stackName = stackName;
|
|
1128
|
-
this.parentStack = parentStack;
|
|
1129
|
-
if (parentLogicalId !== void 0) this.parentLogicalId = parentLogicalId;
|
|
1130
|
-
this.name = "NestedStackChildDirectDestroyError";
|
|
1131
|
-
Object.setPrototypeOf(this, NestedStackChildDirectDestroyError.prototype);
|
|
1132
|
-
}
|
|
1133
|
-
};
|
|
1134
|
-
/**
|
|
1135
|
-
* `cdkd destroy <producer>` refused because at least one consumer stack
|
|
1136
|
-
* still records an `Fn::ImportValue` reference to one of the producer's
|
|
1137
|
-
* outputs. This matches CloudFormation's strong-reference semantics —
|
|
1138
|
-
* CFn rejects `DeleteStack` for an exporter while an importer exists.
|
|
1139
|
-
*
|
|
1140
|
-
* cdkd has no `--force` escape hatch for this (intentionally, mirroring
|
|
1141
|
-
* CFn). The error message lists every offending consumer and points the
|
|
1142
|
-
* user at the two valid resolution paths:
|
|
1143
|
-
*
|
|
1144
|
-
* 1. Destroy the consumer first: `cdkd destroy <consumer>`
|
|
1145
|
-
* 2. Remove the `Fn::ImportValue` from the consumer's template and
|
|
1146
|
-
* redeploy, then retry the producer destroy.
|
|
1147
|
-
*
|
|
1148
|
-
* Weak-reference consumers (`Fn::GetStackOutput`, cdkd-specific) never
|
|
1149
|
-
* trigger this error by design — the producer stays deletable
|
|
1150
|
-
* independently of consumers when the user intentionally chose a weak
|
|
1151
|
-
* reference at template-authoring time.
|
|
1152
|
-
*
|
|
1153
|
-
* Exit code 2 (same as `PartialFailureError`) so multi-stack `cdkd
|
|
1154
|
-
* destroy --all` runs that partially succeed still surface as
|
|
1155
|
-
* non-zero without being indistinguishable from a fatal cdkd error.
|
|
1156
|
-
*/
|
|
1157
|
-
var StackHasActiveImportsError = class StackHasActiveImportsError extends CdkdError {
|
|
1158
|
-
exitCode = 2;
|
|
1159
|
-
producerStack;
|
|
1160
|
-
producerRegion;
|
|
1161
|
-
consumers;
|
|
1162
|
-
constructor(producerStack, producerRegion, consumers, cause) {
|
|
1163
|
-
const lines = consumers.map((c) => ` - ${c.consumerStack} (${c.consumerRegion}): imports export '${c.exportName}'`);
|
|
1164
|
-
super(`Cannot destroy stack '${producerStack}' (${producerRegion}): the following stacks still import its outputs via Fn::ImportValue:\n${lines.join("\n")}\n\nThis matches CloudFormation's strong-reference semantics — exports are\nprotected as long as a consumer references them.\n\nTo proceed:\n 1. Destroy the consumer first: cdkd destroy <consumer-stack>\n 2. Or remove the Fn::ImportValue from the consumer's template\n (e.g. inline the value, or refactor) and re-deploy the consumer,\n then retry this destroy.\n\nNote: cdkd's Fn::GetStackOutput intrinsic is a weak alternative that\ndoes NOT protect the producer — use it when you intentionally want\nthe producer to be deletable independently of consumers.`, "STACK_HAS_ACTIVE_IMPORTS", cause);
|
|
1165
|
-
this.producerStack = producerStack;
|
|
1166
|
-
this.producerRegion = producerRegion;
|
|
1167
|
-
this.consumers = consumers;
|
|
1168
|
-
this.name = "StackHasActiveImportsError";
|
|
1169
|
-
Object.setPrototypeOf(this, StackHasActiveImportsError.prototype);
|
|
1170
|
-
}
|
|
1171
|
-
};
|
|
1172
|
-
/**
|
|
1173
|
-
* Signals a `cdkd local start-service` orchestration failure (Phase 2
|
|
1174
|
-
* of #262 — `AWS::ECS::Service` emulator). Distinct from
|
|
1175
|
-
* `LocalRunTaskError` because the service runner has its own lifecycle
|
|
1176
|
-
* (long-running replica pool, restart-on-exit), so a failure inside it
|
|
1177
|
-
* carries different operator semantics than a one-shot task failure.
|
|
1178
|
-
*/
|
|
1179
|
-
var LocalStartServiceError = class LocalStartServiceError extends CdkdError {
|
|
1180
|
-
constructor(message, cause) {
|
|
1181
|
-
super(message, "LOCAL_START_SERVICE_ERROR", cause);
|
|
1182
|
-
this.name = "LocalStartServiceError";
|
|
1183
|
-
Object.setPrototypeOf(this, LocalStartServiceError.prototype);
|
|
1184
|
-
}
|
|
1185
|
-
};
|
|
1186
|
-
/**
|
|
1187
|
-
* Signals that the upstream `cdk` CLI is not available on PATH (or at
|
|
1188
|
-
* the override path passed via `--cdk-bin`). Surfaced from `cdkd migrate`
|
|
1189
|
-
* (#465 PR A) before any other work runs.
|
|
1190
|
-
*
|
|
1191
|
-
* The message includes the install hint `npm install -g aws-cdk@latest`
|
|
1192
|
-
* so users on a fresh machine see exactly how to recover.
|
|
1193
|
-
*/
|
|
1194
|
-
var MissingCdkCliError = class MissingCdkCliError extends CdkdError {
|
|
1195
|
-
constructor(detail, cause) {
|
|
1196
|
-
super(`${detail ?? "upstream 'cdk' CLI not found on PATH"}. 'cdkd migrate' shells out to the upstream aws-cdk CLI for L1 codegen — install it with 'npm install -g aws-cdk@latest' (or pass --cdk-bin <path>).`, "MISSING_CDK_CLI", cause);
|
|
1197
|
-
this.name = "MissingCdkCliError";
|
|
1198
|
-
Object.setPrototypeOf(this, MissingCdkCliError.prototype);
|
|
1199
|
-
}
|
|
1200
|
-
};
|
|
1201
|
-
/**
|
|
1202
|
-
* Generic local-migrate orchestration failure (#465 PR A). Used by
|
|
1203
|
-
* `cdkd migrate` for pre-flight rejections (Custom Resource / nested
|
|
1204
|
-
* stack / non-terminal CFn stack state), output-dir collisions, and
|
|
1205
|
-
* `cdk migrate` subprocess failures whose underlying stderr is folded
|
|
1206
|
-
* into the error message. Exit code 2 (partial-failure family) because
|
|
1207
|
-
* some pre-flight failures leave the user with a partially-populated
|
|
1208
|
-
* output directory that's still useful for debugging.
|
|
1209
|
-
*/
|
|
1210
|
-
var LocalMigrateError = class LocalMigrateError extends CdkdError {
|
|
1211
|
-
exitCode = 2;
|
|
1212
|
-
constructor(message, cause) {
|
|
1213
|
-
super(message, "LOCAL_MIGRATE_ERROR", cause);
|
|
1214
|
-
this.name = "LocalMigrateError";
|
|
1215
|
-
Object.setPrototypeOf(this, LocalMigrateError.prototype);
|
|
1216
|
-
}
|
|
1217
|
-
};
|
|
1218
|
-
/**
|
|
1219
|
-
* CloudFormation macro / `Fn::Transform` expansion failure (#463).
|
|
1220
|
-
*
|
|
1221
|
-
* cdkd hands templates that declare `Transform: [...]` (or carry
|
|
1222
|
-
* `Fn::Transform: {...}` snippets) to CloudFormation server-side via a
|
|
1223
|
-
* transient `CreateChangeSet --change-set-type CREATE` against a
|
|
1224
|
-
* `cdkd-macro-expand-<id>` stack name. This error wraps every failure
|
|
1225
|
-
* mode of that round-trip:
|
|
1226
|
-
*
|
|
1227
|
-
* - `CreateChangeSet` rejection (bad template, missing macro IAM
|
|
1228
|
-
* permission, custom macro not found in the account).
|
|
1229
|
-
* - Changeset settles in `FAILED` (`StatusReason` from CFn is
|
|
1230
|
-
* surfaced verbatim — typically a custom macro Lambda error).
|
|
1231
|
-
* - Waiter timeout (the macro Lambda is stuck or oversized).
|
|
1232
|
-
* - `GetTemplate --template-stage Processed` returns no body (would
|
|
1233
|
-
* indicate a CFn-side regression — fail loud rather than silently
|
|
1234
|
-
* proceed with the un-expanded template).
|
|
1235
|
-
* - Multi-stage detection: the expanded template still contains
|
|
1236
|
-
* macros, which cdkd v1 does not support (the design intentionally
|
|
1237
|
-
* rejects this so a second round-trip is not silently triggered).
|
|
1238
|
-
*
|
|
1239
|
-
* The error surfaces at exit code 2 (partial-failure family) — the
|
|
1240
|
-
* cleanup `finally` in the expander always runs `DeleteChangeSet` +
|
|
1241
|
-
* `DeleteStack` regardless of this error firing, so a failed
|
|
1242
|
-
* expansion never leaves a transient CFn stack behind in a routine
|
|
1243
|
-
* case. The user can re-run `cdkd deploy` once the upstream cause is
|
|
1244
|
-
* fixed.
|
|
1245
|
-
*/
|
|
1246
|
-
var MacroExpansionError = class MacroExpansionError extends CdkdError {
|
|
1247
|
-
exitCode = 2;
|
|
1248
|
-
constructor(message, cause) {
|
|
1249
|
-
super(message, "MACRO_EXPANSION_ERROR", cause);
|
|
1250
|
-
this.name = "MacroExpansionError";
|
|
1251
|
-
Object.setPrototypeOf(this, MacroExpansionError.prototype);
|
|
1252
|
-
}
|
|
1253
|
-
};
|
|
1254
|
-
/**
|
|
1255
|
-
* Check if error is a cdkd error
|
|
1256
|
-
*/
|
|
1257
|
-
function isCdkdError(error) {
|
|
1258
|
-
return error instanceof CdkdError;
|
|
1259
|
-
}
|
|
1260
|
-
/**
|
|
1261
|
-
* Format error for display
|
|
1262
|
-
*/
|
|
1263
|
-
function formatError(error) {
|
|
1264
|
-
if (isCdkdError(error)) {
|
|
1265
|
-
let message = `${error.name}: ${error.message}`;
|
|
1266
|
-
if (error.cause) message += `\nCaused by: ${error.cause.message}`;
|
|
1267
|
-
return message;
|
|
1268
|
-
}
|
|
1269
|
-
if (error instanceof Error) return `${error.name}: ${error.message}`;
|
|
1270
|
-
return String(error);
|
|
1271
|
-
}
|
|
1272
|
-
/**
|
|
1273
|
-
* Global error handler
|
|
1274
|
-
*
|
|
1275
|
-
* Default exit code is 1 (general error). `PartialFailureError`
|
|
1276
|
-
* overrides it to 2 so callers can distinguish "command crashed /
|
|
1277
|
-
* unauthorized / bad arguments" from "command completed but some
|
|
1278
|
-
* resources are still in an error state, re-run to clean up".
|
|
1279
|
-
*
|
|
1280
|
-
* A {@link CdkdError} subclass may set `silent = true` to suppress the
|
|
1281
|
-
* default `logger.error` line — used by `cdkd drift` where the command
|
|
1282
|
-
* has already printed a richer report and only needs the exit code.
|
|
1283
|
-
*/
|
|
1284
|
-
function handleError(error) {
|
|
1285
|
-
const logger = getLogger();
|
|
1286
|
-
if (!(error instanceof CdkdError && error.silent)) logger.error(formatError(error));
|
|
1287
|
-
if (error instanceof Error && error.stack) logger.debug("Stack trace:", error.stack);
|
|
1288
|
-
const customExitCode = error instanceof CdkdError ? error.exitCode : void 0;
|
|
1289
|
-
const exitCode = typeof customExitCode === "number" ? customExitCode : 1;
|
|
1290
|
-
process.exit(exitCode);
|
|
1291
|
-
}
|
|
1292
|
-
/**
|
|
1293
|
-
* Wrap async function with error handling
|
|
1294
|
-
*
|
|
1295
|
-
* Note: Uses `any[]` for args to support Commander.js action handlers
|
|
1296
|
-
* which can have various parameter types
|
|
1297
|
-
*/
|
|
1298
|
-
function withErrorHandling(fn) {
|
|
1299
|
-
return async (...args) => {
|
|
1300
|
-
try {
|
|
1301
|
-
await fn(...args);
|
|
1302
|
-
} catch (error) {
|
|
1303
|
-
handleError(error);
|
|
1304
|
-
}
|
|
1305
|
-
};
|
|
1306
|
-
}
|
|
1307
|
-
/**
|
|
1308
|
-
* Convert AWS SDK v3's synthetic `Unknown` / `UnknownError` exception into
|
|
1309
|
-
* an actionable `Error` keyed off `$metadata.httpStatusCode`.
|
|
1310
|
-
*
|
|
1311
|
-
* Background — why this helper exists:
|
|
1312
|
-
* AWS SDK v3 produces a synthetic `name: 'Unknown'`, `message:
|
|
1313
|
-
* 'UnknownError'` exception when the protocol parser hits a HEAD response
|
|
1314
|
-
* with an empty body. The most common trigger is `HeadBucket` against a
|
|
1315
|
-
* bucket in a different region than the client (S3 returns 301
|
|
1316
|
-
* PermanentRedirect with `x-amz-bucket-region` set, but the redirect
|
|
1317
|
-
* middleware doesn't recover from the empty body). Surfacing the literal
|
|
1318
|
-
* string `UnknownError` to users is uninformative.
|
|
1319
|
-
*
|
|
1320
|
-
* Behavior:
|
|
1321
|
-
* - Non-AWS-SDK errors (anything where `name` is not `Unknown` and
|
|
1322
|
-
* `message` is not `UnknownError`) pass through unchanged.
|
|
1323
|
-
* - AWS SDK Unknown errors are mapped by HTTP status:
|
|
1324
|
-
* - 301 → `Bucket '<name>' is in a different region…` (auto-resolved
|
|
1325
|
-
* elsewhere; if this surfaces, it's a bug worth reporting).
|
|
1326
|
-
* - 403 → `Access denied to bucket '<name>'.`
|
|
1327
|
-
* - 404 → `Bucket '<name>' does not exist.`
|
|
1328
|
-
* - other / unknown → `S3 error during <operation> on '<bucket>' (HTTP
|
|
1329
|
-
* <status>).`
|
|
1330
|
-
*/
|
|
1331
|
-
function normalizeAwsError(err, context = {}) {
|
|
1332
|
-
if (!(err instanceof Error)) return new Error(String(err));
|
|
1333
|
-
if (!(err.name === "Unknown" || err.message === "UnknownError")) return err;
|
|
1334
|
-
const status = err.$metadata?.httpStatusCode;
|
|
1335
|
-
const bucket = context.bucket ?? "<unknown bucket>";
|
|
1336
|
-
const operation = context.operation ?? "operation";
|
|
1337
|
-
switch (status) {
|
|
1338
|
-
case 301: {
|
|
1339
|
-
const responseHeaders = err.$response?.headers;
|
|
1340
|
-
const region = responseHeaders?.["x-amz-bucket-region"] ?? responseHeaders?.["X-Amz-Bucket-Region"];
|
|
1341
|
-
const where = region ? ` (in ${region})` : "";
|
|
1342
|
-
return /* @__PURE__ */ new Error(`Bucket '${bucket}'${where} is in a different region than the client. cdkd resolves this automatically; if you see this message, please report it.`);
|
|
1343
|
-
}
|
|
1344
|
-
case 403: return /* @__PURE__ */ new Error(`Access denied to bucket '${bucket}'. Verify credentials and bucket policy.`);
|
|
1345
|
-
case 404: return /* @__PURE__ */ new Error(`Bucket '${bucket}' does not exist.`);
|
|
1346
|
-
default: {
|
|
1347
|
-
const statusStr = status !== void 0 ? `HTTP ${status}` : "unknown HTTP status";
|
|
1348
|
-
return /* @__PURE__ */ new Error(`S3 error during ${operation} on '${bucket}' (${statusStr}). See CloudTrail for details.`);
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
//#endregion
|
|
1354
30
|
//#region src/utils/aws-region-resolver.ts
|
|
1355
31
|
/**
|
|
1356
32
|
* Per-bucket region cache.
|
|
@@ -3212,7 +1888,7 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
|
|
|
3212
1888
|
logger.debug("No state bucket specified, resolving default from account...");
|
|
3213
1889
|
const { GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
|
|
3214
1890
|
const { S3Client } = await import("@aws-sdk/client-s3");
|
|
3215
|
-
const { getAwsClients } = await import("./aws-clients-
|
|
1891
|
+
const { getAwsClients } = await import("./aws-clients-pjPwZz1r.js").then((n) => n.n);
|
|
3216
1892
|
const accountId = (await getAwsClients().sts.send(new GetCallerIdentityCommand({}))).Account;
|
|
3217
1893
|
const newName = getDefaultStateBucketName(accountId);
|
|
3218
1894
|
const legacyName = getLegacyStateBucketName(accountId, region);
|
|
@@ -7616,36 +6292,6 @@ var IntrinsicFunctionResolver = class {
|
|
|
7616
6292
|
}
|
|
7617
6293
|
};
|
|
7618
6294
|
|
|
7619
|
-
//#endregion
|
|
7620
|
-
//#region src/provisioning/ec2-termination-protection.ts
|
|
7621
|
-
/**
|
|
7622
|
-
* Flip `DisableApiTermination` off on an instance. Idempotent — EC2 accepts the
|
|
7623
|
-
* call when the attribute is already false. Non-fatal: a NotFound (already
|
|
7624
|
-
* gone) or any other error is swallowed at debug so the actual delete still
|
|
7625
|
-
* proceeds (it will surface the real failure if the instance truly cannot be
|
|
7626
|
-
* deleted).
|
|
7627
|
-
*/
|
|
7628
|
-
async function disableInstanceApiTermination(client, instanceId, logger) {
|
|
7629
|
-
try {
|
|
7630
|
-
await client.send(new ModifyInstanceAttributeCommand({
|
|
7631
|
-
InstanceId: instanceId,
|
|
7632
|
-
DisableApiTermination: { Value: false }
|
|
7633
|
-
}));
|
|
7634
|
-
logger.debug(`Disabled DisableApiTermination on EC2 Instance ${instanceId} before deletion`);
|
|
7635
|
-
} catch (flipError) {
|
|
7636
|
-
logger.debug(`Could not disable DisableApiTermination on ${instanceId}: ${flipError instanceof Error ? flipError.message : String(flipError)}`);
|
|
7637
|
-
}
|
|
7638
|
-
}
|
|
7639
|
-
/**
|
|
7640
|
-
* Does this error message indicate the terminate / delete raced the
|
|
7641
|
-
* `DisableApiTermination` flip-off propagation (so re-flipping + retrying is
|
|
7642
|
-
* the right move)? Matches both the SDK `TerminateInstances` 400 and the Cloud
|
|
7643
|
-
* Control `DeleteResource` wrapper of the same underlying EC2 error.
|
|
7644
|
-
*/
|
|
7645
|
-
function isTerminationProtectionPropagationError(message) {
|
|
7646
|
-
return /may not be terminated|disableApiTermination/i.test(message);
|
|
7647
|
-
}
|
|
7648
|
-
|
|
7649
6295
|
//#endregion
|
|
7650
6296
|
//#region src/provisioning/json-patch-generator.ts
|
|
7651
6297
|
/**
|
|
@@ -7742,45 +6388,6 @@ var JsonPatchGenerator = class {
|
|
|
7742
6388
|
}
|
|
7743
6389
|
};
|
|
7744
6390
|
|
|
7745
|
-
//#endregion
|
|
7746
|
-
//#region src/provisioning/region-check.ts
|
|
7747
|
-
/**
|
|
7748
|
-
* Verify that the AWS client's region matches the region the resource is
|
|
7749
|
-
* expected to live in before treating a `NotFound` error as idempotent
|
|
7750
|
-
* delete success.
|
|
7751
|
-
*
|
|
7752
|
-
* Why: a destroy run with the wrong region would otherwise receive
|
|
7753
|
-
* `*NotFound` for every resource and silently strip them all from state,
|
|
7754
|
-
* leaving the actual AWS resources orphaned in the real region. The
|
|
7755
|
-
* silent-failure incident that motivated this check was a Lambda in
|
|
7756
|
-
* `us-west-2` removed from state by a destroy that ran with a `us-east-1`
|
|
7757
|
-
* client.
|
|
7758
|
-
*
|
|
7759
|
-
* Behavior:
|
|
7760
|
-
* - If `expectedRegion` is unset, this is a no-op (back-compat: existing
|
|
7761
|
-
* idempotent semantics preserved for callers that have not been
|
|
7762
|
-
* threaded with state region).
|
|
7763
|
-
* - If `clientRegion` matches `expectedRegion`, returns silently.
|
|
7764
|
-
* - Otherwise throws `ProvisioningError` so the caller surfaces the
|
|
7765
|
-
* mismatch instead of swallowing the NotFound.
|
|
7766
|
-
*
|
|
7767
|
-
* @param clientRegion Region resolved from the AWS SDK client config
|
|
7768
|
-
* (typically `await client.config.region()`).
|
|
7769
|
-
* @param expectedRegion Region recorded in stack state, or undefined if
|
|
7770
|
-
* the caller has no expected region.
|
|
7771
|
-
* @param resourceType CloudFormation resource type, used in the error
|
|
7772
|
-
* message and on the thrown ProvisioningError.
|
|
7773
|
-
* @param logicalId Logical ID of the resource, used in the error message
|
|
7774
|
-
* and on the thrown ProvisioningError.
|
|
7775
|
-
* @param physicalId Optional physical ID, used in the error message and
|
|
7776
|
-
* on the thrown ProvisioningError.
|
|
7777
|
-
*/
|
|
7778
|
-
function assertRegionMatch(clientRegion, expectedRegion, resourceType, logicalId, physicalId) {
|
|
7779
|
-
if (!expectedRegion) return;
|
|
7780
|
-
if (!clientRegion) throw new ProvisioningError(`Refusing to treat NotFound as idempotent delete success for ${logicalId} (${resourceType}): AWS client region is unknown but stack state expects ${expectedRegion}. The resource may exist in ${expectedRegion} and would be silently removed from state if this NotFound were trusted.`, resourceType, logicalId, physicalId);
|
|
7781
|
-
if (clientRegion !== expectedRegion) throw new ProvisioningError(`Refusing to treat NotFound as idempotent delete success for ${logicalId} (${resourceType}): AWS client region ${clientRegion} does not match stack state region ${expectedRegion}. The resource likely still exists in ${expectedRegion}; rerun the destroy with the correct region (e.g. --region ${expectedRegion}).`, resourceType, logicalId, physicalId);
|
|
7782
|
-
}
|
|
7783
|
-
|
|
7784
6391
|
//#endregion
|
|
7785
6392
|
//#region src/provisioning/unsupported-types.generated.ts
|
|
7786
6393
|
/**
|
|
@@ -8127,6 +6734,12 @@ var CloudControlProvider = class {
|
|
|
8127
6734
|
*/
|
|
8128
6735
|
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
8129
6736
|
this.logger.debug(`Deleting resource ${logicalId} (${resourceType}), physical ID: ${physicalId}`);
|
|
6737
|
+
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
6738
|
+
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
6739
|
+
const { ASGProvider } = await import("./asg-provider-B_hrCxRx.js").then((n) => n.n);
|
|
6740
|
+
await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
6741
|
+
return;
|
|
6742
|
+
}
|
|
8130
6743
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
8131
6744
|
if (isProtectedEc2Instance) await disableInstanceApiTermination(getAwsClients().ec2, physicalId, this.logger);
|
|
8132
6745
|
const maxAttempts = isProtectedEc2Instance ? 5 : 1;
|
|
@@ -11426,91 +10039,6 @@ function isCustomResource(resourceType) {
|
|
|
11426
10039
|
return resourceType.startsWith("Custom::") || resourceType === "AWS::CloudFormation::CustomResource";
|
|
11427
10040
|
}
|
|
11428
10041
|
|
|
11429
|
-
//#endregion
|
|
11430
|
-
//#region src/provisioning/import-helpers.ts
|
|
11431
|
-
/**
|
|
11432
|
-
* Read an explicit name field from template properties. Returns `undefined`
|
|
11433
|
-
* when the property is missing or not a string — callers fall back to
|
|
11434
|
-
* tag-based lookup in that case.
|
|
11435
|
-
*/
|
|
11436
|
-
function readNameProperty(input, propertyName) {
|
|
11437
|
-
const value = input.properties?.[propertyName];
|
|
11438
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
11439
|
-
}
|
|
11440
|
-
/**
|
|
11441
|
-
* Resolve the physical id when the template provides an explicit name OR the
|
|
11442
|
-
* caller passed `--resource`/`--resource-mapping`. Returns `undefined` when
|
|
11443
|
-
* neither shortcut applies — caller must then fall back to tag-based lookup.
|
|
11444
|
-
*
|
|
11445
|
-
* Does NOT verify the resource exists: callers should follow up with a
|
|
11446
|
-
* service-specific `Head*`/`Get*`/`Describe*` to fail fast if the named
|
|
11447
|
-
* resource is missing.
|
|
11448
|
-
*/
|
|
11449
|
-
function resolveExplicitPhysicalId(input, nameProperty) {
|
|
11450
|
-
if (input.knownPhysicalId) return input.knownPhysicalId;
|
|
11451
|
-
if (nameProperty) {
|
|
11452
|
-
const name = readNameProperty(input, nameProperty);
|
|
11453
|
-
if (name) return name;
|
|
11454
|
-
}
|
|
11455
|
-
}
|
|
11456
|
-
/**
|
|
11457
|
-
* The standard tag CDK puts on every deployed resource — its construct path
|
|
11458
|
-
* within the app, e.g. `MyStack/MyConstruct/MyBucket`. Used as the lookup key
|
|
11459
|
-
* when no explicit name is in the template.
|
|
11460
|
-
*/
|
|
11461
|
-
const CDK_PATH_TAG = "aws:cdk:path";
|
|
11462
|
-
/**
|
|
11463
|
-
* Match an AWS resource's tag set against the CDK path the template carries.
|
|
11464
|
-
* Returns true if the resource was deployed by the same CDK construct.
|
|
11465
|
-
*/
|
|
11466
|
-
function matchesCdkPath(tags, cdkPath) {
|
|
11467
|
-
if (!tags || !cdkPath) return false;
|
|
11468
|
-
for (const t of tags) if (t.Key === "aws:cdk:path" && t.Value === cdkPath) return true;
|
|
11469
|
-
return false;
|
|
11470
|
-
}
|
|
11471
|
-
/**
|
|
11472
|
-
* Re-shape an AWS tag list (any of the common shapes — array of `{Key, Value}`,
|
|
11473
|
-
* map keyed by tag name, or v2-style array of `{TagKey, TagValue}`) into the
|
|
11474
|
-
* canonical CFn shape (`Array<{Key, Value}>`) that cdkd state holds, with
|
|
11475
|
-
* `aws:`-prefixed entries filtered out.
|
|
11476
|
-
*
|
|
11477
|
-
* AWS reserves the `aws:` tag prefix; CDK injects `aws:cdk:path` (and
|
|
11478
|
-
* sometimes `aws:cdk:metadata`) on every resource it deploys. Those tags are
|
|
11479
|
-
* NOT in cdkd state's `Tags` (they come from CDK template `Metadata`, not
|
|
11480
|
-
* `Properties.Tags`), so leaving them in the AWS-current snapshot would fire
|
|
11481
|
-
* false-positive drift on every CDK-deployed resource.
|
|
11482
|
-
*
|
|
11483
|
-
* Returns an empty array `[]` when AWS reports no user tags. Callers decide
|
|
11484
|
-
* whether to surface `Tags: []` (most providers — matches the typical
|
|
11485
|
-
* CFn behavior of always emitting Tags in templates) or omit the key
|
|
11486
|
-
* entirely (when the corresponding `create()` only sets Tags when the user
|
|
11487
|
-
* explicitly passes them — see each provider's docstring).
|
|
11488
|
-
*/
|
|
11489
|
-
function normalizeAwsTagsToCfn(tags) {
|
|
11490
|
-
if (!tags) return [];
|
|
11491
|
-
const out = [];
|
|
11492
|
-
if (Array.isArray(tags)) for (const t of tags) {
|
|
11493
|
-
const obj = t;
|
|
11494
|
-
const k = (typeof obj["Key"] === "string" ? obj["Key"] : void 0) ?? (typeof obj["TagKey"] === "string" ? obj["TagKey"] : void 0) ?? (typeof obj["key"] === "string" ? obj["key"] : void 0);
|
|
11495
|
-
const v = (typeof obj["Value"] === "string" ? obj["Value"] : void 0) ?? (typeof obj["TagValue"] === "string" ? obj["TagValue"] : void 0) ?? (typeof obj["value"] === "string" ? obj["value"] : void 0);
|
|
11496
|
-
if (typeof k !== "string" || k.length === 0) continue;
|
|
11497
|
-
if (k.startsWith("aws:")) continue;
|
|
11498
|
-
out.push({
|
|
11499
|
-
Key: k,
|
|
11500
|
-
Value: typeof v === "string" ? v : ""
|
|
11501
|
-
});
|
|
11502
|
-
}
|
|
11503
|
-
else for (const [k, v] of Object.entries(tags)) {
|
|
11504
|
-
if (!k || k.startsWith("aws:")) continue;
|
|
11505
|
-
out.push({
|
|
11506
|
-
Key: k,
|
|
11507
|
-
Value: typeof v === "string" ? v : ""
|
|
11508
|
-
});
|
|
11509
|
-
}
|
|
11510
|
-
out.sort((a, b) => a.Key < b.Key ? -1 : a.Key > b.Key ? 1 : 0);
|
|
11511
|
-
return out;
|
|
11512
|
-
}
|
|
11513
|
-
|
|
11514
10042
|
//#endregion
|
|
11515
10043
|
//#region src/provisioning/providers/iam-role-provider.ts
|
|
11516
10044
|
/**
|
|
@@ -13742,5 +12270,5 @@ var DeployEngine = class {
|
|
|
13742
12270
|
};
|
|
13743
12271
|
|
|
13744
12272
|
//#endregion
|
|
13745
|
-
export {
|
|
13746
|
-
//# sourceMappingURL=deploy-engine-
|
|
12273
|
+
export { WorkGraph as A, resolveCaptureObservedState as B, DagBuilder as C, shouldRetainResource as D, S3StateBackend as E, runDockerStreaming as F, CFN_TEMPLATE_BODY_LIMIT as G, resolveStateBucketWithDefault as H, Synthesizer as I, findLargeInlineResources as J, CFN_TEMPLATE_URL_LIMIT as K, getDefaultStateBucketName as L, formatDockerLoginError as M, getDockerCmd as N, AssetPublisher as O, runDockerForeground as P, resolveBucketRegion as Q, getLegacyStateBucketName as R, DiffCalculator as S, LockManager as T, resolveStateBucketWithDefaultAndSource as U, resolveSkipPrefix as V, warnDeprecatedNoPrefixCliFlag as W, AssemblyReader as X, uploadCfnTemplate as Y, clearBucketRegionCache as Z, ProviderRegistry as _, withRetry as a, IntrinsicFunctionResolver as b, formatResourceLine as c, gray as d, green as f, collectInlinePolicyNamesManagedBySiblings as g, IAMRoleProvider as h, withResourceDeadline as i, buildDockerImage as j, stringifyValue as k, bold as l, yellow as m, DEFAULT_RESOURCE_WARN_AFTER_MS as n, isRetryableTransientError as o, red as p, MIGRATE_TMP_PREFIX as q, DeployEngine as r, IMPLICIT_DELETE_DEPENDENCIES as s, DEFAULT_RESOURCE_TIMEOUT_MS as t, cyan as u, findActionableSilentDrops as v, TemplateParser as w, applyRoleArnIfSet as x, CloudControlProvider as y, resolveApp as z };
|
|
12274
|
+
//# sourceMappingURL=deploy-engine-Drw_e42s.js.map
|