@go-to-k/cdkd 0.281.7 → 0.281.9
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-Lj_P_wtb.js → asg-provider-C4zMjWYv.js} +2 -2
- package/dist/{asg-provider-Lj_P_wtb.js.map → asg-provider-C4zMjWYv.js.map} +1 -1
- package/dist/cli.js +299 -95
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-B8Qo1vPU.js → deploy-engine-DQ9kW3Pu.js} +101 -10
- package/dist/deploy-engine-DQ9kW3Pu.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-B8Qo1vPU.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as replayWarn, $t as uploadCfnTemplate, A as green, An as normalizeAwsError, At as formatDockerLoginError, B as slowCcOperationTimeoutMs, Bt as resolveApp, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Cn as ResourceUpdateNotSupportedError, Ct as BOOTSTRAP_MARKER_PREFIX, D as bold, Dt as validateAssetBucketName, E as formatResourceLine, Et as parseBootstrapMarker, F as clearOnUpdateRemoval, Ft as getDockerImageBySourceHash, G as getAccountInfo, Gt as resolveStateBucketWithDefaultAndSource, H as isTerminationProtectionPropagationError, Ht as resolveCaptureObservedState, I as ProviderRegistry, It as Synthesizer, J as normalizeAwsTagsToCfn, Jt as warnDeprecatedNoPrefixCliFlag, K as refStateLookupFromResource, Kt as resolveUseCdkBootstrapAssets, L as findActionableSilentDrops, Lt as synthesisStatusMessage, M as yellow, Mt as runDockerForeground, N as IAMRoleProvider, Nt as runDockerStreaming, O as cyan, Ot as validateContainerRepoName, P as collectInlinePolicyNamesManagedBySiblings, Pt as AssetManifestLoader, Q as readConfigString, Qt as findLargeInlineResources, R as findSilentDropProperties, Rt as getDefaultStateBucketName, S as extractDeploymentEventError, Sn as ResourceTimeoutError, St as AssetModeResolver, T as renderStatefulReason, Tn as StackTerminationProtectionError, Tt as getBootstrapMarkerKey, U as IntrinsicFunctionResolver, Ut as resolveSkipPrefix, V as disableInstanceApiTermination, Vt as resolveAutoAssetStorage, W as cfnRefValueFromPhysicalId, Wt as resolveStateBucketWithDefault, X as assertRegionMatch, Xt as CFN_TEMPLATE_URL_LIMIT, Y as resolveExplicitPhysicalId, Yt as CFN_TEMPLATE_BODY_LIMIT, Z as configStringRefusal, Zt as MIGRATE_TMP_PREFIX, _ as createPreDeleteFinalSnapshot, _t as WorkGraph, a as DeploymentEventsStore, an as AwsClients, at as describeTypeWithThrottleRetry, b as unsupportedFinalSnapshotError, bn as PartialFailureError, bt as loadPublishableAssetManifest, c as replayFailedOperations, cn as setAwsClients, ct as isThrottlingError, d as IMPLICIT_DELETE_DEPENDENCIES, dt as LockManager, en as expectedOwnerParam, et as requireConfigArray, f as computeImplicitDeleteEdges, ft as S3StateBackend, g as ccRoutedFinalSnapshotError, gn as LocalStartServiceError, gt as stringifyValue, h as buildFinalSnapshotIdentifier, hn as LocalMigrateError, ht as AssetPublisher, i as DeploymentEventsReader, in as resolveBucketRegion, it as DiffCalculator, j as red, jn as withErrorHandling, jt as getDockerCmd, k as gray, kt as buildDockerImage, l as replayRollback, lt as DagBuilder, m as PRE_DELETE_SNAPSHOT_TYPES, mn as LocalInvokeBuildError$1, mt as shouldRetainResource, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as processStackMessages, nt as requireConfigString, o as planFailedOps, on as getAwsClients, ot as withRetry, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as DeployCancelledError, pt as rebuildClientForBucketRegion, q as WAFv2WebACLProvider, qt as stateBucketExistenceConfirmed, r as DeployEngine, rt as applyRoleArnIfSet, s as planRollback, sn as resetAwsClients, st as isRetryableTransientError, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as AssemblyReader, tt as requireConfigObject, u as withResourceDeadline, un as CdkdError, ut as TemplateParser, v as isFinalSnapshotError, vn as MissingCdkCliError, vt as buildAssetRedirectMap, w as isStatefulRecreateTargetSync, wn as StackHasActiveImportsError, wt as ensureAssetStorage, x as makeCanonicalizePropertiesFn, xn as ProvisioningError, xt as rewriteTemplateAssetReferences, y as refusesFinalSnapshot, yn as NestedStackChildDirectDestroyError, yt as createAssetRedirectResolver, z as CloudControlProvider, zt as getLegacyStateBucketName } from "./deploy-engine-DQ9kW3Pu.js";
|
|
3
3
|
import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
|
|
4
|
-
import { t as ASGProvider } from "./asg-provider-
|
|
4
|
+
import { t as ASGProvider } from "./asg-provider-C4zMjWYv.js";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
7
7
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -11746,23 +11746,28 @@ var LambdaLayerVersionProvider = class {
|
|
|
11746
11746
|
* ## What this does NOT cover
|
|
11747
11747
|
*
|
|
11748
11748
|
* The claim is "every composite packer this change reaches", not "every `|`
|
|
11749
|
-
* join in the tree".
|
|
11749
|
+
* join in the tree". One deliberate exclusion, recorded so the scope is not
|
|
11750
11750
|
* read as wider than it is:
|
|
11751
11751
|
*
|
|
11752
|
-
* - **`route53-provider.ts`'s three packers** (`AWS::Route53::RecordSet` and
|
|
11753
|
-
* its siblings) are NOT guarded — the file was owned by a parallel lane when
|
|
11754
|
-
* this shipped. The exposure there is bounded rather than absent:
|
|
11755
|
-
* `parseRecordSetCompositeId` requires EXACTLY three parts, so a four-part
|
|
11756
|
-
* id is REJECTED rather than mis-decoded into a different record. That is
|
|
11757
|
-
* the loud failure mode, not the silent-wrong-resource one this helper
|
|
11758
|
-
* exists for — but the deploy still records an id nothing can decode, so the
|
|
11759
|
-
* type belongs here whenever that lane lands. Tracked in issue
|
|
11760
|
-
* [#1711](https://github.com/go-to-k/cdkd/issues/1711).
|
|
11761
11752
|
* - **`intrinsic-function-resolver.ts`'s `|` joins** (the WAFv2 and
|
|
11762
11753
|
* `AWS::Events::Rule` arms) are out of scope by KIND, not by ownership: they
|
|
11763
11754
|
* build a `Ref` VALUE for the template resolver, never a physicalId cdkd
|
|
11764
11755
|
* records and later splits. Nothing decodes them, so an ambiguous join has
|
|
11765
11756
|
* no decode site to go wrong at.
|
|
11757
|
+
*
|
|
11758
|
+
* ## Guarding the PACKERS is not the whole story
|
|
11759
|
+
*
|
|
11760
|
+
* A packer that refuses ambiguity does nothing about an id an EARLIER binary
|
|
11761
|
+
* already recorded, or one an `import` was handed — and a type whose decoder is
|
|
11762
|
+
* loose will mis-decode both. Issue #1711 is where that was learned:
|
|
11763
|
+
* `AWS::Route53::RecordSet`'s `parseRecordSetCompositeId` accepts any three
|
|
11764
|
+
* NON-EMPTY segments, so a record name carrying two pipes decoded to a
|
|
11765
|
+
* DIFFERENT hosted zone at three sites this helper never sees — an `import`
|
|
11766
|
+
* early accept, an identity-resolution short-circuit, and `delete`'s own parse,
|
|
11767
|
+
* where `cdkd destroy` then reported success over a live record. When adopting
|
|
11768
|
+
* this guard for a new type, audit its DECODE sites in the same change and make
|
|
11769
|
+
* each one cross-check the parsed segments against something it can verify them
|
|
11770
|
+
* with (Route 53 uses the template's own `Name` / `Type`).
|
|
11766
11771
|
*/
|
|
11767
11772
|
/** The character every composite physicalId in this codebase joins segments with. */
|
|
11768
11773
|
const COMPOSITE_ID_SEPARATOR = "|";
|
|
@@ -33705,10 +33710,10 @@ var Route53Provider = class {
|
|
|
33705
33710
|
if (!this.route53Client) this.route53Client = new Route53Client(this.providerRegion ? { region: this.providerRegion } : {});
|
|
33706
33711
|
return this.route53Client;
|
|
33707
33712
|
}
|
|
33708
|
-
async create(logicalId, resourceType, properties) {
|
|
33713
|
+
async create(logicalId, resourceType, properties, context) {
|
|
33709
33714
|
switch (resourceType) {
|
|
33710
33715
|
case "AWS::Route53::HostedZone": return this.createHostedZone(logicalId, resourceType, properties);
|
|
33711
|
-
case "AWS::Route53::RecordSet": return this.createRecordSet(logicalId, resourceType, properties);
|
|
33716
|
+
case "AWS::Route53::RecordSet": return this.createRecordSet(logicalId, resourceType, properties, context);
|
|
33712
33717
|
default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId);
|
|
33713
33718
|
}
|
|
33714
33719
|
}
|
|
@@ -33937,11 +33942,25 @@ var Route53Provider = class {
|
|
|
33937
33942
|
default: return;
|
|
33938
33943
|
}
|
|
33939
33944
|
}
|
|
33940
|
-
async createRecordSet(logicalId, resourceType, properties) {
|
|
33945
|
+
async createRecordSet(logicalId, resourceType, properties, context) {
|
|
33941
33946
|
this.logger.debug(`Creating Route 53 record set ${logicalId}`);
|
|
33942
33947
|
const hostedZoneId = await this.resolveHostedZoneId(properties, logicalId, resourceType);
|
|
33943
33948
|
const recordName = properties["Name"];
|
|
33944
33949
|
const recordType = properties["Type"];
|
|
33950
|
+
const compositeId = packCompositeId(resourceType, logicalId, [
|
|
33951
|
+
{
|
|
33952
|
+
name: "hostedZoneId",
|
|
33953
|
+
value: hostedZoneId
|
|
33954
|
+
},
|
|
33955
|
+
{
|
|
33956
|
+
name: "recordName",
|
|
33957
|
+
value: recordName
|
|
33958
|
+
},
|
|
33959
|
+
{
|
|
33960
|
+
name: "recordType",
|
|
33961
|
+
value: recordType
|
|
33962
|
+
}
|
|
33963
|
+
], context?.replayingState === true ? { onRefusal: (message) => this.logger.warn(message) } : void 0);
|
|
33945
33964
|
try {
|
|
33946
33965
|
const resourceRecordSet = this.buildResourceRecordSet(properties);
|
|
33947
33966
|
const comment = properties["Comment"];
|
|
@@ -33955,7 +33974,6 @@ var Route53Provider = class {
|
|
|
33955
33974
|
}]
|
|
33956
33975
|
}
|
|
33957
33976
|
}));
|
|
33958
|
-
const compositeId = `${hostedZoneId}|${recordName}|${recordType}`;
|
|
33959
33977
|
this.logger.debug(`Successfully created record set ${logicalId}: ${compositeId}`);
|
|
33960
33978
|
return {
|
|
33961
33979
|
physicalId: compositeId,
|
|
@@ -33972,6 +33990,20 @@ var Route53Provider = class {
|
|
|
33972
33990
|
const hostedZoneId = await this.resolveHostedZoneId(properties, logicalId, resourceType, physicalId);
|
|
33973
33991
|
const recordName = properties["Name"];
|
|
33974
33992
|
const recordType = properties["Type"];
|
|
33993
|
+
const compositeId = packCompositeId(resourceType, logicalId, [
|
|
33994
|
+
{
|
|
33995
|
+
name: "hostedZoneId",
|
|
33996
|
+
value: hostedZoneId
|
|
33997
|
+
},
|
|
33998
|
+
{
|
|
33999
|
+
name: "recordName",
|
|
34000
|
+
value: recordName
|
|
34001
|
+
},
|
|
34002
|
+
{
|
|
34003
|
+
name: "recordType",
|
|
34004
|
+
value: recordType
|
|
34005
|
+
}
|
|
34006
|
+
], { onRefusal: (message) => this.logger.warn(message) });
|
|
33975
34007
|
try {
|
|
33976
34008
|
const resourceRecordSet = this.buildResourceRecordSet(properties);
|
|
33977
34009
|
const comment = properties["Comment"];
|
|
@@ -33985,7 +34017,6 @@ var Route53Provider = class {
|
|
|
33985
34017
|
}]
|
|
33986
34018
|
}
|
|
33987
34019
|
}));
|
|
33988
|
-
const compositeId = `${hostedZoneId}|${recordName}|${recordType}`;
|
|
33989
34020
|
this.logger.debug(`Successfully updated record set ${logicalId}`);
|
|
33990
34021
|
return {
|
|
33991
34022
|
physicalId: compositeId,
|
|
@@ -34000,7 +34031,8 @@ var Route53Provider = class {
|
|
|
34000
34031
|
async deleteRecordSet(logicalId, physicalId, resourceType, properties, context) {
|
|
34001
34032
|
this.logger.debug(`Deleting Route 53 record set ${logicalId}: ${physicalId}`);
|
|
34002
34033
|
if (!properties) throw new ProvisioningError(`Properties required to delete record set ${logicalId}`, resourceType, logicalId, physicalId);
|
|
34003
|
-
const
|
|
34034
|
+
const parsedComposite = parseRecordSetCompositeId(physicalId);
|
|
34035
|
+
const composite = parsedComposite && this.compositeAgreesWithTemplate(parsedComposite, properties) ? parsedComposite : void 0;
|
|
34004
34036
|
let hostedZoneId;
|
|
34005
34037
|
if (composite) hostedZoneId = composite.hostedZoneId;
|
|
34006
34038
|
else try {
|
|
@@ -34433,7 +34465,7 @@ var Route53Provider = class {
|
|
|
34433
34465
|
*/
|
|
34434
34466
|
async resolveRecordSetIdentity(physicalId, properties, options) {
|
|
34435
34467
|
const composite = parseRecordSetCompositeId(physicalId);
|
|
34436
|
-
if (composite) return composite;
|
|
34468
|
+
if (composite && (!properties || this.compositeAgreesWithTemplate(composite, properties))) return composite;
|
|
34437
34469
|
if (!properties) return void 0;
|
|
34438
34470
|
const name = typeof properties["Name"] === "string" ? properties["Name"] : physicalId;
|
|
34439
34471
|
const type = properties["Type"];
|
|
@@ -34612,6 +34644,52 @@ var Route53Provider = class {
|
|
|
34612
34644
|
}
|
|
34613
34645
|
}
|
|
34614
34646
|
/**
|
|
34647
|
+
* Does a parsed composite agree with the properties recorded alongside it?
|
|
34648
|
+
*
|
|
34649
|
+
* Called from all THREE sites that split a stored id back apart —
|
|
34650
|
+
* `importRecordSet`'s early accept, `resolveRecordSetIdentity`, and
|
|
34651
|
+
* `deleteRecordSet` — because `parseRecordSetCompositeId` asks only for three
|
|
34652
|
+
* NON-EMPTY segments, which a record NAME carrying two pipes satisfies
|
|
34653
|
+
* (issue #1711).
|
|
34654
|
+
*
|
|
34655
|
+
* Each check is applied only when the template side is a usable string, so an
|
|
34656
|
+
* unresolved intrinsic or an absent field leaves the pre-#1711 behavior
|
|
34657
|
+
* exactly as it was. When BOTH are unusable this returns `true` and the
|
|
34658
|
+
* mis-decode is still reachable — an accepted bound, since the alternative is
|
|
34659
|
+
* refusing every id on a bag cdkd cannot read, and the identity resolution the
|
|
34660
|
+
* fall-through leads to needs those same fields anyway.
|
|
34661
|
+
*
|
|
34662
|
+
* The NAME check is what catches the residual the TYPE check alone leaves: a
|
|
34663
|
+
* name like `a|b|A` on a record whose `Type` really is `A` agrees on the type
|
|
34664
|
+
* and still decodes to the wrong zone. The TYPE check is in turn the sole
|
|
34665
|
+
* discriminator only where the NAME is unusable, which is why both are here.
|
|
34666
|
+
*
|
|
34667
|
+
* **A false REJECTION is what this must not do, and the argument is
|
|
34668
|
+
* REACHABILITY rather than cost.** The cost differs per caller and is not
|
|
34669
|
+
* uniformly small: at `deleteRecordSet` the fall-through re-resolves the zone
|
|
34670
|
+
* with `requireUnambiguousZoneName`, which THROWS on a split-horizon
|
|
34671
|
+
* `HostedZoneName` and would turn a working destroy into a failed one. It
|
|
34672
|
+
* cannot fire, because every composite is packed from the same
|
|
34673
|
+
* `properties['Name']` / `['Type']` the engine records beside it — create,
|
|
34674
|
+
* update and the import canonicalization all use one bag — so a genuine
|
|
34675
|
+
* composite always agrees with the bag it is stored with. `Type` being
|
|
34676
|
+
* updateable does not break that: `update()` returns the RE-PACKED id, which
|
|
34677
|
+
* is recorded together with the new properties. The one real divergence is
|
|
34678
|
+
* cosmetic and absorbed on purpose — `canonicalizeQueryName` makes the name
|
|
34679
|
+
* compare case- and trailing-dot-insensitive, so a template spelling the name
|
|
34680
|
+
* without CDK's dot is not rejected.
|
|
34681
|
+
*
|
|
34682
|
+
* Note two of the three callers pass a STATE-borne bag rather than a template
|
|
34683
|
+
* one; the reachability argument above is what covers them.
|
|
34684
|
+
*/
|
|
34685
|
+
compositeAgreesWithTemplate(parsed, properties) {
|
|
34686
|
+
const templateType = properties["Type"];
|
|
34687
|
+
if (typeof templateType === "string" && templateType && parsed.type !== templateType) return false;
|
|
34688
|
+
const templateName = properties["Name"];
|
|
34689
|
+
if (typeof templateName === "string" && templateName && canonicalizeQueryName(parsed.name) !== canonicalizeQueryName(templateName)) return false;
|
|
34690
|
+
return true;
|
|
34691
|
+
}
|
|
34692
|
+
/**
|
|
34615
34693
|
* Adopt an existing record set (issue #1658).
|
|
34616
34694
|
*
|
|
34617
34695
|
* cdkd's physicalId is the composite `<hostedZoneId>|<Name>|<Type>` that
|
|
@@ -34654,7 +34732,8 @@ var Route53Provider = class {
|
|
|
34654
34732
|
async importRecordSet(input) {
|
|
34655
34733
|
const known = input.knownPhysicalId;
|
|
34656
34734
|
if (!known) return null;
|
|
34657
|
-
|
|
34735
|
+
const parsedKnown = parseRecordSetCompositeId(known);
|
|
34736
|
+
if (parsedKnown && this.compositeAgreesWithTemplate(parsedKnown, input.properties)) return {
|
|
34658
34737
|
physicalId: known,
|
|
34659
34738
|
attributes: {}
|
|
34660
34739
|
};
|
|
@@ -34667,7 +34746,22 @@ var Route53Provider = class {
|
|
|
34667
34746
|
};
|
|
34668
34747
|
const identity = await this.resolveRecordSetIdentity(known, input.properties, { requireUnambiguousZoneName: true });
|
|
34669
34748
|
if (!identity) return adoptVerbatim("the template does not unambiguously resolve to a hosted zone + Name + Type");
|
|
34670
|
-
const
|
|
34749
|
+
const segments = [
|
|
34750
|
+
{
|
|
34751
|
+
name: "hostedZoneId",
|
|
34752
|
+
value: identity.hostedZoneId
|
|
34753
|
+
},
|
|
34754
|
+
{
|
|
34755
|
+
name: "recordName",
|
|
34756
|
+
value: identity.name
|
|
34757
|
+
},
|
|
34758
|
+
{
|
|
34759
|
+
name: "recordType",
|
|
34760
|
+
value: identity.type
|
|
34761
|
+
}
|
|
34762
|
+
];
|
|
34763
|
+
if (compositeIdSeparatorRefusal(input.resourceType, input.logicalId, segments) !== void 0) return adoptVerbatim(`the resolved hosted zone + Name + Type would pack an ambiguous id — a segment contains '${"|"}', which cdkd uses as this type's physical-id separator`);
|
|
34764
|
+
const compositeId = packCompositeId(input.resourceType, input.logicalId, segments);
|
|
34671
34765
|
let observed;
|
|
34672
34766
|
try {
|
|
34673
34767
|
observed = await this.readRecordSet(compositeId);
|
|
@@ -36671,6 +36765,51 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
36671
36765
|
}
|
|
36672
36766
|
};
|
|
36673
36767
|
|
|
36768
|
+
//#endregion
|
|
36769
|
+
//#region src/utils/aws-partition.ts
|
|
36770
|
+
/**
|
|
36771
|
+
* AWS partition / URL-suffix derivation, shared across layers.
|
|
36772
|
+
*
|
|
36773
|
+
* Lives in `src/utils/` because it has consumers in two different layers: the
|
|
36774
|
+
* `cdkd local *` command family (which passes a region in once to keep the STS
|
|
36775
|
+
* hop minimal) and the provisioning layer's `AppSyncProvider`, which rebuilds a
|
|
36776
|
+
* child resource's ARN when AWS did not report one.
|
|
36777
|
+
*
|
|
36778
|
+
* It was originally defined in `src/local/ecs-task-resolver.ts`, which
|
|
36779
|
+
* re-exports it so every existing call site is unchanged; a provisioning
|
|
36780
|
+
* provider importing from `src/local/**` would invert the layering.
|
|
36781
|
+
*
|
|
36782
|
+
* NOTE this is the mapping to prefer over `getAccountInfo().partition`
|
|
36783
|
+
* (`src/deployment/intrinsic-function-resolver.ts`), which is hardcoded to
|
|
36784
|
+
* `'aws'` and says so in its own comment.
|
|
36785
|
+
*/
|
|
36786
|
+
/**
|
|
36787
|
+
* Derive the AWS partition / URL suffix for an AWS region. Same mapping
|
|
36788
|
+
* CloudFormation applies to `${AWS::Partition}` / `${AWS::URLSuffix}`.
|
|
36789
|
+
*/
|
|
36790
|
+
function derivePartitionAndUrlSuffix(region) {
|
|
36791
|
+
if (region.startsWith("cn-")) return {
|
|
36792
|
+
partition: "aws-cn",
|
|
36793
|
+
urlSuffix: "amazonaws.com.cn"
|
|
36794
|
+
};
|
|
36795
|
+
if (region.startsWith("us-gov-")) return {
|
|
36796
|
+
partition: "aws-us-gov",
|
|
36797
|
+
urlSuffix: "amazonaws.com"
|
|
36798
|
+
};
|
|
36799
|
+
if (region.startsWith("us-iso-")) return {
|
|
36800
|
+
partition: "aws-iso",
|
|
36801
|
+
urlSuffix: "c2s.ic.gov"
|
|
36802
|
+
};
|
|
36803
|
+
if (region.startsWith("us-isob-")) return {
|
|
36804
|
+
partition: "aws-iso-b",
|
|
36805
|
+
urlSuffix: "sc2s.sgov.gov"
|
|
36806
|
+
};
|
|
36807
|
+
return {
|
|
36808
|
+
partition: "aws",
|
|
36809
|
+
urlSuffix: "amazonaws.com"
|
|
36810
|
+
};
|
|
36811
|
+
}
|
|
36812
|
+
|
|
36674
36813
|
//#endregion
|
|
36675
36814
|
//#region src/provisioning/providers/appsync-provider.ts
|
|
36676
36815
|
const MUTABLE_GRAPHQL_API_CONFIG_PROPERTIES = [
|
|
@@ -36788,6 +36927,111 @@ var AppSyncProvider = class {
|
|
|
36788
36927
|
return this.client;
|
|
36789
36928
|
}
|
|
36790
36929
|
/**
|
|
36930
|
+
* Build a child-resource ARN from the deploy's REAL partition / region /
|
|
36931
|
+
* account (issue #1681).
|
|
36932
|
+
*
|
|
36933
|
+
* The three child types record an ARN attribute because CloudFormation's
|
|
36934
|
+
* `Ref` for each of them returns the resource ARN (docs-verified 2026-08-12)
|
|
36935
|
+
* and `Fn::GetAtt` serves the same value from the same cached map — this
|
|
36936
|
+
* provider's `getAttribute` always resolves `undefined`, so the recorded
|
|
36937
|
+
* attribute is the ONLY source for both intrinsics.
|
|
36938
|
+
*
|
|
36939
|
+
* Until #1681 those attributes were string-built as
|
|
36940
|
+
* `arn:aws:appsync:*:*:...`, i.e. with literal `*` in the region and account
|
|
36941
|
+
* positions, so every consumer received an ARN AWS cannot resolve. Prefer the
|
|
36942
|
+
* ARN the create response reports (`dataSourceArn` / `resolverArn`); this
|
|
36943
|
+
* helper is for `AWS::AppSync::ApiKey`, whose `CreateApiKey` response carries
|
|
36944
|
+
* no ARN field at all, and as the fallback for the other two when a response
|
|
36945
|
+
* comes back without one.
|
|
36946
|
+
*
|
|
36947
|
+
* `getAccountInfo` is the same STS-backed, process-cached resolver
|
|
36948
|
+
* `CloudControlProvider` uses for its own ARN reconstruction, so this costs
|
|
36949
|
+
* at most one `GetCallerIdentity` per deploy.
|
|
36950
|
+
*/
|
|
36951
|
+
async buildAppSyncArn(suffix) {
|
|
36952
|
+
const accountInfo = await getAccountInfo(this.providerRegion ?? await this.getClient().config.region());
|
|
36953
|
+
const { partition } = derivePartitionAndUrlSuffix(accountInfo.region);
|
|
36954
|
+
return `arn:${partition}:appsync:${accountInfo.region}:${accountInfo.accountId}:${suffix}`;
|
|
36955
|
+
}
|
|
36956
|
+
/**
|
|
36957
|
+
* {@link buildAppSyncArn} for the POST-CREATE sites, where throwing is not an
|
|
36958
|
+
* option (issue #1681 PR review).
|
|
36959
|
+
*
|
|
36960
|
+
* Moving the ARN build outside the create `try` stops a failure being
|
|
36961
|
+
* re-labelled as a creation failure — but on its own it does NOT stop the
|
|
36962
|
+
* resource being orphaned: `create()` still throws, the engine still journals
|
|
36963
|
+
* no physicalId for a failed CREATE, and the resource still sits in AWS
|
|
36964
|
+
* untracked (the issue #1710 class). Since the ARN is bookkeeping and the
|
|
36965
|
+
* resource already exists, the honest answer is to never fail the create for
|
|
36966
|
+
* it: warn, omit the attribute, and let `Ref` fall back to the compound id
|
|
36967
|
+
* exactly as it does for an imported child. The resource's next update heals
|
|
36968
|
+
* the record via `childRefAttributes`.
|
|
36969
|
+
*/
|
|
36970
|
+
async buildAppSyncArnOrWarn(suffix, logicalId, physicalId) {
|
|
36971
|
+
try {
|
|
36972
|
+
return await this.buildAppSyncArn(suffix);
|
|
36973
|
+
} catch (error) {
|
|
36974
|
+
this.logger.warn(`Created ${logicalId} (${physicalId}) but could not build its ARN attribute: ${error instanceof Error ? error.message : String(error)}. Ref will resolve to the compound physical id until the next update.`);
|
|
36975
|
+
return;
|
|
36976
|
+
}
|
|
36977
|
+
}
|
|
36978
|
+
/**
|
|
36979
|
+
* Rebuild a child type's COMPLETE attribute set from its compound physical id
|
|
36980
|
+
* (issue #1681), for the update path to return.
|
|
36981
|
+
*
|
|
36982
|
+
* This is what heals a record written by a pre-#1681 binary. `update()`
|
|
36983
|
+
* previously returned no attributes, and the deploy engine carries the
|
|
36984
|
+
* existing ones forward when a provider reports none — so without this a
|
|
36985
|
+
* resource created before the fix would keep its `arn:aws:appsync:*:*:...`
|
|
36986
|
+
* placeholder for the rest of its life, since only a REPLACEMENT re-runs
|
|
36987
|
+
* `create()`. `Fn::GetAtt` reads the same cached map, so the placeholder was
|
|
36988
|
+
* breaking that intrinsic too, independently of the `Ref` defect #1681 is
|
|
36989
|
+
* about.
|
|
36990
|
+
*
|
|
36991
|
+
* It must return EVERY key the create path records, not just the ARN: an
|
|
36992
|
+
* `attributes` map returned from `update()` REPLACES the record's map
|
|
36993
|
+
* wholesale rather than merging into it (`deploy-engine.ts`), so a partial
|
|
36994
|
+
* answer would silently drop `Name` / `ApiKey`.
|
|
36995
|
+
*
|
|
36996
|
+
* Returns `undefined` for an id whose arity does not match the type — a
|
|
36997
|
+
* record that malformed cannot be healed by guessing, and carrying the
|
|
36998
|
+
* existing attributes forward is the safe answer.
|
|
36999
|
+
*/
|
|
37000
|
+
async childRefAttributes(resourceType, physicalId) {
|
|
37001
|
+
const parts = physicalId.split("|");
|
|
37002
|
+
if (resourceType === "AWS::AppSync::DataSource" && parts.length === 2) {
|
|
37003
|
+
const [apiId, name] = parts;
|
|
37004
|
+
return {
|
|
37005
|
+
DataSourceArn: await this.buildAppSyncArn(`apis/${apiId}/datasources/${name}`),
|
|
37006
|
+
Name: name
|
|
37007
|
+
};
|
|
37008
|
+
}
|
|
37009
|
+
if (resourceType === "AWS::AppSync::Resolver" && parts.length === 3) {
|
|
37010
|
+
const [apiId, typeName, fieldName] = parts;
|
|
37011
|
+
return { ResolverArn: await this.buildAppSyncArn(`apis/${apiId}/types/${typeName}/resolvers/${fieldName}`) };
|
|
37012
|
+
}
|
|
37013
|
+
if (resourceType === "AWS::AppSync::ApiKey" && parts.length === 2) {
|
|
37014
|
+
const [apiId, apiKeyId] = parts;
|
|
37015
|
+
return {
|
|
37016
|
+
ApiKey: apiKeyId,
|
|
37017
|
+
Arn: await this.buildAppSyncArn(`apis/${apiId}/apikey/${apiKeyId}`)
|
|
37018
|
+
};
|
|
37019
|
+
}
|
|
37020
|
+
}
|
|
37021
|
+
/**
|
|
37022
|
+
* The no-replacement update result for a child type, carrying the healed
|
|
37023
|
+
* attribute set (issue #1681). Reporting none is still the correct answer for
|
|
37024
|
+
* an unhealable id — the engine then carries the existing attributes forward.
|
|
37025
|
+
*/
|
|
37026
|
+
async childUpdateResult(resourceType, physicalId) {
|
|
37027
|
+
const attributes = await this.childRefAttributes(resourceType, physicalId);
|
|
37028
|
+
return {
|
|
37029
|
+
physicalId,
|
|
37030
|
+
wasReplaced: false,
|
|
37031
|
+
...attributes && { attributes }
|
|
37032
|
+
};
|
|
37033
|
+
}
|
|
37034
|
+
/**
|
|
36791
37035
|
* Lazy S3 client for the `*S3Location` properties (Resolver
|
|
36792
37036
|
* `CodeS3Location` / `RequestMappingTemplateS3Location` /
|
|
36793
37037
|
* `ResponseMappingTemplateS3Location`, GraphQLSchema
|
|
@@ -36977,10 +37221,7 @@ var AppSyncProvider = class {
|
|
|
36977
37221
|
"EventBridgeConfig",
|
|
36978
37222
|
"RelationalDatabaseConfig",
|
|
36979
37223
|
"MetricsConfig"
|
|
36980
|
-
].some((key) => (key in properties || key in previousProperties) && !this.deepEqual(properties[key], previousProperties[key]))) return
|
|
36981
|
-
physicalId,
|
|
36982
|
-
wasReplaced: false
|
|
36983
|
-
};
|
|
37224
|
+
].some((key) => (key in properties || key in previousProperties) && !this.deepEqual(properties[key], previousProperties[key]))) return this.childUpdateResult(resourceType, physicalId);
|
|
36984
37225
|
const input = {
|
|
36985
37226
|
apiId,
|
|
36986
37227
|
name,
|
|
@@ -36992,10 +37233,7 @@ var AppSyncProvider = class {
|
|
|
36992
37233
|
} catch (error) {
|
|
36993
37234
|
throw this.wrapUpdateError(error, resourceType, logicalId, physicalId, "DataSource");
|
|
36994
37235
|
}
|
|
36995
|
-
return
|
|
36996
|
-
physicalId,
|
|
36997
|
-
wasReplaced: false
|
|
36998
|
-
};
|
|
37236
|
+
return this.childUpdateResult(resourceType, physicalId);
|
|
36999
37237
|
}
|
|
37000
37238
|
async updateResolver(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
37001
37239
|
for (const field of [
|
|
@@ -37025,10 +37263,7 @@ var AppSyncProvider = class {
|
|
|
37025
37263
|
"CodeS3Location",
|
|
37026
37264
|
"RequestMappingTemplateS3Location",
|
|
37027
37265
|
"ResponseMappingTemplateS3Location"
|
|
37028
|
-
].some((key) => (key in properties || key in previousProperties) && !this.deepEqual(properties[key], previousProperties[key]))) return
|
|
37029
|
-
physicalId,
|
|
37030
|
-
wasReplaced: false
|
|
37031
|
-
};
|
|
37266
|
+
].some((key) => (key in properties || key in previousProperties) && !this.deepEqual(properties[key], previousProperties[key]))) return this.childUpdateResult(resourceType, physicalId);
|
|
37032
37267
|
const input = {
|
|
37033
37268
|
apiId,
|
|
37034
37269
|
typeName,
|
|
@@ -37040,10 +37275,7 @@ var AppSyncProvider = class {
|
|
|
37040
37275
|
} catch (error) {
|
|
37041
37276
|
throw this.wrapUpdateError(error, resourceType, logicalId, physicalId, "Resolver");
|
|
37042
37277
|
}
|
|
37043
|
-
return
|
|
37044
|
-
physicalId,
|
|
37045
|
-
wasReplaced: false
|
|
37046
|
-
};
|
|
37278
|
+
return this.childUpdateResult(resourceType, physicalId);
|
|
37047
37279
|
}
|
|
37048
37280
|
async updateApiKey(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
37049
37281
|
if (properties["ApiId"] !== void 0 && previousProperties["ApiId"] !== void 0 && properties["ApiId"] !== previousProperties["ApiId"]) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS AppSync ApiKey.ApiId is immutable — destroy + redeploy to change");
|
|
@@ -37053,10 +37285,7 @@ var AppSyncProvider = class {
|
|
|
37053
37285
|
const oldDesc = previousProperties["Description"];
|
|
37054
37286
|
const newExp = properties["Expires"];
|
|
37055
37287
|
const oldExp = previousProperties["Expires"];
|
|
37056
|
-
if (newDesc === oldDesc && newExp === oldExp) return
|
|
37057
|
-
physicalId,
|
|
37058
|
-
wasReplaced: false
|
|
37059
|
-
};
|
|
37288
|
+
if (newDesc === oldDesc && newExp === oldExp) return this.childUpdateResult(resourceType, physicalId);
|
|
37060
37289
|
const input = {
|
|
37061
37290
|
apiId,
|
|
37062
37291
|
id: apiKeyId
|
|
@@ -37068,10 +37297,7 @@ var AppSyncProvider = class {
|
|
|
37068
37297
|
} catch (error) {
|
|
37069
37298
|
throw this.wrapUpdateError(error, resourceType, logicalId, physicalId, "ApiKey");
|
|
37070
37299
|
}
|
|
37071
|
-
return
|
|
37072
|
-
physicalId,
|
|
37073
|
-
wasReplaced: false
|
|
37074
|
-
};
|
|
37300
|
+
return this.childUpdateResult(resourceType, physicalId);
|
|
37075
37301
|
}
|
|
37076
37302
|
/**
|
|
37077
37303
|
* Apply a Tags diff to a GraphqlApi via TagResource / UntagResource.
|
|
@@ -37733,6 +37959,7 @@ var AppSyncProvider = class {
|
|
|
37733
37959
|
name: "name",
|
|
37734
37960
|
value: name
|
|
37735
37961
|
}], context?.replayingState === true ? { onRefusal: (message) => this.logger.warn(message) } : void 0);
|
|
37962
|
+
let reportedArn;
|
|
37736
37963
|
try {
|
|
37737
37964
|
const input = {
|
|
37738
37965
|
apiId,
|
|
@@ -37740,19 +37967,20 @@ var AppSyncProvider = class {
|
|
|
37740
37967
|
type
|
|
37741
37968
|
};
|
|
37742
37969
|
this.applyDataSourceConfig(input, resourceType, logicalId, properties);
|
|
37743
|
-
await this.getClient().send(new CreateDataSourceCommand(input));
|
|
37970
|
+
reportedArn = (await this.getClient().send(new CreateDataSourceCommand(input))).dataSource?.dataSourceArn;
|
|
37744
37971
|
this.logger.debug(`Successfully created DataSource ${logicalId}: ${physicalId}`);
|
|
37745
|
-
return {
|
|
37746
|
-
physicalId,
|
|
37747
|
-
attributes: {
|
|
37748
|
-
DataSourceArn: `arn:aws:appsync:*:*:apis/${apiId}/datasources/${name}`,
|
|
37749
|
-
Name: name
|
|
37750
|
-
}
|
|
37751
|
-
};
|
|
37752
37972
|
} catch (error) {
|
|
37753
37973
|
const cause = error instanceof Error ? error : void 0;
|
|
37754
37974
|
throw new ProvisioningError(`Failed to create DataSource ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
37755
37975
|
}
|
|
37976
|
+
const dataSourceArn = reportedArn ?? await this.buildAppSyncArnOrWarn(`apis/${apiId}/datasources/${name}`, logicalId, physicalId);
|
|
37977
|
+
return {
|
|
37978
|
+
physicalId,
|
|
37979
|
+
attributes: {
|
|
37980
|
+
...dataSourceArn !== void 0 && { DataSourceArn: dataSourceArn },
|
|
37981
|
+
Name: name
|
|
37982
|
+
}
|
|
37983
|
+
};
|
|
37756
37984
|
}
|
|
37757
37985
|
async deleteDataSource(logicalId, physicalId, resourceType, context) {
|
|
37758
37986
|
this.logger.debug(`Deleting DataSource ${logicalId}: ${physicalId}`);
|
|
@@ -37797,6 +38025,7 @@ var AppSyncProvider = class {
|
|
|
37797
38025
|
value: fieldName
|
|
37798
38026
|
}
|
|
37799
38027
|
], context?.replayingState === true ? { onRefusal: (message) => this.logger.warn(message) } : void 0);
|
|
38028
|
+
let reportedArn;
|
|
37800
38029
|
try {
|
|
37801
38030
|
const input = {
|
|
37802
38031
|
apiId,
|
|
@@ -37804,16 +38033,17 @@ var AppSyncProvider = class {
|
|
|
37804
38033
|
fieldName
|
|
37805
38034
|
};
|
|
37806
38035
|
await this.applyResolverConfig(input, resourceType, logicalId, properties);
|
|
37807
|
-
await this.getClient().send(new CreateResolverCommand(input));
|
|
38036
|
+
reportedArn = (await this.getClient().send(new CreateResolverCommand(input))).resolver?.resolverArn;
|
|
37808
38037
|
this.logger.debug(`Successfully created Resolver ${logicalId}: ${physicalId}`);
|
|
37809
|
-
return {
|
|
37810
|
-
physicalId,
|
|
37811
|
-
attributes: { ResolverArn: `arn:aws:appsync:*:*:apis/${apiId}/types/${typeName}/resolvers/${fieldName}` }
|
|
37812
|
-
};
|
|
37813
38038
|
} catch (error) {
|
|
37814
38039
|
const cause = error instanceof Error ? error : void 0;
|
|
37815
38040
|
throw new ProvisioningError(`Failed to create Resolver ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
37816
38041
|
}
|
|
38042
|
+
const resolverArn = reportedArn ?? await this.buildAppSyncArnOrWarn(`apis/${apiId}/types/${typeName}/resolvers/${fieldName}`, logicalId, physicalId);
|
|
38043
|
+
return {
|
|
38044
|
+
physicalId,
|
|
38045
|
+
attributes: { ...resolverArn !== void 0 && { ResolverArn: resolverArn } }
|
|
38046
|
+
};
|
|
37817
38047
|
}
|
|
37818
38048
|
async deleteResolver(logicalId, physicalId, resourceType, context) {
|
|
37819
38049
|
this.logger.debug(`Deleting Resolver ${logicalId}: ${physicalId}`);
|
|
@@ -37855,17 +38085,19 @@ var AppSyncProvider = class {
|
|
|
37855
38085
|
const cause = error instanceof Error ? error : void 0;
|
|
37856
38086
|
throw new ProvisioningError(`Failed to create ApiKey ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
37857
38087
|
}
|
|
38088
|
+
const physicalId = packCompositeId(resourceType, logicalId, [{
|
|
38089
|
+
name: "apiId",
|
|
38090
|
+
value: apiId
|
|
38091
|
+
}, {
|
|
38092
|
+
name: "apiKeyId",
|
|
38093
|
+
value: apiKeyId
|
|
38094
|
+
}], context?.replayingState === true ? { onRefusal: (message) => this.logger.warn(message) } : void 0);
|
|
38095
|
+
const apiKeyArn = await this.buildAppSyncArnOrWarn(`apis/${apiId}/apikey/${apiKeyId}`, logicalId, physicalId);
|
|
37858
38096
|
return {
|
|
37859
|
-
physicalId
|
|
37860
|
-
name: "apiId",
|
|
37861
|
-
value: apiId
|
|
37862
|
-
}, {
|
|
37863
|
-
name: "apiKeyId",
|
|
37864
|
-
value: apiKeyId
|
|
37865
|
-
}], context?.replayingState === true ? { onRefusal: (message) => this.logger.warn(message) } : void 0),
|
|
38097
|
+
physicalId,
|
|
37866
38098
|
attributes: {
|
|
37867
38099
|
ApiKey: apiKeyId,
|
|
37868
|
-
Arn:
|
|
38100
|
+
...apiKeyArn !== void 0 && { Arn: apiKeyArn }
|
|
37869
38101
|
}
|
|
37870
38102
|
};
|
|
37871
38103
|
}
|
|
@@ -64534,34 +64766,6 @@ function notFoundError$1(target, stack, resources) {
|
|
|
64534
64766
|
|
|
64535
64767
|
//#endregion
|
|
64536
64768
|
//#region src/local/ecs-task-resolver.ts
|
|
64537
|
-
/**
|
|
64538
|
-
* Derive the AWS partition / URL suffix for an AWS region. Same mapping
|
|
64539
|
-
* CloudFormation applies to `${AWS::Partition}` / `${AWS::URLSuffix}`.
|
|
64540
|
-
* Exported so the CLI can keep the STS hop minimal — caller passes the
|
|
64541
|
-
* region in once, this returns the matching partition + suffix.
|
|
64542
|
-
*/
|
|
64543
|
-
function derivePartitionAndUrlSuffix(region) {
|
|
64544
|
-
if (region.startsWith("cn-")) return {
|
|
64545
|
-
partition: "aws-cn",
|
|
64546
|
-
urlSuffix: "amazonaws.com.cn"
|
|
64547
|
-
};
|
|
64548
|
-
if (region.startsWith("us-gov-")) return {
|
|
64549
|
-
partition: "aws-us-gov",
|
|
64550
|
-
urlSuffix: "amazonaws.com"
|
|
64551
|
-
};
|
|
64552
|
-
if (region.startsWith("us-iso-")) return {
|
|
64553
|
-
partition: "aws-iso",
|
|
64554
|
-
urlSuffix: "c2s.ic.gov"
|
|
64555
|
-
};
|
|
64556
|
-
if (region.startsWith("us-isob-")) return {
|
|
64557
|
-
partition: "aws-iso-b",
|
|
64558
|
-
urlSuffix: "sc2s.sgov.gov"
|
|
64559
|
-
};
|
|
64560
|
-
return {
|
|
64561
|
-
partition: "aws",
|
|
64562
|
-
urlSuffix: "amazonaws.com"
|
|
64563
|
-
};
|
|
64564
|
-
}
|
|
64565
64769
|
function detectEcsImageResolutionNeeds(stack) {
|
|
64566
64770
|
const resources = stack.template.Resources ?? {};
|
|
64567
64771
|
let needsPseudoParameters = false;
|
|
@@ -73207,7 +73411,7 @@ function createMigrateCommand() {
|
|
|
73207
73411
|
*/
|
|
73208
73412
|
function buildProgram() {
|
|
73209
73413
|
const program = new Command();
|
|
73210
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.281.
|
|
73414
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.281.9");
|
|
73211
73415
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
73212
73416
|
const { profile } = actionCommand.optsWithGlobals();
|
|
73213
73417
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|