@go-to-k/cdkd 0.252.3 → 0.254.0

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.
@@ -9194,7 +9194,7 @@ var IntrinsicFunctionResolver = class {
9194
9194
  }
9195
9195
  }
9196
9196
  }
9197
- const value = await this.constructAttribute(resource, attributeName, context);
9197
+ const value = await this.constructAttribute(resource, attributeName, context, logicalId);
9198
9198
  this.logger.debug(`Resolved Fn::GetAtt: ${logicalId}.${attributeName} -> ${stringifyValue(value)}`);
9199
9199
  return value;
9200
9200
  }
@@ -9204,7 +9204,7 @@ var IntrinsicFunctionResolver = class {
9204
9204
  * Many CloudFormation attributes are not returned by Cloud Control API,
9205
9205
  * so we need to construct them manually.
9206
9206
  */
9207
- async constructAttribute(resource, attributeName, _context) {
9207
+ async constructAttribute(resource, attributeName, _context, logicalId) {
9208
9208
  const { resourceType, physicalId } = resource;
9209
9209
  const { region, accountId, partition } = await getAccountInfo(this.resolverRegion);
9210
9210
  if (resourceType === "AWS::DynamoDB::Table" || resourceType === "AWS::DynamoDB::GlobalTable") switch (attributeName) {
@@ -9472,6 +9472,9 @@ var IntrinsicFunctionResolver = class {
9472
9472
  }
9473
9473
  return physicalId;
9474
9474
  }
9475
+ const expectsArnShape = attributeName.endsWith("Arn") && !physicalId.startsWith("arn:");
9476
+ const expectsUrlShape = attributeName.endsWith("Url") && !/^https?:\/\//.test(physicalId);
9477
+ if (expectsArnShape || expectsUrlShape) throw new Error(`Cannot resolve Fn::GetAtt [${logicalId}, ${attributeName}] for ${resourceType}: attributes are not enriched for this resource type, and the physical ID fallback "${physicalId}" is not ${expectsArnShape ? "an ARN (arn:...)" : "a URL (http(s)://...)"}. CloudFormation would return a different value here, so falling back to the physical ID would silently produce a wrong value (e.g. in stack Outputs). Avoid this Fn::GetAtt, or file an issue at https://github.com/go-to-k/cdkd/issues so cdkd can enrich ${resourceType}.${attributeName}.`);
9475
9478
  this.logger.warn(`Unknown attribute ${attributeName} for resource type ${resourceType}, returning physical ID`);
9476
9479
  return physicalId;
9477
9480
  }
@@ -10766,7 +10769,8 @@ var CloudControlProvider = class {
10766
10769
  this.logger.debug(`Created resource ${logicalId}, physical ID: ${progressEvent.Identifier}`);
10767
10770
  const result = { physicalId: progressEvent.Identifier };
10768
10771
  if (progressEvent.ResourceModel) result.attributes = this.parseResourceModel(progressEvent.ResourceModel);
10769
- result.attributes = await this.enrichResourceAttributes(resourceType, progressEvent.Identifier, result.attributes || {});
10772
+ result.attributes = await this.mergeSparseModelReadback(resourceType, progressEvent.Identifier, result.attributes || {});
10773
+ result.attributes = await this.enrichResourceAttributes(resourceType, progressEvent.Identifier, result.attributes);
10770
10774
  return result;
10771
10775
  } catch (error) {
10772
10776
  await this.cleanupFailedCreateRemnant(error, resourceType, logicalId);
@@ -10860,7 +10864,8 @@ var CloudControlProvider = class {
10860
10864
  wasReplaced: false
10861
10865
  };
10862
10866
  if (progressEvent.ResourceModel) result.attributes = this.parseResourceModel(progressEvent.ResourceModel);
10863
- result.attributes = await this.enrichResourceAttributes(resourceType, physicalId, result.attributes || {});
10867
+ result.attributes = await this.mergeSparseModelReadback(resourceType, physicalId, result.attributes || {});
10868
+ result.attributes = await this.enrichResourceAttributes(resourceType, physicalId, result.attributes);
10864
10869
  return result;
10865
10870
  } catch (error) {
10866
10871
  this.handleError(error, "UPDATE", resourceType, logicalId, physicalId);
@@ -10873,7 +10878,7 @@ var CloudControlProvider = class {
10873
10878
  this.logger.debug(`Deleting resource ${logicalId} (${resourceType}), physical ID: ${physicalId}`);
10874
10879
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
10875
10880
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
10876
- const { ASGProvider } = await import("./asg-provider-D4zKdIrY.js").then((n) => n.n);
10881
+ const { ASGProvider } = await import("./asg-provider-BgcH5ymP.js").then((n) => n.n);
10877
10882
  await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
10878
10883
  return;
10879
10884
  }
@@ -11264,6 +11269,48 @@ var CloudControlProvider = class {
11264
11269
  return enriched;
11265
11270
  }
11266
11271
  /**
11272
+ * Generic sparse-model read-back (issue #1105). When the CREATE / UPDATE
11273
+ * `ProgressEvent.ResourceModel` yielded a sparse attribute map, issue ONE
11274
+ * best-effort `GetResource` read-back and merge the returned model over the
11275
+ * parsed attributes. Closes the "pure-CC type with a sparse CREATE model →
11276
+ * empty state attributes → `Fn::GetAtt` silently resolves to the bare
11277
+ * physicalId" class generically instead of per-type (previously fixed
11278
+ * type-by-type in #984 / #1103). Runs BEFORE `enrichResourceAttributes` so
11279
+ * the per-type overlays' `if (!enriched['X'])` gating composes naturally
11280
+ * (no second GetResource for a type the read-back already filled).
11281
+ * Best-effort: a failed read-back leaves the attributes as-is and never
11282
+ * fails the deploy (same never-throw contract as `readCcResourceModel`).
11283
+ */
11284
+ async mergeSparseModelReadback(resourceType, physicalId, attributes) {
11285
+ if (!this.isSparseAttributeMap(attributes, physicalId)) return attributes;
11286
+ const model = await this.readCcResourceModel(resourceType, physicalId);
11287
+ if (!model) return attributes;
11288
+ this.logger.debug(`Merged CC GetResource read-back over sparse ${resourceType} attributes for ${physicalId}`);
11289
+ return {
11290
+ ...attributes,
11291
+ ...model
11292
+ };
11293
+ }
11294
+ /**
11295
+ * Conservative sparseness predicate for `mergeSparseModelReadback`. A map
11296
+ * is sparse when it is empty or carries nothing beyond an echo of the
11297
+ * identifier — every value is a string equal to the physicalId or to one
11298
+ * segment of a compound `|`-joined CC primaryIdentifier. Sparseness is
11299
+ * empirically per-type: `AWS::ApiGatewayV2::Api` returns `ApiEndpoint` in
11300
+ * its CREATE model (NOT sparse — no extra GetResource), while Pipes /
11301
+ * S3 AccessPoint / ResourceGroups / Backup return nothing usable (sparse —
11302
+ * read-back fires). Any non-identifier value (a URL, an ARN, an echoed
11303
+ * input property, a nested object) means the model carried real
11304
+ * information, so we skip the extra API call.
11305
+ */
11306
+ isSparseAttributeMap(attributes, physicalId) {
11307
+ const values = Object.values(attributes);
11308
+ if (values.length === 0) return true;
11309
+ const identifierEchoes = new Set(physicalId.split("|"));
11310
+ identifierEchoes.add(physicalId);
11311
+ return values.every((value) => typeof value === "string" && identifierEchoes.has(value));
11312
+ }
11313
+ /**
11267
11314
  * Read the Cloud Control GetResource model for a pure-CC resource and
11268
11315
  * return its parsed property map, or `undefined` on any failure. Types with
11269
11316
  * no SDK provider always route through Cloud Control, whose async CREATE
@@ -11272,7 +11319,8 @@ var CloudControlProvider = class {
11272
11319
  * VersionId, SelectionId) — the type's registry schema lists them under
11273
11320
  * readOnlyProperties, which the CC read handler does return. Originally
11274
11321
  * Backup-scoped (issue #984); generalized for Pipes / S3 AccessPoint /
11275
- * ResourceGroups in issue #1103. Best-effort: never throws.
11322
+ * ResourceGroups in issue #1103, and reused by the generic sparse-model
11323
+ * read-back (issue #1105). Best-effort: never throws.
11276
11324
  */
11277
11325
  async readCcResourceModel(resourceType, physicalId) {
11278
11326
  try {
@@ -17439,4 +17487,4 @@ var DeployEngine = class {
17439
17487
 
17440
17488
  //#endregion
17441
17489
  export { BOOTSTRAP_MARKER_PREFIX as $, StateError as $t, refStateLookupFromResource as A, AssemblyReader as At, TemplateParser as B, DependencyError as Bt, ProviderRegistry as C, warnDeprecatedNoPrefixCliFlag as Ct, isTerminationProtectionPropagationError as D, findLargeInlineResources as Dt, disableInstanceApiTermination as E, MIGRATE_TMP_PREFIX as Et, resolveExplicitPhysicalId as F, resetAwsClients as Ft, AssetPublisher as G, MissingCdkCliError as Gt, S3StateBackend as H, LocalMigrateError as Ht, assertRegionMatch as I, setAwsClients as It, buildAssetRedirectMap as J, ProvisioningError as Jt, stringifyValue as K, NestedStackChildDirectDestroyError as Kt, applyRoleArnIfSet as L, AssetError as Lt, CDK_PATH_TAG as M, resolveBucketRegion as Mt, matchesCdkPath as N, AwsClients as Nt, IntrinsicFunctionResolver as O, uploadCfnTemplate as Ot, normalizeAwsTagsToCfn as P, getAwsClients as Pt, AssetModeResolver as Q, StackTerminationProtectionError as Qt, DiffCalculator as R, CdkdError as Rt, collectInlinePolicyNamesManagedBySiblings as S, resolveUseCdkBootstrapAssets as St, CloudControlProvider as T, CFN_TEMPLATE_URL_LIMIT as Tt, rebuildClientForBucketRegion as U, LocalStartServiceError as Ut, LockManager as V, LocalInvokeBuildError as Vt, shouldRetainResource as W, LockError as Wt, loadPublishableAssetManifest as X, ResourceUpdateNotSupportedError as Xt, createAssetRedirectResolver as Y, ResourceTimeoutError as Yt, rewriteTemplateAssetReferences as Z, StackHasActiveImportsError as Zt, gray as _, resolveAutoAssetStorage as _t, withRetry as a, __exportAll as an, buildDockerImage as at, yellow as b, resolveStateBucketWithDefault as bt, IMPLICIT_DELETE_DEPENDENCIES as c, runDockerForeground as ct, MULTI_REGION_RECREATE_BLOCKED_TYPES as d, getDockerImageBySourceHash as dt, SynthesisError as en, ensureAssetStorage as et, isStatefulRecreateTargetSync as f, Synthesizer as ft, cyan as g, resolveApp as gt, bold as h, getLegacyStateBucketName as ht, withResourceDeadline as i, withErrorHandling as in, validateContainerRepoName as it, WAFv2WebACLProvider as j, clearBucketRegionCache as jt, cfnRefValueFromPhysicalId as k, expectedOwnerParam as kt, computeImplicitDeleteEdges as l, runDockerStreaming as lt, formatResourceLine as m, getDefaultStateBucketName as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, isCdkdError as nn, parseBootstrapMarker as nt, isRetryableTransientError as o, formatDockerLoginError as ot, renderStatefulReason as p, synthesisStatusMessage as pt, WorkGraph as q, PartialFailureError as qt, DeployEngine as r, normalizeAwsError as rn, validateAssetBucketName as rt, isThrottlingError as s, getDockerCmd as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, formatError as tn, getBootstrapMarkerKey as tt, extractDeploymentEventError as u, AssetManifestLoader as ut, green as v, resolveCaptureObservedState as vt, findActionableSilentDrops as w, CFN_TEMPLATE_BODY_LIMIT as wt, IAMRoleProvider as x, resolveStateBucketWithDefaultAndSource as xt, red as y, resolveSkipPrefix as yt, DagBuilder as z, ConfigError as zt };
17442
- //# sourceMappingURL=deploy-engine-BHpSZlZr.js.map
17490
+ //# sourceMappingURL=deploy-engine-d-cwg8zS.js.map