@go-to-k/cdkd 0.219.1 → 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.
@@ -1,13 +1,13 @@
1
- import { r as getAwsClients } from "./aws-clients-DWUnLza1.js";
2
- import { AsyncLocalStorage } from "node:async_hooks";
3
- import { createHash, randomUUID } from "node:crypto";
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, ModifyInstanceAttributeCommand } from "@aws-sdk/client-ec2";
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-DWUnLza1.js").then((n) => n.n);
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 { CFN_TEMPLATE_URL_LIMIT as $, DagBuilder as A, setLogger as At, getDockerCmd as B, CloudControlProvider as C, SynthesisError as Ct, IntrinsicFunctionResolver as D, withErrorHandling as Dt, isTerminationProtectionPropagationError as E, normalizeAwsError as Et, AssetPublisher as F, generateResourceName as Ft, getLegacyStateBucketName as G, runDockerStreaming as H, stringifyValue as I, generateResourceNameWithFallback as It, resolveSkipPrefix as J, resolveApp as K, WorkGraph as L, withSkipPrefix as Lt, LockManager as M, getLiveRenderer as Mt, S3StateBackend as N, PATTERN_B_NAME_PROPERTIES as Nt, applyRoleArnIfSet as O, ConsoleLogger as Ot, shouldRetainResource as P, PATTERN_B_RESOURCE_TYPES as Pt, CFN_TEMPLATE_BODY_LIMIT as Q, buildDockerImage as R, withStackName as Rt, findActionableSilentDrops as S, StateError as St, disableInstanceApiTermination as T, isCdkdError as Tt, Synthesizer as U, runDockerForeground as V, getDefaultStateBucketName as W, resolveStateBucketWithDefaultAndSource as X, resolveStateBucketWithDefault as Y, warnDeprecatedNoPrefixCliFlag as Z, CDK_PATH_TAG as _, ProvisioningError as _t, withRetry as a, resolveBucketRegion as at, resolveExplicitPhysicalId as b, StackHasActiveImportsError as bt, formatResourceLine as c, ConfigError as ct, gray as d, LocalMigrateError as dt, MIGRATE_TMP_PREFIX as et, green as f, LocalStartServiceError as ft, collectInlinePolicyNamesManagedBySiblings as g, PartialFailureError as gt, IAMRoleProvider as h, NestedStackChildDirectDestroyError as ht, withResourceDeadline as i, clearBucketRegionCache as it, TemplateParser as j, runStackBuffered as jt, DiffCalculator as k, getLogger as kt, bold as l, DependencyError as lt, yellow as m, MissingCdkCliError as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, uploadCfnTemplate as nt, isRetryableTransientError as o, AssetError as ot, red as p, LockError as pt, resolveCaptureObservedState as q, DeployEngine as r, AssemblyReader as rt, IMPLICIT_DELETE_DEPENDENCIES as s, CdkdError as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, findLargeInlineResources as tt, cyan as u, LocalInvokeBuildError as ut, matchesCdkPath as v, ResourceTimeoutError as vt, assertRegionMatch as w, formatError as wt, ProviderRegistry as x, StackTerminationProtectionError as xt, normalizeAwsTagsToCfn as y, ResourceUpdateNotSupportedError as yt, formatDockerLoginError as z };
13746
- //# sourceMappingURL=deploy-engine-B6CuzOHi.js.map
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