@go-to-k/cdkd 0.290.15 → 0.290.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{asg-provider-D5-3SGmd.js → asg-provider-CvkcE8rH.js} +22 -5
- package/dist/asg-provider-CvkcE8rH.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-C2qLzc-5.js → deploy-engine-B91NMqm1.js} +38 -12
- package/dist/deploy-engine-B91NMqm1.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{program-BBgCW2BX.js → program-U03H43s7.js} +379 -63
- package/dist/{program-BBgCW2BX.js.map → program-U03H43s7.js.map} +1 -1
- package/dist/{version-BnegtHzZ.js → version-1FTpsWNc.js} +2 -2
- package/dist/{version-BnegtHzZ.js.map → version-1FTpsWNc.js.map} +1 -1
- package/package.json +1 -1
- package/dist/asg-provider-D5-3SGmd.js.map +0 -1
- package/dist/deploy-engine-C2qLzc-5.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $ as secretBearing, $n as BOOTSTRAP_MARKER_PREFIX, $r as getAwsClients, $t as s3BucketRegionalDomainName, A as extractDeploymentEventError, Ai as markNonRetryable, An as buildForceUnlockCommand, Ar as resolveAutoAssetStorage, At as parameterTypeMayLoseSecretIdentity, B as toCfnInteger, Bn as importableOutputs, Br as MIGRATE_TMP_PREFIX, Bt as configIntegerRefusal, C as buildFinalSnapshotIdentifier, Cn as recordMaskOnlyValue, Cr as AssetManifestLoader, Ct as IntrinsicFunctionResolver, D as refusesFinalSnapshot, Di as isRetryableTransientError, Dn as LockManager, Dr as getDefaultStateBucketName, Dt as getAccountInfo, E as isFinalSnapshotError, Ei as isMarkedNonRetryable, En as scrubResourceRecord, Er as synthesisStatusMessage, Et as coerceParameterTypedValue, F as isStatefulRecreateTargetSync, Fn as CUSTOM_RESOURCE_RESPONSE_PREFIX, Fr as resolveUseCdkBootstrapAssets, Ft as resolveExplicitPhysicalId, G as gray, Gn as AssetPublisher, Gr as PARTITION_TABLE, Gt as requireConfigObject, H as formatResourceLine, Hn as orphansAfterRollback, Hr as uploadCfnTemplate, Ht as readConfigString, I as renderStatefulReason, In as DEFAULT_STATE_PREFIX, Ir as stateBucketExistenceConfirmed, It as assertRegionMatch, J as yellow, Jn as buildAssetRedirectMap, Jr as AssemblyReader, Jt as producerRegionsFromState, K as green, Kn as stringifyValue, Kr as canonicalizeRegion, Kt as requireConfigString, L as WARM_THROUGHPUT_MEMBERS, Ln as exportNamesCarriedFrom, Lr as warnDeprecatedNoPrefixCliFlag, Lt as coerceCfnBoolean, M as planOrphanAdoption, Mi as retryClassificationText, Mn as forceQuitRecoveryClause, Mr as resolveSkipPrefix, Mt as isSettledInstanceState, N as MULTI_REGION_RECREATE_BLOCKED_TYPES, Nn as formatLockExpiry, Nr as resolveStateBucketWithDefault, Nt as WAFv2WebACLProvider, O as unsupportedFinalSnapshotError, Oi as isThrottlingError, On as S3StateBackend, Or as getLegacyStateBucketName, Ot as isImpossibleEmptyStoredAttribute, P as isStatefulRecreateTargetForReplace, Pn as shellQuote, Pr as resolveStateBucketWithDefaultAndSource, Pt as normalizeAwsTagsToCfn, Q as isExportAliasCollision, Qn as AssetModeResolver, Qr as AwsClients, Qt as s3BucketDualStackDomainName, R as coerceWarmThroughput$1, Rn as hasReadableExportSet, Rr as CFN_TEMPLATE_BODY_LIMIT, Rt as coerceCfnInteger, S as PRE_DELETE_SNAPSHOT_TYPES, Sn as maskSecretsInText, Sr as stripControlChars, St as isTerminationProtectionPropagationError, T as createPreDeleteFinalSnapshot, Ti as withErrorHandling, Tn as redactSecretsForState, Tr as Synthesizer, Tt as cfnRefValueFromPhysicalId, U as bold, Un as orphansCarriedFrom, Ur as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, Ut as replayWarn, V as toFiniteNumber, Vn as isReadableBag, Vr as findLargeInlineResources, Vt as configStringRefusal, W as cyan, Wn as shouldRetainResource, Wr as expectedOwnerParam, Wt as requireConfigArray, X as collectPublishedOutputNames, Xn as loadPublishableAssetManifest, Xt as s3BucketArn, Y as collectDeclaredOutputNames, Yn as createAssetRedirectResolver, Yr as processStackMessages, Yt as withSharedDrainBudget, Z as exportAliasCollisionScrubWarning, Zn as rewriteTemplateAssetReferences, Zr as resolveBucketRegion, Zt as s3BucketDomainName, _ as isSecretBearingReferenceString, _i as ResourceUpdateNotSupportedError, _n as errorCauseChain, _r as partitionSensitiveEnv, _t as slowCcOperationTimeoutMs, a as DeploymentEventsStore, ai as CrossAccountSecretRefusalError, an as findSilentDropProperties, ar as readBootstrapMarkerBody, at as clearOnUpdateRemoval, b as bindingSkippedOutputs, bn as markSameGenerationBag, br as runDockerStreaming, bt as deleteSkipReason, c as replayFailedOperations, ci as DynamicReferenceRegionAmbiguousError, cn as DagBuilder, cr as buildDenyExternalAccessPolicy, ct as createMaskedRetryLogger, d as updatePartialReason, di as LocalStartServiceError, dn as STATE_SOURCED_CROSS_GENERATION_RULES, dr as describeDockerCapturedOutput, dt as beginCommandInterruptScope, ei as resetAwsClients, en as s3BucketWebsiteUrl, er as assertAssetBucketRegion, et as secretBearingStateKeyWarning, f as withResourceDeadline, fn as STATE_SOURCED_READBACK_RULES, fr as describeDockerExecFailure, ft as endCommandInterruptScope, g as bagHoldsSecretExpression, gi as ResourceTimeoutError, gn as dynamicReferenceTokens, gr as getDockerCmd, gt as CloudControlProvider, h as computeImplicitDeleteEdges, hi as ProvisioningError, hn as createSecretMasker, hr as formatDockerLoginError, ht as startInterruptWatch, i as DeploymentEventsReader, in as findActionableSilentDrops, ir as parseBootstrapMarker, it as collectInlinePolicyNamesManagedBySiblings, j as makeSiblingClaimReader, ji as markRedactedCause, jn as buildLockContentionMessage, jr as resolveCaptureObservedState, jt as refStateLookupFromResource, k as makeCanonicalizePropertiesFn, ki as isTransientServerError, kn as rebuildClientForBucketRegion, kr as resolveApp, kt as isUnboundTemplateParameter, l as replayRollback, li as IntrinsicResolutionRefusalError, ln as TemplateParser, lr as describeAwsFailure, lt as maskDeep, m as IMPLICIT_DELETE_DEPENDENCIES, mi as PartialFailureError, mn as carriesSecretMask, mr as dockerSpawnEnvWithSensitive, mt as isInterruptedWaitError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as DiffCalculator, nr as getBootstrapMarkerKey, nt as getCurrentResourceSecrets, o as planFailedOps, on as describeTypeWithThrottleRetry, or as validateAssetBucketName, ot as ProviderRegistry, p as maskingRetryLogger, pi as NestedStackChildDirectDestroyError, pn as TEMPLATE_SOURCED_RULES, pr as describeDockerFailure, pt as interruptWatchListenerCount, q as red, qn as WorkGraph, qr as derivePartitionAndUrlSuffix, qt as classifyReplaySecretRegion, r as DeployEngine, ri as CdkdError, rn as INTRINSIC_KEYS, rr as isCrossRegionRedirect, rt as IAMRoleProvider, s as planRollback, si as DeployCancelledError, sn as withRetry, sr as validateContainerRepoName, st as wouldReturnToSdkProvider, t as DEFAULT_RESOURCE_TIMEOUT_MS, ti as setAwsClients, tn as applyRoleArnIfSet, tr as ensureAssetStorage, tt as secretSafeKeyDisplay, u as updatePartialMessage, ui as LocalInvokeBuildError$1, un as STATE_SOURCED_BASELINE_RULES, ur as buildDockerImage, ut as maskerOrIdentity, v as keptWholeReasonText, vi as StackHasActiveImportsError, vn as identityKeyFor, vr as redactDockerArgvValues, vt as UNSPECIFIED_SKIP_REASON, w as ccRoutedFinalSnapshotError, wi as normalizeAwsError, wn as recoverMaskedOutput, wr as getDockerImageBySourceHash, wt as carriesDynamicReference, x as ATOMIC_FINAL_SNAPSHOT_TYPES, xn as maskSecretsInError, xr as escapeRegExp, xt as disableInstanceApiTermination, y as mergeNoChangeOutputs, yi as StackTerminationProtectionError, yn as isSingleDynamicReferenceToken, yr as runDockerForeground, yt as deleteIndeterminateGuards, z as isWarmThroughputDecrease, zn as importableOutputKeys, zr as CFN_TEMPLATE_URL_LIMIT, zt as configBooleanRefusal } from "./deploy-engine-
|
|
1
|
+
import { $ as secretBearing, $n as BOOTSTRAP_MARKER_PREFIX, $r as getAwsClients, $t as s3BucketRegionalDomainName, A as extractDeploymentEventError, Ai as markNonRetryable, An as buildForceUnlockCommand, Ar as resolveAutoAssetStorage, At as parameterTypeMayLoseSecretIdentity, B as toCfnInteger, Bn as importableOutputs, Br as MIGRATE_TMP_PREFIX, Bt as configIntegerRefusal, C as buildFinalSnapshotIdentifier, Cn as recordMaskOnlyValue, Cr as AssetManifestLoader, Ct as IntrinsicFunctionResolver, D as refusesFinalSnapshot, Di as isRetryableTransientError, Dn as LockManager, Dr as getDefaultStateBucketName, Dt as getAccountInfo, E as isFinalSnapshotError, Ei as isMarkedNonRetryable, En as scrubResourceRecord, Er as synthesisStatusMessage, Et as coerceParameterTypedValue, F as isStatefulRecreateTargetSync, Fn as CUSTOM_RESOURCE_RESPONSE_PREFIX, Fr as resolveUseCdkBootstrapAssets, Ft as resolveExplicitPhysicalId, G as gray, Gn as AssetPublisher, Gr as PARTITION_TABLE, Gt as requireConfigObject, H as formatResourceLine, Hn as orphansAfterRollback, Hr as uploadCfnTemplate, Ht as readConfigString, I as renderStatefulReason, In as DEFAULT_STATE_PREFIX, Ir as stateBucketExistenceConfirmed, It as assertRegionMatch, J as yellow, Jn as buildAssetRedirectMap, Jr as AssemblyReader, Jt as producerRegionsFromState, K as green, Kn as stringifyValue, Kr as canonicalizeRegion, Kt as requireConfigString, L as WARM_THROUGHPUT_MEMBERS, Ln as exportNamesCarriedFrom, Lr as warnDeprecatedNoPrefixCliFlag, Lt as coerceCfnBoolean, M as planOrphanAdoption, Mi as retryClassificationText, Mn as forceQuitRecoveryClause, Mr as resolveSkipPrefix, Mt as isSettledInstanceState, N as MULTI_REGION_RECREATE_BLOCKED_TYPES, Nn as formatLockExpiry, Nr as resolveStateBucketWithDefault, Nt as WAFv2WebACLProvider, O as unsupportedFinalSnapshotError, Oi as isThrottlingError, On as S3StateBackend, Or as getLegacyStateBucketName, Ot as isImpossibleEmptyStoredAttribute, P as isStatefulRecreateTargetForReplace, Pn as shellQuote, Pr as resolveStateBucketWithDefaultAndSource, Pt as normalizeAwsTagsToCfn, Q as isExportAliasCollision, Qn as AssetModeResolver, Qr as AwsClients, Qt as s3BucketDualStackDomainName, R as coerceWarmThroughput$1, Rn as hasReadableExportSet, Rr as CFN_TEMPLATE_BODY_LIMIT, Rt as coerceCfnInteger, S as PRE_DELETE_SNAPSHOT_TYPES, Sn as maskSecretsInText, Sr as stripControlChars, St as isTerminationProtectionPropagationError, T as createPreDeleteFinalSnapshot, Ti as withErrorHandling, Tn as redactSecretsForState, Tr as Synthesizer, Tt as cfnRefValueFromPhysicalId, U as bold, Un as orphansCarriedFrom, Ur as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, Ut as replayWarn, V as toFiniteNumber, Vn as isReadableBag, Vr as findLargeInlineResources, Vt as configStringRefusal, W as cyan, Wn as shouldRetainResource, Wr as expectedOwnerParam, Wt as requireConfigArray, X as collectPublishedOutputNames, Xn as loadPublishableAssetManifest, Xt as s3BucketArn, Y as collectDeclaredOutputNames, Yn as createAssetRedirectResolver, Yr as processStackMessages, Yt as withSharedDrainBudget, Z as exportAliasCollisionScrubWarning, Zn as rewriteTemplateAssetReferences, Zr as resolveBucketRegion, Zt as s3BucketDomainName, _ as isSecretBearingReferenceString, _i as ResourceUpdateNotSupportedError, _n as errorCauseChain, _r as partitionSensitiveEnv, _t as slowCcOperationTimeoutMs, a as DeploymentEventsStore, ai as CrossAccountSecretRefusalError, an as findSilentDropProperties, ar as readBootstrapMarkerBody, at as clearOnUpdateRemoval, b as bindingSkippedOutputs, bn as markSameGenerationBag, br as runDockerStreaming, bt as deleteSkipReason, c as replayFailedOperations, ci as DynamicReferenceRegionAmbiguousError, cn as DagBuilder, cr as buildDenyExternalAccessPolicy, ct as createMaskedRetryLogger, d as updatePartialReason, di as LocalStartServiceError, dn as STATE_SOURCED_CROSS_GENERATION_RULES, dr as describeDockerCapturedOutput, dt as beginCommandInterruptScope, ei as resetAwsClients, en as s3BucketWebsiteUrl, er as assertAssetBucketRegion, et as secretBearingStateKeyWarning, f as withResourceDeadline, fn as STATE_SOURCED_READBACK_RULES, fr as describeDockerExecFailure, ft as endCommandInterruptScope, g as bagHoldsSecretExpression, gi as ResourceTimeoutError, gn as dynamicReferenceTokens, gr as getDockerCmd, gt as CloudControlProvider, h as computeImplicitDeleteEdges, hi as ProvisioningError, hn as createSecretMasker, hr as formatDockerLoginError, ht as startInterruptWatch, i as DeploymentEventsReader, in as findActionableSilentDrops, ir as parseBootstrapMarker, it as collectInlinePolicyNamesManagedBySiblings, j as makeSiblingClaimReader, ji as markRedactedCause, jn as buildLockContentionMessage, jr as resolveCaptureObservedState, jt as refStateLookupFromResource, k as makeCanonicalizePropertiesFn, ki as isTransientServerError, kn as rebuildClientForBucketRegion, kr as resolveApp, kt as isUnboundTemplateParameter, l as replayRollback, li as IntrinsicResolutionRefusalError, ln as TemplateParser, lr as describeAwsFailure, lt as maskDeep, m as IMPLICIT_DELETE_DEPENDENCIES, mi as PartialFailureError, mn as carriesSecretMask, mr as dockerSpawnEnvWithSensitive, mt as isInterruptedWaitError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as DiffCalculator, nr as getBootstrapMarkerKey, nt as getCurrentResourceSecrets, o as planFailedOps, on as describeTypeWithThrottleRetry, or as validateAssetBucketName, ot as ProviderRegistry, p as maskingRetryLogger, pi as NestedStackChildDirectDestroyError, pn as TEMPLATE_SOURCED_RULES, pr as describeDockerFailure, pt as interruptWatchListenerCount, q as red, qn as WorkGraph, qr as derivePartitionAndUrlSuffix, qt as classifyReplaySecretRegion, r as DeployEngine, ri as CdkdError, rn as INTRINSIC_KEYS, rr as isCrossRegionRedirect, rt as IAMRoleProvider, s as planRollback, si as DeployCancelledError, sn as withRetry, sr as validateContainerRepoName, st as wouldReturnToSdkProvider, t as DEFAULT_RESOURCE_TIMEOUT_MS, ti as setAwsClients, tn as applyRoleArnIfSet, tr as ensureAssetStorage, tt as secretSafeKeyDisplay, u as updatePartialMessage, ui as LocalInvokeBuildError$1, un as STATE_SOURCED_BASELINE_RULES, ur as buildDockerImage, ut as maskerOrIdentity, v as keptWholeReasonText, vi as StackHasActiveImportsError, vn as identityKeyFor, vr as redactDockerArgvValues, vt as UNSPECIFIED_SKIP_REASON, w as ccRoutedFinalSnapshotError, wi as normalizeAwsError, wn as recoverMaskedOutput, wr as getDockerImageBySourceHash, wt as carriesDynamicReference, x as ATOMIC_FINAL_SNAPSHOT_TYPES, xn as maskSecretsInError, xr as escapeRegExp, xt as disableInstanceApiTermination, y as mergeNoChangeOutputs, yi as StackTerminationProtectionError, yn as isSingleDynamicReferenceToken, yr as runDockerForeground, yt as deleteIndeterminateGuards, z as isWarmThroughputDecrease, zn as importableOutputKeys, zr as CFN_TEMPLATE_URL_LIMIT, zt as configBooleanRefusal } from "./deploy-engine-B91NMqm1.js";
|
|
2
2
|
import { C as displaySafe, S as displayIdent, _ as withSkipPrefix, b as STACK_REF_MAX_CODE_POINTS, c as PATTERN_B_NAME_OPTIONS, f as explicitNamePropertyFor, h as getCurrentStackName, i as reserveStdoutForPayload, l as PATTERN_B_NAME_PROPERTIES, m as generateResourceNameWithFallback, n as getLogger, o as runStackBuffered, p as generateResourceName, s as getLiveRenderer, u as PATTERN_B_RESOURCE_TYPES, v as withStackName, w as truncateCodePoints, x as UNRENDERABLE } from "./logger-C17H06QA.js";
|
|
3
3
|
import { t as awsClientDefaults } from "./aws-client-defaults-D-iYiIJ6.js";
|
|
4
|
-
import { t as getCdkdVersion } from "./version-
|
|
5
|
-
import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-
|
|
4
|
+
import { t as getCdkdVersion } from "./version-1FTpsWNc.js";
|
|
5
|
+
import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-CvkcE8rH.js";
|
|
6
6
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
7
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
8
8
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -7079,6 +7079,46 @@ function isTruthyCfnBoolean(value) {
|
|
|
7079
7079
|
//#endregion
|
|
7080
7080
|
//#region src/provisioning/providers/s3-bucket-provider.ts
|
|
7081
7081
|
/**
|
|
7082
|
+
* The "remove this bucket by hand" clause both partial-create cleanup arms end
|
|
7083
|
+
* with, rendered through the shared sanitize / shell-quote / SUPPRESS
|
|
7084
|
+
* (`renderDisableCommand`, the issue
|
|
7085
|
+
* [#2669](https://github.com/go-to-k/cdkd/issues/2669) shape; adopted here by
|
|
7086
|
+
* issue [#3136](https://github.com/go-to-k/cdkd/issues/3136)).
|
|
7087
|
+
*
|
|
7088
|
+
* `bucketName` is TEMPLATE-chosen — `Properties.BucketName`, or the name cdkd
|
|
7089
|
+
* generated for the resource — and until now both arms hand-quoted it as
|
|
7090
|
+
* `--bucket '<name>'`, so a `'` in the value broke out of the quoting and a
|
|
7091
|
+
* control byte forged lines on the operator's terminal. (A WARN, so that is
|
|
7092
|
+
* its whole reach — the recorder persists a thrown `error.message`, not this.)
|
|
7093
|
+
* When sanitizing CHANGES the name the whole command is
|
|
7094
|
+
* SUPPRESSED rather than shown with the sanitized value, because such a command
|
|
7095
|
+
* would delete a DIFFERENT bucket — the wrong-target harm the shared renderer
|
|
7096
|
+
* exists to prevent, and the reason emitting no command is the honest answer
|
|
7097
|
+
* rather than a fallback.
|
|
7098
|
+
*
|
|
7099
|
+
* ONE clause for both arms so the two cannot come to render the same value
|
|
7100
|
+
* differently. The prose `(${bucketName})` each arm carries BESIDE it is still
|
|
7101
|
+
* interpolated as-is: this clause takes only the pasteable half, and
|
|
7102
|
+
* display-sanitizing the PROSE of provider warnings is tracked as issue
|
|
7103
|
+
* [#3269](https://github.com/go-to-k/cdkd/issues/3269) (#3136 covers the
|
|
7104
|
+
* COMMAND half across providers, not prose).
|
|
7105
|
+
*
|
|
7106
|
+
* `maskSecrets` is REQUIRED rather than optional, and both call sites build it
|
|
7107
|
+
* from `context?.maskSecrets` (security review of #3136, which found these two
|
|
7108
|
+
* arms reaching no masker at all). It does two things: the arms now route
|
|
7109
|
+
* their whole warning through it, and it makes `renderDisableCommand` SUPPRESS
|
|
7110
|
+
* the command for a secret-bearing bucket name — which a message-level mask
|
|
7111
|
+
* could not catch once `shellQuote` has escaped an inner quote.
|
|
7112
|
+
*/
|
|
7113
|
+
function manualBucketDeletionClause(bucketName, maskSecrets) {
|
|
7114
|
+
const command = renderDisableCommand({
|
|
7115
|
+
before: "aws s3api delete-bucket --bucket",
|
|
7116
|
+
identifier: bucketName,
|
|
7117
|
+
maskSecrets
|
|
7118
|
+
});
|
|
7119
|
+
return command ? `Manual deletion may be required before the next deploy: ${command}` : "Manual deletion may be required before the next deploy, via the console: the bucket name cannot be reproduced safely on a command line, so any command shown here would act on a different bucket.";
|
|
7120
|
+
}
|
|
7121
|
+
/**
|
|
7082
7122
|
* A plain (non-array) object. `typeof x === 'object'` alone accepts arrays and
|
|
7083
7123
|
* `null`; a `Transition: []` or an unresolved intrinsic pushed through as a
|
|
7084
7124
|
* single transition entry makes S3 answer `MalformedXML` for the WHOLE
|
|
@@ -10440,11 +10480,13 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
10440
10480
|
this.logger.debug(`Cleaned up partially-created S3 bucket ${logicalId} (${bucketName}) after wiring failure`);
|
|
10441
10481
|
} catch (cleanupError) {
|
|
10442
10482
|
this.logger.debug(`DeleteBucket cleanup failed for S3 bucket ${logicalId} (${bucketName}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
10443
|
-
|
|
10483
|
+
const maskSecrets = maskerOrIdentity(context?.maskSecrets);
|
|
10484
|
+
this.logger.warn(maskSecrets(`Failed to clean up partially-created S3 bucket ${logicalId} (${bucketName}) (${cleanupError instanceof Error ? cleanupError.name : typeof cleanupError}). Re-run with --verbose for AWS's own message. ` + manualBucketDeletionClause(bucketName, maskSecrets)));
|
|
10444
10485
|
}
|
|
10445
10486
|
else if (preflight.kind === "indeterminate") {
|
|
10446
10487
|
this.logger.debug(`GetBucketLocation failed for S3 bucket ${bucketName} (${logicalId}) during create: ${preflight.reason}`);
|
|
10447
|
-
|
|
10488
|
+
const maskSecrets = maskerOrIdentity(context?.maskSecrets);
|
|
10489
|
+
this.logger.warn(maskSecrets(`Not cleaning up S3 bucket ${logicalId} (${bucketName}) after a wiring failure: this deploy could not confirm whether it created the bucket (region probe failed: ${preflight.errorName}), and in us-east-1 a successful CreateBucket does not prove it. Re-run with --verbose for AWS's own message. If cdkd created it, the bucket is an orphan. ` + manualBucketDeletionClause(bucketName, maskSecrets)));
|
|
10448
10490
|
}
|
|
10449
10491
|
throw innerError;
|
|
10450
10492
|
}
|
|
@@ -17894,10 +17936,28 @@ function mapSSESpecification(raw) {
|
|
|
17894
17936
|
* still are not.
|
|
17895
17937
|
*/
|
|
17896
17938
|
function readCapacityNumber(block, member) {
|
|
17897
|
-
if (
|
|
17939
|
+
if (!isPlainCapacityBlock(block)) return void 0;
|
|
17898
17940
|
return coerceCfnInteger(block[member]);
|
|
17899
17941
|
}
|
|
17900
17942
|
/**
|
|
17943
|
+
* Is this a `ProvisionedThroughput` block whose MEMBERS can be read at all?
|
|
17944
|
+
*
|
|
17945
|
+
* One spelling, shared by {@link readCapacityNumber} — where a `false` answer
|
|
17946
|
+
* means "no usable member" — and by
|
|
17947
|
+
* {@link DynamoDBTableProvider.coerceIndexCapacityBlock}, where it means
|
|
17948
|
+
* "forward this VERBATIM and let AWS name the shape" (issue
|
|
17949
|
+
* [#3255](https://github.com/go-to-k/cdkd/issues/3255)). The two conclusions
|
|
17950
|
+
* differ; the shape test must not, or the create forwarder could rewrite a
|
|
17951
|
+
* block the flip's reader refuses to read (or vice versa).
|
|
17952
|
+
*
|
|
17953
|
+
* An ARRAY is excluded deliberately: `[]` indexes to `undefined` for both
|
|
17954
|
+
* members, so treating it as a block would DROP nothing and report nothing
|
|
17955
|
+
* while `CreateTable` rejects the list by name anyway.
|
|
17956
|
+
*/
|
|
17957
|
+
function isPlainCapacityBlock(value) {
|
|
17958
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17959
|
+
}
|
|
17960
|
+
/**
|
|
17901
17961
|
* Whether a desired `GlobalSecondaryIndexes[]` entry declares BOTH capacity
|
|
17902
17962
|
* members usably — the same test the BillingMode flip's per-index block applies
|
|
17903
17963
|
* before it forwards the index, expressed as a predicate for the pre-flip
|
|
@@ -17919,11 +17979,23 @@ function hasUsableDeclaredCapacity(entry) {
|
|
|
17919
17979
|
return readCapacityNumber(declared, "ReadCapacityUnits") !== void 0 && readCapacityNumber(declared, "WriteCapacityUnits") !== void 0;
|
|
17920
17980
|
}
|
|
17921
17981
|
/**
|
|
17922
|
-
* The two
|
|
17923
|
-
*
|
|
17924
|
-
*
|
|
17982
|
+
* The two `ProvisionedThroughput` members, in the order the forwarders build
|
|
17983
|
+
* them. Named once so {@link hasUsableTableCapacity}, {@link tableCapacityForSend}
|
|
17984
|
+
* and the per-INDEX create forwarder
|
|
17985
|
+
* ({@link DynamoDBTableProvider.coerceIndexCapacityBlock}) cannot come to
|
|
17986
|
+
* disagree about the membership.
|
|
17987
|
+
*
|
|
17988
|
+
* Deliberately NOT `TABLE_CAPACITY_MEMBERS` any more (issue
|
|
17989
|
+
* [#3255](https://github.com/go-to-k/cdkd/issues/3255)): CloudFormation's
|
|
17990
|
+
* `ProvisionedThroughput` block has the same two members at the TABLE level and
|
|
17991
|
+
* inside every `GlobalSecondaryIndexes[]` entry, and a second list for the
|
|
17992
|
+
* per-index reader would be exactly the drift this constant exists to prevent.
|
|
17993
|
+
* What differs between the two levels is what an ABSENT member does — the table
|
|
17994
|
+
* level substitutes {@link DEFAULT_TABLE_CAPACITY_UNITS}, the per-index level
|
|
17995
|
+
* deliberately has no default ({@link readCapacityNumber}) — and that is a
|
|
17996
|
+
* property of each forwarder, not of the membership.
|
|
17925
17997
|
*/
|
|
17926
|
-
const
|
|
17998
|
+
const PROVISIONED_CAPACITY_MEMBERS = ["ReadCapacityUnits", "WriteCapacityUnits"];
|
|
17927
17999
|
/**
|
|
17928
18000
|
* The capacity both TABLE-level forwarders substitute for a member the
|
|
17929
18001
|
* template does not declare at all — `create()`'s `CreateTable` and the
|
|
@@ -17967,7 +18039,7 @@ function hasUsableTableCapacity(value) {
|
|
|
17967
18039
|
if (!value) return false;
|
|
17968
18040
|
if (typeof value !== "object" || Array.isArray(value)) return true;
|
|
17969
18041
|
const pt = value;
|
|
17970
|
-
for (const member of
|
|
18042
|
+
for (const member of PROVISIONED_CAPACITY_MEMBERS) {
|
|
17971
18043
|
const raw = pt[member];
|
|
17972
18044
|
if (raw === void 0 || raw === null) continue;
|
|
17973
18045
|
const n = coerceCfnInteger(raw);
|
|
@@ -18374,7 +18446,7 @@ function reverseMapSecondaryIndex(live, desired, bagInformative) {
|
|
|
18374
18446
|
* predicate EVERY per-index write path calls — the `Create` / `Update` GSI
|
|
18375
18447
|
* actions in `applyGsiUpdates` AND `create()`'s `CreateTable` forward, which
|
|
18376
18448
|
* maps each entry through
|
|
18377
|
-
* {@link DynamoDBTableProvider.
|
|
18449
|
+
* {@link DynamoDBTableProvider.coerceIndexThroughputForCreate}. It is
|
|
18378
18450
|
* TIGHTER than truthiness (at least one member resolving to a finite
|
|
18379
18451
|
* number), so `WarmThroughput: {}` is neither sent nor emitted on any path.
|
|
18380
18452
|
* An earlier version of this bullet carved out the TABLE-create path as an
|
|
@@ -18383,9 +18455,15 @@ function reverseMapSecondaryIndex(live, desired, bagInformative) {
|
|
|
18383
18455
|
* template failed on a fresh create and succeeded on a later GSI add. Fixed
|
|
18384
18456
|
* in PR review round 6; the carve-out is gone because the divergence is.
|
|
18385
18457
|
* - `ProvisionedThroughput` / `OnDemandThroughput` keep TRUTHINESS, which is
|
|
18386
|
-
* what their write path does:
|
|
18387
|
-
*
|
|
18388
|
-
*
|
|
18458
|
+
* still what their write path does: `applyGsiUpdates` gates on
|
|
18459
|
+
* `gsi.ProvisionedThroughput` alone, `OnDemandThroughput` is forwarded
|
|
18460
|
+
* verbatim on every path, and the `ProvisionedThroughput` coercion issue
|
|
18461
|
+
* [#3255](https://github.com/go-to-k/cdkd/issues/3255) added to ALL FOUR
|
|
18462
|
+
* per-index send sites (`create()`'s mapper plus `applyGsiUpdates`'
|
|
18463
|
+
* adopted-repair, `Create` and same-name `Update` actions) never
|
|
18464
|
+
* SUPPRESSES the block — it rewrites members inside a block that is sent
|
|
18465
|
+
* either way, so "would cdkd send this block" is unchanged by it, even
|
|
18466
|
+
* where both members were dropped and an empty block goes out. Widening
|
|
18389
18467
|
* `isSendableWarmThroughput` over them would be wrong twice over — it reads
|
|
18390
18468
|
* members those blocks do not have (`ReadUnitsPerSecond` vs
|
|
18391
18469
|
* `ReadCapacityUnits`), so every declared capacity would read as undeclared.
|
|
@@ -18577,7 +18655,7 @@ var DynamoDBTableProvider = class {
|
|
|
18577
18655
|
};
|
|
18578
18656
|
if (billingMode === "PROVISIONED") {
|
|
18579
18657
|
const pt = properties["ProvisionedThroughput"];
|
|
18580
|
-
const onUnusable = (member, raw) => this.
|
|
18658
|
+
const onUnusable = (member, raw) => this.warnUnusableProvisionedCapacity(`AWS::DynamoDB::Table ${logicalId}`, member, raw, maskSecrets);
|
|
18581
18659
|
createParams.ProvisionedThroughput = {
|
|
18582
18660
|
ReadCapacityUnits: tableCapacityForSend(pt, "ReadCapacityUnits", onUnusable),
|
|
18583
18661
|
WriteCapacityUnits: tableCapacityForSend(pt, "WriteCapacityUnits", onUnusable)
|
|
@@ -18593,7 +18671,7 @@ var DynamoDBTableProvider = class {
|
|
|
18593
18671
|
};
|
|
18594
18672
|
if (properties["GlobalSecondaryIndexes"]) {
|
|
18595
18673
|
const declaredGsis = properties["GlobalSecondaryIndexes"];
|
|
18596
|
-
createParams.GlobalSecondaryIndexes = Array.isArray(declaredGsis) ? declaredGsis.map((entry) => this.
|
|
18674
|
+
createParams.GlobalSecondaryIndexes = Array.isArray(declaredGsis) ? declaredGsis.map((entry) => this.coerceIndexThroughputForCreate(logicalId, entry, maskSecrets)) : declaredGsis;
|
|
18597
18675
|
}
|
|
18598
18676
|
if (properties["LocalSecondaryIndexes"]) createParams.LocalSecondaryIndexes = properties["LocalSecondaryIndexes"];
|
|
18599
18677
|
const sse = mapSSESpecification(properties["SSESpecification"]);
|
|
@@ -18711,7 +18789,7 @@ var DynamoDBTableProvider = class {
|
|
|
18711
18789
|
if (tableClassChanged) updateInput.TableClass = normalizeTableClass(properties["TableClass"]);
|
|
18712
18790
|
if (billingOrThroughputChanged && billingMode !== "PAY_PER_REQUEST" && properties["ProvisionedThroughput"]) {
|
|
18713
18791
|
const pt = properties["ProvisionedThroughput"];
|
|
18714
|
-
const onUnusable = (member, raw) => this.
|
|
18792
|
+
const onUnusable = (member, raw) => this.warnUnusableProvisionedCapacity(`AWS::DynamoDB::Table ${logicalId}`, member, raw, maskSecrets);
|
|
18715
18793
|
updateInput.ProvisionedThroughput = {
|
|
18716
18794
|
ReadCapacityUnits: tableCapacityForSend(pt, "ReadCapacityUnits", onUnusable),
|
|
18717
18795
|
WriteCapacityUnits: tableCapacityForSend(pt, "WriteCapacityUnits", onUnusable)
|
|
@@ -19403,7 +19481,7 @@ var DynamoDBTableProvider = class {
|
|
|
19403
19481
|
const adopted = { IndexName: name };
|
|
19404
19482
|
let adoptedHasMember = false;
|
|
19405
19483
|
if (liveCapacityComparable && gsi.ProvisionedThroughput && !handledByBillingFlip.has(name) && !liveCapacityAlreadyMatches(live.ProvisionedThroughput, gsi.ProvisionedThroughput) && !this.skipZeroCapacityIndexUpdate(name, physicalId, gsi.ProvisionedThroughput, maskSecrets)) {
|
|
19406
|
-
adopted.ProvisionedThroughput = gsi.ProvisionedThroughput;
|
|
19484
|
+
adopted.ProvisionedThroughput = this.indexCapacityForSend(this.indexScopeAt(name, physicalId, maskSecrets), gsi.ProvisionedThroughput, maskSecrets);
|
|
19407
19485
|
adoptedHasMember = true;
|
|
19408
19486
|
}
|
|
19409
19487
|
const adoptedWarm = this.warmThroughputOpFor(name, physicalId, gsi, void 0, live, maskSecrets);
|
|
@@ -19415,13 +19493,13 @@ var DynamoDBTableProvider = class {
|
|
|
19415
19493
|
warn(`GSI ${maskSecrets(name)} was adopted from AWS rather than created, so cdkd could not verify its KeySchema / Projection match the template. Run \`cdkd drift ${physicalId}\` to confirm, and \`cdkd drift --accept\` if AWS is the source of truth.`);
|
|
19416
19494
|
continue;
|
|
19417
19495
|
}
|
|
19418
|
-
this.warnRefusedWarmThroughput(
|
|
19419
|
-
const createWarm = this.coerceWarmThroughputForSend(
|
|
19496
|
+
this.warnRefusedWarmThroughput(this.indexScopeAt(name, physicalId, maskSecrets), gsi.WarmThroughput, maskSecrets);
|
|
19497
|
+
const createWarm = this.coerceWarmThroughputForSend(this.indexScopeAt(name, physicalId, maskSecrets), gsi.WarmThroughput, maskSecrets);
|
|
19420
19498
|
ops.push({ Create: {
|
|
19421
19499
|
IndexName: name,
|
|
19422
19500
|
KeySchema: gsi.KeySchema,
|
|
19423
19501
|
Projection: gsi.Projection,
|
|
19424
|
-
...gsi.ProvisionedThroughput ? { ProvisionedThroughput: gsi.ProvisionedThroughput } : {},
|
|
19502
|
+
...gsi.ProvisionedThroughput ? { ProvisionedThroughput: this.indexCapacityForSend(this.indexScopeAt(name, physicalId, maskSecrets), gsi.ProvisionedThroughput, maskSecrets) } : {},
|
|
19425
19503
|
...gsi.OnDemandThroughput ? { OnDemandThroughput: gsi.OnDemandThroughput } : {},
|
|
19426
19504
|
...createWarm ? { WarmThroughput: createWarm } : {}
|
|
19427
19505
|
} });
|
|
@@ -19433,7 +19511,7 @@ var DynamoDBTableProvider = class {
|
|
|
19433
19511
|
if (gsi.ProvisionedThroughput && !handledByBillingFlip.has(name) && JSON.stringify(before.ProvisionedThroughput) !== JSON.stringify(gsi.ProvisionedThroughput)) {
|
|
19434
19512
|
if (liveCapacityComparable && liveCapacityAlreadyMatches(liveIndexByName?.get(name)?.ProvisionedThroughput, gsi.ProvisionedThroughput)) this.logger.debug(`GSI ${name} on DynamoDB table ${physicalId} already carries the requested capacity in AWS; skipping its throughput Update`);
|
|
19435
19513
|
else if (!this.skipZeroCapacityIndexUpdate(name, physicalId, gsi.ProvisionedThroughput, maskSecrets)) {
|
|
19436
|
-
update.ProvisionedThroughput = gsi.ProvisionedThroughput;
|
|
19514
|
+
update.ProvisionedThroughput = this.indexCapacityForSend(this.indexScopeAt(name, physicalId, maskSecrets), gsi.ProvisionedThroughput, maskSecrets);
|
|
19437
19515
|
updateHasMember = true;
|
|
19438
19516
|
}
|
|
19439
19517
|
}
|
|
@@ -19465,45 +19543,201 @@ var DynamoDBTableProvider = class {
|
|
|
19465
19543
|
return coerced.spec;
|
|
19466
19544
|
}
|
|
19467
19545
|
/**
|
|
19468
|
-
*
|
|
19469
|
-
*
|
|
19546
|
+
* `GSI <name> on AWS::DynamoDB::Table <logicalId>` — the scope every
|
|
19547
|
+
* create-path per-index warning interpolates.
|
|
19548
|
+
*
|
|
19549
|
+
* The index NAME is a RESOLVED property value, so it is masked before it
|
|
19550
|
+
* becomes part of a message (issue #1997). It is also an UNCHECKED cast off
|
|
19551
|
+
* the template: `IndexName: 2024` (unquoted YAML) reaches here as a NUMBER,
|
|
19552
|
+
* and the real masker is a `String.prototype.replace` call that THROWS on
|
|
19553
|
+
* one — which would take the whole deploy down from a diagnostic path. So
|
|
19554
|
+
* the type test is the guard, not merely `!== undefined`: anything that is
|
|
19555
|
+
* not a string has no name to print and takes the `<unnamed>` arm, exactly
|
|
19556
|
+
* as an absent one does. (Reached by the review of issue
|
|
19557
|
+
* [#3255](https://github.com/go-to-k/cdkd/issues/3255): before it, the scope
|
|
19558
|
+
* was built only for an entry declaring `WarmThroughput`, so the crash was
|
|
19559
|
+
* unreachable for an ordinary PROVISIONED template.)
|
|
19560
|
+
*/
|
|
19561
|
+
indexScope(indexName, logicalId, maskSecrets) {
|
|
19562
|
+
return `GSI ${typeof indexName === "string" ? maskSecrets(indexName) : "<unnamed>"} on AWS::DynamoDB::Table ${logicalId}`;
|
|
19563
|
+
}
|
|
19564
|
+
/**
|
|
19565
|
+
* `GSI <name> on DynamoDB table <physicalId>` — {@link indexScope}'s twin for
|
|
19566
|
+
* the UPDATE path, which names the LIVE table rather than the template's
|
|
19567
|
+
* logical id.
|
|
19568
|
+
*
|
|
19569
|
+
* Same guard, same reason, and the reason is why this exists at all rather
|
|
19570
|
+
* than the five call sites spelling `maskSecrets(name)` inline: `name` is a
|
|
19571
|
+
* key of a map built from `g.IndexName!` off an UNCHECKED template cast, so
|
|
19572
|
+
* `IndexName: 2024` (unquoted YAML) is truthy, becomes the key, and arrives
|
|
19573
|
+
* here as a NUMBER — on which the real masker's `String.prototype.replace`
|
|
19574
|
+
* THROWS. The create path was guarded when {@link indexScope} was added
|
|
19575
|
+
* (the review of issue #3255); the update sites that now build a scope
|
|
19576
|
+
* EAGERLY for the capacity coercion were not, which newly exposed the same
|
|
19577
|
+
* crash on an ordinary PROVISIONED capacity update with a non-empty secret
|
|
19578
|
+
* bag (found by the review of that round).
|
|
19579
|
+
*/
|
|
19580
|
+
indexScopeAt(indexName, physicalId, maskSecrets) {
|
|
19581
|
+
return `GSI ${typeof indexName === "string" ? maskSecrets(indexName) : "<unnamed>"} on DynamoDB table ${physicalId}`;
|
|
19582
|
+
}
|
|
19583
|
+
/**
|
|
19584
|
+
* The per-index `ProvisionedThroughput` an `UpdateTable` action should put on
|
|
19585
|
+
* the wire (the review of issue
|
|
19586
|
+
* [#3255](https://github.com/go-to-k/cdkd/issues/3255)).
|
|
19587
|
+
*
|
|
19588
|
+
* Exists because coercing only `create()`'s forward left the file
|
|
19589
|
+
* INTERNALLY divergent in the direction the issue is about: the same index
|
|
19590
|
+
* entry succeeded on a fresh create and was rejected by AWS when added by a
|
|
19591
|
+
* later update, which is the `WarmThroughput` round-6 story with the
|
|
19592
|
+
* polarity flipped. All three `applyGsiUpdates` send sites — the adopted
|
|
19593
|
+
* index's repair `Update`, the `Create` action and the same-name `Update`
|
|
19594
|
+
* action — now read through {@link coerceIndexCapacityBlock}, the same
|
|
19595
|
+
* reader `create()` uses.
|
|
19596
|
+
*
|
|
19597
|
+
* **The GUARDS around those sites deliberately stay on `toFiniteNumber`**,
|
|
19598
|
+
* and that is the split `dynamodb-warm-throughput.ts`'s header already
|
|
19599
|
+
* records: a FORWARDER reads CloudFormation's grammar, a GUARD reads the
|
|
19600
|
+
* wider one, because over-acceptance is the safe side of an
|
|
19601
|
+
* already-matches / zero-capacity / change-detection test. Nothing moves as
|
|
19602
|
+
* a result — `liveCapacityAlreadyMatches` and `skipZeroCapacityIndexUpdate`
|
|
19603
|
+
* are asked about the DECLARED block exactly as before, and the change
|
|
19604
|
+
* detector still compares the declared block against the recorded one, both
|
|
19605
|
+
* raw. Only what reaches AWS changes.
|
|
19606
|
+
*/
|
|
19607
|
+
indexCapacityForSend(scope, declared, maskSecrets) {
|
|
19608
|
+
if (declared === void 0) return void 0;
|
|
19609
|
+
return this.coerceIndexCapacityBlock(scope, declared, maskSecrets) ?? declared;
|
|
19610
|
+
}
|
|
19611
|
+
/**
|
|
19612
|
+
* One `CreateTable` index entry with BOTH of its throughput blocks coerced —
|
|
19613
|
+
* `WarmThroughput` (PR review round 6) and `ProvisionedThroughput` (issue
|
|
19614
|
+
* [#3255](https://github.com/go-to-k/cdkd/issues/3255)).
|
|
19470
19615
|
*
|
|
19471
19616
|
* `create()` forwards the declared `GlobalSecondaryIndexes` array to
|
|
19472
|
-
* `CreateTable`, so it is a SEND SITE for the same per-index
|
|
19473
|
-
* update path coerces
|
|
19474
|
-
*
|
|
19475
|
-
*
|
|
19476
|
-
*
|
|
19477
|
-
*
|
|
19478
|
-
*
|
|
19479
|
-
*
|
|
19480
|
-
*
|
|
19481
|
-
|
|
19482
|
-
|
|
19617
|
+
* `CreateTable`, so it is a SEND SITE for the same per-index values the
|
|
19618
|
+
* update path coerces. `WarmThroughput` was the one the round-5 sweep
|
|
19619
|
+
* missed; `ProvisionedThroughput` was missed by round 6 AND by issue #3147's
|
|
19620
|
+
* own enumeration, because this forwarder is a CAST rather than a call, so
|
|
19621
|
+
* neither sweep's grep could see it. The BillingMode flip's per-index reader
|
|
19622
|
+
* ({@link readCapacityNumber}) has been on the grammar since #3147, so until
|
|
19623
|
+
* now create and flip disagreed about the same property: a CFn-legal
|
|
19624
|
+
* `ReadCapacityUnits: '7'` reached `CreateTable` as a STRING in a `number`
|
|
19625
|
+
* field, and a `' 7 '` CloudFormation refuses the template for was forwarded
|
|
19626
|
+
* unchanged.
|
|
19627
|
+
*
|
|
19628
|
+
* Entries are rebuilt rather than mutated: the input bag belongs to the
|
|
19629
|
+
* caller (the resolved template, which the engine also records into state),
|
|
19630
|
+
* and a provider that edits it in place would change what state reports cdkd
|
|
19631
|
+
* sent.
|
|
19632
|
+
*
|
|
19633
|
+
* An entry that is not a plain object, and one declaring NEITHER throughput
|
|
19634
|
+
* block, is returned UNCHANGED — identity included. An entry that DOES
|
|
19635
|
+
* declare one is rebuilt whenever that block's coercion changes anything;
|
|
19636
|
+
* the `WarmThroughput` half rebuilds even for an already-numeric value,
|
|
19637
|
+
* which is pre-existing behaviour and costs one spread per declared block.
|
|
19638
|
+
*/
|
|
19639
|
+
coerceIndexThroughputForCreate(logicalId, entry, maskSecrets = (text) => text) {
|
|
19483
19640
|
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return entry;
|
|
19484
|
-
const
|
|
19485
|
-
|
|
19486
|
-
const
|
|
19487
|
-
|
|
19488
|
-
|
|
19489
|
-
|
|
19490
|
-
|
|
19491
|
-
|
|
19641
|
+
const bag = entry;
|
|
19642
|
+
const declaredWarm = bag["WarmThroughput"];
|
|
19643
|
+
const declaredCapacity = bag["ProvisionedThroughput"];
|
|
19644
|
+
if (declaredWarm === void 0 && !isPlainCapacityBlock(declaredCapacity)) return entry;
|
|
19645
|
+
const scope = this.indexScope(entry.IndexName, logicalId, maskSecrets);
|
|
19646
|
+
let out = entry;
|
|
19647
|
+
if (declaredWarm !== void 0) {
|
|
19648
|
+
const coerced = this.coerceWarmThroughputForSend(scope, declaredWarm, maskSecrets);
|
|
19649
|
+
if (coerced === void 0) {
|
|
19650
|
+
this.warnRefusedWarmThroughput(scope, declaredWarm, maskSecrets);
|
|
19651
|
+
const { WarmThroughput: _dropped, ...rest } = out;
|
|
19652
|
+
out = rest;
|
|
19653
|
+
} else out = {
|
|
19654
|
+
...out,
|
|
19655
|
+
WarmThroughput: coerced
|
|
19656
|
+
};
|
|
19492
19657
|
}
|
|
19493
|
-
|
|
19494
|
-
|
|
19495
|
-
|
|
19658
|
+
const capacity = this.coerceIndexCapacityBlock(scope, declaredCapacity, maskSecrets);
|
|
19659
|
+
if (capacity !== void 0) out = {
|
|
19660
|
+
...out,
|
|
19661
|
+
ProvisionedThroughput: capacity
|
|
19496
19662
|
};
|
|
19663
|
+
return out;
|
|
19497
19664
|
}
|
|
19498
19665
|
/**
|
|
19499
|
-
*
|
|
19500
|
-
*
|
|
19501
|
-
* [#
|
|
19502
|
-
*
|
|
19503
|
-
*
|
|
19504
|
-
*
|
|
19505
|
-
*
|
|
19506
|
-
*
|
|
19666
|
+
* One `CreateTable` index entry's `ProvisionedThroughput`, with each DECLARED
|
|
19667
|
+
* member read through CloudFormation's DynamoDB Integer grammar (issue
|
|
19668
|
+
* [#3255](https://github.com/go-to-k/cdkd/issues/3255)). Returns `undefined`
|
|
19669
|
+
* when the block needs no rewriting at all.
|
|
19670
|
+
*
|
|
19671
|
+
* It reads through {@link readCapacityNumber} — the function the BillingMode
|
|
19672
|
+
* flip's per-index forwarder calls — rather than restating the grammar, for
|
|
19673
|
+
* the same reason {@link hasUsableDeclaredCapacity} does: that is what keeps
|
|
19674
|
+
* create and flip answering identically about one template value.
|
|
19675
|
+
*
|
|
19676
|
+
* THREE decisions, each of which had a plausible alternative:
|
|
19677
|
+
*
|
|
19678
|
+
* - **A rejected spelling drops the MEMBER, not the whole block.** This is
|
|
19679
|
+
* what {@link tableCapacityForSend} already does one level up for the
|
|
19680
|
+
* identical grammar, so create's two capacity forwarders answer the same
|
|
19681
|
+
* way; it keeps a sibling member the template spelled LEGALLY, which
|
|
19682
|
+
* dropping the block would discard; and it is the more informative
|
|
19683
|
+
* failure at AWS — `CreateTable` names the missing member at its exact
|
|
19684
|
+
* index position, where a missing block yields only
|
|
19685
|
+
* `ProvisionedThroughput must be specified for index: <name>`. Both
|
|
19686
|
+
* directions FAIL the deploy (DynamoDB requires both members on a
|
|
19687
|
+
* PROVISIONED index), so this is a choice of error TEXT, never of
|
|
19688
|
+
* outcome — what matters is that neither silently succeeds at a capacity
|
|
19689
|
+
* CloudFormation refuses the template for.
|
|
19690
|
+
*
|
|
19691
|
+
* **That is also why this drop needs NO `effectiveProperties`**, which
|
|
19692
|
+
* `.claude/rules/provider-property-fidelity.md` otherwise requires of any
|
|
19693
|
+
* announced narrowing: the rule exists because a SUCCEEDING call plus a
|
|
19694
|
+
* record describing the declared value is permanent phantom drift. Here
|
|
19695
|
+
* `CreateTable` FAILS, so `create()` never returns and nothing is
|
|
19696
|
+
* recorded — the same reasoning `tableCapacityForSend` states for the
|
|
19697
|
+
* table-level omit one level up.
|
|
19698
|
+
* - **An ABSENT member stays absent — no `5` default.** The per-index
|
|
19699
|
+
* reader deliberately has none ({@link readCapacityNumber}'s doc, issue
|
|
19700
|
+
* #1588): a defaulted per-index capacity would land in cdkd state as if
|
|
19701
|
+
* the template had declared it, with no later call to correct it. Only
|
|
19702
|
+
* the TABLE level defaults.
|
|
19703
|
+
* - **A block that is not a plain object is forwarded VERBATIM**, the
|
|
19704
|
+
* fail-OPEN direction this file takes everywhere: an unresolved intrinsic
|
|
19705
|
+
* or a mis-nested template value is AWS's to reject by name, and that is
|
|
19706
|
+
* also the pre-existing behaviour of this forwarder.
|
|
19707
|
+
*
|
|
19708
|
+
* A member name the grammar does not know is preserved untouched, for the
|
|
19709
|
+
* same fail-open reason — a misspelled `ReadCapacityUnit` reaches AWS and is
|
|
19710
|
+
* named there rather than vanishing here.
|
|
19711
|
+
*/
|
|
19712
|
+
coerceIndexCapacityBlock(scope, declared, maskSecrets = (text) => text) {
|
|
19713
|
+
if (!isPlainCapacityBlock(declared)) return void 0;
|
|
19714
|
+
const block = declared;
|
|
19715
|
+
let rewritten;
|
|
19716
|
+
for (const member of PROVISIONED_CAPACITY_MEMBERS) {
|
|
19717
|
+
if (!(member in block)) continue;
|
|
19718
|
+
const coerced = readCapacityNumber(block, member);
|
|
19719
|
+
if (coerced === block[member]) continue;
|
|
19720
|
+
rewritten ??= { ...block };
|
|
19721
|
+
if (coerced === void 0) {
|
|
19722
|
+
this.warnUnusableProvisionedCapacity(scope, member, block[member], maskSecrets);
|
|
19723
|
+
delete rewritten[member];
|
|
19724
|
+
} else rewritten[member] = coerced;
|
|
19725
|
+
}
|
|
19726
|
+
return rewritten;
|
|
19727
|
+
}
|
|
19728
|
+
/**
|
|
19729
|
+
* Announce a `ProvisionedThroughput` member a forwarder DROPPED (issue
|
|
19730
|
+
* [#3147](https://github.com/go-to-k/cdkd/issues/3147); widened to the
|
|
19731
|
+
* per-index create forwarder by issue
|
|
19732
|
+
* [#3255](https://github.com/go-to-k/cdkd/issues/3255)).
|
|
19733
|
+
*
|
|
19734
|
+
* Called from all THREE forwarders that can drop one — `create()`'s
|
|
19735
|
+
* `CreateTable` table-level block, the BillingMode flip's `UpdateTable`
|
|
19736
|
+
* table-level block, and `create()`'s per-`GlobalSecondaryIndexes[]` block —
|
|
19737
|
+
* because the member vanishes at each independently, and a drop that is
|
|
19738
|
+
* never announced is the silent-narrowing class this file's other warn arms
|
|
19739
|
+
* exist to end. `scope` names the resource or the index, so a table with
|
|
19740
|
+
* several GSIs says WHICH one.
|
|
19507
19741
|
*
|
|
19508
19742
|
* It says NO capacity was substituted, which is the whole decision: the
|
|
19509
19743
|
* sibling `AWS::DynamoDB::GlobalTable` forwarders announce a 5/5 FALLBACK,
|
|
@@ -19511,9 +19745,9 @@ var DynamoDBTableProvider = class {
|
|
|
19511
19745
|
* table that does not exist. {@link tableCapacityForSend}'s doc carries why
|
|
19512
19746
|
* this type differs.
|
|
19513
19747
|
*/
|
|
19514
|
-
|
|
19748
|
+
warnUnusableProvisionedCapacity(scope, member, raw, maskSecrets = (text) => text) {
|
|
19515
19749
|
const warn = (message) => this.logger.warn(maskSecrets(message));
|
|
19516
|
-
warn(`${scope}: ProvisionedThroughput.${member} ${JSON.stringify(maskLeafValue$1(raw, maskSecrets))} is not an Integer CloudFormation accepts (an optional sign and decimal digits only — no surrounding whitespace, hex, exponent or decimal point), so it was NOT sent and NO capacity was substituted for it. DynamoDB requires both members
|
|
19750
|
+
warn(`${scope}: ProvisionedThroughput.${member} ${JSON.stringify(maskLeafValue$1(raw, maskSecrets))} is not an Integer CloudFormation accepts (an optional sign and decimal digits only — no surrounding whitespace, hex, exponent or decimal point), so it was NOT sent and NO capacity was substituted for it. DynamoDB requires both members wherever a PROVISIONED ProvisionedThroughput block is declared — the table itself, and every GlobalSecondaryIndexes[] entry of a PROVISIONED table — and will reject the request naming this one; CloudFormation refuses the same template at properties validation. Check for an unresolved intrinsic, or spell the value as a decimal integer.`);
|
|
19517
19751
|
}
|
|
19518
19752
|
/**
|
|
19519
19753
|
* Announce a `WarmThroughput` the send rule REFUSES (PR review of issue
|
|
@@ -25748,7 +25982,13 @@ var SSMParameterProvider = class {
|
|
|
25748
25982
|
await this.ssmClient.send(new DeleteParameterCommand({ Name: name }));
|
|
25749
25983
|
debug(`Cleaned up partially-created SSM parameter ${logicalId} (${name}) after wiring failure`);
|
|
25750
25984
|
} catch (cleanupError) {
|
|
25751
|
-
|
|
25985
|
+
const deleteCommand = renderDisableCommand({
|
|
25986
|
+
before: "aws ssm delete-parameter --name",
|
|
25987
|
+
identifier: name,
|
|
25988
|
+
maskSecrets: mask
|
|
25989
|
+
});
|
|
25990
|
+
const manualStep = deleteCommand ? `Manual deletion may be required before the next deploy: ${deleteCommand}` : "Manual deletion may be required before the next deploy, via the console: the parameter name cannot be reproduced safely on a command line, and a command naming the sanitized form would delete a DIFFERENT parameter.";
|
|
25991
|
+
warn(`Failed to clean up partially-created SSM parameter ${logicalId} (${name}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. ${manualStep}`);
|
|
25752
25992
|
}
|
|
25753
25993
|
throw innerError;
|
|
25754
25994
|
}
|
|
@@ -25976,7 +26216,13 @@ var SSMParameterProvider = class {
|
|
|
25976
26216
|
const shape = isArn ? "an ARN" : "a version / label selector";
|
|
25977
26217
|
const remedy = input.knownPhysicalId === explicit ? `pass the parameter NAME instead: --resource ${input.logicalId}=<parameterName>` : `set Properties.Name to the parameter NAME rather than ${shape}`;
|
|
25978
26218
|
const whyNotDerived = isArn ? " cdkd deliberately does NOT derive the name from the ARN: the leading \"/\" is not recoverable (arn:...:parameter/foo is the ARN of BOTH the simple name \"foo\" and the hierarchical name \"/foo\"), and a parameter shared from another account has no name form at all — so a derived name could silently address a DIFFERENT parameter." : "";
|
|
25979
|
-
|
|
26219
|
+
const readCommand = renderDisableCommand({
|
|
26220
|
+
before: "aws ssm get-parameter --name",
|
|
26221
|
+
identifier: explicit,
|
|
26222
|
+
after: "--query Parameter.Name --output text"
|
|
26223
|
+
});
|
|
26224
|
+
const howToRead = readCommand ? ` Read the name AWS holds with: ${readCommand}` : " Read the name AWS holds via the console: the value cdkd was given cannot be reproduced safely on a command line, so any command shown here would read a different parameter.";
|
|
26225
|
+
throw new ProvisioningError(`Cannot adopt SSM parameter ${input.logicalId} from ${shape} ('${explicit}'): cdkd records a parameter's NAME as its physical id, because SSM's write APIs accept only the name (PutParameter and DeleteParameter both reject an ARN, and a name cannot contain ':'), so the next cdkd deploy and cdkd destroy would fail with a ValidationException. ${remedy}.${whyNotDerived}${howToRead}`, input.resourceType, input.logicalId);
|
|
25980
26226
|
}
|
|
25981
26227
|
/**
|
|
25982
26228
|
* Adopt an existing SSM parameter into cdkd state.
|
|
@@ -66054,7 +66300,7 @@ function indexNestedChildTemplates(template, templatePath) {
|
|
|
66054
66300
|
if (resource?.Type !== "AWS::CloudFormation::Stack") continue;
|
|
66055
66301
|
const assetPath = resource.Metadata?.["aws:asset:path"];
|
|
66056
66302
|
if (typeof assetPath !== "string" || assetPath.length === 0) continue;
|
|
66057
|
-
if (isAbsoluteCrossPlatform(assetPath)) throw new Error(`Nested stack '${logicalId}' has Metadata['aws:asset:path']='${assetPath}' which is absolute. CDK emits relative asset paths for nested templates; an absolute path indicates the synth output was hand-modified or generated by a non-CDK toolchain. Refusing to load.`);
|
|
66303
|
+
if (isAbsoluteCrossPlatform(assetPath)) throw new Error(`Nested stack '${displaySafe(logicalId)}' has Metadata['aws:asset:path']='${displaySafe(assetPath)}' which is absolute. CDK emits relative asset paths for nested templates; an absolute path indicates the synth output was hand-modified or generated by a non-CDK toolchain. Refusing to load.`);
|
|
66058
66304
|
result[logicalId] = path.join(dir, assetPath);
|
|
66059
66305
|
}
|
|
66060
66306
|
return result;
|
|
@@ -66354,7 +66600,7 @@ async function resolveChildStackParameters(parentStackRow, parentTemplate, paren
|
|
|
66354
66600
|
* fail at deploy time.
|
|
66355
66601
|
*/
|
|
66356
66602
|
async function buildDiffTree(args) {
|
|
66357
|
-
const { stackName, displayName, region, template, nestedTemplates, recursive, stateBackend, diffCalculator, parentHasSecretReference, parameters, canonicalizeProperties, assetRedirect, cfnFallback, previewOrphanAdoption } = args;
|
|
66603
|
+
const { stackName, displayName, region, template, nestedTemplates, recursive, stateBackend, diffCalculator, parentHasSecretReference, parameters, canonicalizeProperties, assetRedirect, cfnFallback, previewOrphanAdoption, ancestorTemplatePaths } = args;
|
|
66358
66604
|
const state = await loadStateOrEmpty(stackName, region, stateBackend);
|
|
66359
66605
|
const secretBearingAbove = parentHasSecretReference === true || templateHasSecretDynamicReference(template);
|
|
66360
66606
|
const { changes, outputChanges, adoptedOrphans, adoptedRecords, blocking } = await computeStackDiff(state, template, region, stackName, stateBackend, diffCalculator, {
|
|
@@ -66390,6 +66636,9 @@ async function buildDiffTree(args) {
|
|
|
66390
66636
|
const childTemplatePath = nestedTemplates[logicalId];
|
|
66391
66637
|
if (!childTemplatePath) throw new Error(`Nested template file not found for ${NESTED_STACK_RESOURCE_TYPE} '${logicalId}' under stack '${stackName}'. Verify the synth output emits Metadata['aws:asset:path'] on this resource (CDK 2.x cdk.NestedStack does so by default), then re-run synth.`);
|
|
66392
66638
|
const childStackName = `${stackName}~${logicalId}`;
|
|
66639
|
+
const resolvedChildPath = path.resolve(childTemplatePath);
|
|
66640
|
+
if (ancestorTemplatePaths?.has(resolvedChildPath) === true) throw new Error(`Nested stack '${displaySafe(logicalId)}' under stack '${displaySafe(stackName)}' resolves to nested template '${displaySafe(resolvedChildPath)}', which is already being diffed higher up the same nesting chain. Its Metadata['aws:asset:path'] closes a cycle; CDK emits an acyclic nested template tree, so this indicates the synth output was hand-modified or generated by a non-CDK toolchain. Refusing to diff.`);
|
|
66641
|
+
const childAncestorTemplatePaths = new Set(ancestorTemplatePaths ?? []).add(resolvedChildPath);
|
|
66393
66642
|
const childTemplate = readNestedTemplate(childTemplatePath);
|
|
66394
66643
|
if (assetRedirect) rewriteTemplateAssetReferences(childTemplate, assetRedirect);
|
|
66395
66644
|
const grandchildTemplates = indexNestedChildTemplates(childTemplate, childTemplatePath);
|
|
@@ -66408,6 +66657,7 @@ async function buildDiffTree(args) {
|
|
|
66408
66657
|
...assetRedirect && { assetRedirect },
|
|
66409
66658
|
...cfnFallback !== void 0 && { cfnFallback },
|
|
66410
66659
|
...previewOrphanAdoption && { previewOrphanAdoption },
|
|
66660
|
+
ancestorTemplatePaths: childAncestorTemplatePaths,
|
|
66411
66661
|
parentHasSecretReference: secretBearingAbove
|
|
66412
66662
|
}));
|
|
66413
66663
|
}
|
|
@@ -74649,6 +74899,39 @@ function createStateMigrateCommand() {
|
|
|
74649
74899
|
//#endregion
|
|
74650
74900
|
//#region src/cli/commands/state-list-tree.ts
|
|
74651
74901
|
/**
|
|
74902
|
+
* How deep a node may sit below its root, counting the root as 0.
|
|
74903
|
+
*
|
|
74904
|
+
* A node that would sit deeper is made a root instead (see
|
|
74905
|
+
* {@link buildStackTree}). The value is far beyond any nesting an app is
|
|
74906
|
+
* written with: CloudFormation stops at five levels of nested stacks, so an
|
|
74907
|
+
* app that also has to deploy through CloudFormation cannot exceed that.
|
|
74908
|
+
* cdkd deploys nested stacks through its own engine and imposes no limit of
|
|
74909
|
+
* its own, so a deliberately deeper app CAN produce a tree this reshapes —
|
|
74910
|
+
* which is the point. The view stays whole either way.
|
|
74911
|
+
*
|
|
74912
|
+
* It exists because every step AFTER the tree is built recurses once per
|
|
74913
|
+
* level: this module's own child sort, the box-drawing renderer and
|
|
74914
|
+
* {@link stackTreeToJson}, plus the `JSON.stringify` that serializes that
|
|
74915
|
+
* shape for `--tree --json`. Capping the tree bounds all four at once, which
|
|
74916
|
+
* an iterative rewrite of any of them could not: `JSON.stringify` recurses
|
|
74917
|
+
* into whatever nesting it is handed, and the text view indents four
|
|
74918
|
+
* characters per level, so a chain deep enough would need more indentation
|
|
74919
|
+
* than a string can hold.
|
|
74920
|
+
*
|
|
74921
|
+
* It bounds the DEPTH, not the bucket, and what it does to the failure at the
|
|
74922
|
+
* far end is change its KIND. Before the cap, one deep chain exhausted the
|
|
74923
|
+
* CALL STACK, at a record count nothing fixes — V8's budget moves with frame
|
|
74924
|
+
* size and with what else is on the stack. After it, every recursion is at
|
|
74925
|
+
* most a hundred frames and the remaining ceiling is V8's maximum STRING
|
|
74926
|
+
* length: a capped tree still costs a roughly constant number of characters
|
|
74927
|
+
* per record (the cap's own pretty-print indent dominates in `--tree --json`),
|
|
74928
|
+
* so `JSON.stringify` refuses a large enough bucket deterministically instead
|
|
74929
|
+
* of at a moving depth. Both are far past `renderTreeMode`'s unbounded
|
|
74930
|
+
* one-read-per-reference fan-out, which gives out first. Read the cap as what
|
|
74931
|
+
* stops a SINGLE chain taking the view down, not as a total bound.
|
|
74932
|
+
*/
|
|
74933
|
+
const MAX_STACK_TREE_DEPTH = 100;
|
|
74934
|
+
/**
|
|
74652
74935
|
* Build a parent → child tree from the flat list of state records.
|
|
74653
74936
|
*
|
|
74654
74937
|
* Children are linked to their parent by `(parentStack, parentRegion)`
|
|
@@ -74664,6 +74947,17 @@ function createStateMigrateCommand() {
|
|
|
74664
74947
|
* from both the text and the JSON view. A node hanging off a loop still sits
|
|
74665
74948
|
* under its parent, which is now visible (issue #3069).
|
|
74666
74949
|
*
|
|
74950
|
+
* A node that would sit deeper than {@link MAX_STACK_TREE_DEPTH} levels below
|
|
74951
|
+
* its root is placed at the root too, so the chain resumes there as its own
|
|
74952
|
+
* tree. Every record still appears exactly once, and a tree within the cap is
|
|
74953
|
+
* built as before. Without it a long enough chain took the whole view down with
|
|
74954
|
+
* a `RangeError` instead of costing only its own rows, since the recursive
|
|
74955
|
+
* steps AFTER this function are not covered by the per-stack guard around the
|
|
74956
|
+
* state read. Reaching the depths that failed takes thousands of records — in
|
|
74957
|
+
* practice a hand-edited bucket, or records planted by someone holding
|
|
74958
|
+
* `s3:PutObject` on it — but nothing in cdkd bounds the depth, so the cap does
|
|
74959
|
+
* (issue #3155).
|
|
74960
|
+
*
|
|
74667
74961
|
* The roots and every child list are sorted alphabetically by `stackName`,
|
|
74668
74962
|
* then by `region` (legacy `undefined` last), so output is stable across
|
|
74669
74963
|
* runs.
|
|
@@ -74690,10 +74984,26 @@ function buildStackTree(entries) {
|
|
|
74690
74984
|
if (current !== void 0 && onPath.has(current)) for (const member of path.slice(onPath.get(current))) loopMembers.add(member);
|
|
74691
74985
|
for (const node of path) settled.add(node);
|
|
74692
74986
|
}
|
|
74987
|
+
const depthOf = /* @__PURE__ */ new Map();
|
|
74988
|
+
for (const member of loopMembers) depthOf.set(member, 0);
|
|
74989
|
+
for (const start of byKey.values()) {
|
|
74990
|
+
if (depthOf.has(start)) continue;
|
|
74991
|
+
const path = [];
|
|
74992
|
+
let current = start;
|
|
74993
|
+
while (current !== void 0 && !depthOf.has(current)) {
|
|
74994
|
+
path.push(current);
|
|
74995
|
+
current = parentOf(current);
|
|
74996
|
+
}
|
|
74997
|
+
let depth = current === void 0 ? -1 : depthOf.get(current);
|
|
74998
|
+
for (let i = path.length - 1; i >= 0; i--) {
|
|
74999
|
+
depth = depth + 1 > 100 ? 0 : depth + 1;
|
|
75000
|
+
depthOf.set(path[i], depth);
|
|
75001
|
+
}
|
|
75002
|
+
}
|
|
74693
75003
|
const roots = [];
|
|
74694
75004
|
for (const node of byKey.values()) {
|
|
74695
75005
|
const parent = parentOf(node);
|
|
74696
|
-
if (parent &&
|
|
75006
|
+
if (parent && depthOf.get(node) > 0) {
|
|
74697
75007
|
parent.children.push(node);
|
|
74698
75008
|
continue;
|
|
74699
75009
|
}
|
|
@@ -78727,6 +79037,12 @@ async function stateListCommand(options) {
|
|
|
78727
79037
|
*
|
|
78728
79038
|
* `tree --json` emits the nested {@link import('./state-list-tree.js').StackTreeJson}
|
|
78729
79039
|
* shape; plain `tree` renders `tree(1)`-style box-drawing.
|
|
79040
|
+
*
|
|
79041
|
+
* The `JSON.stringify` below recurses once per level of the shape it is handed,
|
|
79042
|
+
* and so does the box-drawing renderer. Neither needs a depth guard here:
|
|
79043
|
+
* `buildStackTree` caps how deep a node may sit
|
|
79044
|
+
* ({@link import('./state-list-tree.js').MAX_STACK_TREE_DEPTH}), which bounds
|
|
79045
|
+
* both (issue #3155).
|
|
78730
79046
|
*/
|
|
78731
79047
|
async function renderTreeMode(refs, stateBackend, asJson) {
|
|
78732
79048
|
const entries = await Promise.all(refs.map(async (ref) => {
|
|
@@ -94172,4 +94488,4 @@ function buildProgram() {
|
|
|
94172
94488
|
|
|
94173
94489
|
//#endregion
|
|
94174
94490
|
export { buildProgram };
|
|
94175
|
-
//# sourceMappingURL=program-
|
|
94491
|
+
//# sourceMappingURL=program-U03H43s7.js.map
|