@go-to-k/cdkd 0.116.1 → 0.117.1

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/cli.js CHANGED
@@ -44,10 +44,10 @@ import { CreateWebACLCommand, DeleteWebACLCommand, GetWebACLCommand, ListTagsFor
44
44
  import { CognitoIdentityProviderClient, CreateUserPoolCommand, DeleteUserPoolCommand, DescribeUserPoolCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$14, ListUserPoolsCommand, ResourceNotFoundException as ResourceNotFoundException$6, UpdateUserPoolCommand } from "@aws-sdk/client-cognito-identity-provider";
45
45
  import { AddTagsToResourceCommand as AddTagsToResourceCommand$4, CreateCacheClusterCommand, CreateCacheSubnetGroupCommand, DeleteCacheClusterCommand, DeleteCacheSubnetGroupCommand, DescribeCacheClustersCommand, DescribeCacheSubnetGroupsCommand, ElastiCacheClient, ListTagsForResourceCommand as ListTagsForResourceCommand$15, ModifyCacheClusterCommand, ModifyCacheSubnetGroupCommand, RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand$4 } from "@aws-sdk/client-elasticache";
46
46
  import { CreatePrivateDnsNamespaceCommand, CreateServiceCommand as CreateServiceCommand$1, DeleteNamespaceCommand, DeleteServiceCommand as DeleteServiceCommand$1, GetNamespaceCommand, GetOperationCommand, GetServiceCommand, ListNamespacesCommand, ListServicesCommand as ListServicesCommand$1, ListTagsForResourceCommand as ListTagsForResourceCommand$16, NamespaceNotFound, ServiceDiscoveryClient, ServiceNotFound, UpdatePrivateDnsNamespaceCommand, UpdateServiceCommand as UpdateServiceCommand$1 } from "@aws-sdk/client-servicediscovery";
47
- import { AppSyncClient, CreateApiKeyCommand, CreateDataSourceCommand, CreateGraphqlApiCommand, CreateResolverCommand, DeleteApiKeyCommand, DeleteDataSourceCommand, DeleteGraphqlApiCommand, DeleteResolverCommand, GetDataSourceCommand, GetGraphqlApiCommand, GetIntrospectionSchemaCommand, GetResolverCommand, ListApiKeysCommand, ListGraphqlApisCommand, NotFoundException as NotFoundException$4, StartSchemaCreationCommand } from "@aws-sdk/client-appsync";
47
+ import { AppSyncClient, CreateApiKeyCommand, CreateDataSourceCommand, CreateGraphqlApiCommand, CreateResolverCommand, DeleteApiKeyCommand, DeleteDataSourceCommand, DeleteGraphqlApiCommand, DeleteResolverCommand, GetDataSourceCommand, GetGraphqlApiCommand, GetIntrospectionSchemaCommand, GetResolverCommand, ListApiKeysCommand, ListGraphqlApisCommand, NotFoundException as NotFoundException$4, StartSchemaCreationCommand, TagResourceCommand as TagResourceCommand$13, UntagResourceCommand as UntagResourceCommand$12, UpdateApiKeyCommand, UpdateDataSourceCommand, UpdateGraphqlApiCommand, UpdateResolverCommand } from "@aws-sdk/client-appsync";
48
48
  import { parse, print } from "graphql";
49
49
  import { CreateConnectionCommand, CreateCrawlerCommand, CreateDatabaseCommand, CreateJobCommand, CreateSecurityConfigurationCommand, CreateTableCommand as CreateTableCommand$1, CreateTriggerCommand, CreateWorkflowCommand, DeleteConnectionCommand, DeleteCrawlerCommand, DeleteDatabaseCommand, DeleteJobCommand, DeleteSecurityConfigurationCommand, DeleteTableCommand as DeleteTableCommand$1, DeleteTriggerCommand, DeleteWorkflowCommand, EntityNotFoundException, GetConnectionCommand, GetCrawlerCommand, GetDatabaseCommand, GetDatabasesCommand, GetJobCommand, GetSecurityConfigurationCommand, GetSecurityConfigurationsCommand, GetTableCommand, GetTablesCommand, GetTagsCommand, GetTriggerCommand, GetWorkflowCommand, GlueClient, ListWorkflowsCommand, StartCrawlerScheduleCommand, StartTriggerCommand, StopCrawlerScheduleCommand, StopTriggerCommand, UpdateConnectionCommand, UpdateCrawlerCommand, UpdateDatabaseCommand, UpdateJobCommand, UpdateTableCommand as UpdateTableCommand$1, UpdateTriggerCommand, UpdateWorkflowCommand } from "@aws-sdk/client-glue";
50
- import { AddTagsToStreamCommand, CreateStreamCommand, DecreaseStreamRetentionPeriodCommand, DeleteStreamCommand, DeregisterStreamConsumerCommand, DescribeStreamCommand, DescribeStreamConsumerCommand, IncreaseStreamRetentionPeriodCommand, KinesisClient, ListStreamsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$17, ListTagsForStreamCommand, RegisterStreamConsumerCommand, RemoveTagsFromStreamCommand, ResourceNotFoundException as ResourceNotFoundException$7, StartStreamEncryptionCommand, StopStreamEncryptionCommand, TagResourceCommand as TagResourceCommand$13, UntagResourceCommand as UntagResourceCommand$12, UpdateShardCountCommand } from "@aws-sdk/client-kinesis";
50
+ import { AddTagsToStreamCommand, CreateStreamCommand, DecreaseStreamRetentionPeriodCommand, DeleteStreamCommand, DeregisterStreamConsumerCommand, DescribeStreamCommand, DescribeStreamConsumerCommand, IncreaseStreamRetentionPeriodCommand, KinesisClient, ListStreamsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$17, ListTagsForStreamCommand, RegisterStreamConsumerCommand, RemoveTagsFromStreamCommand, ResourceNotFoundException as ResourceNotFoundException$7, StartStreamEncryptionCommand, StopStreamEncryptionCommand, TagResourceCommand as TagResourceCommand$14, UntagResourceCommand as UntagResourceCommand$13, UpdateShardCountCommand } from "@aws-sdk/client-kinesis";
51
51
  import { AccessPointNotFound, CreateAccessPointCommand, CreateFileSystemCommand, CreateMountTargetCommand, DeleteAccessPointCommand, DeleteFileSystemCommand, DeleteMountTargetCommand, DescribeAccessPointsCommand, DescribeBackupPolicyCommand, DescribeFileSystemsCommand, DescribeLifecycleConfigurationCommand, DescribeMountTargetSecurityGroupsCommand, DescribeMountTargetsCommand, EFSClient, FileSystemNotFound, ModifyMountTargetSecurityGroupsCommand, MountTargetNotFound, UpdateFileSystemCommand } from "@aws-sdk/client-efs";
52
52
  import { CreateDeliveryStreamCommand, DeleteDeliveryStreamCommand, DescribeDeliveryStreamCommand, FirehoseClient, ListDeliveryStreamsCommand, ListTagsForDeliveryStreamCommand, ResourceNotFoundException as ResourceNotFoundException$8 } from "@aws-sdk/client-firehose";
53
53
  import { AddTagsCommand as AddTagsCommand$1, CloudTrailClient, CreateTrailCommand, DeleteTrailCommand, GetEventSelectorsCommand, GetInsightSelectorsCommand, GetTrailCommand, GetTrailStatusCommand, ListTagsCommand as ListTagsCommand$1, ListTrailsCommand, PutEventSelectorsCommand, PutInsightSelectorsCommand, RemoveTagsCommand as RemoveTagsCommand$1, StartLoggingCommand, StopLoggingCommand, TrailNotFoundException, UpdateTrailCommand } from "@aws-sdk/client-cloudtrail";
@@ -7375,7 +7375,7 @@ var LambdaLayerVersionProvider = class {
7375
7375
  * template should re-deploy with `--replace`.
7376
7376
  */
7377
7377
  async update(logicalId, _physicalId, resourceType, _properties, _previousProperties) {
7378
- return Promise.reject(new ResourceUpdateNotSupportedError(resourceType, logicalId, "Lambda layer versions are immutable on AWS; re-deploy with cdkd deploy --replace, or change the resource definition to publish a new version"));
7378
+ return Promise.reject(new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS Lambda LayerVersion is immutable on AWS — there is no UpdateLayerVersion API; every change requires PublishLayerVersion (a new version with a new LayerVersionArn). Re-deploy with cdkd deploy --replace, or change the resource definition to publish a new version."));
7379
7379
  }
7380
7380
  /**
7381
7381
  * Delete a Lambda layer version
@@ -11212,7 +11212,7 @@ var EC2Provider = class {
11212
11212
  case "AWS::EC2::Instance": return this.updateInstance(logicalId, physicalId, resourceType, properties, previousProperties);
11213
11213
  case "AWS::EC2::NetworkAcl":
11214
11214
  case "AWS::EC2::NetworkAclEntry":
11215
- case "AWS::EC2::SubnetNetworkAclAssociation": throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "destroy + redeploy. The property surface for this resource type is effectively immutable in cdkd today.");
11215
+ case "AWS::EC2::SubnetNetworkAclAssociation": throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS provides no in-place Update API for this EC2 sub-resource type; every property change requires Delete + Create. Re-deploy with cdkd deploy --replace, or destroy + redeploy.");
11216
11216
  default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
11217
11217
  }
11218
11218
  }
@@ -13727,7 +13727,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
13727
13727
  * `ResourceUpdateNotSupportedError` instead of silently no-op'ing.
13728
13728
  */
13729
13729
  updateDeployment(logicalId, _physicalId, _resourceType) {
13730
- return Promise.reject(new ResourceUpdateNotSupportedError("AWS::ApiGateway::Deployment", logicalId, "API Gateway Deployment is immutable; re-deploy with cdkd deploy --replace, or change the resource definition to create a new Deployment"));
13730
+ return Promise.reject(new ResourceUpdateNotSupportedError("AWS::ApiGateway::Deployment", logicalId, "API Gateway Deployment is immutable on AWS — there is no UpdateDeployment API for the deployment itself (UpdateStage is for the stage that points at the deployment); every change requires CreateDeployment to produce a new immutable deployment. Re-deploy with cdkd deploy --replace, or change the resource definition to create a new Deployment."));
13731
13731
  }
13732
13732
  /**
13733
13733
  * Delete an API Gateway Deployment
@@ -14520,7 +14520,7 @@ var ApiGatewayV2Provider = class {
14520
14520
  case "AWS::ApiGatewayV2::Integration": return this.updateIntegration(logicalId, physicalId, resourceType, properties, previousProperties);
14521
14521
  case "AWS::ApiGatewayV2::Route": return this.updateRoute(logicalId, physicalId, resourceType, properties, previousProperties);
14522
14522
  case "AWS::ApiGatewayV2::Authorizer": return this.updateAuthorizer(logicalId, physicalId, resourceType, properties, previousProperties);
14523
- default: throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "unsupported API Gateway V2 resource type for in-place update; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack");
14523
+ default: throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "Unsupported API Gateway V2 resource type for in-place update in cdkd; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack.");
14524
14524
  }
14525
14525
  }
14526
14526
  async delete(logicalId, physicalId, resourceType, properties, context) {
@@ -16617,7 +16617,7 @@ var ECSProvider = class {
16617
16617
  }
16618
16618
  }
16619
16619
  async updateTaskDefinition(logicalId, _physicalId, _resourceType, _properties) {
16620
- return Promise.reject(new ResourceUpdateNotSupportedError("AWS::ECS::TaskDefinition", logicalId, "TaskDefinition revisions are immutable; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack"));
16620
+ return Promise.reject(new ResourceUpdateNotSupportedError("AWS::ECS::TaskDefinition", logicalId, "ECS TaskDefinition revisions are immutable on AWS — there is no UpdateTaskDefinition API; every change registers a new revision via RegisterTaskDefinition. Re-deploy with cdkd deploy --replace, or destroy + redeploy the stack."));
16621
16621
  }
16622
16622
  async deleteTaskDefinition(logicalId, physicalId, resourceType, context) {
16623
16623
  this.logger.debug(`Deleting ECS task definition ${logicalId}: ${physicalId}`);
@@ -17398,7 +17398,7 @@ var ELBv2Provider = class {
17398
17398
  for (const [k, v] of Object.entries(p)) if (!handledKeys.has(k)) out[k] = v;
17399
17399
  return out;
17400
17400
  };
17401
- if (JSON.stringify(stripHandled(properties)) !== JSON.stringify(stripHandled(previousProperties))) throw new ResourceUpdateNotSupportedError("AWS::ElasticLoadBalancingV2::LoadBalancer", logicalId, "ELBv2 LoadBalancer in-place updates are supported for LoadBalancerAttributes / Subnets / SubnetMappings / SecurityGroups / IpAddressType / Tags only; for Name / Type / Scheme, re-deploy with cdkd deploy --replace, or destroy + redeploy the stack");
17401
+ if (JSON.stringify(stripHandled(properties)) !== JSON.stringify(stripHandled(previousProperties))) throw new ResourceUpdateNotSupportedError("AWS::ElasticLoadBalancingV2::LoadBalancer", logicalId, "ELBv2 LoadBalancer Name / Type / Scheme are immutable on AWS — none of the ELBv2 Modify* / Set* APIs accept these fields; they are fixed at creation. cdkd handles LoadBalancerAttributes / Subnets / SubnetMappings / SecurityGroups / IpAddressType / Tags in-place; for Name / Type / Scheme re-deploy with cdkd deploy --replace, or destroy + redeploy the stack.");
17402
17402
  const newAttrs = properties["LoadBalancerAttributes"] ?? [];
17403
17403
  const oldAttrs = previousProperties["LoadBalancerAttributes"] ?? [];
17404
17404
  const newAttrMap = new Map(newAttrs.map((a) => [a.Key, a.Value]));
@@ -23242,6 +23242,20 @@ var AppSyncProvider = class {
23242
23242
  client;
23243
23243
  providerRegion = process.env["AWS_REGION"];
23244
23244
  logger = getLogger().child("AppSyncProvider");
23245
+ /**
23246
+ * Cache of `apiId -> GraphqlApi ARN` for the lifetime of this provider
23247
+ * instance. Populated lazily by `applyTagDiff` and reused on subsequent
23248
+ * tag-diff updates against the same API so we don't pay an extra
23249
+ * `GetGraphqlApi` round-trip per call. Mirrors the existing
23250
+ * `attributeCache` pattern used elsewhere in this provider family.
23251
+ *
23252
+ * Invalidation: the ARN of a GraphqlApi is stable for the life of the
23253
+ * API (it embeds the apiId), so the cache never needs to be invalidated
23254
+ * within a process — the only way the ARN changes is if the API itself
23255
+ * is replaced, in which case a new `physicalId` flows through `update()`
23256
+ * and the old entry simply becomes unreachable.
23257
+ */
23258
+ arnCache = /* @__PURE__ */ new Map();
23245
23259
  handledProperties = new Map([
23246
23260
  ["AWS::AppSync::GraphQLApi", new Set([
23247
23261
  "Name",
@@ -23298,15 +23312,307 @@ var AppSyncProvider = class {
23298
23312
  }
23299
23313
  }
23300
23314
  /**
23301
- * AppSync resources are treated as immutable by cdkd: every supported
23302
- * type (`GraphQLApi`, `GraphQLSchema`, `DataSource`, `Resolver`,
23303
- * `ApiKey`) is recreated on property changes via the deploy engine's
23304
- * immutable-property replacement path. There is no in-place update,
23305
- * so `cdkd drift --revert` surfaces a clear "use --replace or
23306
- * re-deploy" message instead of silently no-op'ing the revert.
23315
+ * Update an AppSync resource in-place via the SDK's `Update*` calls.
23316
+ *
23317
+ * Per-type API path:
23318
+ * - `GraphQLApi` → `UpdateGraphqlApiCommand` (`AuthenticationType` /
23319
+ * `XrayEnabled` / `LogConfig`) + `TagResource` / `UntagResource`
23320
+ * for `Tags` diff. `Name` is immutable on AWS.
23321
+ * - `DataSource` → `UpdateDataSourceCommand` (`Description` /
23322
+ * `ServiceRoleArn` / `DynamoDBConfig` / `LambdaConfig` / `HttpConfig`).
23323
+ * `ApiId` / `Name` / `Type` are immutable identity fields.
23324
+ * - `Resolver` → `UpdateResolverCommand` (`DataSourceName` /
23325
+ * `RequestMappingTemplate` / `ResponseMappingTemplate` / `Kind` /
23326
+ * `PipelineConfig` / `Runtime` / `Code`). `ApiId` / `TypeName` /
23327
+ * `FieldName` are immutable identity fields.
23328
+ * - `ApiKey` → `UpdateApiKeyCommand` (`Description` / `Expires`).
23329
+ * `ApiId` is immutable; the AWS-generated key id is immutable.
23330
+ * - `GraphQLSchema` → `StartSchemaCreationCommand` (re-upload the
23331
+ * SDL; this is the canonical AppSync schema-update path).
23332
+ *
23333
+ * Every Update* call uses `!== undefined` field gates per
23334
+ * memory rule `feedback_update_optional_field_undefined_check.md` so
23335
+ * `cdkd drift --revert` can clear a console-side ADD via an empty
23336
+ * string / 0 / false. Identity / immutable field changes throw
23337
+ * `ResourceUpdateNotSupportedError` as defense-in-depth — the deploy
23338
+ * engine's replacement-detection layer should normally route those
23339
+ * through CREATE+DELETE.
23307
23340
  */
23308
- update(logicalId, _physicalId, resourceType, _properties, _previousProperties) {
23309
- return Promise.reject(new ResourceUpdateNotSupportedError(resourceType, logicalId, "AppSync resources are recreated on property changes; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack"));
23341
+ async update(logicalId, physicalId, resourceType, properties, previousProperties) {
23342
+ switch (resourceType) {
23343
+ case "AWS::AppSync::GraphQLApi": return this.updateGraphQLApi(logicalId, physicalId, resourceType, properties, previousProperties);
23344
+ case "AWS::AppSync::GraphQLSchema": return this.updateGraphQLSchema(logicalId, physicalId, resourceType, properties, previousProperties);
23345
+ case "AWS::AppSync::DataSource": return this.updateDataSource(logicalId, physicalId, resourceType, properties, previousProperties);
23346
+ case "AWS::AppSync::Resolver": return this.updateResolver(logicalId, physicalId, resourceType, properties, previousProperties);
23347
+ case "AWS::AppSync::ApiKey": return this.updateApiKey(logicalId, physicalId, resourceType, properties, previousProperties);
23348
+ default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
23349
+ }
23350
+ }
23351
+ /**
23352
+ * Structural equality for the small object / array shapes that ride on
23353
+ * AppSync update inputs. `JSON.stringify` is sufficient because none of
23354
+ * these shapes contain `undefined` keys at this layer (the create /
23355
+ * readCurrentState paths filter them out).
23356
+ */
23357
+ deepEqual(a, b) {
23358
+ return JSON.stringify(a) === JSON.stringify(b);
23359
+ }
23360
+ async updateGraphQLApi(logicalId, physicalId, resourceType, properties, previousProperties) {
23361
+ if (properties["Name"] !== void 0 && previousProperties["Name"] !== void 0 && properties["Name"] !== previousProperties["Name"]) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS AppSync GraphqlApi.Name is immutable — destroy + redeploy to rename");
23362
+ const newAuthType = properties["AuthenticationType"];
23363
+ const oldAuthType = previousProperties["AuthenticationType"];
23364
+ const newXray = properties["XrayEnabled"];
23365
+ const oldXray = previousProperties["XrayEnabled"];
23366
+ const newLog = properties["LogConfig"];
23367
+ const oldLog = previousProperties["LogConfig"];
23368
+ const hasXrayDiff = ("XrayEnabled" in properties || "XrayEnabled" in previousProperties) && newXray !== oldXray;
23369
+ const hasAuthDiff = ("AuthenticationType" in properties || "AuthenticationType" in previousProperties) && newAuthType !== oldAuthType;
23370
+ const hasLogDiff = ("LogConfig" in properties || "LogConfig" in previousProperties) && !this.deepEqual(newLog, oldLog);
23371
+ if (hasAuthDiff || hasXrayDiff || hasLogDiff) {
23372
+ const input = {
23373
+ apiId: physicalId,
23374
+ name: properties["Name"] ?? previousProperties["Name"],
23375
+ authenticationType: newAuthType ?? oldAuthType ?? "API_KEY"
23376
+ };
23377
+ if (newXray !== void 0) input.xrayEnabled = newXray;
23378
+ if (newLog !== void 0) input.logConfig = {
23379
+ cloudWatchLogsRoleArn: newLog["CloudWatchLogsRoleArn"],
23380
+ fieldLogLevel: newLog["FieldLogLevel"],
23381
+ excludeVerboseContent: newLog["ExcludeVerboseContent"]
23382
+ };
23383
+ else if (oldLog !== void 0) {
23384
+ const existingRoleArn = oldLog["CloudWatchLogsRoleArn"];
23385
+ if (existingRoleArn) input.logConfig = {
23386
+ cloudWatchLogsRoleArn: existingRoleArn,
23387
+ fieldLogLevel: "NONE"
23388
+ };
23389
+ else this.logger.warn(`AppSync GraphqlApi ${logicalId}: cannot clear LogConfig — previous state has no CloudWatchLogsRoleArn to reuse for the disable call`);
23390
+ }
23391
+ try {
23392
+ await this.getClient().send(new UpdateGraphqlApiCommand(input));
23393
+ } catch (error) {
23394
+ throw this.wrapUpdateError(error, resourceType, logicalId, physicalId, "GraphqlApi");
23395
+ }
23396
+ }
23397
+ await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
23398
+ return {
23399
+ physicalId,
23400
+ wasReplaced: false,
23401
+ attributes: {}
23402
+ };
23403
+ }
23404
+ async updateGraphQLSchema(logicalId, physicalId, resourceType, properties, previousProperties) {
23405
+ const newDef = properties["Definition"];
23406
+ const oldDef = previousProperties["Definition"];
23407
+ if (newDef === void 0 || newDef === oldDef) return {
23408
+ physicalId,
23409
+ wasReplaced: false,
23410
+ attributes: {}
23411
+ };
23412
+ const apiId = properties["ApiId"] ?? physicalId;
23413
+ try {
23414
+ await this.getClient().send(new StartSchemaCreationCommand({
23415
+ apiId,
23416
+ definition: Buffer.from(newDef, "utf-8")
23417
+ }));
23418
+ } catch (error) {
23419
+ throw this.wrapUpdateError(error, resourceType, logicalId, physicalId, "GraphqlSchema");
23420
+ }
23421
+ return {
23422
+ physicalId,
23423
+ wasReplaced: false,
23424
+ attributes: {}
23425
+ };
23426
+ }
23427
+ async updateDataSource(logicalId, physicalId, resourceType, properties, previousProperties) {
23428
+ for (const field of [
23429
+ "ApiId",
23430
+ "Name",
23431
+ "Type"
23432
+ ]) {
23433
+ const next = properties[field];
23434
+ const prev = previousProperties[field];
23435
+ if (next !== void 0 && prev !== void 0 && next !== prev) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS AppSync DataSource.${field} is immutable — destroy + redeploy to change`);
23436
+ }
23437
+ const [apiId, name] = physicalId.split("|");
23438
+ if (!apiId || !name) throw new ProvisioningError(`Invalid DataSource physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
23439
+ const type = properties["Type"] ?? previousProperties["Type"];
23440
+ const newDesc = properties["Description"];
23441
+ const oldDesc = previousProperties["Description"];
23442
+ const newRole = properties["ServiceRoleArn"];
23443
+ const oldRole = previousProperties["ServiceRoleArn"];
23444
+ const newDDB = properties["DynamoDBConfig"];
23445
+ const oldDDB = previousProperties["DynamoDBConfig"];
23446
+ const newLambda = properties["LambdaConfig"];
23447
+ const oldLambda = previousProperties["LambdaConfig"];
23448
+ const newHttp = properties["HttpConfig"];
23449
+ const oldHttp = previousProperties["HttpConfig"];
23450
+ if (!(newDesc !== oldDesc || newRole !== oldRole || !this.deepEqual(newDDB, oldDDB) || !this.deepEqual(newLambda, oldLambda) || !this.deepEqual(newHttp, oldHttp))) return {
23451
+ physicalId,
23452
+ wasReplaced: false,
23453
+ attributes: {}
23454
+ };
23455
+ const input = {
23456
+ apiId,
23457
+ name,
23458
+ type
23459
+ };
23460
+ if (newDesc !== void 0) input.description = newDesc;
23461
+ if (newRole !== void 0) input.serviceRoleArn = newRole;
23462
+ if (newDDB !== void 0) input.dynamodbConfig = {
23463
+ tableName: newDDB["TableName"],
23464
+ awsRegion: newDDB["AwsRegion"],
23465
+ useCallerCredentials: newDDB["UseCallerCredentials"]
23466
+ };
23467
+ if (newLambda !== void 0) input.lambdaConfig = { lambdaFunctionArn: newLambda["LambdaFunctionArn"] };
23468
+ if (newHttp !== void 0) input.httpConfig = { endpoint: newHttp["Endpoint"] };
23469
+ try {
23470
+ await this.getClient().send(new UpdateDataSourceCommand(input));
23471
+ } catch (error) {
23472
+ throw this.wrapUpdateError(error, resourceType, logicalId, physicalId, "DataSource");
23473
+ }
23474
+ return {
23475
+ physicalId,
23476
+ wasReplaced: false,
23477
+ attributes: {}
23478
+ };
23479
+ }
23480
+ async updateResolver(logicalId, physicalId, resourceType, properties, previousProperties) {
23481
+ for (const field of [
23482
+ "ApiId",
23483
+ "TypeName",
23484
+ "FieldName"
23485
+ ]) {
23486
+ const next = properties[field];
23487
+ const prev = previousProperties[field];
23488
+ if (next !== void 0 && prev !== void 0 && next !== prev) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS AppSync Resolver.${field} is immutable — destroy + redeploy to change`);
23489
+ }
23490
+ const parts = physicalId.split("|");
23491
+ if (parts.length < 3) throw new ProvisioningError(`Invalid Resolver physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
23492
+ const [apiId, typeName, fieldName] = parts;
23493
+ if (![
23494
+ "DataSourceName",
23495
+ "RequestMappingTemplate",
23496
+ "ResponseMappingTemplate",
23497
+ "Kind",
23498
+ "PipelineConfig",
23499
+ "Runtime",
23500
+ "Code"
23501
+ ].some((key) => !this.deepEqual(properties[key], previousProperties[key]))) return {
23502
+ physicalId,
23503
+ wasReplaced: false,
23504
+ attributes: {}
23505
+ };
23506
+ const input = {
23507
+ apiId,
23508
+ typeName,
23509
+ fieldName
23510
+ };
23511
+ const effectiveKind = properties["Kind"] ?? previousProperties["Kind"] ?? "UNIT";
23512
+ if (effectiveKind === "UNIT" && properties["DataSourceName"] !== void 0) input.dataSourceName = properties["DataSourceName"];
23513
+ if (properties["RequestMappingTemplate"] !== void 0) input.requestMappingTemplate = properties["RequestMappingTemplate"];
23514
+ if (properties["ResponseMappingTemplate"] !== void 0) input.responseMappingTemplate = properties["ResponseMappingTemplate"];
23515
+ if (properties["Kind"] !== void 0) input.kind = properties["Kind"];
23516
+ if (effectiveKind === "PIPELINE" && properties["PipelineConfig"] !== void 0) input.pipelineConfig = { functions: properties["PipelineConfig"]["Functions"] };
23517
+ if (properties["Runtime"] !== void 0) {
23518
+ const runtime = properties["Runtime"];
23519
+ input.runtime = {
23520
+ name: runtime["Name"],
23521
+ runtimeVersion: runtime["RuntimeVersion"]
23522
+ };
23523
+ }
23524
+ if (properties["Code"] !== void 0) input.code = properties["Code"];
23525
+ try {
23526
+ await this.getClient().send(new UpdateResolverCommand(input));
23527
+ } catch (error) {
23528
+ throw this.wrapUpdateError(error, resourceType, logicalId, physicalId, "Resolver");
23529
+ }
23530
+ return {
23531
+ physicalId,
23532
+ wasReplaced: false,
23533
+ attributes: {}
23534
+ };
23535
+ }
23536
+ async updateApiKey(logicalId, physicalId, resourceType, properties, previousProperties) {
23537
+ if (properties["ApiId"] !== void 0 && previousProperties["ApiId"] !== void 0 && properties["ApiId"] !== previousProperties["ApiId"]) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS AppSync ApiKey.ApiId is immutable — destroy + redeploy to change");
23538
+ const [apiId, apiKeyId] = physicalId.split("|");
23539
+ if (!apiId || !apiKeyId) throw new ProvisioningError(`Invalid ApiKey physical ID format: ${physicalId}`, resourceType, logicalId, physicalId);
23540
+ const newDesc = properties["Description"];
23541
+ const oldDesc = previousProperties["Description"];
23542
+ const newExp = properties["Expires"];
23543
+ const oldExp = previousProperties["Expires"];
23544
+ if (newDesc === oldDesc && newExp === oldExp) return {
23545
+ physicalId,
23546
+ wasReplaced: false,
23547
+ attributes: {}
23548
+ };
23549
+ const input = {
23550
+ apiId,
23551
+ id: apiKeyId
23552
+ };
23553
+ if (newDesc !== void 0) input.description = newDesc;
23554
+ if (newExp !== void 0) input.expires = newExp;
23555
+ try {
23556
+ await this.getClient().send(new UpdateApiKeyCommand(input));
23557
+ } catch (error) {
23558
+ throw this.wrapUpdateError(error, resourceType, logicalId, physicalId, "ApiKey");
23559
+ }
23560
+ return {
23561
+ physicalId,
23562
+ wasReplaced: false,
23563
+ attributes: {}
23564
+ };
23565
+ }
23566
+ /**
23567
+ * Apply a Tags diff to a GraphqlApi via TagResource / UntagResource.
23568
+ *
23569
+ * Tags are keyed by the GraphqlApi ARN — recover it from
23570
+ * `GetGraphqlApi`. Failure to recover the ARN is a hard error (the API
23571
+ * itself just changed) rather than a silent drop, so the user knows
23572
+ * the tag diff was not applied.
23573
+ */
23574
+ async applyTagDiff(apiId, resourceType, logicalId, oldTags, newTags) {
23575
+ const oldMap = this.tagsToMap(oldTags ?? []);
23576
+ const newMap = this.tagsToMap(newTags ?? []);
23577
+ if (this.deepEqual(oldMap, newMap)) return;
23578
+ let arn = this.arnCache.get(apiId);
23579
+ if (!arn) {
23580
+ try {
23581
+ arn = (await this.getClient().send(new GetGraphqlApiCommand({ apiId }))).graphqlApi?.arn;
23582
+ } catch (error) {
23583
+ throw this.wrapUpdateError(error, resourceType, logicalId, apiId, "GraphqlApi");
23584
+ }
23585
+ if (!arn) throw new ProvisioningError(`Could not resolve ARN for AppSync GraphqlApi ${apiId} to apply tags diff`, resourceType, logicalId, apiId);
23586
+ this.arnCache.set(apiId, arn);
23587
+ }
23588
+ const tagKeysToRemove = Object.keys(oldMap).filter((k) => !(k in newMap));
23589
+ const tagsToAdd = {};
23590
+ for (const [k, v] of Object.entries(newMap)) if (oldMap[k] !== v) tagsToAdd[k] = v;
23591
+ if (tagKeysToRemove.length > 0) try {
23592
+ await this.getClient().send(new UntagResourceCommand$12({
23593
+ resourceArn: arn,
23594
+ tagKeys: tagKeysToRemove
23595
+ }));
23596
+ } catch (error) {
23597
+ throw this.wrapUpdateError(error, resourceType, logicalId, apiId, "GraphqlApi (untag)");
23598
+ }
23599
+ if (Object.keys(tagsToAdd).length > 0) try {
23600
+ await this.getClient().send(new TagResourceCommand$13({
23601
+ resourceArn: arn,
23602
+ tags: tagsToAdd
23603
+ }));
23604
+ } catch (error) {
23605
+ throw this.wrapUpdateError(error, resourceType, logicalId, apiId, "GraphqlApi (tag)");
23606
+ }
23607
+ }
23608
+ tagsToMap(tags) {
23609
+ const out = {};
23610
+ for (const t of tags) if (t.Key !== void 0 && t.Value !== void 0) out[t.Key] = t.Value;
23611
+ return out;
23612
+ }
23613
+ wrapUpdateError(error, resourceType, logicalId, physicalId, subType) {
23614
+ const cause = error instanceof Error ? error : void 0;
23615
+ return new ProvisioningError(`Failed to update AppSync ${subType} ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
23310
23616
  }
23311
23617
  async delete(logicalId, physicalId, resourceType, _properties, context) {
23312
23618
  switch (resourceType) {
@@ -24528,7 +24834,7 @@ var GlueSecurityConfigurationProvider = class {
24528
24834
  }
24529
24835
  }
24530
24836
  async update(logicalId, _physicalId, resourceType, _properties, _previousProperties) {
24531
- throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS::Glue::SecurityConfiguration is immutable; AWS provides no Update API. Use cdkd deploy --replace, or destroy + redeploy with the new EncryptionConfiguration.");
24837
+ throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS Glue SecurityConfiguration is immutable on AWS there is no UpdateSecurityConfiguration API; every change requires DeleteSecurityConfiguration + CreateSecurityConfiguration. Use cdkd deploy --replace, or destroy + redeploy with the new EncryptionConfiguration.");
24532
24838
  }
24533
24839
  async delete(logicalId, physicalId, resourceType, _properties, context) {
24534
24840
  this.logger.debug(`Deleting Glue SecurityConfiguration ${logicalId}: ${physicalId}`);
@@ -26393,7 +26699,7 @@ var KinesisStreamConsumerProvider = class {
26393
26699
  const oldConsumerName = previousProperties["ConsumerName"];
26394
26700
  const newStreamArn = properties["StreamARN"];
26395
26701
  const oldStreamArn = previousProperties["StreamARN"];
26396
- if (newConsumerName !== oldConsumerName || newStreamArn !== oldStreamArn) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS::Kinesis::StreamConsumer ConsumerName / StreamARN are immutable; re-deploy with cdkd deploy --replace, or destroy + redeploy");
26702
+ if (newConsumerName !== oldConsumerName || newStreamArn !== oldStreamArn) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS::Kinesis::StreamConsumer ConsumerName / StreamARN are immutable on AWS — there is no UpdateStreamConsumer API; every change registers a new consumer (RegisterStreamConsumer). Re-deploy with cdkd deploy --replace, or destroy + redeploy.");
26397
26703
  await this.applyTagDiff(physicalId, previousProperties["Tags"], properties["Tags"]);
26398
26704
  let attrs = {};
26399
26705
  try {
@@ -26508,14 +26814,14 @@ var KinesisStreamConsumerProvider = class {
26508
26814
  const tagsToRemove = [];
26509
26815
  for (const k of Object.keys(oldMap)) if (!(k in newMap)) tagsToRemove.push(k);
26510
26816
  if (tagsToRemove.length > 0) {
26511
- await this.getClient().send(new UntagResourceCommand$12({
26817
+ await this.getClient().send(new UntagResourceCommand$13({
26512
26818
  ResourceARN: consumerArn,
26513
26819
  TagKeys: tagsToRemove
26514
26820
  }));
26515
26821
  this.logger.debug(`Removed ${tagsToRemove.length} tag(s) from Kinesis stream consumer ${consumerArn}`);
26516
26822
  }
26517
26823
  if (Object.keys(tagsToAdd).length > 0) {
26518
- await this.getClient().send(new TagResourceCommand$13({
26824
+ await this.getClient().send(new TagResourceCommand$14({
26519
26825
  ResourceARN: consumerArn,
26520
26826
  Tags: tagsToAdd
26521
26827
  }));
@@ -26623,7 +26929,7 @@ var EFSProvider = class {
26623
26929
  switch (resourceType) {
26624
26930
  case "AWS::EFS::FileSystem": return this.updateFileSystem(logicalId, physicalId, resourceType, properties, previousProperties);
26625
26931
  case "AWS::EFS::MountTarget": return this.updateMountTarget(logicalId, physicalId, resourceType, properties);
26626
- case "AWS::EFS::AccessPoint": return Promise.reject(new ResourceUpdateNotSupportedError(resourceType, logicalId, "EFS AccessPoint is recreated on property changes; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack"));
26932
+ case "AWS::EFS::AccessPoint": return Promise.reject(new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS EFS AccessPoint has no in-place update API — there is no UpdateAccessPoint command; every property change requires DeleteAccessPoint + CreateAccessPoint. Re-deploy with cdkd deploy --replace, or destroy + redeploy the stack."));
26627
26933
  default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
26628
26934
  }
26629
26935
  }
@@ -26635,7 +26941,7 @@ var EFSProvider = class {
26635
26941
  ]) {
26636
26942
  const next = properties[key];
26637
26943
  const prev = previousProperties[key];
26638
- if (next !== void 0 && prev !== void 0 && JSON.stringify(next) !== JSON.stringify(prev)) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `EFS FileSystem ${key} is immutable; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack`);
26944
+ if (next !== void 0 && prev !== void 0 && JSON.stringify(next) !== JSON.stringify(prev)) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS EFS FileSystem ${key} is immutable on AWS — UpdateFileSystem does not accept ${key}; the property is fixed at creation. Re-deploy with cdkd deploy --replace, or destroy + redeploy the stack.`);
26639
26945
  }
26640
26946
  const newThroughputMode = properties["ThroughputMode"];
26641
26947
  const newProvisioned = properties["ProvisionedThroughputInMibps"];
@@ -27276,15 +27582,19 @@ var FirehoseProvider = class {
27276
27582
  }
27277
27583
  }
27278
27584
  /**
27279
- * Firehose delivery streams are treated as immutable by cdkd. Most
27280
- * destination-config changes require replacement, and AWS's
27281
- * `UpdateDestination` API surface is deep enough that the deploy engine's
27282
- * immutable-property replacement path covers the common cases more
27283
- * reliably. `cdkd drift --revert` therefore surfaces a clear "use
27284
- * --replace or re-deploy" message instead of silently no-op'ing.
27585
+ * Firehose delivery streams are treated as immutable by cdkd. AWS DOES
27586
+ * provide an `UpdateDestination` API, but the per-destination shape
27587
+ * matrix (Extended S3 / Redshift / OpenSearch / Splunk / HttpEndpoint /
27588
+ * Iceberg / etc.) is deep enough that the deploy engine's immutable-
27589
+ * property replacement path covers the common cases more reliably.
27590
+ * Treating the type as fully immutable for `cdkd drift --revert` is
27591
+ * the conservative choice; users who want in-place destination updates
27592
+ * should re-deploy with `cdkd deploy --replace` so the new shape is
27593
+ * applied via a fresh `CreateDeliveryStream`. Tracked as a follow-up
27594
+ * to issue (#443).
27285
27595
  */
27286
27596
  update(logicalId, _physicalId, resourceType, _properties, _previousProperties) {
27287
- return Promise.reject(new ResourceUpdateNotSupportedError(resourceType, logicalId, "Firehose delivery streams are recreated on property changes; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack"));
27597
+ return Promise.reject(new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS::KinesisFirehose::DeliveryStream in-place update is not implemented in cdkd; AWS provides UpdateDestination but the per-destination shape matrix is large. Re-deploy with cdkd deploy --replace, or destroy + redeploy the stack."));
27288
27598
  }
27289
27599
  /**
27290
27600
  * Delete a Firehose delivery stream
@@ -29787,10 +30097,10 @@ var ASGProvider = class {
29787
30097
  if (resourceType !== "AWS::AutoScaling::AutoScalingGroup") throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
29788
30098
  this.logger.debug(`Updating AutoScalingGroup ${logicalId}: ${physicalId}`);
29789
30099
  const stringEq = (a, b) => JSON.stringify(a) === JSON.stringify(b);
29790
- if (!stringEq(properties["AutoScalingGroupName"], previousProperties["AutoScalingGroupName"])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AutoScalingGroupName is immutable; use cdkd deploy --replace to replace the group");
29791
- if (!stringEq(properties["Tags"] ?? [], previousProperties["Tags"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "Tags updates on AWS::AutoScaling::AutoScalingGroup are not yet supported by cdkd; use cdkd deploy --replace, or update the tags via AWS console / CLI");
29792
- if (!stringEq(properties["LoadBalancerNames"] ?? [], previousProperties["LoadBalancerNames"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "LoadBalancerNames diffs require Attach/Detach calls; use cdkd deploy --replace");
29793
- if (!stringEq(properties["TargetGroupARNs"] ?? [], previousProperties["TargetGroupARNs"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "TargetGroupARNs diffs require Attach/Detach calls; use cdkd deploy --replace");
30100
+ if (!stringEq(properties["AutoScalingGroupName"], previousProperties["AutoScalingGroupName"])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AutoScalingGroupName is immutable on AWS — UpdateAutoScalingGroup does not accept a new name; the name is fixed at creation. Use cdkd deploy --replace to replace the group.");
30101
+ if (!stringEq(properties["Tags"] ?? [], previousProperties["Tags"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "Tags updates on AWS::AutoScaling::AutoScalingGroup are not yet implemented in cdkd (AWS exposes CreateOrUpdateTags / DeleteTags); use cdkd deploy --replace, or update the tags via AWS console / CLI.");
30102
+ if (!stringEq(properties["LoadBalancerNames"] ?? [], previousProperties["LoadBalancerNames"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "LoadBalancerNames diffs on AWS::AutoScaling::AutoScalingGroup are not yet implemented in cdkd (AWS exposes AttachLoadBalancers / DetachLoadBalancers); use cdkd deploy --replace.");
30103
+ if (!stringEq(properties["TargetGroupARNs"] ?? [], previousProperties["TargetGroupARNs"] ?? [])) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "TargetGroupARNs diffs on AWS::AutoScaling::AutoScalingGroup are not yet implemented in cdkd (AWS exposes AttachLoadBalancerTargetGroups / DetachLoadBalancerTargetGroups); use cdkd deploy --replace.");
29794
30104
  try {
29795
30105
  await this.applyMetricsCollectionDiff(physicalId, properties["MetricsCollection"], previousProperties["MetricsCollection"]);
29796
30106
  await this.applyLifecycleHooksDiff(physicalId, properties["LifecycleHookSpecificationList"], previousProperties["LifecycleHookSpecificationList"]);
@@ -35783,6 +36093,7 @@ function extractLambdaProperties(stack, logicalId, resource, resources) {
35783
36093
  const props = resource.Properties ?? {};
35784
36094
  const memoryMb = typeof props["MemorySize"] === "number" ? props["MemorySize"] : 128;
35785
36095
  const timeoutSec = typeof props["Timeout"] === "number" ? props["Timeout"] : 3;
36096
+ const ephemeralStorageMb = extractEphemeralStorageMb(props, logicalId);
35786
36097
  const code = props["Code"] ?? {};
35787
36098
  const imageUri = extractImageUri(code["ImageUri"], logicalId, stack.stackName, resources);
35788
36099
  if (imageUri !== void 0) return extractImageLambdaProperties({
@@ -35792,7 +36103,8 @@ function extractLambdaProperties(stack, logicalId, resource, resources) {
35792
36103
  memoryMb,
35793
36104
  timeoutSec,
35794
36105
  props,
35795
- imageUri
36106
+ imageUri,
36107
+ ...ephemeralStorageMb !== void 0 && { ephemeralStorageMb }
35796
36108
  });
35797
36109
  const runtime = typeof props["Runtime"] === "string" ? props["Runtime"] : "";
35798
36110
  const handler = typeof props["Handler"] === "string" ? props["Handler"] : "";
@@ -35813,10 +36125,44 @@ function extractLambdaProperties(stack, logicalId, resource, resources) {
35813
36125
  timeoutSec,
35814
36126
  codePath,
35815
36127
  layers,
36128
+ ...ephemeralStorageMb !== void 0 && { ephemeralStorageMb },
35816
36129
  ...inlineCode !== void 0 && { inlineCode }
35817
36130
  };
35818
36131
  }
35819
36132
  /**
36133
+ * Parse `Properties.EphemeralStorage.Size` (issue #440). CFn shape:
36134
+ * `{ EphemeralStorage: { Size: <MiB> } }`. CDK's
36135
+ * `cdk.Size.gibibytes(N)` serializes to `N * 1024`. AWS-side range is
36136
+ * 512..10240 MiB (the deployed function rejects anything outside that
36137
+ * range at create time); cdkd rejects > 10240 here so a misconfigured
36138
+ * template fails fast at `cdkd local invoke` boot rather than hanging
36139
+ * on a `docker run` that AWS would have refused anyway. The 512 floor
36140
+ * is AWS's minimum (the default when `EphemeralStorage` is omitted is
36141
+ * also 512), but we deliberately accept values DOWN to 1 so users can
36142
+ * exercise the cap with a deliberately-small `/tmp` in local tests —
36143
+ * `--tmpfs /tmp:size=Nm` itself enforces no lower bound; the only
36144
+ * cross-check is "would AWS accept this?", which the deploy side
36145
+ * already gates upstream.
36146
+ *
36147
+ * Returns `undefined` when the property is absent, NaN, < 1, or
36148
+ * non-numeric. Hard-rejects > 10240. Intrinsic-valued sizes (the
36149
+ * `{ Ref: 'SomeParam' }` shape that's uncommon for EphemeralStorage
36150
+ * but theoretically valid) drop to `undefined` with a one-line warn
36151
+ * via the calling logger — local invoke can't resolve those without
36152
+ * the template's Parameters context the deploy engine has, and the
36153
+ * fallback (no `--tmpfs`) is safer than guessing.
36154
+ */
36155
+ function extractEphemeralStorageMb(props, logicalId) {
36156
+ const raw = props["EphemeralStorage"];
36157
+ if (raw === void 0 || raw === null) return void 0;
36158
+ if (typeof raw !== "object" || Array.isArray(raw)) return void 0;
36159
+ const size = raw["Size"];
36160
+ if (typeof size !== "number") return;
36161
+ if (!Number.isFinite(size) || size < 1) return void 0;
36162
+ if (size > 10240) throw new LocalInvokeResolutionError(`Lambda '${logicalId}' has Properties.EphemeralStorage.Size = ${size} MiB, which exceeds the AWS limit of 10240 MiB. AWS would reject the function at deploy time; cap the value to <= 10240 (10 GiB) and retry.`);
36163
+ return Math.floor(size);
36164
+ }
36165
+ /**
35820
36166
  * Extract the `Code.ImageUri` value across the shapes CDK actually synthesizes.
35821
36167
  *
35822
36168
  * Supported shapes:
@@ -35868,7 +36214,7 @@ function extractImageUri(value, logicalId, stackName, resources) {
35868
36214
  * optional in CFn — the defaults match the AWS-side defaults.
35869
36215
  */
35870
36216
  function extractImageLambdaProperties(args) {
35871
- const { stack, logicalId, resource, memoryMb, timeoutSec, props, imageUri } = args;
36217
+ const { stack, logicalId, resource, memoryMb, timeoutSec, ephemeralStorageMb, props, imageUri } = args;
35872
36218
  const rawImageConfig = props["ImageConfig"] ?? {};
35873
36219
  const imageConfig = {};
35874
36220
  if (Array.isArray(rawImageConfig["Command"])) imageConfig.command = rawImageConfig["Command"].filter((s) => typeof s === "string");
@@ -35892,7 +36238,8 @@ function extractImageLambdaProperties(args) {
35892
36238
  imageUri,
35893
36239
  imageConfig,
35894
36240
  architecture,
35895
- layers: []
36241
+ layers: [],
36242
+ ...ephemeralStorageMb !== void 0 && { ephemeralStorageMb }
35896
36243
  };
35897
36244
  }
35898
36245
  /**
@@ -37432,6 +37779,7 @@ async function runDetached(opts) {
37432
37779
  args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
37433
37780
  }
37434
37781
  for (const [k, v] of Object.entries(opts.env)) args.push("-e", `${k}=${v}`);
37782
+ if (opts.tmpfs) args.push("--tmpfs", `${opts.tmpfs.target}:rw,size=${opts.tmpfs.sizeMb}m`);
37435
37783
  if (opts.workingDir) args.push("--workdir", opts.workingDir);
37436
37784
  let entryPointTail = [];
37437
37785
  if (opts.entryPoint && opts.entryPoint.length > 0) {
@@ -38882,7 +39230,8 @@ function createContainerPool(specs, options) {
38882
39230
  hostPort,
38883
39231
  host: spec.containerHost,
38884
39232
  name,
38885
- ...spec.debugPort !== void 0 && { debugPort: spec.debugPort }
39233
+ ...spec.debugPort !== void 0 && { debugPort: spec.debugPort },
39234
+ ...spec.tmpfs !== void 0 && { tmpfs: spec.tmpfs }
38886
39235
  });
38887
39236
  const stopLogStream = streamingEnabled ? streamLogs(containerId) : () => void 0;
38888
39237
  try {
@@ -42313,13 +42662,18 @@ async function buildContainerSpec(args) {
42313
42662
  if (stsRegion) dockerEnv["AWS_REGION"] = stsRegion;
42314
42663
  } else forwardAwsEnv$1(dockerEnv);
42315
42664
  if (debugPort !== void 0) dockerEnv["NODE_OPTIONS"] = `--inspect-brk=0.0.0.0:${debugPort}`;
42665
+ const tmpfs = lambda.ephemeralStorageMb !== void 0 ? {
42666
+ target: "/tmp",
42667
+ sizeMb: lambda.ephemeralStorageMb
42668
+ } : void 0;
42316
42669
  return {
42317
42670
  lambda,
42318
42671
  codeDir,
42319
42672
  env: dockerEnv,
42320
42673
  containerHost,
42321
42674
  ...optDir !== void 0 && { optDir },
42322
- ...debugPort !== void 0 && { debugPort }
42675
+ ...debugPort !== void 0 && { debugPort },
42676
+ ...tmpfs !== void 0 && { tmpfs }
42323
42677
  };
42324
42678
  }
42325
42679
  /**
@@ -42371,6 +42725,7 @@ function resolveLambdaByLogicalId(logicalId, stacks) {
42371
42725
  let codePath = null;
42372
42726
  if (!inlineCode) codePath = resolveAssetCodePath(stack, logicalId, resource);
42373
42727
  const layers = resolveLambdaLayers(stack, logicalId, props);
42728
+ const ephemeralStorageMb = extractEphemeralStorageMb(props, logicalId);
42374
42729
  return {
42375
42730
  kind: "zip",
42376
42731
  stack,
@@ -42382,7 +42737,8 @@ function resolveLambdaByLogicalId(logicalId, stacks) {
42382
42737
  timeoutSec,
42383
42738
  codePath,
42384
42739
  layers,
42385
- ...inlineCode !== void 0 && { inlineCode }
42740
+ ...inlineCode !== void 0 && { inlineCode },
42741
+ ...ephemeralStorageMb !== void 0 && { ephemeralStorageMb }
42386
42742
  };
42387
42743
  }
42388
42744
  throw new Error(`No AWS::Lambda::Function resource named '${logicalId}' found in target stacks. This is likely a synthesis bug — the route-discovery phase resolved a route to this logical ID.`);
@@ -43940,7 +44296,8 @@ async function localInvokeCommand(target, options) {
43940
44296
  ...debugPort !== void 0 && { debugPort },
43941
44297
  ...imagePlan.platform !== void 0 && { platform: imagePlan.platform },
43942
44298
  ...imagePlan.entryPoint !== void 0 && { entryPoint: imagePlan.entryPoint },
43943
- ...imagePlan.workingDir !== void 0 && { workingDir: imagePlan.workingDir }
44299
+ ...imagePlan.workingDir !== void 0 && { workingDir: imagePlan.workingDir },
44300
+ ...imagePlan.tmpfs !== void 0 && { tmpfs: imagePlan.tmpfs }
43944
44301
  });
43945
44302
  stopLogs = streamLogs(containerId);
43946
44303
  sigintHandler = () => {
@@ -43987,6 +44344,7 @@ async function resolveZipImagePlan(lambda, options) {
43987
44344
  await pullImage(image, options.pull === false);
43988
44345
  const layerPlan = materializeLambdaLayers(lambda.layers);
43989
44346
  const containerCodePath = resolveRuntimeCodeMountPath(lambda.runtime);
44347
+ const tmpfs = resolveTmpfsForLambda(lambda);
43990
44348
  return {
43991
44349
  image,
43992
44350
  mounts: [{
@@ -43997,7 +44355,36 @@ async function resolveZipImagePlan(lambda, options) {
43997
44355
  extraMounts: layerPlan.mount ? [layerPlan.mount] : [],
43998
44356
  cmd: [lambda.handler],
43999
44357
  ...inlineTmpDir !== void 0 && { inlineTmpDir },
44000
- ...layerPlan.tmpDir !== void 0 && { layersTmpDir: layerPlan.tmpDir }
44358
+ ...layerPlan.tmpDir !== void 0 && { layersTmpDir: layerPlan.tmpDir },
44359
+ ...tmpfs !== void 0 && { tmpfs }
44360
+ };
44361
+ }
44362
+ /**
44363
+ * Build the `--tmpfs /tmp:rw,size=<N>m` plan for a Lambda (issue #440).
44364
+ *
44365
+ * The shape is identical for ZIP and IMAGE Lambdas — `--tmpfs` overlays
44366
+ * mount-time inside any container, regardless of whether the image is a
44367
+ * public Lambda base image (ZIP path) or a user-built container Lambda.
44368
+ * Returns `undefined` when the template did not declare
44369
+ * `EphemeralStorage`, in which case the caller emits no `--tmpfs` flag
44370
+ * and the container's `/tmp` is whatever the base image provides
44371
+ * (matches pre-#440 behavior). The lambda-resolver's
44372
+ * `extractEphemeralStorageMb` already enforces the AWS 10240 MiB
44373
+ * ceiling at parse time.
44374
+ *
44375
+ * Target path is always `/tmp` — AWS Lambda's `/tmp` is the ONLY
44376
+ * sized-tmpfs surface the `EphemeralStorage.Size` property controls,
44377
+ * and the constant is centralized here so a future fixture / docs
44378
+ * update has a single grep target.
44379
+ */
44380
+ function resolveTmpfsForLambda(lambda) {
44381
+ if (lambda.ephemeralStorageMb === void 0) return void 0;
44382
+ const logger = getLogger();
44383
+ if (lambda.kind === "image") logger.info(`Lambda ${lambda.logicalId}: capping /tmp at ${lambda.ephemeralStorageMb} MiB via --tmpfs (overlays any base-image /tmp content)`);
44384
+ else logger.debug(`Lambda ${lambda.logicalId}: applying EphemeralStorage cap via --tmpfs /tmp:size=${lambda.ephemeralStorageMb}m`);
44385
+ return {
44386
+ target: "/tmp",
44387
+ sizeMb: lambda.ephemeralStorageMb
44001
44388
  };
44002
44389
  }
44003
44390
  /**
@@ -44065,6 +44452,7 @@ async function resolveContainerImagePlan(lambda, options) {
44065
44452
  ...options.region !== void 0 && { region: options.region }
44066
44453
  });
44067
44454
  }
44455
+ const tmpfs = resolveTmpfsForLambda(lambda);
44068
44456
  return {
44069
44457
  image: imageRef,
44070
44458
  mounts: [],
@@ -44072,7 +44460,8 @@ async function resolveContainerImagePlan(lambda, options) {
44072
44460
  cmd: lambda.imageConfig.command ?? [],
44073
44461
  platform,
44074
44462
  ...lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
44075
- ...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory }
44463
+ ...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory },
44464
+ ...tmpfs !== void 0 && { tmpfs }
44076
44465
  };
44077
44466
  }
44078
44467
  /**
@@ -45642,7 +46031,7 @@ function reorderArgs(argv) {
45642
46031
  */
45643
46032
  async function main() {
45644
46033
  const program = new Command();
45645
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.116.1");
46034
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.117.1");
45646
46035
  program.addCommand(createBootstrapCommand());
45647
46036
  program.addCommand(createSynthCommand());
45648
46037
  program.addCommand(createListCommand());