@go-to-k/cdkd 0.302.1 → 0.302.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/{asg-provider-BpRcm_UB.js → asg-provider-DCrwgSCZ.js} +27 -9
  2. package/dist/asg-provider-DCrwgSCZ.js.map +1 -0
  3. package/dist/cli.js +2 -2
  4. package/dist/{deploy-engine-CYVt2NQR.js → deploy-engine-D9SDE-Pj.js} +359 -4269
  5. package/dist/deploy-engine-D9SDE-Pj.js.map +1 -0
  6. package/dist/{iam-policy-targets-CmHNH1DY.js → iam-policy-targets-OtGPguLH.js} +3 -2
  7. package/dist/{iam-policy-targets-CmHNH1DY.js.map → iam-policy-targets-OtGPguLH.js.map} +1 -1
  8. package/dist/{iam-role-provider-R1GC6KcT.js → iam-role-provider-Q1sv3tF1.js} +9 -5
  9. package/dist/iam-role-provider-Q1sv3tF1.js.map +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +3 -3
  12. package/dist/{neptune-provider-DzTl6-74.js → neptune-provider-DjVgEWGf.js} +121 -11
  13. package/dist/neptune-provider-DjVgEWGf.js.map +1 -0
  14. package/dist/{program-CvRs5pV_.js → program-DSbJoNKe.js} +559 -305
  15. package/dist/program-DSbJoNKe.js.map +1 -0
  16. package/dist/{provider-classes-B2_u4Fg0.js → provider-classes-CDtquwkU.js} +673 -131
  17. package/dist/provider-classes-CDtquwkU.js.map +1 -0
  18. package/dist/{rds-provider-CmKbYAvr.js → rds-provider-ByCpdpUq.js} +208 -42
  19. package/dist/rds-provider-ByCpdpUq.js.map +1 -0
  20. package/dist/secret-redaction-BHWS-PZK.js +3937 -0
  21. package/dist/secret-redaction-BHWS-PZK.js.map +1 -0
  22. package/dist/{version-CaejipV3.js → version-DDpKuzTw.js} +2 -2
  23. package/dist/{version-CaejipV3.js.map → version-DDpKuzTw.js.map} +1 -1
  24. package/package.json +2 -2
  25. package/dist/asg-provider-BpRcm_UB.js.map +0 -1
  26. package/dist/deploy-engine-CYVt2NQR.js.map +0 -1
  27. package/dist/iam-role-provider-R1GC6KcT.js.map +0 -1
  28. package/dist/neptune-provider-DzTl6-74.js.map +0 -1
  29. package/dist/program-CvRs5pV_.js.map +0 -1
  30. package/dist/provider-classes-B2_u4Fg0.js.map +0 -1
  31. package/dist/rds-provider-CmKbYAvr.js.map +0 -1
@@ -1,9 +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-CmHNH1DY.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";
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 resolvePendingCloudControlRequests, $a as refuseMalformedOutputsForDestroy, $c as validateAssetBucketName, $i as carriesDynamicReference, $l as hasPlainPrototype, $n as noEchoParameterNamesOf, $o as templateResourceTypes, $r as customResourceResponseExpirationWarning, $s as recordPhysicalNameCopy, $t as nameGenerationHighWaterOf, A as inheritedProvenanceForChildDiff, Aa as malformedLocalResourcesWarning, Ac as importableOutputKeys, Ai as keepHeldTokenProvenance, Al as resolveSkipPrefix, An as destroyStackRecordsView, Ao as hasNoCloudControlHandlers, As as logOnlyValueCount, At as removeProtectionTypeList, B as conditionFingerprint, Ba as malformedResourcePropertiesWarning, Bc as WorkGraph, Bi as AWS_CREDENTIAL_ENV_KEYS, Bl as findLargeInlineResources, Bn as addSuperseded, Br as CC_BROKEN_REASON, Bs as scrubResourceRecord, Bt as resolveReplacementOldType, Ca as isReadableOrphanRecord, Cc as splitImportedOps, Cl as synthesisStatusMessage, Cn as DEFAULT_RESOURCE_TIMEOUT_MS, Co as unreadableResourceEntries, Cs as redactForState, Ct as formatResourceLine, D as IMPLICIT_DELETE_DEPENDENCIES, Da as malformedExportSourceWarning, Dc as hasReadableExportSet, Di as resolveDynamicReferences, Dl as resolveApp, Dn as findDestructiveChanges, Do as unwrittenCreateOnlyReplacement, Dr as DeploymentEventsStore, Ds as createUnionSecretMasker, Ea as malformedExportNamesWarning, Ec as exportNamesCarriedFrom, El as loadCdkJson, En as constructPathOf, Er as DeploymentEventsReader, Es as carryLogOnlyValues, F as findNestedTemplateTreeDefect, Fa as malformedOrphansWarning, Fc as shouldRetainResource, Fi as assertFlagRoleArn, Fl as warnDeprecatedNoPrefixCliFlag, Fn as cyan, Fo as isStatefulRecreateTargetSync, Fs as unionOfSecretBags, Ft as planFailedOps, G as diffSecurity, Ga as refuseDivergentRecordRegionForDestroy, Gc as AssetModeResolver, Gi as classifyReplaySecretRegion, Gl as PARTITION_TABLE, Gn as supersededAfterRollback, Gs as isUncertifiedBaselineMaskPosition, Gt as inheritProducerRegions, H as parentSuppliedValues, Ha as malformedScrubResourceEntriesRefusalMessage, Hc as createAssetRedirectResolver, Hi as callerEnvCredentials, Hl as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, Hn as holdsSupersededResources, Hr as ccBrokenReason, Ht as orphanNeedsIdentity, I as isAbsoluteAssetPath, Ia as malformedOutputsRefusalMessage, Ic as stackInstanceIdCarriedFrom, Ii as assertSendableRoleArn, Il as ssmResolvedValueType, In as gray, Io as renderStatefulReason, Is as createSecretMasker, It as planRollback, J as mergeNoChangeOutputs, Ja as refuseMalformedOrphanRecordsForDestroy, Jc as ensureAssetStorage, Ji as coerceParameterTypedValue, Jl as AssemblyReader, Jn as supersededResourcesOf, Jr as isCustomResourceType$1, Js as inheritNestedStackParameterAssociations, K as isSecretBearingReferenceString, Kc as BOOTSTRAP_MARKER_PREFIX, Ki as producerRegionsFromState, Kl as canonicalizeRegion, Kn as supersededHeldByOtherTypeWarning, Kr as TemplateNoEchoReresolver, Ks as pathCrossesDottedKey, L as listNestedTemplateRows, La as malformedOutputsWarning, Lc as AssetPublisher, Li as explicitRoleArnOrThrow, Ll as CFN_TEMPLATE_BODY_LIMIT, Ln as green, Ls as errorCauseChain, Lt as recheckFailedPlan, M as findServiceTokenRefusals, Ma as malformedOrphanRecordsWarning, Mc as isReadableBag, Mi as recordedOutputReferenceRegions, Ml as resolveStateBucketWithDefaultAndSource, Mn as withStackRecords, Mo as shownType, Ms as recordLogOnlyParameterValue, Mt as demoteSupersededOrphans, N as serviceTokenBlockingReason, Na as malformedOrphanRowsKeptWarning, Nc as orphansAfterRollback, Ni as recordedReferenceRegions, Nl as resolveUseCdkBootstrapAssets, No as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ns as recordLogOnlyValue, Nt as isJournaledOrphan, O as computeImplicitDeleteEdges, Oa as malformedLocalOutputsWarning, Oc as hasReasonlessBaselineRefusal, Oi as producerLookupOver, Ol as resolveAutoAssetStorage, On as formatDestructiveChange, Or as extractDeploymentEventError, Os as hasMaskableValues, Ot as replayFailedOperations, P as childTemplateLoader, Pa as malformedOrphansRefusalMessage, Pc as orphansCarriedFrom, Pi as applyRoleArnIfSet, Pl as stateBucketExistenceConfirmed, Pn as bold, Po as isStatefulRecreateTargetForReplace, Ps as shareLogOnlyValues, Pt as isReplacementOrphan, Q as pendingRequestCount, Qa as refuseMalformedOutputs, Qc as readBootstrapMarkerBody, Qi as isImpossibleEmptyStoredAttribute, Ql as hasOwnKey, Qn as noEchoExactEchoLeavesOf, Qo as prefetchCreateOnlyPropertyPaths, Qr as applyCustomResourceResponseExpiration, Qt as nameGenerationCarriedFrom, R as renderNestedTemplateTreeDefect, Ra as malformedRenderedContainersWarning, Rc as isSensitiveAttributeName, Ri as isIamRoleArn, Rl as CFN_TEMPLATE_URL_LIMIT, Rn as red, Rs as maskSecretsInError, Rt as recordUnderIdIsNotOwn, Sa as hasReadableResources, Sc as withStackInstanceIdWithheld, Sl as Synthesizer, Sn as bindingSkippedOutputs, So as unreadableOrphanRecords, Sr as ledgerForStack, St as sameJournaledOrphans, Ta as malformedDriftResourcePropertiesWarning, Tc as describeRegionValueKind, Tl as getLegacyStateBucketName, Tn as maskingRetryLogger, To as findActionableSilentDrops, U as readRecordedConditionVerdicts, Ua as malformedStateRefusalMessage, Uc as loadPublishableAssetManifest, Ui as envCredentialsAreAssumedRole, Ul as decodeListingKey, Un as isSupersededResourceRecord, Ur as isCustomResource, Us as DYNAMIC_REFERENCE_TOKEN_SCAN, Ut as findNestedStackTypeChanges, V as conditionInputsFrom, Va as malformedResourcesWarning, Vc as buildAssetRedirectMap, Vi as applyCallerIdentityCredentials, Vl as uploadCfnTemplate, Vn as deleteSupersededEntry, Vr as ProviderRegistry, Vs as withPhysicalNameCopies, Vt as seedsDeleteFirstGuard, W as withResourceDeadline, Wa as previewableOrphanRecords, Wc as rewriteTemplateAssetReferences, Wi as classifyRecordedSecretRegion, Wl as expectedOwnerParam, Wn as removeSuperseded, Wr as wouldReturnToSdkProvider, Ws as dynamicReferenceTokens, X as makeSiblingClaimReader, Xa as refuseMalformedOrphansForDestroy, Xc as isCrossRegionRedirect, Xi as parameterTypeMayLoseSecretIdentity, Xl as processStackMessages, Xn as noEchoAttributeNamesOf, Xr as withPrintingSecrets, Xt as updatePartialMessage, Y as makeCanonicalizePropertiesFn, Ya as refuseMalformedOrphans, Yc as getBootstrapMarkerKey, Yi as isUnboundTemplateParameter, Yl as StageLoadError, Yn as withoutSuperseded, Ys as recordNestedStackParameterExpressions, Z as planOrphanAdoption, Za as refuseMalformedOrphansForOrphan, Zc as parseBootstrapMarker, Zi as getAccountInfo, Zl as defineOwnKey, Zn as noEchoComparisonForTemplate, Zr as CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID, Zs as physicalNameCopiesOf, Zt as updatePartialReason, _a as accountArgs, _c as applyCrossPrefixScan, _i as DiffCalculator, _l as runDockerForeground, _n as isWholeDynamicReferenceValue, _o as repairMalformedOutputsForReadOnly, _r as effectiveDeletionPolicy, _s as readbackPathFor, _t as dropFailedHint, a as isProtectionValueActive, aa as isStalePlaceholderArnAttribute, ac as recordNoEchoAttributeValues, ai as deleteIndeterminateGuards, al as describeDockerExecFailure, an as namesAnyDeclaredParameter, ao as refuseMalformedResourceEntriesForImportSave, ar as orphanRecordsPrintingBag, as as DagBuilder, at as dropSettledNestedJournals, au as renderAssemblyPathEscape, ba as hasReadableOrphans, bc as isNotImplemented, bi as poisonRenderedSpellingsCollidingIn, bl as AssetManifestLoader, bn as collectPublishedOutputNames, bo as repairMalformedResourcesForReadOnly, br as unsupportedFinalSnapshotError, bs as valueAtCoordinate, bt as loadJournaledOrphans, ca as withSharedDrainBudget, cc as wholeStringLeavesOf, cl as finchSecretArgvRefusal, cn as WITHHELD_NAME_DISPLAY, co as refuseMalformedResourcePropertiesForDrift, cs as isMarkedCoordinate, ct as recordDisplacedSkips, cu as injectedAwsRegionValue, da as declaresNoEcho, dc as LockManager, dl as isDockerClientEnvKey, dn as secretBearing, do as refuseMalformedResourcesForDeploy, dr as storedSecretNameNeedles, ds as maskWholeValue, dt as withNestedRevertRun, ea as carriesFetchableDynamicReference, ec as splitGetAttStringForm, ei as CloudControlProvider, el as validateContainerRepoName, en as nameScopeOf, eo as refuseMalformedResourceAttributesForOrphan, er as createReadOnlyAttributeHealerFactory, es as describeTypeWithThrottleRetry, et as keptForRetainedRecord, eu as nullPrototypeRecord, fa as JSON_LISTING_HOLE_VALUE, fc as isLockInfoExpired, fl as isMalformedEnvKey, fn as secretBearingStateKeyWarning, fo as refuseMalformedResourcesForDestroy, fr as ATOMIC_FINAL_SNAPSHOT_TYPES, fs as maskedLeafCoordinatesOf, ft as collectNestedChildUnaddressed, ga as UNREADABLE_RESOURCES_MAP_ROW, gc as CrossPrefixScanCache, gl as redactedDockerCause, gn as exportNameSecretExposure, go as repairMalformedOrphansForReadOnly, gr as createPreDeleteFinalSnapshot, gt as dropFailedCommands, ha as UNREADABLE_ORPHANS_CONTAINER_ROW, hc as CrossPrefixReadError, hl as redactedCause, hn as exportNameNoEchoParameters, ho as repairMalformedOrphanRecordsForReadOnly, hr as ccRoutedFinalSnapshotError, hs as noEchoOutputsComparison, ht as deleteJournaledOrphans, i as PROTECTION_PROPERTY_BY_TYPE, ia as cfnRefValueFromPhysicalId, ic as recordMaskOnlyValuesIn, ii as UNSPECIFIED_SKIP_REASON, il as describeDockerCapturedOutput, in as computeParameterTaint, io as refuseMalformedResourceEntriesForImport, ir as namingSecretsWithRecordedNoEcho, it as displacedPhysicalIdShown, iu as displayAssemblyPath, j as deferredServiceTokenWarning, ja as malformedOrphanRecordsRefusalMessage, jc as importableOutputs, jl as resolveStateBucketWithDefault, jo as findReplacedReadersOfRecreateTargets, js as printingCorpusOf, jt as recordAfterRollbackUpdate, k as crossStackOutputProvenanceSource, ka as malformedLocalResourceEntriesWarning, kc as hasUnverifiableParameterRefusal, ki as refuseUnreadableCdkCrossAccountRefs, kl as resolveCaptureObservedState, ko as NO_CC_HANDLERS_REASON, ks as literalSplitDelimitersOf, kt as replayRollback, la as parameterInputsFor, lc as WHOLE_DYNAMIC_REFERENCE_PATTERN, li as isWaitAbandonedError, ll as formatDockerLoginError, ln as displayTextOrWithheld, lo as refuseMalformedResourcePropertiesForExport, lr as secretNamedRecordNeedles, ls as maskAtCoordinates, ma as STATE_RESOURCES_MALFORMED, mc as rebuildClientForBucketRegion, ml as redactDockerArgvValues, mn as carriedExportAliasExposure, mo as refuseMalformedState, mr as buildFinalSnapshotIdentifier, ms as noEchoLeavesOf, mt as withNestedStackContext, n as recordedProtectionEvidence, na as keepsSecretReferenceToken, nc as provenPublicValue, nl as buildDockerImage, nn as retiredNameGenerationsAfter, no as refuseMalformedResourceEntriesForDeploy, nr as journaledOrphanPrintingBag, nt as NESTED_PENDING_PARENT_REASON, nu as absoluteAssemblyPathEscape, o as perType, oa as refStateLookupFromResource, oc as recordNoEchoParameterFreshValue, oi as deleteLeftInPlace, ol as describeDockerFailure, on as reachableDivergentParameters, oo as refuseMalformedResourceEntriesForOrphan, or as secretNamePrintingBag, os as TemplateParser, ou as resolveAssemblyPath, pa as STATE_REGION_DIVERGED, pc as S3StateBackend, pl as partitionSensitiveEnv, pn as secretSafeKeyDisplay, po as refuseMalformedResourcesForExport, pr as PRE_DELETE_SNAPSHOT_TYPES, ps as noEchoCoordinatesOf, pt as getCurrentNestedStackContext, q as keptWholeReasonText, qa as refuseMalformedOrphanRecords, qc as assertAssetBucketRegion, qi as regionLessSecretName, ql as derivePartitionAndUrlSuffix, qn as supersededHolderOf, qr as readsNoEchoDeleteValues, qs as identityKeyFor, r as recordedProtectionNote, ra as AWS_NO_VALUE, rc as recordMaskOnlyValue, ri as RollbackInlinePolicyWriters, rl as resolveDockerContextDirectory, rn as retiredNameGenerationsLeaving, ro as refuseMalformedResourceEntriesForDestroy, rr as maskEventTextWithBoundBags, rt as displacedOpClause, ru as describeFileReadFailure, s as readProtection, sc as recordProvenPublicExpression, si as deleteSkipReason, sl as dockerSpawnEnvWithSensitive, sn as resourcesNamingDeclaredParameter, so as refuseMalformedResourcePropertiesForDestroy, sr as secretNamePrintingBags, ss as canonicalCoordinates, st as nestedChildStackName$1, su as injectAwsRegion, t as DeployEngine, ta as isNamelessDynamicReferenceError, tc as carriesSecretMask, ti as slowCcOperationTimeoutMs, tl as buildDenyExternalAccessPolicy, tn as retiredAfterRollback, to as refuseMalformedResourceEntries, tr as completedReplayEntries, ts as withRetry, tt as recordRetainedForReadoption, tu as ownValue, uc as isSingleDynamicReferenceToken, ul as getDockerCmd, un as exportAliasCollisionScrubWarning, uo as refuseMalformedResourcePropertiesForOrphan, ur as stateSecretNameNeedles, us as maskReadbackAtCoordinates, ut as revertedNestedRowIds, uu as resolveBucketRegion, va as deployRefusesOrphanRowsReason, vc as crossPrefixDeniedWarning, vi as INTRINSIC_KEYS, vl as runDockerStreaming, vn as noEchoParameterValueSeed, vo as repairMalformedResourceEntriesForReadOnly, vr as isFinalSnapshotError, vs as readsNoEchoSource, vt as isHandledOrphan, wa as isReadableResourceEntry, wc as acceptedCreateOnlyDropsOf, wl as getDefaultStateBucketName, wn as DEFAULT_RESOURCE_WARN_AFTER_MS, wo as withheldAccountClause, wr as withCreateTokenLedger, xa as hasReadableOutputs, xc as stackInstanceIdOf, xl as getDockerImageBySourceHash, xn as isExportAliasCollision, xo as unpreviewableOrphanRecords, xs as liveMatchesUnresolvedTokenFrame, xt as makeForeignHolderScan, ya as displayLogicalId, yc as isAccessDenied, yi as IntrinsicFunctionResolver, yl as warnFinchArgvExposure, yn as collectDeclaredOutputNames, yo as repairMalformedResourcePropertiesForReadOnly, yr as refusesFinalSnapshot, ys as recordedNoEchoValuesOf, yt as journaledOrphanLines, z as templateIdentity, za as malformedResourceEntriesWarning, zc as stringifyValue, zi as sendableAssumeRoleCommand, zl as MIGRATE_TMP_PREFIX, zn as yellow, zs as maskSecretsInText, zt as replacementNeverSwapped } from "./deploy-engine-CYVt2NQR.js";
6
- import { t as getCdkdVersion } from "./version-CaejipV3.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-D9SDE-Pj.js";
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-DDpKuzTw.js";
7
8
  import { randomBytes, randomUUID } from "node:crypto";
8
9
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutBucketVersioningCommand, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
9
10
  import { GetRoleCommand, GetUserCommand } from "@aws-sdk/client-iam";
@@ -1098,14 +1099,149 @@ function pathGlobMatches(pattern, subject) {
1098
1099
  return can[0];
1099
1100
  }
1100
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
+
1101
1156
  //#endregion
1102
1157
  //#region src/cli/stack-matcher.ts
1103
- function matchStacks(stacks, patterns) {
1158
+ function matchStacks(stacks, patterns, options = {}) {
1104
1159
  if (patterns.length === 0) return [];
1105
1160
  const selected = /* @__PURE__ */ new Set();
1106
- 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));
1107
1163
  const seen = /* @__PURE__ */ new Set();
1108
- 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.");
1109
1245
  }
1110
1246
  function stacksForPattern(stacks, pattern) {
1111
1247
  const byId = stacks.filter((s) => pathGlobMatches(pattern, s.displayName ?? s.stackName));
@@ -1283,7 +1419,7 @@ async function synthCommand(stackPatterns, options) {
1283
1419
  ...Object.keys(context).length > 0 && { context }
1284
1420
  };
1285
1421
  const { stacks: allStacks, assemblyDir } = await synthesizer.synthesize(synthOptions);
1286
- const selected = stackPatterns.length > 0 ? matchStacks(allStacks, stackPatterns) : allStacks;
1422
+ const selected = stackPatterns.length > 0 ? matchStacks(allStacks, stackPatterns, { dedupe: "identity" }) : allStacks;
1287
1423
  if (selected.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
1288
1424
  const stacks = selected;
1289
1425
  processStackMessages(stacks, logger, {
@@ -1296,15 +1432,17 @@ async function synthCommand(stackPatterns, options) {
1296
1432
  } else logger.info(`Supply a stack id (${stacks.map(describeStack).join(", ")}) to display its template.`);
1297
1433
  const found = stacks.length === allStacks.length ? `Found ${stacks.length} stack(s):` : `Found ${stacks.length} of ${allStacks.length} stack(s):`;
1298
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));
1299
1436
  for (const stack of stacks) {
1437
+ const shared = sharedNames.has(stack.stackName);
1300
1438
  const resourceCount = countDeployableResources(stack.template);
1301
1439
  const outputCount = Object.keys(stack.template.Outputs ?? {}).length;
1302
- logger.info(` • ${stack.stackName}`);
1440
+ logger.info(` • ${shared ? describeStack(stack) : stack.stackName}`);
1303
1441
  logger.info(` - Resources: ${resourceCount}`);
1304
1442
  logger.info(` - Outputs: ${outputCount}`);
1305
1443
  logger.info(` - Has assets: ${assemblyReader.hasAssets(stack) ? "Yes" : "No"}`);
1306
1444
  if (options.verbose) {
1307
- const templatePath = resolveVerboseTemplatePath(options.output, stack.stackName);
1445
+ const templatePath = resolveVerboseTemplatePath(options.output, shared ? `${stack.stackName}.${stack.region ?? "env-agnostic"}` : stack.stackName);
1308
1446
  writeFileSync(templatePath, JSON.stringify(stack.template, null, 2));
1309
1447
  logger.debug(` - Template written to: ${displaySafe(templatePath)}`);
1310
1448
  }
@@ -1326,20 +1464,16 @@ function createSynthCommand() {
1326
1464
  //#endregion
1327
1465
  //#region src/cli/commands/list.ts
1328
1466
  function sortByDependency(stacks) {
1329
- const byName = new Map(stacks.map((s) => [s.stackName, s]));
1330
1467
  const visited = /* @__PURE__ */ new Set();
1331
1468
  const result = [];
1332
1469
  const visit = (stack, ancestors) => {
1333
- if (visited.has(stack.stackName)) return;
1334
- if (ancestors.has(stack.stackName)) return;
1335
- ancestors.add(stack.stackName);
1336
- for (const depName of stack.dependencyNames) {
1337
- const dep = byName.get(depName);
1338
- if (dep) visit(dep, ancestors);
1339
- }
1340
- ancestors.delete(stack.stackName);
1341
- if (!visited.has(stack.stackName)) {
1342
- 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);
1343
1477
  result.push(stack);
1344
1478
  }
1345
1479
  };
@@ -1384,7 +1518,7 @@ async function listCommand(patterns, options) {
1384
1518
  };
1385
1519
  const allStacks = (await synthesizer.synthesize(synthOptions)).stacks;
1386
1520
  if (allStacks.length === 0) throw new Error(renderNoStackMatch(patterns, allStacks));
1387
- const selected = patterns.length > 0 ? matchStacks(allStacks, patterns) : allStacks;
1521
+ const selected = patterns.length > 0 ? matchStacks(allStacks, patterns, { dedupe: "identity" }) : allStacks;
1388
1522
  if (selected.length === 0) throw new Error(renderNoStackMatch(patterns, allStacks));
1389
1523
  const sorted = sortByDependency(selected);
1390
1524
  if (options.long) {
@@ -2484,40 +2618,65 @@ var ExportIndexStore = class {
2484
2618
  //#endregion
2485
2619
  //#region src/analyzer/cross-stack-deps.ts
2486
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) {
2487
2630
  const kinds = opts?.kinds ?? ["ImportValue", "GetStackOutput"];
2488
2631
  const wantImportValue = kinds.includes("ImportValue");
2489
2632
  const wantGetStackOutput = kinds.includes("GetStackOutput");
2490
- const exportOwner = /* @__PURE__ */ new Map();
2633
+ const exporters = /* @__PURE__ */ new Map();
2491
2634
  for (const stack of stacks) {
2492
2635
  const outputs = stack.template.Outputs;
2493
2636
  if (!outputs) continue;
2494
2637
  for (const output of Object.values(outputs)) {
2495
2638
  const name = output?.Export?.Name;
2496
2639
  if (typeof name === "string" && name !== "") {
2497
- 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);
2498
2643
  }
2499
2644
  }
2500
2645
  }
2501
- 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
+ };
2502
2650
  const result = /* @__PURE__ */ new Map();
2503
2651
  for (const stack of stacks) {
2504
2652
  const producers = /* @__PURE__ */ new Set();
2505
2653
  collectTemplateCrossStackRefs(stack.template, (kind, value, unconditional) => {
2506
- let producer;
2654
+ let found = [];
2507
2655
  if (kind === "ImportValue") {
2508
2656
  if (!wantImportValue) return;
2509
- 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
+ }
2510
2661
  } else {
2511
2662
  if (opts?.onRoleArnReference && unconditional && value && typeof value === "object" && !Array.isArray(value) && Object.hasOwn(value, "RoleArn")) opts.onRoleArnReference(stack.stackName, value);
2512
2663
  if (!wantGetStackOutput) return;
2513
2664
  if (value && typeof value === "object" && !Array.isArray(value)) {
2514
- const sn = value["StackName"];
2515
- 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
+ }
2516
2675
  }
2517
2676
  }
2518
- if (producer && producer !== stack.stackName && stackNames.has(producer)) producers.add(producer);
2677
+ for (const producer of found) producers.add(producer);
2519
2678
  });
2520
- result.set(stack.stackName, producers);
2679
+ result.set(stack, producers);
2521
2680
  }
2522
2681
  return result;
2523
2682
  }
@@ -2559,7 +2718,7 @@ function collectCrossStackRefs(node, onRef, unconditional) {
2559
2718
  //#region src/provisioning/register-providers.ts
2560
2719
  let providerClasses;
2561
2720
  function loadProviderClasses() {
2562
- providerClasses ??= import("./provider-classes-B2_u4Fg0.js");
2721
+ providerClasses ??= import("./provider-classes-CDtquwkU.js");
2563
2722
  return providerClasses;
2564
2723
  }
2565
2724
  function registerAllProviders(registry, classes) {
@@ -3183,7 +3342,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3183
3342
  if (topLevel.length === 0) throw new Error(renderAllNoTopLevelStacks(inStages));
3184
3343
  allLeftOutStageStacks = inStages;
3185
3344
  targetStacks = topLevel;
3186
- } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns);
3345
+ } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
3187
3346
  else if (allStacks.length === 1) targetStacks = allStacks;
3188
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)`);
3189
3348
  if (targetStacks.length === 0) {
@@ -3191,42 +3350,39 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3191
3350
  throw new Error(renderNoStackMatch(stackPatterns, allStacks) + (gone.stacks.length > 0 ? `\n${renderStacksNoLongerSelected(gone.patterns, gone.stacks)}` : ""));
3192
3351
  }
3193
3352
  const roleArnReferences = [];
3194
- const inferredCrossStackDeps = inferCrossStackStackDeps(allStacks, { onRoleArnReference: (consumer, args) => roleArnReferences.push({
3353
+ const inferredCrossStackDeps = inferCrossStackDepsByStack(allStacks, { onRoleArnReference: (consumer, args) => roleArnReferences.push({
3195
3354
  consumer,
3196
3355
  args
3197
3356
  }) });
3198
3357
  const producerLookup = producerLookupOver(allStacks);
3199
- const effectiveStackDeps = (stackName, deps) => {
3200
- const union = new Set(deps);
3201
- for (const producer of inferredCrossStackDeps.get(stackName) ?? []) union.add(producer);
3202
- return union;
3203
- };
3204
- const inferredStrongCrossStackDeps = inferCrossStackStackDeps(allStacks, { kinds: ["ImportValue"] });
3205
- const effectiveStrongStackDeps = (stackName, deps) => {
3206
- const union = new Set(deps);
3207
- for (const producer of inferredStrongCrossStackDeps.get(stackName) ?? []) union.add(producer);
3208
- 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;
3209
3364
  };
3365
+ const inferredStrongCrossStackDeps = inferCrossStackDepsByStack(allStacks, { kinds: ["ImportValue"] });
3210
3366
  if (!options.exclusively) {
3211
- const targetNames = new Set(targetStacks.map((s) => s.stackName));
3212
- const allStackMap = new Map(allStacks.map((s) => [s.stackName, s]));
3213
- const addDependencies = (stackName) => {
3214
- const stack = allStackMap.get(stackName);
3215
- if (!stack) return;
3216
- for (const depName of effectiveStrongStackDeps(stackName, stack.dependencyNames)) if (!targetNames.has(depName)) {
3217
- const depStack = allStackMap.get(depName);
3218
- if (depStack) {
3219
- targetNames.add(depName);
3220
- targetStacks.push(depStack);
3221
- logger.debug(`Auto-including dependency stack: ${depName} (required by ${stackName})`);
3222
- addDependencies(depName);
3223
- }
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);
3224
3375
  }
3225
3376
  };
3226
- for (const stack of [...targetStacks]) addDependencies(stack.stackName);
3377
+ for (const stack of [...targetStacks]) addDependencies(stack);
3227
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);
3228
3384
  const deployedNames = new Set(targetStacks.map((s) => s.stackName));
3229
- const leftOut = allLeftOutStageStacks.filter((s) => !deployedNames.has(s.stackName));
3385
+ const leftOut = allLeftOutStageStacks.filter((s) => !deployedStacks.has(s));
3230
3386
  if (leftOut.length > 0) logger.warn(renderAllLeftOutStageStacks(leftOut));
3231
3387
  if (!options.all && stackPatterns.length > 0) {
3232
3388
  const gone = stacksNoLongerSelected(allStacks, stackPatterns, deployedNames);
@@ -3251,7 +3407,8 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3251
3407
  logger,
3252
3408
  siblings: allStacks.filter((s) => !s.region).map((s) => s.stackName)
3253
3409
  });
3254
- 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);
3255
3412
  const crossPrefixGuard = new CrossPrefixGuard(preflightStateBackend, { readOnly: options.dryRun === true });
3256
3413
  await synthesizer.expandMacrosForStacks(targetStacks, synthOptions);
3257
3414
  const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
@@ -3283,13 +3440,14 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3283
3440
  const dagBuilder = new DagBuilder({ relaxCdkVpcDefensiveDeps: !!options.aggressiveVpcParallel });
3284
3441
  const diffCalculator = new DiffCalculator();
3285
3442
  const workGraph = new WorkGraph();
3286
- 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;
3287
3445
  const stackRedirects = /* @__PURE__ */ new Map();
3288
3446
  for (const stack of targetStacks) {
3289
- const stackNodeId = `stack:${stack.stackName}`;
3447
+ const stackNodeId = `stack:${graphKey(stack)}`;
3290
3448
  const stackDeps = /* @__PURE__ */ new Set();
3291
3449
  if (stack.assetManifestPath) {
3292
- const assetRegion = stackRegions.get(stack.stackName) ?? deployStackRegion(stack, baseRegion);
3450
+ const assetRegion = stackRegions.get(stack) ?? deployStackRegion(stack, baseRegion);
3293
3451
  const manifest = loadPublishableAssetManifest(stack.assetManifestPath);
3294
3452
  if (manifest) {
3295
3453
  const assetMode = await assetModeResolver.resolve(stack.region || rawNamedRegion || assetRegion);
@@ -3298,7 +3456,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3298
3456
  if (assetMode.mode === "cdkd-assets") {
3299
3457
  redirect = buildAssetRedirectMap(manifest, assetMode.marker, accountId, assetRegion);
3300
3458
  if (redirect.entries.length > 0) {
3301
- stackRedirects.set(stack.stackName, redirect);
3459
+ stackRedirects.set(stack, redirect);
3302
3460
  const rewritten = rewriteTemplateAssetReferences(stack.template, redirect);
3303
3461
  logger.debug(`Rewrote ${rewritten} asset reference(s) to cdkd asset storage (${assetMode.marker.assetBucket} / ${assetMode.marker.containerRepo}) in template of stack ${stack.stackName}`);
3304
3462
  } else redirect = void 0;
@@ -3308,7 +3466,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3308
3466
  accountId,
3309
3467
  region: assetRegion,
3310
3468
  ...options.profile && { profile: options.profile },
3311
- nodePrefix: `${stack.stackName}:`,
3469
+ nodePrefix: `${graphKey(stack)}:`,
3312
3470
  ...redirect && { redirect },
3313
3471
  ...stack.assetOutdir !== void 0 && { assetOutdir: stack.assetOutdir }
3314
3472
  });
@@ -3316,7 +3474,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3316
3474
  }
3317
3475
  }
3318
3476
  }
3319
- 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)}`);
3320
3478
  workGraph.addNode({
3321
3479
  id: stackNodeId,
3322
3480
  type: "stack",
@@ -3336,7 +3494,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3336
3494
  };
3337
3495
  const runStackInner = async (stackInfo) => {
3338
3496
  if (deployInterrupted) throw new DeployCancelledError(`Deploy interrupted before stack '${stackInfo.stackName}' started — not starting it.`);
3339
- const stackRegion = stackRegions.get(stackInfo.stackName) ?? deployStackRegion(stackInfo, baseRegion);
3497
+ const stackRegion = stackRegions.get(stackInfo) ?? deployStackRegion(stackInfo, baseRegion);
3340
3498
  logger.info(`\n${cyan("Deploying stack:")} ${bold(cyan(stackInfo.stackName))}${stackRegion !== baseRegion ? gray(` (region: ${stackRegion})`) : ""}`);
3341
3499
  const stackAwsClients = new AwsClients({
3342
3500
  region: stackRegion,
@@ -3452,7 +3610,7 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
3452
3610
  })) return;
3453
3611
  }
3454
3612
  }
3455
- const assetRedirect = stackRedirects.get(stackInfo.stackName);
3613
+ const assetRedirect = stackRedirects.get(stackInfo);
3456
3614
  const deployEngineOptions = {
3457
3615
  concurrency: options.concurrency,
3458
3616
  dryRun: options.dryRun,
@@ -6141,7 +6299,7 @@ async function diffCommand(stacks, options) {
6141
6299
  if (topLevel.length === 0) throw new Error(renderAllNoTopLevelStacks(inStages));
6142
6300
  if (inStages.length > 0) logger.info(renderAllLeftOutStageStacks(inStages));
6143
6301
  targetStacks = topLevel;
6144
- } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns);
6302
+ } else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
6145
6303
  else if (allStacks.length === 1) targetStacks = allStacks;
6146
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)`);
6147
6305
  if (targetStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
@@ -6237,8 +6395,10 @@ async function diffCommand(stacks, options) {
6237
6395
  });
6238
6396
  const trees = [];
6239
6397
  const producerLookup = producerLookupOver(allStacks);
6398
+ const sharedNames = new Set(targetStacks.map((s) => s.stackName).filter((name, i, names) => names.indexOf(name) !== i));
6240
6399
  for (const stackInfo of targetStacks) {
6241
- 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}`);
6242
6402
  const stackRegion = await regionForStack(stackInfo.stackName, stackInfo.region);
6243
6403
  const assetRedirect = await resolveAssetRedirect(stackInfo.assetManifestPath, stackRegion);
6244
6404
  if (assetRedirect) {
@@ -6247,7 +6407,7 @@ async function diffCommand(stacks, options) {
6247
6407
  }
6248
6408
  trees.push(await buildDiffTree({
6249
6409
  stackName: stackInfo.stackName,
6250
- displayName: stackInfo.stackName,
6410
+ displayName: shownName,
6251
6411
  region: stackRegion,
6252
6412
  template: stackInfo.template,
6253
6413
  nestedTemplates: stackInfo.nestedTemplates ?? nullPrototypeRecord(),
@@ -6722,7 +6882,7 @@ async function scrubCommand(stacks, options) {
6722
6882
  if (allStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
6723
6883
  let targetStacks;
6724
6884
  if (options.all) targetStacks = allStacks;
6725
- else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns);
6885
+ else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
6726
6886
  else if (allStacks.length === 1) targetStacks = allStacks;
6727
6887
  else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all`);
6728
6888
  if (targetStacks.length === 0) {
@@ -6804,10 +6964,10 @@ async function scrubCommand(stacks, options) {
6804
6964
  logger,
6805
6965
  siblings: allStacks.filter((s) => !s.region).map((s) => s.stackName)
6806
6966
  });
6807
- 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)])));
6808
6968
  const work = targetStacks.map((stack) => ({
6809
6969
  stackName: stack.stackName,
6810
- region: stackRegions.get(stack.stackName) ?? region,
6970
+ region: stackRegions.get(stack) ?? region,
6811
6971
  load: () => {
6812
6972
  const defect = stack.nestedTemplates ? findNestedTemplateTreeDefect(stack.nestedTemplates) : void 0;
6813
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");
@@ -6909,8 +7069,9 @@ async function scrubCommand(stacks, options) {
6909
7069
  const parentName = item.parentRow.stackName;
6910
7070
  const row = `${displayStackName(parentName)} (row ${displayIdent(item.parentRow.logicalId)})`;
6911
7071
  if (repaired.changed > 0) {
6912
- if (!rewrittenStacks.has(parentName)) totalStacksScrubbed++;
6913
- rewrittenStacks.add(parentName);
7072
+ const parentKey = producerRecordKey(parentName, stackRegion);
7073
+ if (!rewrittenStacks.has(parentKey)) totalStacksScrubbed++;
7074
+ rewrittenStacks.add(parentKey);
6914
7075
  logger.info(safeMsg`${options.dryRun ? "Would scrub" : "Scrubbed"} ${repaired.changed} nested-stack output attribute(s) in ${row}, from ${shownStack}'s outputs`);
6915
7076
  }
6916
7077
  if (repaired.unmatched.length > 0) {
@@ -6922,10 +7083,11 @@ async function scrubCommand(stacks, options) {
6922
7083
  if (!failures.some((f) => f.stackName === label)) failures.push({ stackName: label });
6923
7084
  logger.error(safeMsg`Scrub of ${displayStackName(item.parentRow.stackName)}'s nested-stack output attributes for ${shownStack} failed: ${describeFailure(err)}`);
6924
7085
  }
6925
- if (scrubbed.historyPurged) historyPurgedStacks.add(stackName);
7086
+ const recordKey = producerRecordKey(stackName, stackRegion);
7087
+ if (scrubbed.historyPurged) historyPurgedStacks.add(recordKey);
6926
7088
  if (scrubbed.recordsChanged > 0) {
6927
- if (!rewrittenStacks.has(stackName)) totalStacksScrubbed++;
6928
- rewrittenStacks.add(stackName);
7089
+ if (!rewrittenStacks.has(recordKey)) totalStacksScrubbed++;
7090
+ rewrittenStacks.add(recordKey);
6929
7091
  logger.info(`${options.dryRun ? "Would scrub" : "Scrubbed"} ${scrubbed.recordsChanged} resource record(s) in ${shownStack}`);
6930
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}`);
6931
7093
  if (scrubbed.malformedResources || scrubbed.malformedResourceRows) malformedRecords.push(stackName);
@@ -9278,6 +9440,8 @@ const CC_API_FALLBACK_DENY_LIST = {
9278
9440
  "AWS::ApiGateway::RestApi": "Body / BodyS3Location are write-only inputs not returned by CC API GetResource; cdkd state preserves them",
9279
9441
  "AWS::CloudFormation::Stack": "cdkd deploys nested stacks itself: no CloudFormation stack exists, and the physicalId is a cdkd-local placeholder ARN",
9280
9442
  "AWS::CloudWatch::AnomalyDetector": "the physicalId is a cdkd-derived metric descriptor, not the primaryIdentifier Cloud Control's GetResource requires",
9443
+ "AWS::EMR::InstanceFleetConfig": "the physicalId is the bare fleet id, not the composite primaryIdentifier Cloud Control's GetResource requires",
9444
+ "AWS::EMR::InstanceGroupConfig": "the physicalId is the bare instance group id, not the composite primaryIdentifier Cloud Control's GetResource requires",
9281
9445
  "AWS::EC2::LaunchTemplate": "CC API returns version-bumped LaunchTemplateData with synthetic LatestVersionNumber that diverges from the CFn input shape"
9282
9446
  };
9283
9447
 
@@ -12888,6 +13052,7 @@ async function destroyCommand(stackArgs, options) {
12888
13052
  displayName: s.displayName,
12889
13053
  ...s.stagePath !== void 0 && { stagePath: s.stagePath },
12890
13054
  ...s.region && { region: s.region },
13055
+ ...s.account && { account: s.account },
12891
13056
  ...s.terminationProtection !== void 0 && { terminationProtection: s.terminationProtection },
12892
13057
  template: s.template,
12893
13058
  ...s.nestedTemplates !== void 0 && { nestedTemplates: s.nestedTemplates }
@@ -12942,18 +13107,23 @@ async function destroyCommand(stackArgs, options) {
12942
13107
  let interrupted = false;
12943
13108
  const runInterrupted = () => interrupted || interruptWatch.interrupted();
12944
13109
  let stoppedEarly = false;
12945
- 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;
12946
13116
  const namesAppStack = /* @__PURE__ */ new Set();
12947
13117
  if (options.all) {
12948
13118
  const { topLevel, inStages } = partitionTopLevel(candidateStacks);
12949
13119
  if (inStages.length > 0) logger.warn(renderAllLeftOutStageStacks(inStages));
12950
- stackNames = topLevel.map((s) => s.stackName);
13120
+ targets = topLevel.map(toTarget);
12951
13121
  } else if (stackPatterns.length > 0) {
12952
13122
  const selectFrom = appStacks.length > 0 ? appStacks : candidateStacks;
12953
13123
  const inState = new Set(candidateStacks.map((s) => s.stackName));
12954
- 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);
12955
13125
  if (appStacks.length > 0) {
12956
- const gone = stacksNoLongerSelected(candidateStacks, stackPatterns, new Set(stackNames));
13126
+ const gone = stacksNoLongerSelected(candidateStacks, stackPatterns, new Set(targets.map((t) => t.stackName)));
12957
13127
  if (gone.stacks.length > 0) logger.warn(renderStacksNoLongerSelected(gone.patterns, gone.stacks));
12958
13128
  }
12959
13129
  const stateNames = new Set(allStateRefs.map((r) => r.stackName));
@@ -12964,13 +13134,13 @@ async function destroyCommand(stackArgs, options) {
12964
13134
  const inStateOnly = unmatched.filter((p) => stateNames.has(p) && !namesAppStack.has(p));
12965
13135
  const absent = unmatched.filter((p) => !inStateOnly.includes(p));
12966
13136
  if (absent.length > 0) logger.warn(renderUnmatchedPatternsWarning(absent, "in state"));
12967
- if (stackNames.length > 0 && inStateOnly.length > 0) logger.warn(renderNotInAppWarning(inStateOnly));
12968
- } 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);
12969
13139
  else if (candidateStacks.length === 0) {
12970
13140
  logger.info("No stacks found in state");
12971
13141
  return;
12972
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)`);
12973
- if (stackNames.length === 0) {
13143
+ if (targets.length === 0) {
12974
13144
  if (stackPatterns.length > 0) {
12975
13145
  const allStateNamesSet = new Set(allStateRefs.map((r) => r.stackName));
12976
13146
  const notInApp = [];
@@ -12992,12 +13162,22 @@ async function destroyCommand(stackArgs, options) {
12992
13162
  logger.info("No matching stacks found in state");
12993
13163
  return;
12994
13164
  }
12995
- if (synthScanStacks.length > 0 && stackNames.length > 1) {
12996
- const inSet = new Set(stackNames);
12997
- const inferred = inferCrossStackStackDeps(synthScanStacks.filter((s) => inSet.has(s.stackName)));
12998
- stackNames = orderConsumersBeforeProducers(stackNames, inferred);
12999
- }
13000
- 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(", ")}`);
13001
13181
  const accountId = "unknown";
13002
13182
  const stateRefsByName = /* @__PURE__ */ new Map();
13003
13183
  for (const ref of allStateRefs) {
@@ -13006,20 +13186,46 @@ async function destroyCommand(stackArgs, options) {
13006
13186
  stateRefsByName.set(ref.stackName, arr);
13007
13187
  }
13008
13188
  const crossPrefixCheck = { cache: new CrossPrefixGuard(stateBackend) };
13009
- if (stackNames.length > 1) deferRegistryTail = (released) => deferredTails.push(released);
13189
+ if (targets.length > 1) deferRegistryTail = (released) => deferredTails.push(released);
13010
13190
  const fallbackRegionByName = /* @__PURE__ */ new Map();
13011
- for (const name of stackNames) if ((stateRefsByName.get(name) ?? []).some((r) => !r.region)) fallbackRegionByName.set(name, await regionForStack(name));
13012
- for (const name of stackNames) {
13013
- const synth = appStacks.find((s) => s.stackName === name);
13014
- if (synth?.terminationProtection === true && !options.removeProtection) continue;
13015
- const planned = plannedDestroyRegion(stateRefsByName.get(name) ?? [], synth?.region, fallbackRegionByName.get(name) ?? region);
13016
- 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);
13017
13206
  }
13018
- for (const [stackIndex, stackName] of stackNames.entries()) {
13019
- 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
+ }
13020
13227
  const refs = stateRefsByName.get(stackName) ?? [];
13021
- const synthStack = appStacks.find((s) => s.stackName === stackName);
13022
- const synthRegion = synthStack?.region;
13228
+ const synthStack = target.synth;
13023
13229
  if (synthStack?.terminationProtection === true) {
13024
13230
  if (options.removeProtection) logger.warn(`Stack ${displaySafe(stackName)} has terminationProtection: true — bypassing because --remove-protection set`);
13025
13231
  else {
@@ -13032,11 +13238,15 @@ async function destroyCommand(stackArgs, options) {
13032
13238
  continue;
13033
13239
  }
13034
13240
  }
13035
- const plannedRegion = plannedDestroyRegion(refs, synthRegion, fallbackRegionByName.get(stackName) ?? region);
13241
+ const plannedRegion = plannedRegionFor(target);
13242
+ const strict = strictRegion.get(target);
13036
13243
  let stackTargetRegion;
13037
13244
  if (refs.length === 0) {
13038
13245
  logger.warn(`No state found for stack ${displaySafe(stackName)}, skipping`);
13039
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;
13040
13250
  } else if (plannedRegion !== void 0) stackTargetRegion = plannedRegion;
13041
13251
  else {
13042
13252
  const regions = refs.map((r) => r.region === void 0 ? "(legacy)" : plainOrDescribed(r.region, "region")).join(", ");
@@ -13163,7 +13373,7 @@ async function destroyCommand(stackArgs, options) {
13163
13373
  interrupted: stackInterrupted || stackCancelled
13164
13374
  }, logger);
13165
13375
  if (runInterrupted()) {
13166
- if (stackIndex < stackNames.length - 1) stoppedEarly = true;
13376
+ if (stackIndex < targets.length - 1) stoppedEarly = true;
13167
13377
  break;
13168
13378
  }
13169
13379
  }
@@ -13398,60 +13608,6 @@ function mixedLeafSsmTokens(source) {
13398
13608
  return tokens;
13399
13609
  }
13400
13610
 
13401
- //#endregion
13402
- //#region src/cli/cdk-path.ts
13403
- function readCdkPath(resource) {
13404
- const meta = resource.Metadata;
13405
- if (!meta) return "";
13406
- const v = meta["aws:cdk:path"];
13407
- return typeof v === "string" ? v : "";
13408
- }
13409
- function readCdkPathOrUndefined(resource) {
13410
- const path = readCdkPath(resource);
13411
- return path === "" ? void 0 : path;
13412
- }
13413
- function buildCdkPathIndex(template) {
13414
- const index = /* @__PURE__ */ new Map();
13415
- for (const [logicalId, resource] of Object.entries(template.Resources)) {
13416
- if (resource.Type === "AWS::CDK::Metadata") continue;
13417
- const path = readCdkPath(resource);
13418
- if (path) index.set(path, logicalId);
13419
- }
13420
- return index;
13421
- }
13422
- function resolveCdkPathToLogicalIds(input, index) {
13423
- const seen = /* @__PURE__ */ new Map();
13424
- const prefix = `${input}/`;
13425
- for (const [path, logicalId] of index) if (path === input || path.startsWith(prefix)) {
13426
- if (!seen.has(logicalId)) seen.set(logicalId, path);
13427
- }
13428
- return [...seen.entries()].map(([logicalId, cdkPath]) => ({
13429
- logicalId,
13430
- cdkPath
13431
- }));
13432
- }
13433
- function stackForConstructPath(path, stacks) {
13434
- let best;
13435
- let bestRank = -1;
13436
- for (const s of stacks) {
13437
- const names = [[s.displayName, 1], [s.stackName, 0]];
13438
- for (const [name, preference] of names) {
13439
- if (typeof name !== "string" || name.length === 0) continue;
13440
- if (!path.startsWith(`${name}/`)) continue;
13441
- const rank = name.length * 2 + preference;
13442
- if (rank > bestRank) {
13443
- best = s;
13444
- bestRank = rank;
13445
- }
13446
- }
13447
- }
13448
- return best;
13449
- }
13450
- function stackForPathFormTarget(parsed, target, stacks) {
13451
- if (!parsed.isPath || parsed.pathOrId !== target) return void 0;
13452
- return stackForConstructPath(parsed.pathOrId, stacks);
13453
- }
13454
-
13455
13611
  //#endregion
13456
13612
  //#region src/analyzer/orphan-rewriter.ts
13457
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";
@@ -20720,7 +20876,7 @@ async function publishAssetsCommand(stacks, options) {
20720
20876
  let targetStacks;
20721
20877
  if (allStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
20722
20878
  if (options.all) targetStacks = allStacks;
20723
- else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns);
20879
+ else if (stackPatterns.length > 0) targetStacks = matchStacks(allStacks, stackPatterns, { dedupe: "identity" });
20724
20880
  else if (allStacks.length === 1) targetStacks = allStacks;
20725
20881
  else throw new Error(`Multiple stacks found: ${allStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all`);
20726
20882
  if (targetStacks.length === 0) throw new Error(renderNoStackMatch(stackPatterns, allStacks));
@@ -22836,16 +22992,13 @@ function resolveLambdaTarget(target, stacks) {
22836
22992
  return extractLambdaProperties(stack, logicalId, resource, resources);
22837
22993
  }
22838
22994
  function pickStack$1(parsed, stacks, target) {
22839
- if (parsed.stackPattern === null) {
22840
- if (stacks.length === 1) return stacks[0];
22841
- 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));
22842
23001
  }
22843
- const byPrefix = stackForPathFormTarget(parsed, target, stacks);
22844
- if (byPrefix) return byPrefix;
22845
- const matched = matchStacks(stacks, [parsed.stackPattern]);
22846
- if (matched.length === 0) throw new LocalInvokeResolutionError(`Stack '${parsed.stackPattern}' not found. Available stacks: ${stacks.map((s) => s.stackName).join(", ")}.`);
22847
- 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.");
22848
- return matched[0];
22849
23002
  }
22850
23003
  function extractLambdaProperties(stack, logicalId, resource, resources) {
22851
23004
  const props = resource.Properties ?? {};
@@ -23349,16 +23502,13 @@ function resolveEcsTaskTarget(target, stacks, context) {
23349
23502
  return extractTaskDefinitionProperties(stack, logicalId, resource, context);
23350
23503
  }
23351
23504
  function pickStack(parsed, stacks, target) {
23352
- if (parsed.stackPattern === null) {
23353
- if (stacks.length === 1) return stacks[0];
23354
- 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));
23355
23511
  }
23356
- const byPrefix = stackForPathFormTarget(parsed, target, stacks);
23357
- if (byPrefix) return byPrefix;
23358
- const matched = matchStacks(stacks, [parsed.stackPattern]);
23359
- if (matched.length === 0) throw new EcsTaskResolutionError(`Stack '${parsed.stackPattern}' not found. Available stacks: ${stacks.map((s) => s.stackName).join(", ")}.`);
23360
- 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.");
23361
- return matched[0];
23362
23512
  }
23363
23513
  function extractTaskDefinitionProperties(stack, logicalId, resource, context) {
23364
23514
  const props = resource.Properties ?? {};
@@ -25209,7 +25359,7 @@ async function localStartApiCommand(target, options) {
25209
25359
  const layerTmpDirs = /* @__PURE__ */ new Set();
25210
25360
  let profileCredsFile;
25211
25361
  let credsHostPath;
25212
- const authorizerCache = createAuthorizerCache();
25362
+ const authorizerCaches = /* @__PURE__ */ new Map();
25213
25363
  const jwksCache = createJwksCache();
25214
25364
  const jwksWarnedAt = /* @__PURE__ */ new Map();
25215
25365
  let sigV4CredentialsLoader;
@@ -25242,23 +25392,11 @@ async function localStartApiCommand(target, options) {
25242
25392
  if (wsDiscovery.errors.length > 0) for (const e of wsDiscovery.errors) logger.warn(`WebSocket discovery: ${e}`);
25243
25393
  const webSocketApis = wsDiscovery.apis;
25244
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.");
25245
- const stageMap = /* @__PURE__ */ new Map();
25246
- for (const stack of targetStacks) {
25247
- const m = buildStageMap(stack.template, options.stage);
25248
- for (const [k, v] of m) stageMap.set(k, v);
25249
- }
25250
- if (options.stage) {
25251
- const missingApis = /* @__PURE__ */ new Set();
25252
- for (const r of routes) {
25253
- if (!r.apiLogicalId) continue;
25254
- if (!stageMap.has(r.apiLogicalId)) missingApis.add(r.apiLogicalId);
25255
- }
25256
- 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.`);
25257
- }
25258
- 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.`);
25259
25397
  let routesWithAuth = attachAuthorizers(targetStacks, routes);
25260
25398
  if (apiFilter !== void 0) {
25261
- 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(", ")}.`);
25262
25400
  const filtered = filterRoutesByApiIdentifier(routesWithAuth, apiFilter);
25263
25401
  if (filtered.length === 0) {
25264
25402
  const available = availableApiIdentifiers(routesWithAuth).join(", ") || "(none)";
@@ -25266,13 +25404,11 @@ async function localStartApiCommand(target, options) {
25266
25404
  }
25267
25405
  routesWithAuth = filtered;
25268
25406
  }
25269
- const corsConfigByApiId = /* @__PURE__ */ new Map();
25270
- for (const stack of targetStacks) {
25271
- const fromCloudFront = buildCorsConfigFromCloudFrontChain(stack.template);
25272
- for (const [k, v] of fromCloudFront) corsConfigByApiId.set(k, v);
25273
- const direct = buildCorsConfigByApiId(stack.template);
25274
- for (const [k, v] of direct) corsConfigByApiId.set(k, v);
25275
- }
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);
25276
25412
  const stateByStack = options.fromState || isCfnFlagPresent(options) ? await loadStateForRoutedStacks(targetStacks, routes, routesWithAuth, options) : /* @__PURE__ */ new Map();
25277
25413
  const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
25278
25414
  if (options.profile && profileCredentials && !profileCredsFile) profileCredsFile = await writeProfileCredentialsFile(options.profile, profileCredentials, {
@@ -25283,36 +25419,30 @@ async function localStartApiCommand(target, options) {
25283
25419
  credsHostPath = void 0;
25284
25420
  }
25285
25421
  });
25286
- const lambdaIds = uniqueLambdaIds(routes, routesWithAuth, webSocketApis);
25287
- const specs = /* @__PURE__ */ new Map();
25288
- for (let i = 0; i < lambdaIds.length; i++) {
25289
- const logicalId = lambdaIds[i];
25290
- const spec = await buildContainerSpec({
25291
- logicalId,
25292
- stacks: targetStacks,
25293
- overrides,
25294
- assumeRole: options.assumeRole,
25295
- containerHost: options.containerHost,
25296
- ...debugPortBase !== void 0 && { debugPort: debugPortBase + i },
25297
- stsRegion: canonicalizeRegion(options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"]),
25298
- inlineTmpDirs,
25299
- layerTmpDirs,
25300
- stateByStack,
25301
- skipPull: options.pull === false,
25302
- ...options.layerRoleArn !== void 0 && { layerRoleArn: options.layerRoleArn },
25303
- ...profileCredentials && { profileCredentials },
25304
- ...profileCredsFile && { profileCredsFile },
25305
- ...dynamicReferenceSpecOptions(options)
25306
- });
25307
- specs.set(logicalId, spec);
25308
- }
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
+ }));
25309
25439
  const distinctImages = /* @__PURE__ */ new Set();
25310
25440
  for (const spec of specs.values()) if (spec.kind === "zip") distinctImages.add(resolveRuntimeImage(spec.lambda.runtime));
25311
25441
  for (const image of distinctImages) await pullImage(image, options.pull === false);
25312
25442
  return {
25313
25443
  routes: routesWithAuth,
25314
25444
  specs,
25315
- corsConfigByApiId,
25445
+ corsConfigByStack,
25316
25446
  webSocketApis,
25317
25447
  stacks: targetStacks
25318
25448
  };
@@ -25331,7 +25461,7 @@ async function localStartApiCommand(target, options) {
25331
25461
  };
25332
25462
  const initialMaterial = await synthesizeAndBuild();
25333
25463
  await prewarmJwks(initialMaterial.routes, jwksCache);
25334
- warnVpcConfigLambdas(initialMaterial.routes, initialMaterial.stacks ?? []);
25464
+ warnVpcConfigLambdas(initialMaterial.routes, initialMaterial.stacks);
25335
25465
  sigV4CredentialsLoader = defaultCredentialsLoader();
25336
25466
  warnIamRoutes(initialMaterial.routes);
25337
25467
  let maxTimeoutSec = 0;
@@ -25345,12 +25475,12 @@ async function localStartApiCommand(target, options) {
25345
25475
  const servers = [];
25346
25476
  let nextPort = basePort;
25347
25477
  for (const group of initialGroups) {
25348
- const groupSpecs = filterSpecsForGroup(group, initialMaterial.specs);
25478
+ const groupSpecs = filterSpecsForGroup(group, initialMaterial);
25349
25479
  const groupPool = buildPool(groupSpecs);
25350
25480
  const groupState = {
25351
25481
  routes: group.routes,
25352
25482
  pool: groupPool,
25353
- corsConfigByApiId: initialMaterial.corsConfigByApiId
25483
+ corsConfigByApiId: corsConfigForGroup(group, initialMaterial)
25354
25484
  };
25355
25485
  if (options.warm) {
25356
25486
  logger.info(`Pre-warming ${groupSpecs.size} container(s) for ${group.displayName}...`);
@@ -25365,7 +25495,7 @@ async function localStartApiCommand(target, options) {
25365
25495
  host: options.host,
25366
25496
  ...mtlsConfig && { mtls: mtlsConfig },
25367
25497
  port: basePort === 0 ? 0 : nextPort,
25368
- authorizerCache,
25498
+ authorizerCache: perStack(authorizerCaches, groupStackName(group, initialMaterial.stacks), createAuthorizerCache),
25369
25499
  jwksCache,
25370
25500
  jwksWarnedAt,
25371
25501
  sigV4CredentialsLoader,
@@ -25389,12 +25519,7 @@ async function localStartApiCommand(target, options) {
25389
25519
  }
25390
25520
  for (const api of initialWsApis) {
25391
25521
  if (api.unsupported) continue;
25392
- const wsLambdaIds = new Set(api.routes.map((r) => r.targetLambdaLogicalId));
25393
- const wsSpecs = /* @__PURE__ */ new Map();
25394
- for (const id of wsLambdaIds) {
25395
- const spec = initialMaterial.specs.get(id);
25396
- if (spec) wsSpecs.set(id, spec);
25397
- }
25522
+ const wsSpecs = filterSpecsForWebSocketApi(api, initialMaterial);
25398
25523
  if (wsSpecs.size === 0) {
25399
25524
  logger.warn(`WebSocket API ${api.declaredAt}: no resolvable Lambda backing routes; skipping.`);
25400
25525
  continue;
@@ -25412,7 +25537,7 @@ async function localStartApiCommand(target, options) {
25412
25537
  rieTimeoutMs,
25413
25538
  host: options.host,
25414
25539
  port: basePort === 0 ? 0 : nextPort,
25415
- authorizerCache,
25540
+ authorizerCache: perStack(authorizerCaches, api.apiStackName, createAuthorizerCache),
25416
25541
  jwksCache,
25417
25542
  jwksWarnedAt,
25418
25543
  sigV4WarnedForeignIds,
@@ -25437,9 +25562,7 @@ async function localStartApiCommand(target, options) {
25437
25562
  host: "host.docker.internal",
25438
25563
  ip: "host-gateway"
25439
25564
  }];
25440
- for (const id of wsLambdaIds) {
25441
- const spec = initialMaterial.specs.get(id);
25442
- if (!spec) continue;
25565
+ for (const spec of wsSpecs.values()) {
25443
25566
  spec.env["AWS_ENDPOINT_URL_APIGATEWAYMANAGEMENTAPI"] = mgmtEndpoint;
25444
25567
  if (!spec.env["AWS_ACCESS_KEY_ID"]) {
25445
25568
  spec.env["AWS_ACCESS_KEY_ID"] = "AKIAIOSFODNN7EXAMPLE";
@@ -25605,12 +25728,14 @@ function installFatalShutdownHandlers(logger, shutdown) {
25605
25728
  }
25606
25729
  function targetStackHint(target, stacks) {
25607
25730
  if (target?.includes("/") !== true) return void 0;
25608
- 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;
25609
25734
  }
25610
25735
  function pickTargetStacks(stacks, pattern, cfnStackFallback, targetFallback) {
25611
25736
  const effective = pattern ?? cfnStackFallback ?? targetFallback;
25612
25737
  if (effective !== void 0 && typeof effective !== "string") return [effective];
25613
- if (effective) return matchStacks(stacks, [effective]);
25738
+ if (effective) return matchStacks(stacks, [effective], { dedupe: "identity" });
25614
25739
  if (stacks.length === 1) return stacks;
25615
25740
  if (stacks.length === 0) return [];
25616
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(", ")}.`);
@@ -25629,32 +25754,110 @@ function tryEmitFromCfnRedundancyTipOnce(fromCfnStack, routedStackNames, emitted
25629
25754
  emit(routedStackName);
25630
25755
  emittedRef.value = true;
25631
25756
  }
25632
- 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 = []) {
25633
25838
  const seen = /* @__PURE__ */ new Set();
25634
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
+ };
25635
25849
  for (const r of routes) {
25636
25850
  if (r.unsupported || r.mockCors || r.serviceIntegration) continue;
25637
25851
  if (r.lambdaLogicalId.length === 0) continue;
25638
- if (!seen.has(r.lambdaLogicalId)) {
25639
- seen.add(r.lambdaLogicalId);
25640
- out.push(r.lambdaLogicalId);
25641
- }
25852
+ add(r.apiStackName, r.lambdaLogicalId);
25642
25853
  }
25643
25854
  for (const entry of routesWithAuth) {
25644
25855
  if (entry.route.unsupported || entry.route.mockCors || entry.route.serviceIntegration) continue;
25645
25856
  const auth = entry.authorizer;
25646
25857
  if (!auth) continue;
25647
- if (auth.kind === "lambda-token" || auth.kind === "lambda-request") {
25648
- if (!seen.has(auth.lambdaLogicalId)) {
25649
- seen.add(auth.lambdaLogicalId);
25650
- out.push(auth.lambdaLogicalId);
25651
- }
25652
- }
25653
- }
25654
- for (const api of webSocketApis) for (const r of api.routes) if (!seen.has(r.targetLambdaLogicalId)) {
25655
- seen.add(r.targetLambdaLogicalId);
25656
- out.push(r.targetLambdaLogicalId);
25858
+ if (auth.kind === "lambda-token" || auth.kind === "lambda-request") add(entry.route.apiStackName, auth.lambdaLogicalId);
25657
25859
  }
25860
+ for (const api of webSocketApis) for (const r of api.routes) add(r.lambdaStackName, r.targetLambdaLogicalId);
25658
25861
  return out;
25659
25862
  }
25660
25863
  async function prewarmJwks(routesWithAuth, jwksCache) {
@@ -25672,27 +25875,29 @@ async function prewarmJwks(routesWithAuth, jwksCache) {
25672
25875
  }
25673
25876
  function warnVpcConfigLambdas(routesWithAuth, stacks) {
25674
25877
  const logger = getLogger();
25675
- const seen = /* @__PURE__ */ new Set();
25676
- const reachable = [];
25677
- for (const entry of routesWithAuth) {
25678
- if (!seen.has(entry.route.lambdaLogicalId)) {
25679
- seen.add(entry.route.lambdaLogicalId);
25680
- reachable.push(entry.route.lambdaLogicalId);
25681
- }
25682
- const auth = entry.authorizer;
25683
- if (auth && (auth.kind === "lambda-token" || auth.kind === "lambda-request")) {
25684
- if (!seen.has(auth.lambdaLogicalId)) {
25685
- seen.add(auth.lambdaLogicalId);
25686
- reachable.push(auth.lambdaLogicalId);
25687
- }
25688
- }
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
+ });
25689
25889
  }
25690
- for (const logicalId of reachable) for (const stack of stacks) {
25691
- const resource = stack.template.Resources?.[logicalId];
25692
- if (!resource || resource.Type !== "AWS::Lambda::Function") continue;
25693
- const vpcConfig = (resource.Properties ?? {})["VpcConfig"];
25694
- 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.`);
25695
- 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
+ }
25696
25901
  }
25697
25902
  }
25698
25903
  function warnIamRoutes(routesWithAuth) {
@@ -25916,9 +26121,10 @@ async function materializeLambdaLayers$1(layers, layerTmpDirs, layerRoleArn) {
25916
26121
  return dir;
25917
26122
  }
25918
26123
  function resolveLambdaByLogicalId(logicalId, stacks) {
25919
- for (const stack of stacks) {
25920
- const resource = stack.template.Resources?.[logicalId];
25921
- 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];
25922
26128
  const props = resource.Properties ?? {};
25923
26129
  const memoryMb = typeof props["MemorySize"] === "number" ? props["MemorySize"] : 128;
25924
26130
  const timeoutSec = typeof props["Timeout"] === "number" ? props["Timeout"] : 3;
@@ -26163,20 +26369,78 @@ function parsePerLambdaConcurrency(raw) {
26163
26369
  }
26164
26370
  return parsed;
26165
26371
  }
26166
- function filterSpecsForGroup(group, allSpecs) {
26167
- 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
+ };
26168
26421
  for (const rwa of group.routes) {
26169
- ids.add(rwa.route.lambdaLogicalId);
26422
+ add(rwa.route.apiStackName, rwa.route.lambdaLogicalId);
26170
26423
  const auth = rwa.authorizer;
26171
- 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);
26172
26425
  }
26426
+ return out;
26427
+ }
26428
+ function filterSpecsForWebSocketApi(api, material) {
26173
26429
  const out = /* @__PURE__ */ new Map();
26174
- for (const id of ids) {
26175
- const spec = allSpecs.get(id);
26176
- 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);
26177
26437
  }
26178
26438
  return out;
26179
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
+ }
26180
26444
  function printPerServerRouteTables(servers) {
26181
26445
  for (const { group, server } of servers) {
26182
26446
  process.stdout.write(`\n${group.displayName} (http://${formatAuthority(server.host, server.port)})\n`);
@@ -26229,11 +26493,11 @@ async function reloadAllServers(args) {
26229
26493
  for (const booted of servers) {
26230
26494
  const group = newByKey.get(booted.group.serverKey);
26231
26495
  if (!group) continue;
26232
- const newPool = buildPool(filterSpecsForGroup(group, material.specs));
26496
+ const newPool = buildPool(filterSpecsForGroup(group, material));
26233
26497
  const newState = {
26234
26498
  routes: group.routes,
26235
26499
  pool: newPool,
26236
- corsConfigByApiId: material.corsConfigByApiId
26500
+ corsConfigByApiId: corsConfigForGroup(group, material)
26237
26501
  };
26238
26502
  const previousState = booted.server.setServerState(newState);
26239
26503
  booted.group = group;
@@ -26260,24 +26524,14 @@ function envHasIntrinsicValue$1(templateEnv) {
26260
26524
  async function loadStateForRoutedStacks(stacks, routes, routesWithAuth, options) {
26261
26525
  const logger = getLogger();
26262
26526
  const out = /* @__PURE__ */ new Map();
26263
- const lambdaIds = uniqueLambdaIds(routes, routesWithAuth);
26264
26527
  const reachableStackNames = /* @__PURE__ */ new Set();
26265
- for (const logicalId of lambdaIds) for (const stack of stacks) {
26266
- const resource = stack.template.Resources?.[logicalId];
26267
- if (resource && resource.Type === "AWS::Lambda::Function") {
26268
- reachableStackNames.add(stack.stackName);
26269
- break;
26270
- }
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);
26271
26533
  }
26272
- const stackHasIntrinsicEnv = (stackName) => {
26273
- for (const logicalId of lambdaIds) for (const stack of stacks) {
26274
- if (stack.stackName !== stackName) continue;
26275
- const resource = stack.template.Resources?.[logicalId];
26276
- if (!resource || resource.Type !== "AWS::Lambda::Function") continue;
26277
- if (envHasIntrinsicValue$1(getTemplateEnv$1(resource))) return true;
26278
- }
26279
- return false;
26280
- };
26534
+ const stackHasIntrinsicEnv = (stackName) => intrinsicEnvStacks.has(stackName);
26281
26535
  rejectExplicitCfnStackWithMultipleStacks(options, reachableStackNames.size);
26282
26536
  for (const stackName of reachableStackNames) {
26283
26537
  const stack = stacks.find((s) => s.stackName === stackName);
@@ -27587,7 +27841,7 @@ function pickCandidateStack(parsed, target, stacks) {
27587
27841
  if (stacks.length === 1) return stacks[0];
27588
27842
  return;
27589
27843
  }
27590
- const matched = matchStacks(stacks, [stackPattern]);
27844
+ const matched = matchStacks(stacks, [stackPattern], { dedupe: "identity" });
27591
27845
  if (matched.length === 1) return matched[0];
27592
27846
  }
27593
27847
  async function resolveStackAccountId$1(source) {
@@ -29706,4 +29960,4 @@ function collectVerbFlags(program) {
29706
29960
 
29707
29961
  //#endregion
29708
29962
  export { resolveSecretDerivedPrincipals as a, buildProgram, isResolvableSecretPrincipalList as i, runDestroyForStack as n, canonicalizeIpProtocolValue as o, holdsUnprovenSecretPrincipalToken as r, resolvedResourceTimeoutMs as s, canonicalizeIpv4Cidr as t };
29709
- //# sourceMappingURL=program-CvRs5pV_.js.map
29963
+ //# sourceMappingURL=program-DSbJoNKe.js.map