@go-to-k/cdkd 0.302.2 → 0.302.4

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.
Files changed (28) hide show
  1. package/dist/{asg-provider-B5RKfCs2.js → asg-provider-CGqU-6sj.js} +3 -3
  2. package/dist/{asg-provider-B5RKfCs2.js.map → asg-provider-CGqU-6sj.js.map} +1 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/db-instance-modify-retry-D0e5Ryd_.js +38 -0
  5. package/dist/db-instance-modify-retry-D0e5Ryd_.js.map +1 -0
  6. package/dist/{deploy-engine-B_xWnZ4Q.js → deploy-engine-CN2w5GAK.js} +23 -6
  7. package/dist/deploy-engine-CN2w5GAK.js.map +1 -0
  8. package/dist/{iam-policy-targets-OtGPguLH.js → iam-policy-targets-DBAi38y_.js} +85 -2
  9. package/dist/{iam-policy-targets-OtGPguLH.js.map → iam-policy-targets-DBAi38y_.js.map} +1 -1
  10. package/dist/{iam-role-provider-TdX7t0Ac.js → iam-role-provider-Cv7YzUwO.js} +3 -3
  11. package/dist/{iam-role-provider-TdX7t0Ac.js.map → iam-role-provider-Cv7YzUwO.js.map} +1 -1
  12. package/dist/index.js +3 -3
  13. package/dist/{neptune-provider-CUoBJ6Ys.js → neptune-provider-BcENx6g8.js} +42 -31
  14. package/dist/neptune-provider-BcENx6g8.js.map +1 -0
  15. package/dist/{program-DDJHp1K3.js → program-CAibYjpk.js} +556 -306
  16. package/dist/program-CAibYjpk.js.map +1 -0
  17. package/dist/{provider-classes-CUKmyCQ8.js → provider-classes-B52ogqNj.js} +413 -81
  18. package/dist/provider-classes-B52ogqNj.js.map +1 -0
  19. package/dist/{rds-provider-Bxh9YW5y.js → rds-provider-C6jYh60H.js} +74 -59
  20. package/dist/rds-provider-C6jYh60H.js.map +1 -0
  21. package/dist/{version-CZS6bEuG.js → version-CNK8U3qj.js} +2 -2
  22. package/dist/{version-CZS6bEuG.js.map → version-CNK8U3qj.js.map} +1 -1
  23. package/package.json +2 -2
  24. package/dist/deploy-engine-B_xWnZ4Q.js.map +0 -1
  25. package/dist/neptune-provider-CUoBJ6Ys.js.map +0 -1
  26. package/dist/program-DDJHp1K3.js.map +0 -1
  27. package/dist/provider-classes-CUKmyCQ8.js.map +0 -1
  28. package/dist/rds-provider-Bxh9YW5y.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { a as runWithStackAwsClients, i as resetAwsClients, o as setAwsClients, t as AwsClients } from "./aws-clients-B_CEQGE1.js";
2
2
  import { $ as stringifyJsonPayload, A as isNameGeneration, B as SECRET_REF_MAX_CODE_POINTS, C as generateResourceName, F as withSkipPrefix, G as displayAwsMessage, H as UNRENDERABLE, I as withStackScope, J as displayStackName, K as displayIdent, Q as safeMsg, V as STACK_REF_MAX_CODE_POINTS, W as cutMarker, Y as isPasteableIdent, Z as plainIdentOr, _ as PATTERN_B_RESOURCE_TYPES, a as safeStringify, b as derivesPatternBName, c as isStdoutReservedForPayload, d as runStackBuffered, et as terminalSafe, g as PATTERN_B_NAME_PROPERTIES, h as PATTERN_B_NAME_OPTIONS, l as reserveStdoutForPayload, m as getLiveRenderer, n as describeAwsFailure, q as displaySafe, s as getLogger, tt as truncateCodePoints, x as explicitNamePropertyFor, z as SAFE_MSG_ALTERED_CHAR } from "./aws-failure-text-e_ddrDDo.js";
3
- import { $t as ambientCredentialConfig, An as withErrorHandling, Bn as plainOrDescribed, Bt as formatLockOperation, Cn as StackTerminationProtectionError, D as VALUE_NOT_SHOWN, E as assertRegionMatch, Fn as commandHole, Ft as UNREPRODUCIBLE_LOCK_CLAUSE, G as runDeleteAttempt, Gn as setPasteableRunFlags, Gt as DEFAULT_STATE_PREFIX, Hn as shellBoundedDisplay, It as buildForceUnlockCommand, Jt as producerCoordinateKey, Kn as setPasteableVerbFlags, Kt as injectiveKey, Ln as isInertUnquoted, Lt as buildLockContentionMessage, Nn as SHELL_ACTIVE_WHY, P as remedyLogicalId, Qt as ambientClientDefaults, Rn as pasteableCommand, Rt as forceQuitRecoveryClause, Sn as StackHasActiveImportsError, T as RESOURCE_NOT_FOUND, Tn as SynthesisError, Un as shellQuote, Vn as quotedOrDescribed, Vt as formatLockOwner, Wn as withheldTargetClause, Wt as CUSTOM_RESOURCE_RESPONSE_PREFIX, Xt as setPasteableAwsProfile, Yt as producerRecordKey, Z as isAwsCliLiteral, Zt as withPasteableAwsProfile, _n as NestedStackChildDirectDestroyError, _r as isThrottlingError, ar as stripForDisplay, bn as ResourceTimeoutError, cn as DeployCancelledError, dn as IntrinsicResolutionRefusalError, en as clientDefaultsFor, fn as LocalInvokeBuildError$1, fr as isRetryableTransientError, ft as logicalIdShown, gn as MalformedProducerRecordRefusalError, gr as isMarkedNonRetryable, in as CdkdError, ir as stripControlChars, it as isInterruptedWaitError, jn as TIMEOUT_FLAG_RESOURCE_TYPE, kn as normalizeAwsError, lr as isAmbiguousOutcomeError, mr as retryClassificationText, mt as resourceTypeShown, n as RESOLVED_PREVIOUS_PRINCIPAL_KEYS, nn as AccountIdUnavailableError, nt as endCommandInterruptScope, on as CrossAccountSecretRefusalError, pn as LocalStartServiceError, pr as isTransientServerError, rr as escapeRegExp, rt as interruptWatchListenerCount, s as readRecordedPrincipals, t as IAM_PRINCIPAL_NAME, tn as credentialFingerprint, tt as beginCommandInterruptScope, un as DynamicReferenceRegionAmbiguousError, vn as PartialFailureError, vr as markNonRetryable, wn as StateError, xn as ResourceUpdateNotSupportedError, yn as ProvisioningError, zt as formatLockExpiry } from "./iam-policy-targets-OtGPguLH.js";
3
+ import { $t as producerRecordKey, Bt as buildForceUnlockCommand, Cn as ProvisioningError, D as VALUE_NOT_SHOWN, Dn as StackTerminationProtectionError, E as assertRegionMatch, En as StackHasActiveImportsError, Fn as TIMEOUT_FLAG_RESOURCE_TYPE, Gn as quotedOrDescribed, Gt as formatLockOwner, Hn as pasteableCommand, Ht as forceQuitRecoveryClause, Jn as withheldTargetClause, Jt as CUSTOM_RESOURCE_RESPONSE_PREFIX, Kn as shellBoundedDisplay, Ln as SHELL_ACTIVE_WHY, Nn as normalizeAwsError, On as StateError, P as remedyLogicalId, Pn as withErrorHandling, Qt as producerCoordinateKey, Sn as PartialFailureError, Sr as markNonRetryable, T as RESOURCE_NOT_FOUND, Tn as ResourceUpdateNotSupportedError, Ut as formatLockExpiry, Vn as isInertUnquoted, Vt as buildLockContentionMessage, Wn as plainOrDescribed, Wt as formatLockOperation, Xn as setPasteableVerbFlags, Xt as injectiveKey, Y as runDeleteAttempt, Yn as setPasteableRunFlags, Yt as DEFAULT_STATE_PREFIX, _n as LocalStartServiceError, _r as isTransientServerError, an as credentialFingerprint, at as beginCommandInterruptScope, bn as MalformedProducerRecordRefusalError, br as isMarkedNonRetryable, cn as CdkdError, cr as stripControlChars, ct as isInterruptedWaitError, en as setPasteableAwsProfile, fn as DeployCancelledError, gn as LocalInvokeBuildError$1, gr as isRetryableTransientError, gt as logicalIdShown, hn as IntrinsicResolutionRefusalError, in as clientDefaultsFor, kn as SynthesisError, lr as stripForDisplay, mn as DynamicReferenceRegionAmbiguousError, n as RESOLVED_PREVIOUS_PRINCIPAL_KEYS, nn as ambientClientDefaults, on as AccountIdUnavailableError, ot as endCommandInterruptScope, pr as isAmbiguousOutcomeError, qn as shellQuote, rn as ambientCredentialConfig, s as readRecordedPrincipals, sr as escapeRegExp, st as interruptWatchListenerCount, t as IAM_PRINCIPAL_NAME, tn as withPasteableAwsProfile, tt as isAwsCliLiteral, un as CrossAccountSecretRefusalError, vr as retryClassificationText, vt as resourceTypeShown, wn as ResourceTimeoutError, xn as NestedStackChildDirectDestroyError, xr as isThrottlingError, zn as commandHole, zt as UNREPRODUCIBLE_LOCK_CLAUSE } from "./iam-policy-targets-DBAi38y_.js";
4
4
  import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, l as runInStackAwsScope, n as awsClientDefaults, r as getAssumedRoleCredentials, u as formatAuthority } from "./aws-client-defaults-DBXBcg0J.js";
5
- import { $ as pendingRequestCount, $a as refuseMalformedOutputs, $c as absoluteAssemblyPathEscape, $i as isImpossibleEmptyStoredAttribute, $n as noEchoExactEchoLeavesOf, $o as prefetchCreateOnlyPropertyPaths, $r as applyCustomResourceResponseExpiration, $s as buildDockerImage, $t as nameGenerationCarriedFrom, A as inheritedProvenanceForChildDiff, Aa as malformedLocalResourceEntriesWarning, Ac as resolveUseCdkBootstrapAssets, Ai as refuseUnreadableCdkCrossAccountRefs, Ao as NO_CC_HANDLERS_REASON, As as orphansAfterRollback, At as replayRollback, B as conditionFingerprint, Ba as malformedResourceEntriesWarning, Bc as decodeListingKey, Bi as sendableAssumeRoleCommand, Bn as yellow, Bs as loadPublishableAssetManifest, Bt as replacementNeverSwapped, Ca as hasReadableResources, Cc as loadCdkJson, Cn as bindingSkippedOutputs, Co as unreadableOrphanRecords, Cr as ledgerForStack, Cs as exportNamesCarriedFrom, Ct as sameJournaledOrphans, D as IMPLICIT_DELETE_DEPENDENCIES, Da as malformedExportNamesWarning, Dc as resolveSkipPrefix, Dn as constructPathOf, Dr as DeploymentEventsReader, Ds as importableOutputKeys, Ea as malformedDriftResourcePropertiesWarning, Ec as resolveCaptureObservedState, En as maskingRetryLogger, Eo as findActionableSilentDrops, Es as hasUnverifiableParameterRefusal, F as findNestedTemplateTreeDefect, Fa as malformedOrphansRefusalMessage, Fc as CFN_TEMPLATE_URL_LIMIT, Fi as applyRoleArnIfSet, Fn as bold, Fo as isStatefulRecreateTargetForReplace, Fs as isSensitiveAttributeName, Ft as isReplacementOrphan, G as withResourceDeadline, Ga as previewableOrphanRecords, Gc as AssemblyReader, Gi as classifyRecordedSecretRegion, Gn as removeSuperseded, Gr as wouldReturnToSdkProvider, Gs as ensureAssetStorage, H as parentSuppliedValues, Ha as malformedResourcesWarning, Hc as PARTITION_TABLE, Hi as applyCallerIdentityCredentials, Hn as deleteSupersededEntry, Hr as ProviderRegistry, Hs as AssetModeResolver, Ht as seedsDeleteFirstGuard, I as isAbsoluteAssetPath, Ia as malformedOrphansWarning, Ic as MIGRATE_TMP_PREFIX, Ii as assertFlagRoleArn, In as cyan, Io as isStatefulRecreateTargetSync, Is as stringifyValue, It as planFailedOps, J as keptWholeReasonText, Ja as refuseMalformedOrphanRecords, Jc as defineOwnKey, Ji as regionLessSecretName, Jn as supersededHolderOf, Jr as readsNoEchoDeleteValues, Js as parseBootstrapMarker, K as diffSecurity, Ka as refuseDivergentRecordRegionForDestroy, Kc as StageLoadError, Ki as classifyReplaySecretRegion, Kn as supersededAfterRollback, Ks as getBootstrapMarkerKey, Kt as inheritProducerRegions, L as listNestedTemplateRows, La as malformedOutputsRefusalMessage, Lc as findLargeInlineResources, Li as assertSendableRoleArn, Ln as gray, Lo as renderStatefulReason, Ls as WorkGraph, Lt as planRollback, M as findServiceTokenRefusals, Ma as malformedOrphanRecordsRefusalMessage, Mc as warnDeprecatedNoPrefixCliFlag, Mo as findReplacedReadersOfRecreateTargets, Ms as shouldRetainResource, Mt as recordAfterRollbackUpdate, N as serviceTokenBlockingReason, Na as malformedOrphanRecordsWarning, Nc as ssmResolvedValueType, Ni as recordedOutputReferenceRegions, Nn as withStackRecords, No as shownType, Ns as stackInstanceIdCarriedFrom, Nt as demoteSupersededOrphans, O as computeImplicitDeleteEdges, Oa as malformedExportSourceWarning, Oc as resolveStateBucketWithDefault, Oi as resolveDynamicReferences, On as findDestructiveChanges, Oo as unwrittenCreateOnlyReplacement, Or as DeploymentEventsStore, Os as importableOutputs, P as childTemplateLoader, Pa as malformedOrphanRowsKeptWarning, Pc as CFN_TEMPLATE_BODY_LIMIT, Pi as recordedReferenceRegions, Po as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ps as AssetPublisher, Pt as isJournaledOrphan, Q as planOrphanAdoption, Qa as refuseMalformedOrphansForOrphan, Qc as ownValue, Qi as getAccountInfo, Qn as noEchoComparisonForTemplate, Qr as CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID, Qs as buildDenyExternalAccessPolicy, Qt as updatePartialReason, R as renderNestedTemplateTreeDefect, Ra as malformedOutputsWarning, Rc as uploadCfnTemplate, Ri as explicitRoleArnOrThrow, Rn as green, Rs as buildAssetRedirectMap, Rt as recheckFailedPlan, Sa as hasReadableOutputs, Sc as getLegacyStateBucketName, Sn as isExportAliasCollision, So as unpreviewableOrphanRecords, Ss as describeRegionValueKind, St as makeForeignHolderScan, Ta as isReadableResourceEntry, Tc as resolveAutoAssetStorage, Tn as DEFAULT_RESOURCE_WARN_AFTER_MS, To as withheldAccountClause, Tr as withCreateTokenLedger, Ts as hasReasonlessBaselineRefusal, U as readRecordedConditionVerdicts, Ua as malformedScrubResourceEntriesRefusalMessage, Uc as canonicalizeRegion, Ui as callerEnvCredentials, Un as holdsSupersededResources, Ur as ccBrokenReason, Us as BOOTSTRAP_MARKER_PREFIX, Ut as orphanNeedsIdentity, V as conditionInputsFrom, Va as malformedResourcePropertiesWarning, Vc as expectedOwnerParam, Vi as AWS_CREDENTIAL_ENV_KEYS, Vn as addSuperseded, Vr as CC_BROKEN_REASON, Vs as rewriteTemplateAssetReferences, Vt as resolveReplacementOldType, Wa as malformedStateRefusalMessage, Wc as derivePartitionAndUrlSuffix, Wi as envCredentialsAreAssumedRole, Wn as isSupersededResourceRecord, Wr as isCustomResource, Ws as assertAssetBucketRegion, Wt as findNestedStackTypeChanges, X as makeCanonicalizePropertiesFn, Xa as refuseMalformedOrphans, Xc as hasPlainPrototype, Xi as isUnboundTemplateParameter, Xn as withoutSuperseded, Xs as validateAssetBucketName, Y as mergeNoChangeOutputs, Ya as refuseMalformedOrphanRecordsForDestroy, Yc as hasOwnKey, Yi as coerceParameterTypedValue, Yn as supersededResourcesOf, Yr as isCustomResourceType$1, Ys as readBootstrapMarkerBody, Z as makeSiblingClaimReader, Za as refuseMalformedOrphansForDestroy, Zc as nullPrototypeRecord, Zi as parameterTypeMayLoseSecretIdentity, Zn as noEchoAttributeNamesOf, Zr as withPrintingSecrets, Zs as validateContainerRepoName, Zt as updatePartialMessage, _a as UNREADABLE_RESOURCES_MAP_ROW, _c as AssetManifestLoader, _n as exportNameSecretExposure, _o as repairMalformedOrphansForReadOnly, _r as createPreDeleteFinalSnapshot, _s as isNotImplemented, _t as dropFailedCommands, a as isProtectionValueActive, aa as cfnRefValueFromPhysicalId, ac as finchSecretArgvRefusal, ai as UNSPECIFIED_SKIP_REASON, al as injectedAwsRegionValue, an as computeParameterTaint, ao as refuseMalformedResourceEntriesForImport, ar as namingSecretsWithRecordedNoEcho, at as displacedPhysicalIdShown, ba as displayLogicalId, bc as synthesisStatusMessage, bi as IntrinsicFunctionResolver, bn as collectDeclaredOutputNames, bo as repairMalformedResourcePropertiesForReadOnly, br as refusesFinalSnapshot, bs as splitImportedOps, bt as journaledOrphanLines, cc as isDockerClientEnvKey, ci as deleteSkipReason, cn as resourcesNamingDeclaredParameter, co as refuseMalformedResourcePropertiesForDestroy, cr as secretNamePrintingBags, cs as LockManager, ct as nestedChildStackName$1, dc as redactDockerArgvValues, dn as exportAliasCollisionScrubWarning, do as refuseMalformedResourcePropertiesForOrphan, dr as stateSecretNameNeedles, ds as rebuildClientForBucketRegion, dt as revertedNestedRowIds, ea as carriesDynamicReference, ec as resolveDockerContextDirectory, ei as customResourceResponseExpirationWarning, el as describeFileReadFailure, en as nameGenerationHighWaterOf, eo as refuseMalformedOutputsForDestroy, er as noEchoParameterNamesOf, es as templateResourceTypes, et as resolvePendingCloudControlRequests, fa as declaresNoEcho, fc as redactedCause, fn as secretBearing, fo as refuseMalformedResourcesForDeploy, fr as storedSecretNameNeedles, fs as CrossPrefixReadError, ft as withNestedRevertRun, ga as UNREADABLE_ORPHANS_CONTAINER_ROW, gc as warnFinchArgvExposure, gn as exportNameNoEchoParameters, go as repairMalformedOrphanRecordsForReadOnly, gr as ccRoutedFinalSnapshotError, gs as isAccessDenied, gt as deleteJournaledOrphans, ha as STATE_RESOURCES_MALFORMED, hc as runDockerStreaming, hn as carriedExportAliasExposure, ho as refuseMalformedState, hr as buildFinalSnapshotIdentifier, hs as crossPrefixDeniedWarning, ht as withNestedStackContext, i as PROTECTION_PROPERTY_BY_TYPE, ia as AWS_NO_VALUE, ic as dockerSpawnEnvWithSensitive, ii as RollbackInlinePolicyWriters, il as injectAwsRegion, in as retiredNameGenerationsLeaving, io as refuseMalformedResourceEntriesForDestroy, ir as maskEventTextWithBoundBags, it as displacedOpClause, j as deferredServiceTokenWarning, ja as malformedLocalResourcesWarning, jc as stateBucketExistenceConfirmed, ji as keepHeldTokenProvenance, jn as destroyStackRecordsView, jo as hasNoCloudControlHandlers, js as orphansCarriedFrom, jt as removeProtectionTypeList, k as crossStackOutputProvenanceSource, ka as malformedLocalOutputsWarning, kc as resolveStateBucketWithDefaultAndSource, ki as producerLookupOver, kn as formatDestructiveChange, kr as extractDeploymentEventError, ks as isReadableBag, kt as replayFailedOperations, la as withSharedDrainBudget, lc as isMalformedEnvKey, ln as WITHHELD_NAME_DISPLAY, lo as refuseMalformedResourcePropertiesForDrift, ls as isLockInfoExpired, lt as recordDisplacedSkips, ma as STATE_REGION_DIVERGED, mc as runDockerForeground, mn as secretSafeKeyDisplay, mo as refuseMalformedResourcesForExport, mr as PRE_DELETE_SNAPSHOT_TYPES, ms as applyCrossPrefixScan, mt as getCurrentNestedStackContext, n as recordedProtectionEvidence, na as isNamelessDynamicReferenceError, nc as describeDockerExecFailure, ni as slowCcOperationTimeoutMs, nl as renderAssemblyPathEscape, nn as retiredAfterRollback, no as refuseMalformedResourceEntries, nr as completedReplayEntries, ns as withRetry, nt as recordRetainedForReadoption, o as perType, oa as isStalePlaceholderArnAttribute, oc as formatDockerLoginError, oi as deleteIndeterminateGuards, on as namesAnyDeclaredParameter, oo as refuseMalformedResourceEntriesForImportSave, or as orphanRecordsPrintingBag, os as DagBuilder, ot as dropSettledNestedJournals, pa as JSON_LISTING_HOLE_VALUE, pc as redactedDockerCause, pn as secretBearingStateKeyWarning, po as refuseMalformedResourcesForDestroy, pr as ATOMIC_FINAL_SNAPSHOT_TYPES, ps as CrossPrefixScanCache, pt as collectNestedChildUnaddressed, q as isSecretBearingReferenceString, qc as processStackMessages, qi as producerRegionsFromState, qn as supersededHeldByOtherTypeWarning, qr as TemplateNoEchoReresolver, qs as isCrossRegionRedirect, r as recordedProtectionNote, ra as keepsSecretReferenceToken, rc as describeDockerFailure, rl as resolveAssemblyPath, rn as retiredNameGenerationsAfter, ro as refuseMalformedResourceEntriesForDeploy, rr as journaledOrphanPrintingBag, rt as NESTED_PENDING_PARENT_REASON, s as readProtection, sa as refStateLookupFromResource, sc as getDockerCmd, si as deleteLeftInPlace, sl as resolveBucketRegion, sn as reachableDivergentParameters, so as refuseMalformedResourceEntriesForOrphan, sr as secretNamePrintingBag, ss as TemplateParser, t as DeployEngine, ta as carriesFetchableDynamicReference, tc as describeDockerCapturedOutput, ti as CloudControlProvider, tl as displayAssemblyPath, tn as nameScopeOf, to as refuseMalformedResourceAttributesForOrphan, tr as createReadOnlyAttributeHealerFactory, ts as describeTypeWithThrottleRetry, tt as keptForRetainedRecord, ua as parameterInputsFor, uc as partitionSensitiveEnv, ui as isWaitAbandonedError, un as displayTextOrWithheld, uo as refuseMalformedResourcePropertiesForExport, ur as secretNamedRecordNeedles, us as S3StateBackend, va as accountArgs, vc as getDockerImageBySourceHash, vi as DiffCalculator, vn as isWholeDynamicReferenceValue, vo as repairMalformedOutputsForReadOnly, vr as effectiveDeletionPolicy, vs as stackInstanceIdOf, vt as dropFailedHint, wa as isReadableOrphanRecord, wc as resolveApp, wn as DEFAULT_RESOURCE_TIMEOUT_MS, wo as unreadableResourceEntries, ws as hasReadableExportSet, wt as formatResourceLine, xa as hasReadableOrphans, xc as getDefaultStateBucketName, xi as poisonRenderedSpellingsCollidingIn, xn as collectPublishedOutputNames, xo as repairMalformedResourcesForReadOnly, xr as unsupportedFinalSnapshotError, xs as acceptedCreateOnlyDropsOf, xt as loadJournaledOrphans, ya as deployRefusesOrphanRowsReason, yc as Synthesizer, yi as INTRINSIC_KEYS, yn as noEchoParameterValueSeed, yo as repairMalformedResourceEntriesForReadOnly, yr as isFinalSnapshotError, ys as withStackInstanceIdWithheld, yt as isHandledOrphan, z as templateIdentity, za as malformedRenderedContainersWarning, zc as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, zi as isIamRoleArn, zn as red, zs as createAssetRedirectResolver, zt as recordUnderIdIsNotOwn } from "./deploy-engine-B_xWnZ4Q.js";
5
+ import { $ as pendingRequestCount, $a as refuseMalformedOutputs, $c as absoluteAssemblyPathEscape, $i as isImpossibleEmptyStoredAttribute, $n as noEchoExactEchoLeavesOf, $o as prefetchCreateOnlyPropertyPaths, $r as applyCustomResourceResponseExpiration, $s as buildDockerImage, $t as nameGenerationCarriedFrom, A as inheritedProvenanceForChildDiff, Aa as malformedLocalResourceEntriesWarning, Ac as resolveUseCdkBootstrapAssets, Ai as refuseUnreadableCdkCrossAccountRefs, Ao as NO_CC_HANDLERS_REASON, As as orphansAfterRollback, At as replayRollback, B as conditionFingerprint, Ba as malformedResourceEntriesWarning, Bc as decodeListingKey, Bi as sendableAssumeRoleCommand, Bn as yellow, Bs as loadPublishableAssetManifest, Bt as replacementNeverSwapped, Ca as hasReadableResources, Cc as loadCdkJson, Cn as bindingSkippedOutputs, Co as unreadableOrphanRecords, Cr as ledgerForStack, Cs as exportNamesCarriedFrom, Ct as sameJournaledOrphans, D as IMPLICIT_DELETE_DEPENDENCIES, Da as malformedExportNamesWarning, Dc as resolveSkipPrefix, Dn as constructPathOf, Dr as DeploymentEventsReader, Ds as importableOutputKeys, Ea as malformedDriftResourcePropertiesWarning, Ec as resolveCaptureObservedState, En as maskingRetryLogger, Eo as findActionableSilentDrops, Es as hasUnverifiableParameterRefusal, F as findNestedTemplateTreeDefect, Fa as malformedOrphansRefusalMessage, Fc as CFN_TEMPLATE_URL_LIMIT, Fi as applyRoleArnIfSet, Fn as bold, Fo as isStatefulRecreateTargetForReplace, Fs as isSensitiveAttributeName, Ft as isReplacementOrphan, G as withResourceDeadline, Ga as previewableOrphanRecords, Gc as AssemblyReader, Gi as classifyRecordedSecretRegion, Gn as removeSuperseded, Gr as wouldReturnToSdkProvider, Gs as ensureAssetStorage, H as parentSuppliedValues, Ha as malformedResourcesWarning, Hc as PARTITION_TABLE, Hi as applyCallerIdentityCredentials, Hn as deleteSupersededEntry, Hr as ProviderRegistry, Hs as AssetModeResolver, Ht as seedsDeleteFirstGuard, I as isAbsoluteAssetPath, Ia as malformedOrphansWarning, Ic as MIGRATE_TMP_PREFIX, Ii as assertFlagRoleArn, In as cyan, Io as isStatefulRecreateTargetSync, Is as stringifyValue, It as planFailedOps, J as keptWholeReasonText, Ja as refuseMalformedOrphanRecords, Jc as defineOwnKey, Ji as regionLessSecretName, Jn as supersededHolderOf, Jr as readsNoEchoDeleteValues, Js as parseBootstrapMarker, K as diffSecurity, Ka as refuseDivergentRecordRegionForDestroy, Kc as StageLoadError, Ki as classifyReplaySecretRegion, Kn as supersededAfterRollback, Ks as getBootstrapMarkerKey, Kt as inheritProducerRegions, L as listNestedTemplateRows, La as malformedOutputsRefusalMessage, Lc as findLargeInlineResources, Li as assertSendableRoleArn, Ln as gray, Lo as renderStatefulReason, Ls as WorkGraph, Lt as planRollback, M as findServiceTokenRefusals, Ma as malformedOrphanRecordsRefusalMessage, Mc as warnDeprecatedNoPrefixCliFlag, Mo as findReplacedReadersOfRecreateTargets, Ms as shouldRetainResource, Mt as recordAfterRollbackUpdate, N as serviceTokenBlockingReason, Na as malformedOrphanRecordsWarning, Nc as ssmResolvedValueType, Ni as recordedOutputReferenceRegions, Nn as withStackRecords, No as shownType, Ns as stackInstanceIdCarriedFrom, Nt as demoteSupersededOrphans, O as computeImplicitDeleteEdges, Oa as malformedExportSourceWarning, Oc as resolveStateBucketWithDefault, Oi as resolveDynamicReferences, On as findDestructiveChanges, Oo as unwrittenCreateOnlyReplacement, Or as DeploymentEventsStore, Os as importableOutputs, P as childTemplateLoader, Pa as malformedOrphanRowsKeptWarning, Pc as CFN_TEMPLATE_BODY_LIMIT, Pi as recordedReferenceRegions, Po as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ps as AssetPublisher, Pt as isJournaledOrphan, Q as planOrphanAdoption, Qa as refuseMalformedOrphansForOrphan, Qc as ownValue, Qi as getAccountInfo, Qn as noEchoComparisonForTemplate, Qr as CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID, Qs as buildDenyExternalAccessPolicy, Qt as updatePartialReason, R as renderNestedTemplateTreeDefect, Ra as malformedOutputsWarning, Rc as uploadCfnTemplate, Ri as explicitRoleArnOrThrow, Rn as green, Rs as buildAssetRedirectMap, Rt as recheckFailedPlan, Sa as hasReadableOutputs, Sc as getLegacyStateBucketName, Sn as isExportAliasCollision, So as unpreviewableOrphanRecords, Ss as describeRegionValueKind, St as makeForeignHolderScan, Ta as isReadableResourceEntry, Tc as resolveAutoAssetStorage, Tn as DEFAULT_RESOURCE_WARN_AFTER_MS, To as withheldAccountClause, Tr as withCreateTokenLedger, Ts as hasReasonlessBaselineRefusal, U as readRecordedConditionVerdicts, Ua as malformedScrubResourceEntriesRefusalMessage, Uc as canonicalizeRegion, Ui as callerEnvCredentials, Un as holdsSupersededResources, Ur as ccBrokenReason, Us as BOOTSTRAP_MARKER_PREFIX, Ut as orphanNeedsIdentity, V as conditionInputsFrom, Va as malformedResourcePropertiesWarning, Vc as expectedOwnerParam, Vi as AWS_CREDENTIAL_ENV_KEYS, Vn as addSuperseded, Vr as CC_BROKEN_REASON, Vs as rewriteTemplateAssetReferences, Vt as resolveReplacementOldType, Wa as malformedStateRefusalMessage, Wc as derivePartitionAndUrlSuffix, Wi as envCredentialsAreAssumedRole, Wn as isSupersededResourceRecord, Wr as isCustomResource, Ws as assertAssetBucketRegion, Wt as findNestedStackTypeChanges, X as makeCanonicalizePropertiesFn, Xa as refuseMalformedOrphans, Xc as hasPlainPrototype, Xi as isUnboundTemplateParameter, Xn as withoutSuperseded, Xs as validateAssetBucketName, Y as mergeNoChangeOutputs, Ya as refuseMalformedOrphanRecordsForDestroy, Yc as hasOwnKey, Yi as coerceParameterTypedValue, Yn as supersededResourcesOf, Yr as isCustomResourceType$1, Ys as readBootstrapMarkerBody, Z as makeSiblingClaimReader, Za as refuseMalformedOrphansForDestroy, Zc as nullPrototypeRecord, Zi as parameterTypeMayLoseSecretIdentity, Zn as noEchoAttributeNamesOf, Zr as withPrintingSecrets, Zs as validateContainerRepoName, Zt as updatePartialMessage, _a as UNREADABLE_RESOURCES_MAP_ROW, _c as AssetManifestLoader, _n as exportNameSecretExposure, _o as repairMalformedOrphansForReadOnly, _r as createPreDeleteFinalSnapshot, _s as isNotImplemented, _t as dropFailedCommands, a as isProtectionValueActive, aa as cfnRefValueFromPhysicalId, ac as finchSecretArgvRefusal, ai as UNSPECIFIED_SKIP_REASON, al as injectedAwsRegionValue, an as computeParameterTaint, ao as refuseMalformedResourceEntriesForImport, ar as namingSecretsWithRecordedNoEcho, at as displacedPhysicalIdShown, ba as displayLogicalId, bc as synthesisStatusMessage, bi as IntrinsicFunctionResolver, bn as collectDeclaredOutputNames, bo as repairMalformedResourcePropertiesForReadOnly, br as refusesFinalSnapshot, bs as splitImportedOps, bt as journaledOrphanLines, cc as isDockerClientEnvKey, ci as deleteSkipReason, cn as resourcesNamingDeclaredParameter, co as refuseMalformedResourcePropertiesForDestroy, cr as secretNamePrintingBags, cs as LockManager, ct as nestedChildStackName$1, dc as redactDockerArgvValues, dn as exportAliasCollisionScrubWarning, do as refuseMalformedResourcePropertiesForOrphan, dr as stateSecretNameNeedles, ds as rebuildClientForBucketRegion, dt as revertedNestedRowIds, ea as carriesDynamicReference, ec as resolveDockerContextDirectory, ei as customResourceResponseExpirationWarning, el as describeFileReadFailure, en as nameGenerationHighWaterOf, eo as refuseMalformedOutputsForDestroy, er as noEchoParameterNamesOf, es as templateResourceTypes, et as resolvePendingCloudControlRequests, fa as declaresNoEcho, fc as redactedCause, fn as secretBearing, fo as refuseMalformedResourcesForDeploy, fr as storedSecretNameNeedles, fs as CrossPrefixReadError, ft as withNestedRevertRun, ga as UNREADABLE_ORPHANS_CONTAINER_ROW, gc as warnFinchArgvExposure, gn as exportNameNoEchoParameters, go as repairMalformedOrphanRecordsForReadOnly, gr as ccRoutedFinalSnapshotError, gs as isAccessDenied, gt as deleteJournaledOrphans, ha as STATE_RESOURCES_MALFORMED, hc as runDockerStreaming, hn as carriedExportAliasExposure, ho as refuseMalformedState, hr as buildFinalSnapshotIdentifier, hs as crossPrefixDeniedWarning, ht as withNestedStackContext, i as PROTECTION_PROPERTY_BY_TYPE, ia as AWS_NO_VALUE, ic as dockerSpawnEnvWithSensitive, ii as RollbackInlinePolicyWriters, il as injectAwsRegion, in as retiredNameGenerationsLeaving, io as refuseMalformedResourceEntriesForDestroy, ir as maskEventTextWithBoundBags, it as displacedOpClause, j as deferredServiceTokenWarning, ja as malformedLocalResourcesWarning, jc as stateBucketExistenceConfirmed, ji as keepHeldTokenProvenance, jn as destroyStackRecordsView, jo as hasNoCloudControlHandlers, js as orphansCarriedFrom, jt as removeProtectionTypeList, k as crossStackOutputProvenanceSource, ka as malformedLocalOutputsWarning, kc as resolveStateBucketWithDefaultAndSource, ki as producerLookupOver, kn as formatDestructiveChange, kr as extractDeploymentEventError, ks as isReadableBag, kt as replayFailedOperations, la as withSharedDrainBudget, lc as isMalformedEnvKey, ln as WITHHELD_NAME_DISPLAY, lo as refuseMalformedResourcePropertiesForDrift, ls as isLockInfoExpired, lt as recordDisplacedSkips, ma as STATE_REGION_DIVERGED, mc as runDockerForeground, mn as secretSafeKeyDisplay, mo as refuseMalformedResourcesForExport, mr as PRE_DELETE_SNAPSHOT_TYPES, ms as applyCrossPrefixScan, mt as getCurrentNestedStackContext, n as recordedProtectionEvidence, na as isNamelessDynamicReferenceError, nc as describeDockerExecFailure, ni as slowCcOperationTimeoutMs, nl as renderAssemblyPathEscape, nn as retiredAfterRollback, no as refuseMalformedResourceEntries, nr as completedReplayEntries, ns as withRetry, nt as recordRetainedForReadoption, o as perType, oa as isStalePlaceholderArnAttribute, oc as formatDockerLoginError, oi as deleteIndeterminateGuards, on as namesAnyDeclaredParameter, oo as refuseMalformedResourceEntriesForImportSave, or as orphanRecordsPrintingBag, os as DagBuilder, ot as dropSettledNestedJournals, pa as JSON_LISTING_HOLE_VALUE, pc as redactedDockerCause, pn as secretBearingStateKeyWarning, po as refuseMalformedResourcesForDestroy, pr as ATOMIC_FINAL_SNAPSHOT_TYPES, ps as CrossPrefixScanCache, pt as collectNestedChildUnaddressed, q as isSecretBearingReferenceString, qc as processStackMessages, qi as producerRegionsFromState, qn as supersededHeldByOtherTypeWarning, qr as TemplateNoEchoReresolver, qs as isCrossRegionRedirect, r as recordedProtectionNote, ra as keepsSecretReferenceToken, rc as describeDockerFailure, rl as resolveAssemblyPath, rn as retiredNameGenerationsAfter, ro as refuseMalformedResourceEntriesForDeploy, rr as journaledOrphanPrintingBag, rt as NESTED_PENDING_PARENT_REASON, s as readProtection, sa as refStateLookupFromResource, sc as getDockerCmd, si as deleteLeftInPlace, sl as resolveBucketRegion, sn as reachableDivergentParameters, so as refuseMalformedResourceEntriesForOrphan, sr as secretNamePrintingBag, ss as TemplateParser, t as DeployEngine, ta as carriesFetchableDynamicReference, tc as describeDockerCapturedOutput, ti as CloudControlProvider, tl as displayAssemblyPath, tn as nameScopeOf, to as refuseMalformedResourceAttributesForOrphan, tr as createReadOnlyAttributeHealerFactory, ts as describeTypeWithThrottleRetry, tt as keptForRetainedRecord, ua as parameterInputsFor, uc as partitionSensitiveEnv, ui as isWaitAbandonedError, un as displayTextOrWithheld, uo as refuseMalformedResourcePropertiesForExport, ur as secretNamedRecordNeedles, us as S3StateBackend, va as accountArgs, vc as getDockerImageBySourceHash, vi as DiffCalculator, vn as isWholeDynamicReferenceValue, vo as repairMalformedOutputsForReadOnly, vr as effectiveDeletionPolicy, vs as stackInstanceIdOf, vt as dropFailedHint, wa as isReadableOrphanRecord, wc as resolveApp, wn as DEFAULT_RESOURCE_TIMEOUT_MS, wo as unreadableResourceEntries, ws as hasReadableExportSet, wt as formatResourceLine, xa as hasReadableOrphans, xc as getDefaultStateBucketName, xi as poisonRenderedSpellingsCollidingIn, xn as collectPublishedOutputNames, xo as repairMalformedResourcesForReadOnly, xr as unsupportedFinalSnapshotError, xs as acceptedCreateOnlyDropsOf, xt as loadJournaledOrphans, ya as deployRefusesOrphanRowsReason, yc as Synthesizer, yi as INTRINSIC_KEYS, yn as noEchoParameterValueSeed, yo as repairMalformedResourceEntriesForReadOnly, yr as isFinalSnapshotError, ys as withStackInstanceIdWithheld, yt as isHandledOrphan, z as templateIdentity, za as malformedRenderedContainersWarning, zc as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, zi as isIamRoleArn, zn as red, zs as createAssetRedirectResolver, zt as recordUnderIdIsNotOwn } from "./deploy-engine-CN2w5GAK.js";
6
6
  import { $ as recordLogOnlyParameterValue, Cn as WHOLE_DYNAMIC_REFERENCE_PATTERN, Ct as DYNAMIC_REFERENCE_TOKEN_SCAN, Dt as pathCrossesDottedKey, Et as isUncertifiedBaselineMaskPosition, F as redactForState, G as carryLogOnlyValues, It as recordNestedStackParameterExpressions, Jt as physicalNameCopiesOf, Ot as identityKeyFor, Q as printingCorpusOf, S as liveMatchesUnresolvedTokenFrame, Tn as isSingleDynamicReferenceToken, Tt as dynamicReferenceTokens, X as literalSplitDelimitersOf, Xt as recordPhysicalNameCopy, Y as hasMaskableValues, Z as logOnlyValueCount, _n as recordMaskOnlyValuesIn, a as maskReadbackAtCoordinates, at as errorCauseChain, b as valueAtCoordinate, bn as recordProvenPublicExpression, bt as withPhysicalNameCopies, ct as maskSecretsInText, d as noEchoOutputsComparison, g as readsNoEchoSource, gn as recordMaskOnlyValue, h as readbackPathFor, i as maskAtCoordinates, it as createSecretMasker, kt as inheritNestedStackParameterAssociations, l as noEchoCoordinatesOf, nn as carriesSecretMask, nt as shareLogOnlyValues, o as maskWholeValue, pn as provenPublicValue, q as createUnionSecretMasker, r as isMarkedCoordinate, rt as unionOfSecretBags, s as maskedLeafCoordinatesOf, st as maskSecretsInError, t as canonicalCoordinates, tn as splitGetAttStringForm, tt as recordLogOnlyValue, u as noEchoLeavesOf, v as recordedNoEchoValuesOf, vn as recordNoEchoAttributeValues, vt as scrubResourceRecord, xn as wholeStringLeavesOf, yn as recordNoEchoParameterFreshValue } from "./secret-redaction-BHWS-PZK.js";
7
- import { t as getCdkdVersion } from "./version-CZS6bEuG.js";
7
+ import { t as getCdkdVersion } from "./version-CNK8U3qj.js";
8
8
  import { randomBytes, randomUUID } from "node:crypto";
9
9
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutBucketVersioningCommand, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
10
10
  import { GetRoleCommand, GetUserCommand } from "@aws-sdk/client-iam";
@@ -1099,14 +1099,149 @@ function pathGlobMatches(pattern, subject) {
1099
1099
  return can[0];
1100
1100
  }
1101
1101
 
1102
+ //#endregion
1103
+ //#region src/cli/cdk-path.ts
1104
+ function readCdkPath(resource) {
1105
+ const meta = resource.Metadata;
1106
+ if (!meta) return "";
1107
+ const v = meta["aws:cdk:path"];
1108
+ return typeof v === "string" ? v : "";
1109
+ }
1110
+ function readCdkPathOrUndefined(resource) {
1111
+ const path = readCdkPath(resource);
1112
+ return path === "" ? void 0 : path;
1113
+ }
1114
+ function buildCdkPathIndex(template) {
1115
+ const index = /* @__PURE__ */ new Map();
1116
+ for (const [logicalId, resource] of Object.entries(template.Resources)) {
1117
+ if (resource.Type === "AWS::CDK::Metadata") continue;
1118
+ const path = readCdkPath(resource);
1119
+ if (path) index.set(path, logicalId);
1120
+ }
1121
+ return index;
1122
+ }
1123
+ function resolveCdkPathToLogicalIds(input, index) {
1124
+ const seen = /* @__PURE__ */ new Map();
1125
+ const prefix = `${input}/`;
1126
+ for (const [path, logicalId] of index) if (path === input || path.startsWith(prefix)) {
1127
+ if (!seen.has(logicalId)) seen.set(logicalId, path);
1128
+ }
1129
+ return [...seen.entries()].map(([logicalId, cdkPath]) => ({
1130
+ logicalId,
1131
+ cdkPath
1132
+ }));
1133
+ }
1134
+ function stackForConstructPath(path, stacks) {
1135
+ let best;
1136
+ let bestRank = -1;
1137
+ for (const s of stacks) {
1138
+ const names = [[s.displayName, 1], [s.stackName, 0]];
1139
+ for (const [name, preference] of names) {
1140
+ if (typeof name !== "string" || name.length === 0) continue;
1141
+ if (!path.startsWith(`${name}/`)) continue;
1142
+ const rank = name.length * 2 + preference;
1143
+ if (rank > bestRank) {
1144
+ best = s;
1145
+ bestRank = rank;
1146
+ }
1147
+ }
1148
+ }
1149
+ return best;
1150
+ }
1151
+ function stackForPathFormTarget(parsed, target, stacks) {
1152
+ if (!parsed.isPath || parsed.pathOrId !== target) return void 0;
1153
+ return stackForConstructPath(parsed.pathOrId, stacks);
1154
+ }
1155
+
1102
1156
  //#endregion
1103
1157
  //#region src/cli/stack-matcher.ts
1104
- function matchStacks(stacks, patterns) {
1158
+ function matchStacks(stacks, patterns, options = {}) {
1105
1159
  if (patterns.length === 0) return [];
1106
1160
  const selected = /* @__PURE__ */ new Set();
1107
- for (const pattern of patterns) for (const stack of stacksForPattern(stacks, pattern)) selected.add(stack.stackName);
1161
+ for (const pattern of patterns) for (const stack of stacksForPattern(stacks, pattern)) selected.add(stack);
1162
+ if (options.dedupe === "identity") return stacks.filter((s) => selected.has(s));
1108
1163
  const seen = /* @__PURE__ */ new Set();
1109
- return stacks.filter((s) => selected.has(s.stackName) && !seen.has(s.stackName) && seen.add(s.stackName));
1164
+ return stacks.filter((s) => selected.has(s) && !seen.has(s.stackName) && seen.add(s.stackName));
1165
+ }
1166
+ function stackNameRegionCollisions(stacks, regionOf, selected = new Set(stacks)) {
1167
+ const byNameRegion = /* @__PURE__ */ new Map();
1168
+ for (const stack of stacks) {
1169
+ const key = injectiveKey(stack.stackName, regionOf(stack) ?? "");
1170
+ const group = byNameRegion.get(key);
1171
+ if (group) group.push(stack);
1172
+ else byNameRegion.set(key, [stack]);
1173
+ }
1174
+ const sameAccountPossible = (a, b) => a.account === void 0 || b.account === void 0 || a.account === b.account;
1175
+ const groups = [];
1176
+ for (const group of byNameRegion.values()) {
1177
+ const chosen = group.filter((s) => selected.has(s));
1178
+ if (chosen.length === 0) continue;
1179
+ const colliding = group.filter((s) => selected.has(s) || chosen.some((c) => sameAccountPossible(c, s)));
1180
+ if (colliding.length > 1) groups.push(colliding);
1181
+ }
1182
+ return groups;
1183
+ }
1184
+ function stacksForDependency(depName, dependent, pool) {
1185
+ if (depName === dependent.stackName) return [];
1186
+ const candidates = pool.filter((s) => s.stackName === depName);
1187
+ if (candidates.length <= 1) return candidates;
1188
+ const sameStage = candidates.filter((s) => s.stagePath === dependent.stagePath);
1189
+ const inStage = sameStage.length > 0 ? sameStage : candidates;
1190
+ if (inStage.length === 1) return inStage;
1191
+ const sameRegion = inStage.filter((s) => s.region === dependent.region);
1192
+ return sameRegion.length > 0 ? sameRegion : inStage;
1193
+ }
1194
+ function renderStackNameRegionCollision(groups, regionOf) {
1195
+ const ident = (v) => displayIdent(v, { maxCodePoints: STACK_REF_MAX_CODE_POINTS });
1196
+ return `Selected stacks address the same CloudFormation stack: ${groups.map((group) => {
1197
+ const region = regionOf(group[0]);
1198
+ const where = region === void 0 ? "and neither sets env.region, so they deploy to the same region" : `in region ${ident(region)}`;
1199
+ const accounts = [...new Set(group.flatMap((s) => s.account ? [s.account] : []))];
1200
+ const accountNote = accounts.length > 1 ? ` (their accounts ${accounts.map(ident).join(", ")} differ, but one run deploys every selected stack under its own account)` : "";
1201
+ return `${group.map(describeStack).join(", ")} share the physical stack name ${ident(group[0].stackName)} ${where}${accountNote}`;
1202
+ }).join("; ")}. Give each a distinct stackName or env.region, or select only one of them by its CDK path.` + (groups.some((g) => g.some((s) => s.region === void 0 && regionOf(s) !== void 0)) ? " A stack without env.region takes the run's region: pin that Stage's region, or set AWS_REGION to another region for this run." : "");
1203
+ }
1204
+ function refuseStackNameRegionCollisions(stacks, regionOf, selected) {
1205
+ const groups = stackNameRegionCollisions(stacks, regionOf, selected);
1206
+ if (groups.length > 0) throw new CdkdError(renderStackNameRegionCollision(groups, (s) => regionOf(s)), "STACK_NAME_REGION_COLLISION");
1207
+ }
1208
+ function selectTargetStack(parsed, target, stacks) {
1209
+ if (parsed.stackPattern === null) return stacks.length === 1 ? {
1210
+ kind: "found",
1211
+ stack: stacks[0]
1212
+ } : { kind: "no-prefix" };
1213
+ const byPrefix = stackForPathFormTarget(parsed, target, stacks);
1214
+ if (byPrefix) {
1215
+ if (stackForPathFormTarget(parsed, target, [...stacks].reverse()) === byPrefix) return {
1216
+ kind: "found",
1217
+ stack: byPrefix
1218
+ };
1219
+ return {
1220
+ kind: "ambiguous",
1221
+ pattern: byPrefix.stackName,
1222
+ matched: stacks.filter((s) => s.stackName === byPrefix.stackName)
1223
+ };
1224
+ }
1225
+ const matched = matchStacks([...stacks], [parsed.stackPattern], { dedupe: "identity" });
1226
+ if (matched.length === 1) return {
1227
+ kind: "found",
1228
+ stack: matched[0]
1229
+ };
1230
+ if (matched.length === 0) return {
1231
+ kind: "not-found",
1232
+ pattern: parsed.stackPattern
1233
+ };
1234
+ return {
1235
+ kind: "ambiguous",
1236
+ pattern: parsed.stackPattern,
1237
+ matched
1238
+ };
1239
+ }
1240
+ function renderAmbiguousTargetStack(pattern, matched) {
1241
+ const sharedName = matched.length > 1 && matched.every((s) => s.stackName === pattern);
1242
+ const example = matched.find((s) => s.displayName && s.displayName !== s.stackName)?.displayName;
1243
+ const hint = example !== void 0 && displayIdent(example, { maxCodePoints: 1152 }) === example ? ` (e.g. '${example}/<construct path>')` : "";
1244
+ return `Stack pattern ${renderPatternList([pattern])} matched ${matched.length} stacks: ${matched.map(describeStack).join(", ")}` + (sharedName ? ", which share that physical stack name" : "") + (example !== void 0 ? `. Name one stack by its CDK path, shown in parentheses${hint}.` : ". Use a more specific pattern.");
1110
1245
  }
1111
1246
  function stacksForPattern(stacks, pattern) {
1112
1247
  const byId = stacks.filter((s) => pathGlobMatches(pattern, s.displayName ?? s.stackName));
@@ -1284,7 +1419,7 @@ async function synthCommand(stackPatterns, options) {
1284
1419
  ...Object.keys(context).length > 0 && { context }
1285
1420
  };
1286
1421
  const { stacks: allStacks, assemblyDir } = await synthesizer.synthesize(synthOptions);
1287
- const selected = stackPatterns.length > 0 ? matchStacks(allStacks, stackPatterns) : allStacks;
1422
+ const selected = stackPatterns.length > 0 ? matchStacks(allStacks, stackPatterns, { dedupe: "identity" }) : allStacks;
1288
1423
  if (selected.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
1289
1424
  const stacks = selected;
1290
1425
  processStackMessages(stacks, logger, {
@@ -1297,15 +1432,17 @@ async function synthCommand(stackPatterns, options) {
1297
1432
  } else logger.info(`Supply a stack id (${stacks.map(describeStack).join(", ")}) to display its template.`);
1298
1433
  const found = stacks.length === allStacks.length ? `Found ${stacks.length} stack(s):` : `Found ${stacks.length} of ${allStacks.length} stack(s):`;
1299
1434
  logger.info(`\n${green("✓")} ${bold("Synthesis complete!")} ${found}`);
1435
+ const sharedNames = new Set(stacks.map((s) => s.stackName).filter((name, i, names) => names.indexOf(name) !== i));
1300
1436
  for (const stack of stacks) {
1437
+ const shared = sharedNames.has(stack.stackName);
1301
1438
  const resourceCount = countDeployableResources(stack.template);
1302
1439
  const outputCount = Object.keys(stack.template.Outputs ?? {}).length;
1303
- logger.info(` • ${stack.stackName}`);
1440
+ logger.info(` • ${shared ? describeStack(stack) : stack.stackName}`);
1304
1441
  logger.info(` - Resources: ${resourceCount}`);
1305
1442
  logger.info(` - Outputs: ${outputCount}`);
1306
1443
  logger.info(` - Has assets: ${assemblyReader.hasAssets(stack) ? "Yes" : "No"}`);
1307
1444
  if (options.verbose) {
1308
- const templatePath = resolveVerboseTemplatePath(options.output, stack.stackName);
1445
+ const templatePath = resolveVerboseTemplatePath(options.output, shared ? `${stack.stackName}.${stack.region ?? "env-agnostic"}` : stack.stackName);
1309
1446
  writeFileSync(templatePath, JSON.stringify(stack.template, null, 2));
1310
1447
  logger.debug(` - Template written to: ${displaySafe(templatePath)}`);
1311
1448
  }
@@ -1327,20 +1464,16 @@ function createSynthCommand() {
1327
1464
  //#endregion
1328
1465
  //#region src/cli/commands/list.ts
1329
1466
  function sortByDependency(stacks) {
1330
- const byName = new Map(stacks.map((s) => [s.stackName, s]));
1331
1467
  const visited = /* @__PURE__ */ new Set();
1332
1468
  const result = [];
1333
1469
  const visit = (stack, ancestors) => {
1334
- if (visited.has(stack.stackName)) return;
1335
- if (ancestors.has(stack.stackName)) return;
1336
- ancestors.add(stack.stackName);
1337
- for (const depName of stack.dependencyNames) {
1338
- const dep = byName.get(depName);
1339
- if (dep) visit(dep, ancestors);
1340
- }
1341
- ancestors.delete(stack.stackName);
1342
- if (!visited.has(stack.stackName)) {
1343
- visited.add(stack.stackName);
1470
+ if (visited.has(stack)) return;
1471
+ if (ancestors.has(stack)) return;
1472
+ ancestors.add(stack);
1473
+ for (const depName of stack.dependencyNames) for (const dep of stacksForDependency(depName, stack, stacks)) visit(dep, ancestors);
1474
+ ancestors.delete(stack);
1475
+ if (!visited.has(stack)) {
1476
+ visited.add(stack);
1344
1477
  result.push(stack);
1345
1478
  }
1346
1479
  };
@@ -1385,7 +1518,7 @@ async function listCommand(patterns, options) {
1385
1518
  };
1386
1519
  const allStacks = (await synthesizer.synthesize(synthOptions)).stacks;
1387
1520
  if (allStacks.length === 0) throw new Error(renderNoStackMatch(patterns, allStacks));
1388
- const selected = patterns.length > 0 ? matchStacks(allStacks, patterns) : allStacks;
1521
+ const selected = patterns.length > 0 ? matchStacks(allStacks, patterns, { dedupe: "identity" }) : allStacks;
1389
1522
  if (selected.length === 0) throw new Error(renderNoStackMatch(patterns, allStacks));
1390
1523
  const sorted = sortByDependency(selected);
1391
1524
  if (options.long) {
@@ -2485,40 +2618,65 @@ var ExportIndexStore = class {
2485
2618
  //#endregion
2486
2619
  //#region src/analyzer/cross-stack-deps.ts
2487
2620
  function inferCrossStackStackDeps(stacks, opts) {
2621
+ const result = /* @__PURE__ */ new Map();
2622
+ for (const [consumer, producers] of inferCrossStackDepsByStack(stacks, opts)) {
2623
+ const names = result.get(consumer.stackName) ?? /* @__PURE__ */ new Set();
2624
+ for (const producer of producers) if (producer.stackName !== consumer.stackName) names.add(producer.stackName);
2625
+ result.set(consumer.stackName, names);
2626
+ }
2627
+ return result;
2628
+ }
2629
+ function inferCrossStackDepsByStack(stacks, opts) {
2488
2630
  const kinds = opts?.kinds ?? ["ImportValue", "GetStackOutput"];
2489
2631
  const wantImportValue = kinds.includes("ImportValue");
2490
2632
  const wantGetStackOutput = kinds.includes("GetStackOutput");
2491
- const exportOwner = /* @__PURE__ */ new Map();
2633
+ const exporters = /* @__PURE__ */ new Map();
2492
2634
  for (const stack of stacks) {
2493
2635
  const outputs = stack.template.Outputs;
2494
2636
  if (!outputs) continue;
2495
2637
  for (const output of Object.values(outputs)) {
2496
2638
  const name = output?.Export?.Name;
2497
2639
  if (typeof name === "string" && name !== "") {
2498
- if (!exportOwner.has(name)) exportOwner.set(name, stack.stackName);
2640
+ const list = exporters.get(name) ?? [];
2641
+ if (!list.includes(stack)) list.push(stack);
2642
+ exporters.set(name, list);
2499
2643
  }
2500
2644
  }
2501
2645
  }
2502
- const stackNames = new Set(stacks.map((s) => s.stackName));
2646
+ const preferRegion = (candidates, region) => {
2647
+ const same = candidates.filter((c) => c.region === region);
2648
+ return same.length > 0 ? same : candidates;
2649
+ };
2503
2650
  const result = /* @__PURE__ */ new Map();
2504
2651
  for (const stack of stacks) {
2505
2652
  const producers = /* @__PURE__ */ new Set();
2506
2653
  collectTemplateCrossStackRefs(stack.template, (kind, value, unconditional) => {
2507
- let producer;
2654
+ let found = [];
2508
2655
  if (kind === "ImportValue") {
2509
2656
  if (!wantImportValue) return;
2510
- if (typeof value === "string") producer = exportOwner.get(value);
2657
+ if (typeof value === "string") {
2658
+ const owners = (exporters.get(value) ?? []).filter((s) => s !== stack);
2659
+ found = preferRegion(owners, stack.region);
2660
+ }
2511
2661
  } else {
2512
2662
  if (opts?.onRoleArnReference && unconditional && value && typeof value === "object" && !Array.isArray(value) && Object.hasOwn(value, "RoleArn")) opts.onRoleArnReference(stack.stackName, value);
2513
2663
  if (!wantGetStackOutput) return;
2514
2664
  if (value && typeof value === "object" && !Array.isArray(value)) {
2515
- const sn = value["StackName"];
2516
- if (typeof sn === "string") producer = sn;
2665
+ const args = value;
2666
+ const sn = args["StackName"];
2667
+ if (typeof sn === "string") {
2668
+ let named = stacks.filter((s) => s.stackName === sn && s !== stack);
2669
+ const region = args["Region"];
2670
+ if (typeof region === "string") named = named.filter((s) => s.region === region || s.region === void 0);
2671
+ else named = preferRegion(named, stack.region);
2672
+ const sameStage = named.filter((s) => s.stagePath === stack.stagePath);
2673
+ found = sameStage.length > 0 ? sameStage : named;
2674
+ }
2517
2675
  }
2518
2676
  }
2519
- if (producer && producer !== stack.stackName && stackNames.has(producer)) producers.add(producer);
2677
+ for (const producer of found) producers.add(producer);
2520
2678
  });
2521
- result.set(stack.stackName, producers);
2679
+ result.set(stack, producers);
2522
2680
  }
2523
2681
  return result;
2524
2682
  }
@@ -2560,7 +2718,7 @@ function collectCrossStackRefs(node, onRef, unconditional) {
2560
2718
  //#region src/provisioning/register-providers.ts
2561
2719
  let providerClasses;
2562
2720
  function loadProviderClasses() {
2563
- providerClasses ??= import("./provider-classes-CUKmyCQ8.js");
2721
+ providerClasses ??= import("./provider-classes-B52ogqNj.js");
2564
2722
  return providerClasses;
2565
2723
  }
2566
2724
  function registerAllProviders(registry, classes) {
@@ -3184,7 +3342,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3184
3342
  if (topLevel.length === 0) throw new Error(renderAllNoTopLevelStacks(inStages));
3185
3343
  allLeftOutStageStacks = inStages;
3186
3344
  targetStacks = topLevel;
3187
- } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns);
3345
+ } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
3188
3346
  else if (allStacks.length === 1) targetStacks = allStacks;
3189
3347
  else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all (top-level stacks; '**' for every stack)`);
3190
3348
  if (targetStacks.length === 0) {
@@ -3192,42 +3350,39 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3192
3350
  throw new Error(renderNoStackMatch(stackPatterns, allStacks) + (gone.stacks.length > 0 ? `\n${renderStacksNoLongerSelected(gone.patterns, gone.stacks)}` : ""));
3193
3351
  }
3194
3352
  const roleArnReferences = [];
3195
- const inferredCrossStackDeps = inferCrossStackStackDeps(allStacks, { onRoleArnReference: (consumer, args) => roleArnReferences.push({
3353
+ const inferredCrossStackDeps = inferCrossStackDepsByStack(allStacks, { onRoleArnReference: (consumer, args) => roleArnReferences.push({
3196
3354
  consumer,
3197
3355
  args
3198
3356
  }) });
3199
3357
  const producerLookup = producerLookupOver(allStacks);
3200
- const effectiveStackDeps = (stackName, deps) => {
3201
- const union = new Set(deps);
3202
- for (const producer of inferredCrossStackDeps.get(stackName) ?? []) union.add(producer);
3203
- return union;
3204
- };
3205
- const inferredStrongCrossStackDeps = inferCrossStackStackDeps(allStacks, { kinds: ["ImportValue"] });
3206
- const effectiveStrongStackDeps = (stackName, deps) => {
3207
- const union = new Set(deps);
3208
- for (const producer of inferredStrongCrossStackDeps.get(stackName) ?? []) union.add(producer);
3209
- return union;
3358
+ const dependencyStacks = (stack, inferred, pool) => {
3359
+ const deps = /* @__PURE__ */ new Set();
3360
+ for (const depName of stack.dependencyNames) for (const dep of stacksForDependency(depName, stack, pool)) deps.add(dep);
3361
+ const inPool = new Set(pool);
3362
+ for (const producer of inferred.get(stack) ?? []) if (producer !== stack && inPool.has(producer)) deps.add(producer);
3363
+ return deps;
3210
3364
  };
3365
+ const inferredStrongCrossStackDeps = inferCrossStackDepsByStack(allStacks, { kinds: ["ImportValue"] });
3211
3366
  if (!options.exclusively) {
3212
- const targetNames = new Set(targetStacks.map((s) => s.stackName));
3213
- const allStackMap = new Map(allStacks.map((s) => [s.stackName, s]));
3214
- const addDependencies = (stackName) => {
3215
- const stack = allStackMap.get(stackName);
3216
- if (!stack) return;
3217
- for (const depName of effectiveStrongStackDeps(stackName, stack.dependencyNames)) if (!targetNames.has(depName)) {
3218
- const depStack = allStackMap.get(depName);
3219
- if (depStack) {
3220
- targetNames.add(depName);
3221
- targetStacks.push(depStack);
3222
- logger.debug(`Auto-including dependency stack: ${depName} (required by ${stackName})`);
3223
- addDependencies(depName);
3224
- }
3367
+ const included = new Set(targetStacks);
3368
+ const addDependencies = (stack) => {
3369
+ for (const depStack of dependencyStacks(stack, inferredStrongCrossStackDeps, allStacks)) {
3370
+ if (included.has(depStack)) continue;
3371
+ included.add(depStack);
3372
+ targetStacks.push(depStack);
3373
+ logger.debug(`Auto-including dependency stack: ${depStack.stackName} (required by ${stack.stackName})`);
3374
+ addDependencies(depStack);
3225
3375
  }
3226
3376
  };
3227
- for (const stack of [...targetStacks]) addDependencies(stack.stackName);
3377
+ for (const stack of [...targetStacks]) addDependencies(stack);
3228
3378
  }
3379
+ const selectedNames = new Set(targetStacks.map((s) => s.stackName));
3380
+ const selectedSet = new Set(targetStacks);
3381
+ const sameNamedAppStacks = allStacks.filter((s) => selectedSet.has(s) || selectedNames.has(s.stackName) && s.region !== void 0);
3382
+ refuseStackNameRegionCollisions(sameNamedAppStacks, (s) => s.region, selectedSet);
3383
+ const deployedStacks = new Set(targetStacks);
3229
3384
  const deployedNames = new Set(targetStacks.map((s) => s.stackName));
3230
- const leftOut = allLeftOutStageStacks.filter((s) => !deployedNames.has(s.stackName));
3385
+ const leftOut = allLeftOutStageStacks.filter((s) => !deployedStacks.has(s));
3231
3386
  if (leftOut.length > 0) logger.warn(renderAllLeftOutStageStacks(leftOut));
3232
3387
  if (!options.all && stackPatterns.length > 0) {
3233
3388
  const gone = stacksNoLongerSelected(allStacks, stackPatterns, deployedNames);
@@ -3252,7 +3407,8 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3252
3407
  logger,
3253
3408
  siblings: allStacks.filter((s) => !s.region).map((s) => s.stackName)
3254
3409
  });
3255
- const stackRegions = new Map(await Promise.all(targetStacks.map(async (s) => [s.stackName, await regionForStack(s.stackName, s.region)])));
3410
+ const stackRegions = new Map(await Promise.all(targetStacks.map(async (s) => [s, await regionForStack(s.stackName, s.region)])));
3411
+ refuseStackNameRegionCollisions(sameNamedAppStacks, (s) => stackRegions.get(s) ?? s.region, selectedSet);
3256
3412
  const crossPrefixGuard = new CrossPrefixGuard(preflightStateBackend, { readOnly: options.dryRun === true });
3257
3413
  await synthesizer.expandMacrosForStacks(targetStacks, synthOptions);
3258
3414
  const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
@@ -3284,13 +3440,14 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3284
3440
  const dagBuilder = new DagBuilder({ relaxCdkVpcDefensiveDeps: !!options.aggressiveVpcParallel });
3285
3441
  const diffCalculator = new DiffCalculator();
3286
3442
  const workGraph = new WorkGraph();
3287
- const stackMap = new Map(targetStacks.map((s) => [s.stackName, s]));
3443
+ const sharedNames = new Set(targetStacks.map((s) => s.stackName).filter((name, i, names) => names.indexOf(name) !== i));
3444
+ const graphKey = (s) => sharedNames.has(s.stackName) ? `${s.stackName}@${stackRegions.get(s) ?? deployStackRegion(s, baseRegion)}` : s.stackName;
3288
3445
  const stackRedirects = /* @__PURE__ */ new Map();
3289
3446
  for (const stack of targetStacks) {
3290
- const stackNodeId = `stack:${stack.stackName}`;
3447
+ const stackNodeId = `stack:${graphKey(stack)}`;
3291
3448
  const stackDeps = /* @__PURE__ */ new Set();
3292
3449
  if (stack.assetManifestPath) {
3293
- const assetRegion = stackRegions.get(stack.stackName) ?? deployStackRegion(stack, baseRegion);
3450
+ const assetRegion = stackRegions.get(stack) ?? deployStackRegion(stack, baseRegion);
3294
3451
  const manifest = loadPublishableAssetManifest(stack.assetManifestPath);
3295
3452
  if (manifest) {
3296
3453
  const assetMode = await assetModeResolver.resolve(stack.region || rawNamedRegion || assetRegion);
@@ -3299,7 +3456,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3299
3456
  if (assetMode.mode === "cdkd-assets") {
3300
3457
  redirect = buildAssetRedirectMap(manifest, assetMode.marker, accountId, assetRegion);
3301
3458
  if (redirect.entries.length > 0) {
3302
- stackRedirects.set(stack.stackName, redirect);
3459
+ stackRedirects.set(stack, redirect);
3303
3460
  const rewritten = rewriteTemplateAssetReferences(stack.template, redirect);
3304
3461
  logger.debug(`Rewrote ${rewritten} asset reference(s) to cdkd asset storage (${assetMode.marker.assetBucket} / ${assetMode.marker.containerRepo}) in template of stack ${stack.stackName}`);
3305
3462
  } else redirect = void 0;
@@ -3309,7 +3466,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3309
3466
  accountId,
3310
3467
  region: assetRegion,
3311
3468
  ...options.profile && { profile: options.profile },
3312
- nodePrefix: `${stack.stackName}:`,
3469
+ nodePrefix: `${graphKey(stack)}:`,
3313
3470
  ...redirect && { redirect },
3314
3471
  ...stack.assetOutdir !== void 0 && { assetOutdir: stack.assetOutdir }
3315
3472
  });
@@ -3317,7 +3474,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3317
3474
  }
3318
3475
  }
3319
3476
  }
3320
- for (const depName of effectiveStackDeps(stack.stackName, stack.dependencyNames)) if (stackMap.has(depName)) stackDeps.add(`stack:${depName}`);
3477
+ for (const depStack of dependencyStacks(stack, inferredCrossStackDeps, targetStacks)) stackDeps.add(`stack:${graphKey(depStack)}`);
3321
3478
  workGraph.addNode({
3322
3479
  id: stackNodeId,
3323
3480
  type: "stack",
@@ -3337,7 +3494,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3337
3494
  };
3338
3495
  const runStackInner = async (stackInfo) => {
3339
3496
  if (deployInterrupted) throw new DeployCancelledError(`Deploy interrupted before stack '${stackInfo.stackName}' started — not starting it.`);
3340
- const stackRegion = stackRegions.get(stackInfo.stackName) ?? deployStackRegion(stackInfo, baseRegion);
3497
+ const stackRegion = stackRegions.get(stackInfo) ?? deployStackRegion(stackInfo, baseRegion);
3341
3498
  logger.info(`\n${cyan("Deploying stack:")} ${bold(cyan(stackInfo.stackName))}${stackRegion !== baseRegion ? gray(` (region: ${stackRegion})`) : ""}`);
3342
3499
  const stackAwsClients = new AwsClients({
3343
3500
  region: stackRegion,
@@ -3453,7 +3610,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3453
3610
  })) return;
3454
3611
  }
3455
3612
  }
3456
- const assetRedirect = stackRedirects.get(stackInfo.stackName);
3613
+ const assetRedirect = stackRedirects.get(stackInfo);
3457
3614
  const deployEngineOptions = {
3458
3615
  concurrency: options.concurrency,
3459
3616
  dryRun: options.dryRun,
@@ -6142,7 +6299,7 @@ async function diffCommand(stacks, options) {
6142
6299
  if (topLevel.length === 0) throw new Error(renderAllNoTopLevelStacks(inStages));
6143
6300
  if (inStages.length > 0) logger.info(renderAllLeftOutStageStacks(inStages));
6144
6301
  targetStacks = topLevel;
6145
- } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns);
6302
+ } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
6146
6303
  else if (allStacks.length === 1) targetStacks = allStacks;
6147
6304
  else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all (top-level stacks; '**' for every stack)`);
6148
6305
  if (targetStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
@@ -6238,8 +6395,10 @@ async function diffCommand(stacks, options) {
6238
6395
  });
6239
6396
  const trees = [];
6240
6397
  const producerLookup = producerLookupOver(allStacks);
6398
+ const sharedNames = new Set(targetStacks.map((s) => s.stackName).filter((name, i, names) => names.indexOf(name) !== i));
6241
6399
  for (const stackInfo of targetStacks) {
6242
- logger.info(`\nCalculating diff for stack: ${stackInfo.stackName}`);
6400
+ const shownName = sharedNames.has(stackInfo.stackName) ? describeStack(stackInfo) : stackInfo.stackName;
6401
+ logger.info(`\nCalculating diff for stack: ${shownName}`);
6243
6402
  const stackRegion = await regionForStack(stackInfo.stackName, stackInfo.region);
6244
6403
  const assetRedirect = await resolveAssetRedirect(stackInfo.assetManifestPath, stackRegion);
6245
6404
  if (assetRedirect) {
@@ -6248,7 +6407,7 @@ async function diffCommand(stacks, options) {
6248
6407
  }
6249
6408
  trees.push(await buildDiffTree({
6250
6409
  stackName: stackInfo.stackName,
6251
- displayName: stackInfo.stackName,
6410
+ displayName: shownName,
6252
6411
  region: stackRegion,
6253
6412
  template: stackInfo.template,
6254
6413
  nestedTemplates: stackInfo.nestedTemplates ?? nullPrototypeRecord(),
@@ -6723,7 +6882,7 @@ async function scrubCommand(stacks, options) {
6723
6882
  if (allStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
6724
6883
  let targetStacks;
6725
6884
  if (options.all) targetStacks = allStacks;
6726
- else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns);
6885
+ else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
6727
6886
  else if (allStacks.length === 1) targetStacks = allStacks;
6728
6887
  else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all`);
6729
6888
  if (targetStacks.length === 0) {
@@ -6805,10 +6964,10 @@ async function scrubCommand(stacks, options) {
6805
6964
  logger,
6806
6965
  siblings: allStacks.filter((s) => !s.region).map((s) => s.stackName)
6807
6966
  });
6808
- const stackRegions = new Map(await Promise.all(targetStacks.map(async (stack) => [stack.stackName, await regionForStack(stack.stackName, stack.region)])));
6967
+ const stackRegions = new Map(await Promise.all(targetStacks.map(async (stack) => [stack, await regionForStack(stack.stackName, stack.region)])));
6809
6968
  const work = targetStacks.map((stack) => ({
6810
6969
  stackName: stack.stackName,
6811
- region: stackRegions.get(stack.stackName) ?? region,
6970
+ region: stackRegions.get(stack) ?? region,
6812
6971
  load: () => {
6813
6972
  const defect = stack.nestedTemplates ? findNestedTemplateTreeDefect(stack.nestedTemplates) : void 0;
6814
6973
  if (defect) throw new ScrubRefusalError(renderNestedTemplateTreeDefect(defect, stack.stackName, "scrub it or any stack nested under it; no state was written"), "SCRUB_NESTED_TEMPLATE_TREE_MALFORMED");
@@ -6910,8 +7069,9 @@ async function scrubCommand(stacks, options) {
6910
7069
  const parentName = item.parentRow.stackName;
6911
7070
  const row = `${displayStackName(parentName)} (row ${displayIdent(item.parentRow.logicalId)})`;
6912
7071
  if (repaired.changed > 0) {
6913
- if (!rewrittenStacks.has(parentName)) totalStacksScrubbed++;
6914
- rewrittenStacks.add(parentName);
7072
+ const parentKey = producerRecordKey(parentName, stackRegion);
7073
+ if (!rewrittenStacks.has(parentKey)) totalStacksScrubbed++;
7074
+ rewrittenStacks.add(parentKey);
6915
7075
  logger.info(safeMsg`${options.dryRun ? "Would scrub" : "Scrubbed"} ${repaired.changed} nested-stack output attribute(s) in ${row}, from ${shownStack}'s outputs`);
6916
7076
  }
6917
7077
  if (repaired.unmatched.length > 0) {
@@ -6923,10 +7083,11 @@ async function scrubCommand(stacks, options) {
6923
7083
  if (!failures.some((f) => f.stackName === label)) failures.push({ stackName: label });
6924
7084
  logger.error(safeMsg`Scrub of ${displayStackName(item.parentRow.stackName)}'s nested-stack output attributes for ${shownStack} failed: ${describeFailure(err)}`);
6925
7085
  }
6926
- if (scrubbed.historyPurged) historyPurgedStacks.add(stackName);
7086
+ const recordKey = producerRecordKey(stackName, stackRegion);
7087
+ if (scrubbed.historyPurged) historyPurgedStacks.add(recordKey);
6927
7088
  if (scrubbed.recordsChanged > 0) {
6928
- if (!rewrittenStacks.has(stackName)) totalStacksScrubbed++;
6929
- rewrittenStacks.add(stackName);
7089
+ if (!rewrittenStacks.has(recordKey)) totalStacksScrubbed++;
7090
+ rewrittenStacks.add(recordKey);
6930
7091
  logger.info(`${options.dryRun ? "Would scrub" : "Scrubbed"} ${scrubbed.recordsChanged} resource record(s) in ${shownStack}`);
6931
7092
  } else if (scrubbed.secretBearingKeys === 0 && scrubbed.unverifiableReads === 0 && scrubbed.unverifiableLeaves === 0 && scrubbed.unrepairedReadNames === 0 && (scrubbed.keptReadOutputKeys ?? 0) === 0 && (scrubbed.keptAliasOutputKeys ?? 0) === 0 && !scrubbed.droppedOutputReadersUnverified && indexAbsentWithSecret === 0 && indexConverged === 0) logger.info(scrubbed.nestedChildren.some((child) => Boolean(child.input)) ? `No plaintext secrets found in ${shownStack}'s own records${SCRUB_CLEAN_SCOPE_NOTE}; its nested-stack output attributes are checked after each nested stack` : `No plaintext secrets found in ${shownStack}${SCRUB_CLEAN_SCOPE_NOTE}`);
6932
7093
  if (scrubbed.malformedResources || scrubbed.malformedResourceRows) malformedRecords.push(stackName);
@@ -9277,7 +9438,6 @@ function canonicalizeIpProtocols(baseline, aws, resourceType) {
9277
9438
  //#region src/analyzer/drift-cc-api-deny-list.ts
9278
9439
  const CC_API_FALLBACK_DENY_LIST = {
9279
9440
  "AWS::ApiGateway::RestApi": "Body / BodyS3Location are write-only inputs not returned by CC API GetResource; cdkd state preserves them",
9280
- "AWS::Budgets::Budget": "CC API GetResource reorders notification subscribers and adds the defaulted ThresholdType, so an unchanged budget diffs as drift",
9281
9441
  "AWS::CloudFormation::Stack": "cdkd deploys nested stacks itself: no CloudFormation stack exists, and the physicalId is a cdkd-local placeholder ARN",
9282
9442
  "AWS::CloudWatch::AnomalyDetector": "the physicalId is a cdkd-derived metric descriptor, not the primaryIdentifier Cloud Control's GetResource requires",
9283
9443
  "AWS::EMR::InstanceFleetConfig": "the physicalId is the bare fleet id, not the composite primaryIdentifier Cloud Control's GetResource requires",
@@ -12892,6 +13052,7 @@ async function destroyCommand(stackArgs, options) {
12892
13052
  displayName: s.displayName,
12893
13053
  ...s.stagePath !== void 0 && { stagePath: s.stagePath },
12894
13054
  ...s.region && { region: s.region },
13055
+ ...s.account && { account: s.account },
12895
13056
  ...s.terminationProtection !== void 0 && { terminationProtection: s.terminationProtection },
12896
13057
  template: s.template,
12897
13058
  ...s.nestedTemplates !== void 0 && { nestedTemplates: s.nestedTemplates }
@@ -12946,18 +13107,23 @@ async function destroyCommand(stackArgs, options) {
12946
13107
  let interrupted = false;
12947
13108
  const runInterrupted = () => interrupted || interruptWatch.interrupted();
12948
13109
  let stoppedEarly = false;
12949
- let stackNames;
13110
+ const appStackSet = new Set(appStacks);
13111
+ const toTarget = (s) => ({
13112
+ stackName: s.stackName,
13113
+ synth: appStackSet.has(s) ? s : void 0
13114
+ });
13115
+ let targets;
12950
13116
  const namesAppStack = /* @__PURE__ */ new Set();
12951
13117
  if (options.all) {
12952
13118
  const { topLevel, inStages } = partitionTopLevel(candidateStacks);
12953
13119
  if (inStages.length > 0) logger.warn(renderAllLeftOutStageStacks(inStages));
12954
- stackNames = topLevel.map((s) => s.stackName);
13120
+ targets = topLevel.map(toTarget);
12955
13121
  } else if (stackPatterns.length > 0) {
12956
13122
  const selectFrom = appStacks.length > 0 ? appStacks : candidateStacks;
12957
13123
  const inState = new Set(candidateStacks.map((s) => s.stackName));
12958
- stackNames = matchStacks(selectFrom, stackPatterns).map((s) => s.stackName).filter((n) => inState.has(n));
13124
+ targets = matchStacks(selectFrom, stackPatterns, { dedupe: "identity" }).filter((s) => inState.has(s.stackName)).map(toTarget);
12959
13125
  if (appStacks.length > 0) {
12960
- const gone = stacksNoLongerSelected(candidateStacks, stackPatterns, new Set(stackNames));
13126
+ const gone = stacksNoLongerSelected(candidateStacks, stackPatterns, new Set(targets.map((t) => t.stackName)));
12961
13127
  if (gone.stacks.length > 0) logger.warn(renderStacksNoLongerSelected(gone.patterns, gone.stacks));
12962
13128
  }
12963
13129
  const stateNames = new Set(allStateRefs.map((r) => r.stackName));
@@ -12968,13 +13134,13 @@ async function destroyCommand(stackArgs, options) {
12968
13134
  const inStateOnly = unmatched.filter((p) => stateNames.has(p) && !namesAppStack.has(p));
12969
13135
  const absent = unmatched.filter((p) => !inStateOnly.includes(p));
12970
13136
  if (absent.length > 0) logger.warn(renderUnmatchedPatternsWarning(absent, "in state"));
12971
- if (stackNames.length > 0 && inStateOnly.length > 0) logger.warn(renderNotInAppWarning(inStateOnly));
12972
- } else if (candidateStacks.length === 1) stackNames = candidateStacks.map((s) => s.stackName);
13137
+ if (targets.length > 0 && inStateOnly.length > 0) logger.warn(renderNotInAppWarning(inStateOnly));
13138
+ } else if (candidateStacks.length === 1) targets = candidateStacks.map(toTarget);
12973
13139
  else if (candidateStacks.length === 0) {
12974
13140
  logger.info("No stacks found in state");
12975
13141
  return;
12976
13142
  } else throw new Error(`Multiple stacks found: ${candidateStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all (top-level stacks; '**' for every stack)`);
12977
- if (stackNames.length === 0) {
13143
+ if (targets.length === 0) {
12978
13144
  if (stackPatterns.length > 0) {
12979
13145
  const allStateNamesSet = new Set(allStateRefs.map((r) => r.stackName));
12980
13146
  const notInApp = [];
@@ -12996,12 +13162,22 @@ async function destroyCommand(stackArgs, options) {
12996
13162
  logger.info("No matching stacks found in state");
12997
13163
  return;
12998
13164
  }
12999
- if (synthScanStacks.length > 0 && stackNames.length > 1) {
13000
- const inSet = new Set(stackNames);
13001
- const inferred = inferCrossStackStackDeps(synthScanStacks.filter((s) => inSet.has(s.stackName)));
13002
- stackNames = orderConsumersBeforeProducers(stackNames, inferred);
13003
- }
13004
- logger.info(`Found ${stackNames.length} stack(s) to destroy: ${stackNames.map((n) => displaySafe(n)).join(", ")}`);
13165
+ const uniqueNames = [...new Set(targets.map((t) => t.stackName))];
13166
+ if (synthScanStacks.length > 0 && uniqueNames.length > 1) {
13167
+ const inSet = new Set(uniqueNames);
13168
+ targets = orderConsumersBeforeProducers(uniqueNames, inferCrossStackStackDeps(synthScanStacks.filter((s) => inSet.has(s.stackName)))).flatMap((name) => targets.filter((t) => t.stackName === name));
13169
+ }
13170
+ const sharedAppNames = new Set(appStacks.map((s) => s.stackName).filter((name, i, names) => names.indexOf(name) !== i));
13171
+ const strictRegion = /* @__PURE__ */ new Map();
13172
+ for (const target of targets) {
13173
+ if (!sharedAppNames.has(target.stackName) || target.synth === void 0) continue;
13174
+ strictRegion.set(target, target.synth.region ?? await regionForStack(target.stackName));
13175
+ }
13176
+ const strictBySynth = new Map(targets.flatMap((t) => t.synth !== void 0 && strictRegion.has(t) ? [[t.synth, strictRegion.get(t)]] : []));
13177
+ const strictNames = new Set([...strictBySynth.keys()].map((s) => s.stackName));
13178
+ refuseStackNameRegionCollisions(appStacks.filter((s) => strictBySynth.has(s) || strictNames.has(s.stackName) && s.region !== void 0), (s) => strictBySynth.get(s) ?? s.region, new Set(strictBySynth.keys()));
13179
+ const describeTarget = (t) => t.synth !== void 0 && strictRegion.has(t) ? `${describeStack(t.synth)} in ${displaySafe(strictRegion.get(t))}` : displaySafe(t.stackName);
13180
+ logger.info(`Found ${targets.length} stack(s) to destroy: ${targets.map(describeTarget).join(", ")}`);
13005
13181
  const accountId = "unknown";
13006
13182
  const stateRefsByName = /* @__PURE__ */ new Map();
13007
13183
  for (const ref of allStateRefs) {
@@ -13010,20 +13186,46 @@ async function destroyCommand(stackArgs, options) {
13010
13186
  stateRefsByName.set(ref.stackName, arr);
13011
13187
  }
13012
13188
  const crossPrefixCheck = { cache: new CrossPrefixGuard(stateBackend) };
13013
- if (stackNames.length > 1) deferRegistryTail = (released) => deferredTails.push(released);
13189
+ if (targets.length > 1) deferRegistryTail = (released) => deferredTails.push(released);
13014
13190
  const fallbackRegionByName = /* @__PURE__ */ new Map();
13015
- for (const name of stackNames) if ((stateRefsByName.get(name) ?? []).some((r) => !r.region)) fallbackRegionByName.set(name, await regionForStack(name));
13016
- for (const name of stackNames) {
13017
- const synth = appStacks.find((s) => s.stackName === name);
13018
- if (synth?.terminationProtection === true && !options.removeProtection) continue;
13019
- const planned = plannedDestroyRegion(stateRefsByName.get(name) ?? [], synth?.region, fallbackRegionByName.get(name) ?? region);
13020
- if (planned !== void 0) crossPrefixCheck.cache.full(name, planned, "prestart");
13191
+ for (const name of uniqueNames) if ((stateRefsByName.get(name) ?? []).some((r) => !r.region)) fallbackRegionByName.set(name, await regionForStack(name));
13192
+ const wrongAccount = /* @__PURE__ */ new Set();
13193
+ let callerAccountUnreadable = false;
13194
+ const accountPinned = [...strictRegion.keys()].filter((t) => t.synth?.account !== void 0);
13195
+ if (accountPinned.length > 0) {
13196
+ let callerAccount;
13197
+ callerAccountUnreadable = true;
13198
+ try {
13199
+ const { GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
13200
+ callerAccount = (await awsClients.sts.send(new GetCallerIdentityCommand({}))).Account;
13201
+ callerAccountUnreadable = callerAccount === void 0;
13202
+ } catch (err) {
13203
+ logger.debug(safeMsg`Could not read the caller account: ${describeAwsFailure(err).detail}`);
13204
+ }
13205
+ for (const t of accountPinned) if (t.synth.account !== callerAccount) wrongAccount.add(t);
13021
13206
  }
13022
- for (const [stackIndex, stackName] of stackNames.entries()) {
13023
- logger.info(`\nPreparing to destroy stack: ${displaySafe(stackName)}`);
13207
+ const plannedRegionFor = (target) => {
13208
+ if (wrongAccount.has(target)) return void 0;
13209
+ const refs = stateRefsByName.get(target.stackName) ?? [];
13210
+ const strict = strictRegion.get(target);
13211
+ if (strict !== void 0) return refs.some((r) => r.region === strict) ? strict : void 0;
13212
+ return plannedDestroyRegion(refs, target.synth?.region, fallbackRegionByName.get(target.stackName) ?? region);
13213
+ };
13214
+ for (const target of targets) {
13215
+ if (target.synth?.terminationProtection === true && !options.removeProtection) continue;
13216
+ const planned = plannedRegionFor(target);
13217
+ if (planned !== void 0) crossPrefixCheck.cache.full(target.stackName, planned, "prestart");
13218
+ }
13219
+ for (const [stackIndex, target] of targets.entries()) {
13220
+ const stackName = target.stackName;
13221
+ logger.info(`\nPreparing to destroy stack: ${describeTarget(target)}`);
13222
+ if (wrongAccount.has(target)) {
13223
+ logger.error(callerAccountUnreadable ? safeMsg` ✗ Stack ${describeTarget(target)} is pinned to account ${target.synth.account}, and the account this run's credentials resolve to could not be read (STS GetCallerIdentity failed), so it was not destroyed: another stack of the app shares its name, and only that account's credentials address its record. Check the credentials (aws sts get-caller-identity) and re-run destroy.` : safeMsg` ✗ Stack ${describeTarget(target)} is pinned to account ${target.synth.account}, which is not the account this run's credentials resolve to; not destroyed. Run destroy with that account's credentials.`);
13224
+ totalErrors++;
13225
+ continue;
13226
+ }
13024
13227
  const refs = stateRefsByName.get(stackName) ?? [];
13025
- const synthStack = appStacks.find((s) => s.stackName === stackName);
13026
- const synthRegion = synthStack?.region;
13228
+ const synthStack = target.synth;
13027
13229
  if (synthStack?.terminationProtection === true) {
13028
13230
  if (options.removeProtection) logger.warn(`Stack ${displaySafe(stackName)} has terminationProtection: true — bypassing because --remove-protection set`);
13029
13231
  else {
@@ -13036,11 +13238,15 @@ async function destroyCommand(stackArgs, options) {
13036
13238
  continue;
13037
13239
  }
13038
13240
  }
13039
- const plannedRegion = plannedDestroyRegion(refs, synthRegion, fallbackRegionByName.get(stackName) ?? region);
13241
+ const plannedRegion = plannedRegionFor(target);
13242
+ const strict = strictRegion.get(target);
13040
13243
  let stackTargetRegion;
13041
13244
  if (refs.length === 0) {
13042
13245
  logger.warn(`No state found for stack ${displaySafe(stackName)}, skipping`);
13043
13246
  continue;
13247
+ } else if (strict !== void 0 && plannedRegion === void 0) {
13248
+ logger.warn(safeMsg`No state found for stack ${describeTarget(target)}, skipping`);
13249
+ continue;
13044
13250
  } else if (plannedRegion !== void 0) stackTargetRegion = plannedRegion;
13045
13251
  else {
13046
13252
  const regions = refs.map((r) => r.region === void 0 ? "(legacy)" : plainOrDescribed(r.region, "region")).join(", ");
@@ -13167,7 +13373,7 @@ async function destroyCommand(stackArgs, options) {
13167
13373
  interrupted: stackInterrupted || stackCancelled
13168
13374
  }, logger);
13169
13375
  if (runInterrupted()) {
13170
- if (stackIndex < stackNames.length - 1) stoppedEarly = true;
13376
+ if (stackIndex < targets.length - 1) stoppedEarly = true;
13171
13377
  break;
13172
13378
  }
13173
13379
  }
@@ -13402,60 +13608,6 @@ function mixedLeafSsmTokens(source) {
13402
13608
  return tokens;
13403
13609
  }
13404
13610
 
13405
- //#endregion
13406
- //#region src/cli/cdk-path.ts
13407
- function readCdkPath(resource) {
13408
- const meta = resource.Metadata;
13409
- if (!meta) return "";
13410
- const v = meta["aws:cdk:path"];
13411
- return typeof v === "string" ? v : "";
13412
- }
13413
- function readCdkPathOrUndefined(resource) {
13414
- const path = readCdkPath(resource);
13415
- return path === "" ? void 0 : path;
13416
- }
13417
- function buildCdkPathIndex(template) {
13418
- const index = /* @__PURE__ */ new Map();
13419
- for (const [logicalId, resource] of Object.entries(template.Resources)) {
13420
- if (resource.Type === "AWS::CDK::Metadata") continue;
13421
- const path = readCdkPath(resource);
13422
- if (path) index.set(path, logicalId);
13423
- }
13424
- return index;
13425
- }
13426
- function resolveCdkPathToLogicalIds(input, index) {
13427
- const seen = /* @__PURE__ */ new Map();
13428
- const prefix = `${input}/`;
13429
- for (const [path, logicalId] of index) if (path === input || path.startsWith(prefix)) {
13430
- if (!seen.has(logicalId)) seen.set(logicalId, path);
13431
- }
13432
- return [...seen.entries()].map(([logicalId, cdkPath]) => ({
13433
- logicalId,
13434
- cdkPath
13435
- }));
13436
- }
13437
- function stackForConstructPath(path, stacks) {
13438
- let best;
13439
- let bestRank = -1;
13440
- for (const s of stacks) {
13441
- const names = [[s.displayName, 1], [s.stackName, 0]];
13442
- for (const [name, preference] of names) {
13443
- if (typeof name !== "string" || name.length === 0) continue;
13444
- if (!path.startsWith(`${name}/`)) continue;
13445
- const rank = name.length * 2 + preference;
13446
- if (rank > bestRank) {
13447
- best = s;
13448
- bestRank = rank;
13449
- }
13450
- }
13451
- }
13452
- return best;
13453
- }
13454
- function stackForPathFormTarget(parsed, target, stacks) {
13455
- if (!parsed.isPath || parsed.pathOrId !== target) return void 0;
13456
- return stackForConstructPath(parsed.pathOrId, stacks);
13457
- }
13458
-
13459
13611
  //#endregion
13460
13612
  //#region src/analyzer/orphan-rewriter.ts
13461
13613
  const UNREADABLE_ORPHAN_RECORD_REASON = "the orphaned resource's state record is not a readable resource record (not an object, no resource type, or no physical id), so nothing in it can be substituted";
@@ -20724,7 +20876,7 @@ async function publishAssetsCommand(stacks, options) {
20724
20876
  let targetStacks;
20725
20877
  if (allStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
20726
20878
  if (options.all) targetStacks = allStacks;
20727
- else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns);
20879
+ else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
20728
20880
  else if (allStacks.length === 1) targetStacks = allStacks;
20729
20881
  else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all`);
20730
20882
  if (targetStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
@@ -22840,16 +22992,13 @@ function resolveLambdaTarget(target, stacks) {
22840
22992
  return extractLambdaProperties(stack, logicalId, resource, resources);
22841
22993
  }
22842
22994
  function pickStack$1(parsed, stacks, target) {
22843
- if (parsed.stackPattern === null) {
22844
- if (stacks.length === 1) return stacks[0];
22845
- throw new LocalInvokeResolutionError(`Multiple stacks in app, target '${parsed.pathOrId}' is missing a stack prefix. Use 'StackName:${parsed.pathOrId}' or 'StackName/...' (path form). Available stacks: ${stacks.map((s) => s.stackName).join(", ")}.`);
22995
+ const selection = selectTargetStack(parsed, target, stacks);
22996
+ switch (selection.kind) {
22997
+ case "found": return selection.stack;
22998
+ case "no-prefix": throw new LocalInvokeResolutionError(`Multiple stacks in app, target '${parsed.pathOrId}' is missing a stack prefix. Use 'StackName:${parsed.pathOrId}' or 'StackName/...' (path form). Available stacks: ${stacks.map(describeStack).join(", ")}.`);
22999
+ case "not-found": throw new LocalInvokeResolutionError(`Stack '${selection.pattern}' not found. Available stacks: ${stacks.map(describeStack).join(", ")}.`);
23000
+ case "ambiguous": throw new LocalInvokeResolutionError(renderAmbiguousTargetStack(selection.pattern, selection.matched));
22846
23001
  }
22847
- const byPrefix = stackForPathFormTarget(parsed, target, stacks);
22848
- if (byPrefix) return byPrefix;
22849
- const matched = matchStacks(stacks, [parsed.stackPattern]);
22850
- if (matched.length === 0) throw new LocalInvokeResolutionError(`Stack '${parsed.stackPattern}' not found. Available stacks: ${stacks.map((s) => s.stackName).join(", ")}.`);
22851
- if (matched.length > 1) throw new LocalInvokeResolutionError(`Stack pattern '${parsed.stackPattern}' matched ${matched.length} stacks: ` + matched.map((s) => s.stackName).join(", ") + ". Use a more specific pattern.");
22852
- return matched[0];
22853
23002
  }
22854
23003
  function extractLambdaProperties(stack, logicalId, resource, resources) {
22855
23004
  const props = resource.Properties ?? {};
@@ -23353,16 +23502,13 @@ function resolveEcsTaskTarget(target, stacks, context) {
23353
23502
  return extractTaskDefinitionProperties(stack, logicalId, resource, context);
23354
23503
  }
23355
23504
  function pickStack(parsed, stacks, target) {
23356
- if (parsed.stackPattern === null) {
23357
- if (stacks.length === 1) return stacks[0];
23358
- throw new EcsTaskResolutionError(`Multiple stacks in app, target '${parsed.pathOrId}' is missing a stack prefix. Use 'StackName:${parsed.pathOrId}' or 'StackName/...' (path form). Available stacks: ${stacks.map((s) => s.stackName).join(", ")}.`);
23505
+ const selection = selectTargetStack(parsed, target, stacks);
23506
+ switch (selection.kind) {
23507
+ case "found": return selection.stack;
23508
+ case "no-prefix": throw new EcsTaskResolutionError(`Multiple stacks in app, target '${parsed.pathOrId}' is missing a stack prefix. Use 'StackName:${parsed.pathOrId}' or 'StackName/...' (path form). Available stacks: ${stacks.map(describeStack).join(", ")}.`);
23509
+ case "not-found": throw new EcsTaskResolutionError(`Stack '${selection.pattern}' not found. Available stacks: ${stacks.map(describeStack).join(", ")}.`);
23510
+ case "ambiguous": throw new EcsTaskResolutionError(renderAmbiguousTargetStack(selection.pattern, selection.matched));
23359
23511
  }
23360
- const byPrefix = stackForPathFormTarget(parsed, target, stacks);
23361
- if (byPrefix) return byPrefix;
23362
- const matched = matchStacks(stacks, [parsed.stackPattern]);
23363
- if (matched.length === 0) throw new EcsTaskResolutionError(`Stack '${parsed.stackPattern}' not found. Available stacks: ${stacks.map((s) => s.stackName).join(", ")}.`);
23364
- if (matched.length > 1) throw new EcsTaskResolutionError(`Stack pattern '${parsed.stackPattern}' matched ${matched.length} stacks: ` + matched.map((s) => s.stackName).join(", ") + ". Use a more specific pattern.");
23365
- return matched[0];
23366
23512
  }
23367
23513
  function extractTaskDefinitionProperties(stack, logicalId, resource, context) {
23368
23514
  const props = resource.Properties ?? {};
@@ -25213,7 +25359,7 @@ async function localStartApiCommand(target, options) {
25213
25359
  const layerTmpDirs = /* @__PURE__ */ new Set();
25214
25360
  let profileCredsFile;
25215
25361
  let credsHostPath;
25216
- const authorizerCache = createAuthorizerCache();
25362
+ const authorizerCaches = /* @__PURE__ */ new Map();
25217
25363
  const jwksCache = createJwksCache();
25218
25364
  const jwksWarnedAt = /* @__PURE__ */ new Map();
25219
25365
  let sigV4CredentialsLoader;
@@ -25246,23 +25392,11 @@ async function localStartApiCommand(target, options) {
25246
25392
  if (wsDiscovery.errors.length > 0) for (const e of wsDiscovery.errors) logger.warn(`WebSocket discovery: ${e}`);
25247
25393
  const webSocketApis = wsDiscovery.apis;
25248
25394
  if (routes.length === 0 && webSocketApis.length === 0) throw new Error("No supported API routes were discovered. cdkd local start-api supports AWS::ApiGateway::* (REST v1), AWS::ApiGatewayV2::* (HTTP + WebSocket), and AWS::Lambda::Url (Function URL) with AWS_PROXY integrations only.");
25249
- const stageMap = /* @__PURE__ */ new Map();
25250
- for (const stack of targetStacks) {
25251
- const m = buildStageMap(stack.template, options.stage);
25252
- for (const [k, v] of m) stageMap.set(k, v);
25253
- }
25254
- if (options.stage) {
25255
- const missingApis = /* @__PURE__ */ new Set();
25256
- for (const r of routes) {
25257
- if (!r.apiLogicalId) continue;
25258
- if (!stageMap.has(r.apiLogicalId)) missingApis.add(r.apiLogicalId);
25259
- }
25260
- for (const apiId of missingApis) logger.warn(`--stage '${options.stage}' did not match any Stage on API '${apiId}'; routes on that API will get stageVariables: null.`);
25261
- }
25262
- attachStageContext(routes, stageMap);
25395
+ const missingApis = attachStageContextPerStack(targetStacks, routes, options.stage);
25396
+ for (const apiId of missingApis) logger.warn(`--stage '${options.stage}' did not match any Stage on API '${apiId}'; routes on that API will get stageVariables: null.`);
25263
25397
  let routesWithAuth = attachAuthorizers(targetStacks, routes);
25264
25398
  if (apiFilter !== void 0) {
25265
- if (!apiFilter.includes(":") && !apiFilter.includes("/") && targetStacks.length > 1) throw new Error(`Multiple stacks in app, target '${apiFilter}' is missing a stack prefix. Use 'StackName:${apiFilter}' or 'StackName/${apiFilter}' (Construct path form). Available stacks: ${targetStacks.map((s) => s.stackName).join(", ")}.`);
25399
+ if (!apiFilter.includes(":") && !apiFilter.includes("/") && targetStacks.length > 1) throw new Error(`Multiple stacks in app, target '${apiFilter}' is missing a stack prefix. Use 'StackName:${apiFilter}' or 'StackName/${apiFilter}' (Construct path form). Available stacks: ${targetStacks.map(describeStack).join(", ")}.`);
25266
25400
  const filtered = filterRoutesByApiIdentifier(routesWithAuth, apiFilter);
25267
25401
  if (filtered.length === 0) {
25268
25402
  const available = availableApiIdentifiers(routesWithAuth).join(", ") || "(none)";
@@ -25270,13 +25404,11 @@ async function localStartApiCommand(target, options) {
25270
25404
  }
25271
25405
  routesWithAuth = filtered;
25272
25406
  }
25273
- const corsConfigByApiId = /* @__PURE__ */ new Map();
25274
- for (const stack of targetStacks) {
25275
- const fromCloudFront = buildCorsConfigFromCloudFrontChain(stack.template);
25276
- for (const [k, v] of fromCloudFront) corsConfigByApiId.set(k, v);
25277
- const direct = buildCorsConfigByApiId(stack.template);
25278
- for (const [k, v] of direct) corsConfigByApiId.set(k, v);
25279
- }
25407
+ assertServedLogicalIdsUnambiguous(targetStacks, routes, routesWithAuth, webSocketApis, {
25408
+ ...options.assumeRole !== void 0 && { assumeRole: options.assumeRole },
25409
+ ...overrides !== void 0 && { overrides }
25410
+ });
25411
+ const corsConfigByStack = buildCorsConfigByStack(targetStacks);
25280
25412
  const stateByStack = options.fromState || isCfnFlagPresent(options) ? await loadStateForRoutedStacks(targetStacks, routes, routesWithAuth, options) : /* @__PURE__ */ new Map();
25281
25413
  const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
25282
25414
  if (options.profile && profileCredentials && !profileCredsFile) profileCredsFile = await writeProfileCredentialsFile(options.profile, profileCredentials, {
@@ -25287,36 +25419,30 @@ async function localStartApiCommand(target, options) {
25287
25419
  credsHostPath = void 0;
25288
25420
  }
25289
25421
  });
25290
- const lambdaIds = uniqueLambdaIds(routes, routesWithAuth, webSocketApis);
25291
- const specs = /* @__PURE__ */ new Map();
25292
- for (let i = 0; i < lambdaIds.length; i++) {
25293
- const logicalId = lambdaIds[i];
25294
- const spec = await buildContainerSpec({
25295
- logicalId,
25296
- stacks: targetStacks,
25297
- overrides,
25298
- assumeRole: options.assumeRole,
25299
- containerHost: options.containerHost,
25300
- ...debugPortBase !== void 0 && { debugPort: debugPortBase + i },
25301
- stsRegion: canonicalizeRegion(options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"]),
25302
- inlineTmpDirs,
25303
- layerTmpDirs,
25304
- stateByStack,
25305
- skipPull: options.pull === false,
25306
- ...options.layerRoleArn !== void 0 && { layerRoleArn: options.layerRoleArn },
25307
- ...profileCredentials && { profileCredentials },
25308
- ...profileCredsFile && { profileCredsFile },
25309
- ...dynamicReferenceSpecOptions(options)
25310
- });
25311
- specs.set(logicalId, spec);
25312
- }
25422
+ const specs = await buildServedLambdaSpecs(targetStacks, routes, routesWithAuth, webSocketApis, ({ logicalId, stacks, index }) => buildContainerSpec({
25423
+ logicalId,
25424
+ stacks,
25425
+ overrides,
25426
+ assumeRole: options.assumeRole,
25427
+ containerHost: options.containerHost,
25428
+ ...debugPortBase !== void 0 && { debugPort: debugPortBase + index },
25429
+ stsRegion: canonicalizeRegion(options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"]),
25430
+ inlineTmpDirs,
25431
+ layerTmpDirs,
25432
+ stateByStack,
25433
+ skipPull: options.pull === false,
25434
+ ...options.layerRoleArn !== void 0 && { layerRoleArn: options.layerRoleArn },
25435
+ ...profileCredentials && { profileCredentials },
25436
+ ...profileCredsFile && { profileCredsFile },
25437
+ ...dynamicReferenceSpecOptions(options)
25438
+ }));
25313
25439
  const distinctImages = /* @__PURE__ */ new Set();
25314
25440
  for (const spec of specs.values()) if (spec.kind === "zip") distinctImages.add(resolveRuntimeImage(spec.lambda.runtime));
25315
25441
  for (const image of distinctImages) await pullImage(image, options.pull === false);
25316
25442
  return {
25317
25443
  routes: routesWithAuth,
25318
25444
  specs,
25319
- corsConfigByApiId,
25445
+ corsConfigByStack,
25320
25446
  webSocketApis,
25321
25447
  stacks: targetStacks
25322
25448
  };
@@ -25335,7 +25461,7 @@ async function localStartApiCommand(target, options) {
25335
25461
  };
25336
25462
  const initialMaterial = await synthesizeAndBuild();
25337
25463
  await prewarmJwks(initialMaterial.routes, jwksCache);
25338
- warnVpcConfigLambdas(initialMaterial.routes, initialMaterial.stacks ?? []);
25464
+ warnVpcConfigLambdas(initialMaterial.routes, initialMaterial.stacks);
25339
25465
  sigV4CredentialsLoader = defaultCredentialsLoader();
25340
25466
  warnIamRoutes(initialMaterial.routes);
25341
25467
  let maxTimeoutSec = 0;
@@ -25349,12 +25475,12 @@ async function localStartApiCommand(target, options) {
25349
25475
  const servers = [];
25350
25476
  let nextPort = basePort;
25351
25477
  for (const group of initialGroups) {
25352
- const groupSpecs = filterSpecsForGroup(group, initialMaterial.specs);
25478
+ const groupSpecs = filterSpecsForGroup(group, initialMaterial);
25353
25479
  const groupPool = buildPool(groupSpecs);
25354
25480
  const groupState = {
25355
25481
  routes: group.routes,
25356
25482
  pool: groupPool,
25357
- corsConfigByApiId: initialMaterial.corsConfigByApiId
25483
+ corsConfigByApiId: corsConfigForGroup(group, initialMaterial)
25358
25484
  };
25359
25485
  if (options.warm) {
25360
25486
  logger.info(`Pre-warming ${groupSpecs.size} container(s) for ${group.displayName}...`);
@@ -25369,7 +25495,7 @@ async function localStartApiCommand(target, options) {
25369
25495
  host: options.host,
25370
25496
  ...mtlsConfig && { mtls: mtlsConfig },
25371
25497
  port: basePort === 0 ? 0 : nextPort,
25372
- authorizerCache,
25498
+ authorizerCache: perStack(authorizerCaches, groupStackName(group, initialMaterial.stacks), createAuthorizerCache),
25373
25499
  jwksCache,
25374
25500
  jwksWarnedAt,
25375
25501
  sigV4CredentialsLoader,
@@ -25393,12 +25519,7 @@ async function localStartApiCommand(target, options) {
25393
25519
  }
25394
25520
  for (const api of initialWsApis) {
25395
25521
  if (api.unsupported) continue;
25396
- const wsLambdaIds = new Set(api.routes.map((r) => r.targetLambdaLogicalId));
25397
- const wsSpecs = /* @__PURE__ */ new Map();
25398
- for (const id of wsLambdaIds) {
25399
- const spec = initialMaterial.specs.get(id);
25400
- if (spec) wsSpecs.set(id, spec);
25401
- }
25522
+ const wsSpecs = filterSpecsForWebSocketApi(api, initialMaterial);
25402
25523
  if (wsSpecs.size === 0) {
25403
25524
  logger.warn(`WebSocket API ${api.declaredAt}: no resolvable Lambda backing routes; skipping.`);
25404
25525
  continue;
@@ -25416,7 +25537,7 @@ async function localStartApiCommand(target, options) {
25416
25537
  rieTimeoutMs,
25417
25538
  host: options.host,
25418
25539
  port: basePort === 0 ? 0 : nextPort,
25419
- authorizerCache,
25540
+ authorizerCache: perStack(authorizerCaches, api.apiStackName, createAuthorizerCache),
25420
25541
  jwksCache,
25421
25542
  jwksWarnedAt,
25422
25543
  sigV4WarnedForeignIds,
@@ -25441,9 +25562,7 @@ async function localStartApiCommand(target, options) {
25441
25562
  host: "host.docker.internal",
25442
25563
  ip: "host-gateway"
25443
25564
  }];
25444
- for (const id of wsLambdaIds) {
25445
- const spec = initialMaterial.specs.get(id);
25446
- if (!spec) continue;
25565
+ for (const spec of wsSpecs.values()) {
25447
25566
  spec.env["AWS_ENDPOINT_URL_APIGATEWAYMANAGEMENTAPI"] = mgmtEndpoint;
25448
25567
  if (!spec.env["AWS_ACCESS_KEY_ID"]) {
25449
25568
  spec.env["AWS_ACCESS_KEY_ID"] = "AKIAIOSFODNN7EXAMPLE";
@@ -25609,12 +25728,14 @@ function installFatalShutdownHandlers(logger, shutdown) {
25609
25728
  }
25610
25729
  function targetStackHint(target, stacks) {
25611
25730
  if (target?.includes("/") !== true) return void 0;
25612
- return stackForConstructPath(target, stacks) ?? target.slice(0, target.indexOf("/"));
25731
+ const stack = stackForConstructPath(target, stacks);
25732
+ if (stack === void 0) return target.slice(0, target.indexOf("/"));
25733
+ return stackForConstructPath(target, [...stacks].reverse()) === stack ? stack : stack.stackName;
25613
25734
  }
25614
25735
  function pickTargetStacks(stacks, pattern, cfnStackFallback, targetFallback) {
25615
25736
  const effective = pattern ?? cfnStackFallback ?? targetFallback;
25616
25737
  if (effective !== void 0 && typeof effective !== "string") return [effective];
25617
- if (effective) return matchStacks(stacks, [effective]);
25738
+ if (effective) return matchStacks(stacks, [effective], { dedupe: "identity" });
25618
25739
  if (stacks.length === 1) return stacks;
25619
25740
  if (stacks.length === 0) return [];
25620
25741
  throw new Error(`Multi-stack app: pass --stack '<name>', --from-cfn-stack '<name>', or a stack-qualified target like "<StackName>/<construct>" to pick a target. Available stacks: ${stacks.map((s) => plainOrDescribed(s.stackName, "stack name")).join(", ")}.`);
@@ -25633,32 +25754,110 @@ function tryEmitFromCfnRedundancyTipOnce(fromCfnStack, routedStackNames, emitted
25633
25754
  emit(routedStackName);
25634
25755
  emittedRef.value = true;
25635
25756
  }
25636
- function uniqueLambdaIds(routes, routesWithAuth, webSocketApis = []) {
25757
+ const LAMBDA_FUNCTION_TYPE = "AWS::Lambda::Function";
25758
+ function stacksDeclaring(logicalId, stacks, type) {
25759
+ return stacks.filter((stack) => {
25760
+ const resource = stack.template.Resources?.[logicalId];
25761
+ return resource !== void 0 && (type === void 0 || resource.Type === type);
25762
+ });
25763
+ }
25764
+ function renderServeOneStackAdvice(stacks) {
25765
+ const example = stacks.find((s) => s.displayName && s.displayName !== s.stackName)?.displayName;
25766
+ return `Serve one stack at a time: pass --stack with its CDK path${example !== void 0 && displayIdent(example) === example ? ` (e.g. --stack '${example}')` : ""}, or a target starting with that path.`;
25767
+ }
25768
+ function lambdaOwners(ref, stacks) {
25769
+ if (ref.stackName !== void 0) {
25770
+ const own = stacks.filter((s) => s.stackName === ref.stackName);
25771
+ const declaring = stacksDeclaring(ref.logicalId, own, LAMBDA_FUNCTION_TYPE);
25772
+ if (declaring.length > 0) return declaring;
25773
+ }
25774
+ return stacksDeclaring(ref.logicalId, stacks, LAMBDA_FUNCTION_TYPE);
25775
+ }
25776
+ function servedLambdaKey(stackName, logicalId) {
25777
+ return `${stackName}:${logicalId}`;
25778
+ }
25779
+ function servedLambdaKeyFor(ref, stacks) {
25780
+ const owners = lambdaOwners(ref, stacks);
25781
+ return owners.length === 1 ? servedLambdaKey(owners[0].stackName, ref.logicalId) : void 0;
25782
+ }
25783
+ function routeStackName(route, stacks) {
25784
+ if (route.apiStackName !== void 0) return route.apiStackName;
25785
+ return stacks?.length === 1 ? stacks[0].stackName : void 0;
25786
+ }
25787
+ function groupStackName(group, stacks) {
25788
+ const route = group.routes[0]?.route;
25789
+ return route === void 0 ? void 0 : routeStackName(route, stacks);
25790
+ }
25791
+ function perStack(byStack, stackName, make) {
25792
+ const key = JSON.stringify(stackName ?? null);
25793
+ let value = byStack.get(key);
25794
+ if (value === void 0) {
25795
+ value = make();
25796
+ byStack.set(key, value);
25797
+ }
25798
+ return value;
25799
+ }
25800
+ function assertServedLogicalIdsUnambiguous(stacks, routes, routesWithAuth, webSocketApis = [], userIds = {}) {
25801
+ if (stacks.length < 2) return;
25802
+ const byName = /* @__PURE__ */ new Map();
25803
+ for (const stack of stacks) byName.set(stack.stackName, [...byName.get(stack.stackName) ?? [], stack]);
25804
+ for (const [name, sharing] of byName) if (sharing.length > 1) throw new Error(`The served stacks ${sharing.map(describeStack).join(", ")} share the physical stack name ${displayIdent(name)}, and cdkd local start-api reads each stack's deployed state by that name, so it cannot serve them together. ${renderServeOneStackAdvice(sharing)}`);
25805
+ const ownersById = /* @__PURE__ */ new Map();
25806
+ for (const ref of reachedLambdas(routes, routesWithAuth, webSocketApis)) {
25807
+ const owners = lambdaOwners(ref, stacks);
25808
+ if (owners.length > 1) throw new Error(`Lambda ${displayIdent(ref.logicalId)} is declared by ${owners.length} of the served stacks (${owners.map(describeStack).join(", ")}), and cdkd local start-api cannot tell which one its route reaches. ${renderServeOneStackAdvice(owners)}`);
25809
+ for (const owner of owners) {
25810
+ const list = ownersById.get(ref.logicalId) ?? [];
25811
+ if (!list.includes(owner)) list.push(owner);
25812
+ ownersById.set(ref.logicalId, list);
25813
+ }
25814
+ }
25815
+ const perLambda = userIds.assumeRole?.perLambda ?? {};
25816
+ for (const logicalId of Object.keys(perLambda)) {
25817
+ const owners = ownersById.get(logicalId) ?? [];
25818
+ if (owners.length < 2) continue;
25819
+ throw new Error(`--assume-role names Lambda ${displayIdent(logicalId)} by its bare logical ID, which ${owners.length} of the served stacks declare (${owners.map(describeStack).join(", ")}), so it does not say which one to assume the role for. ${renderServeOneStackAdvice(owners)}`);
25820
+ }
25821
+ for (const key of Object.keys(userIds.overrides ?? {})) {
25822
+ if (key === "Parameters") continue;
25823
+ const owners = ownersById.get(key) ?? [];
25824
+ if (owners.length < 2) continue;
25825
+ throw new Error(`--env-vars key ${displayIdent(key)} names a Lambda by its bare logical ID, which ${owners.length} of the served stacks declare (${owners.map(describeStack).join(", ")}), so it does not say which one it overrides. ${renderConstructPathKeyAdvice(key, owners)}`);
25826
+ }
25827
+ }
25828
+ function renderConstructPathKeyAdvice(logicalId, owners) {
25829
+ const paths = [];
25830
+ for (const owner of owners) {
25831
+ const resource = owner.template.Resources?.[logicalId];
25832
+ const path = resource ? readCdkPathOrUndefined(resource)?.replace(/\/Resource$/, "") : void 0;
25833
+ if (path !== void 0 && displayIdent(path) === path) paths.push(JSON.stringify(path));
25834
+ }
25835
+ return paths.length > 0 ? `Key it by the Lambda's construct path instead, which names one stack: ${paths.join(", ")}.` : `Key it by the Lambda's construct path instead, which names one stack.`;
25836
+ }
25837
+ function reachedLambdas(routes, routesWithAuth, webSocketApis = []) {
25637
25838
  const seen = /* @__PURE__ */ new Set();
25638
25839
  const out = [];
25840
+ const add = (stackName, logicalId) => {
25841
+ const key = JSON.stringify([stackName ?? null, logicalId]);
25842
+ if (seen.has(key)) return;
25843
+ seen.add(key);
25844
+ out.push({
25845
+ stackName,
25846
+ logicalId
25847
+ });
25848
+ };
25639
25849
  for (const r of routes) {
25640
25850
  if (r.unsupported || r.mockCors || r.serviceIntegration) continue;
25641
25851
  if (r.lambdaLogicalId.length === 0) continue;
25642
- if (!seen.has(r.lambdaLogicalId)) {
25643
- seen.add(r.lambdaLogicalId);
25644
- out.push(r.lambdaLogicalId);
25645
- }
25852
+ add(r.apiStackName, r.lambdaLogicalId);
25646
25853
  }
25647
25854
  for (const entry of routesWithAuth) {
25648
25855
  if (entry.route.unsupported || entry.route.mockCors || entry.route.serviceIntegration) continue;
25649
25856
  const auth = entry.authorizer;
25650
25857
  if (!auth) continue;
25651
- if (auth.kind === "lambda-token" || auth.kind === "lambda-request") {
25652
- if (!seen.has(auth.lambdaLogicalId)) {
25653
- seen.add(auth.lambdaLogicalId);
25654
- out.push(auth.lambdaLogicalId);
25655
- }
25656
- }
25657
- }
25658
- for (const api of webSocketApis) for (const r of api.routes) if (!seen.has(r.targetLambdaLogicalId)) {
25659
- seen.add(r.targetLambdaLogicalId);
25660
- out.push(r.targetLambdaLogicalId);
25858
+ if (auth.kind === "lambda-token" || auth.kind === "lambda-request") add(entry.route.apiStackName, auth.lambdaLogicalId);
25661
25859
  }
25860
+ for (const api of webSocketApis) for (const r of api.routes) add(r.lambdaStackName, r.targetLambdaLogicalId);
25662
25861
  return out;
25663
25862
  }
25664
25863
  async function prewarmJwks(routesWithAuth, jwksCache) {
@@ -25676,27 +25875,29 @@ async function prewarmJwks(routesWithAuth, jwksCache) {
25676
25875
  }
25677
25876
  function warnVpcConfigLambdas(routesWithAuth, stacks) {
25678
25877
  const logger = getLogger();
25679
- const seen = /* @__PURE__ */ new Set();
25680
- const reachable = [];
25681
- for (const entry of routesWithAuth) {
25682
- if (!seen.has(entry.route.lambdaLogicalId)) {
25683
- seen.add(entry.route.lambdaLogicalId);
25684
- reachable.push(entry.route.lambdaLogicalId);
25685
- }
25686
- const auth = entry.authorizer;
25687
- if (auth && (auth.kind === "lambda-token" || auth.kind === "lambda-request")) {
25688
- if (!seen.has(auth.lambdaLogicalId)) {
25689
- seen.add(auth.lambdaLogicalId);
25690
- reachable.push(auth.lambdaLogicalId);
25691
- }
25692
- }
25878
+ const warned = /* @__PURE__ */ new Set();
25879
+ const reached = [];
25880
+ for (const { route, authorizer: auth } of routesWithAuth) {
25881
+ reached.push({
25882
+ stackName: route.apiStackName,
25883
+ logicalId: route.lambdaLogicalId
25884
+ });
25885
+ if (auth && (auth.kind === "lambda-token" || auth.kind === "lambda-request")) reached.push({
25886
+ stackName: route.apiStackName,
25887
+ logicalId: auth.lambdaLogicalId
25888
+ });
25693
25889
  }
25694
- for (const logicalId of reachable) for (const stack of stacks) {
25695
- const resource = stack.template.Resources?.[logicalId];
25696
- if (!resource || resource.Type !== "AWS::Lambda::Function") continue;
25697
- const vpcConfig = (resource.Properties ?? {})["VpcConfig"];
25698
- if (vpcConfig && typeof vpcConfig === "object" && Object.keys(vpcConfig).length > 0) logger.warn(`Lambda ${logicalId} has VpcConfig — local container will reach external services via the host's network, NOT through the deployed VPC's NAT/private subnets. Calls to private RDS/ElastiCache will fail. See https://cdkd.dev/local-start-api/#vpc-config-lambdas for details.`);
25699
- break;
25890
+ for (const ref of reached) {
25891
+ const owner = lambdaOwners(ref, stacks)[0];
25892
+ if (owner === void 0) continue;
25893
+ const key = servedLambdaKey(owner.stackName, ref.logicalId);
25894
+ if (warned.has(key)) continue;
25895
+ warned.add(key);
25896
+ const vpcConfig = (owner.template.Resources?.[ref.logicalId]?.Properties ?? {})["VpcConfig"];
25897
+ if (vpcConfig && typeof vpcConfig === "object" && Object.keys(vpcConfig).length > 0) {
25898
+ const shown = stacks.length > 1 ? key : ref.logicalId;
25899
+ logger.warn(`Lambda ${shown} has VpcConfig — local container will reach external services via the host's network, NOT through the deployed VPC's NAT/private subnets. Calls to private RDS/ElastiCache will fail. See https://cdkd.dev/local-start-api/#vpc-config-lambdas for details.`);
25900
+ }
25700
25901
  }
25701
25902
  }
25702
25903
  function warnIamRoutes(routesWithAuth) {
@@ -25920,9 +26121,10 @@ async function materializeLambdaLayers$1(layers, layerTmpDirs, layerRoleArn) {
25920
26121
  return dir;
25921
26122
  }
25922
26123
  function resolveLambdaByLogicalId(logicalId, stacks) {
25923
- for (const stack of stacks) {
25924
- const resource = stack.template.Resources?.[logicalId];
25925
- if (!resource || resource.Type !== "AWS::Lambda::Function") continue;
26124
+ const owners = stacksDeclaring(logicalId, stacks, LAMBDA_FUNCTION_TYPE);
26125
+ if (owners.length > 1) throw new Error(`Lambda ${displayIdent(logicalId)} is declared by ${owners.length} stacks (${owners.map(describeStack).join(", ")}). ${renderServeOneStackAdvice(owners)}`);
26126
+ for (const stack of owners) {
26127
+ const resource = stack.template.Resources[logicalId];
25926
26128
  const props = resource.Properties ?? {};
25927
26129
  const memoryMb = typeof props["MemorySize"] === "number" ? props["MemorySize"] : 128;
25928
26130
  const timeoutSec = typeof props["Timeout"] === "number" ? props["Timeout"] : 3;
@@ -26167,20 +26369,78 @@ function parsePerLambdaConcurrency(raw) {
26167
26369
  }
26168
26370
  return parsed;
26169
26371
  }
26170
- function filterSpecsForGroup(group, allSpecs) {
26171
- const ids = /* @__PURE__ */ new Set();
26372
+ function attachStageContextPerStack(stacks, routes, stageOverride) {
26373
+ const missingApis = /* @__PURE__ */ new Set();
26374
+ for (const stack of stacks) {
26375
+ const stageMap = buildStageMap(stack.template, stageOverride);
26376
+ const own = routes.filter((r) => routeStackName(r, stacks) === stack.stackName);
26377
+ if (stageOverride) for (const r of own) {
26378
+ if (!r.apiLogicalId || stageMap.has(r.apiLogicalId)) continue;
26379
+ missingApis.add(stacks.length > 1 ? `${stack.stackName}:${r.apiLogicalId}` : r.apiLogicalId);
26380
+ }
26381
+ attachStageContext(own, stageMap);
26382
+ }
26383
+ return missingApis;
26384
+ }
26385
+ function buildCorsConfigByStack(stacks) {
26386
+ const out = /* @__PURE__ */ new Map();
26387
+ for (const stack of stacks) {
26388
+ const corsConfigByApiId = /* @__PURE__ */ new Map();
26389
+ for (const [k, v] of buildCorsConfigFromCloudFrontChain(stack.template)) corsConfigByApiId.set(k, v);
26390
+ for (const [k, v] of buildCorsConfigByApiId(stack.template)) corsConfigByApiId.set(k, v);
26391
+ out.set(stack.stackName, corsConfigByApiId);
26392
+ }
26393
+ return out;
26394
+ }
26395
+ async function buildServedLambdaSpecs(stacks, routes, routesWithAuth, webSocketApis, build) {
26396
+ const specs = /* @__PURE__ */ new Map();
26397
+ for (const ref of reachedLambdas(routes, routesWithAuth, webSocketApis)) {
26398
+ const owners = lambdaOwners(ref, stacks);
26399
+ const key = owners.length === 1 ? servedLambdaKey(owners[0].stackName, ref.logicalId) : void 0;
26400
+ if (key !== void 0 && specs.has(key)) continue;
26401
+ const spec = await build({
26402
+ logicalId: ref.logicalId,
26403
+ stacks: owners.length === 1 ? owners : stacks,
26404
+ index: specs.size
26405
+ });
26406
+ specs.set(key ?? ref.logicalId, spec);
26407
+ }
26408
+ return specs;
26409
+ }
26410
+ function filterSpecsForGroup(group, material) {
26411
+ const out = /* @__PURE__ */ new Map();
26412
+ const add = (stackName, logicalId) => {
26413
+ if (out.has(logicalId)) return;
26414
+ const key = servedLambdaKeyFor({
26415
+ stackName,
26416
+ logicalId
26417
+ }, material.stacks);
26418
+ const spec = key === void 0 ? void 0 : material.specs.get(key);
26419
+ if (spec) out.set(logicalId, spec);
26420
+ };
26172
26421
  for (const rwa of group.routes) {
26173
- ids.add(rwa.route.lambdaLogicalId);
26422
+ add(rwa.route.apiStackName, rwa.route.lambdaLogicalId);
26174
26423
  const auth = rwa.authorizer;
26175
- if (auth && (auth.kind === "lambda-token" || auth.kind === "lambda-request")) ids.add(auth.lambdaLogicalId);
26424
+ if (auth && (auth.kind === "lambda-token" || auth.kind === "lambda-request")) add(rwa.route.apiStackName, auth.lambdaLogicalId);
26176
26425
  }
26426
+ return out;
26427
+ }
26428
+ function filterSpecsForWebSocketApi(api, material) {
26177
26429
  const out = /* @__PURE__ */ new Map();
26178
- for (const id of ids) {
26179
- const spec = allSpecs.get(id);
26180
- if (spec) out.set(id, spec);
26430
+ for (const r of api.routes) {
26431
+ const key = servedLambdaKeyFor({
26432
+ stackName: r.lambdaStackName,
26433
+ logicalId: r.targetLambdaLogicalId
26434
+ }, material.stacks);
26435
+ const spec = key === void 0 ? void 0 : material.specs.get(key);
26436
+ if (spec) out.set(r.targetLambdaLogicalId, spec);
26181
26437
  }
26182
26438
  return out;
26183
26439
  }
26440
+ function corsConfigForGroup(group, material) {
26441
+ const stackName = groupStackName(group, material.stacks);
26442
+ return (stackName === void 0 ? void 0 : material.corsConfigByStack.get(stackName)) ?? /* @__PURE__ */ new Map();
26443
+ }
26184
26444
  function printPerServerRouteTables(servers) {
26185
26445
  for (const { group, server } of servers) {
26186
26446
  process.stdout.write(`\n${group.displayName} (http://${formatAuthority(server.host, server.port)})\n`);
@@ -26233,11 +26493,11 @@ async function reloadAllServers(args) {
26233
26493
  for (const booted of servers) {
26234
26494
  const group = newByKey.get(booted.group.serverKey);
26235
26495
  if (!group) continue;
26236
- const newPool = buildPool(filterSpecsForGroup(group, material.specs));
26496
+ const newPool = buildPool(filterSpecsForGroup(group, material));
26237
26497
  const newState = {
26238
26498
  routes: group.routes,
26239
26499
  pool: newPool,
26240
- corsConfigByApiId: material.corsConfigByApiId
26500
+ corsConfigByApiId: corsConfigForGroup(group, material)
26241
26501
  };
26242
26502
  const previousState = booted.server.setServerState(newState);
26243
26503
  booted.group = group;
@@ -26264,24 +26524,14 @@ function envHasIntrinsicValue$1(templateEnv) {
26264
26524
  async function loadStateForRoutedStacks(stacks, routes, routesWithAuth, options) {
26265
26525
  const logger = getLogger();
26266
26526
  const out = /* @__PURE__ */ new Map();
26267
- const lambdaIds = uniqueLambdaIds(routes, routesWithAuth);
26268
26527
  const reachableStackNames = /* @__PURE__ */ new Set();
26269
- for (const logicalId of lambdaIds) for (const stack of stacks) {
26270
- const resource = stack.template.Resources?.[logicalId];
26271
- if (resource && resource.Type === "AWS::Lambda::Function") {
26272
- reachableStackNames.add(stack.stackName);
26273
- break;
26274
- }
26528
+ const intrinsicEnvStacks = /* @__PURE__ */ new Set();
26529
+ for (const ref of reachedLambdas(routes, routesWithAuth)) for (const owner of lambdaOwners(ref, stacks)) {
26530
+ reachableStackNames.add(owner.stackName);
26531
+ const resource = owner.template.Resources?.[ref.logicalId];
26532
+ if (resource && envHasIntrinsicValue$1(getTemplateEnv$1(resource))) intrinsicEnvStacks.add(owner.stackName);
26275
26533
  }
26276
- const stackHasIntrinsicEnv = (stackName) => {
26277
- for (const logicalId of lambdaIds) for (const stack of stacks) {
26278
- if (stack.stackName !== stackName) continue;
26279
- const resource = stack.template.Resources?.[logicalId];
26280
- if (!resource || resource.Type !== "AWS::Lambda::Function") continue;
26281
- if (envHasIntrinsicValue$1(getTemplateEnv$1(resource))) return true;
26282
- }
26283
- return false;
26284
- };
26534
+ const stackHasIntrinsicEnv = (stackName) => intrinsicEnvStacks.has(stackName);
26285
26535
  rejectExplicitCfnStackWithMultipleStacks(options, reachableStackNames.size);
26286
26536
  for (const stackName of reachableStackNames) {
26287
26537
  const stack = stacks.find((s) => s.stackName === stackName);
@@ -27591,7 +27841,7 @@ function pickCandidateStack(parsed, target, stacks) {
27591
27841
  if (stacks.length === 1) return stacks[0];
27592
27842
  return;
27593
27843
  }
27594
- const matched = matchStacks(stacks, [stackPattern]);
27844
+ const matched = matchStacks(stacks, [stackPattern], { dedupe: "identity" });
27595
27845
  if (matched.length === 1) return matched[0];
27596
27846
  }
27597
27847
  async function resolveStackAccountId$1(source) {
@@ -29710,4 +29960,4 @@ function collectVerbFlags(program) {
29710
29960
 
29711
29961
  //#endregion
29712
29962
  export { resolveSecretDerivedPrincipals as a, buildProgram, isResolvableSecretPrincipalList as i, runDestroyForStack as n, canonicalizeIpProtocolValue as o, holdsUnprovenSecretPrincipalToken as r, resolvedResourceTimeoutMs as s, canonicalizeIpv4Cidr as t };
29713
- //# sourceMappingURL=program-DDJHp1K3.js.map
29963
+ //# sourceMappingURL=program-CAibYjpk.js.map