@go-to-k/cdkd 0.55.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -24059,18 +24059,23 @@ import {
24059
24059
  ApiGatewayV2Client,
24060
24060
  CreateApiCommand,
24061
24061
  DeleteApiCommand,
24062
+ UpdateApiCommand,
24062
24063
  CreateStageCommand as CreateStageCommand2,
24063
24064
  DeleteStageCommand as DeleteStageCommand2,
24064
24065
  GetStageCommand as GetStageCommand2,
24066
+ UpdateStageCommand as UpdateStageCommand2,
24065
24067
  CreateIntegrationCommand,
24066
24068
  DeleteIntegrationCommand,
24067
24069
  GetIntegrationCommand,
24070
+ UpdateIntegrationCommand,
24068
24071
  CreateRouteCommand as CreateRouteCommand2,
24069
24072
  DeleteRouteCommand as DeleteRouteCommand2,
24070
24073
  GetRouteCommand,
24074
+ UpdateRouteCommand,
24071
24075
  CreateAuthorizerCommand as CreateAuthorizerCommand2,
24072
24076
  DeleteAuthorizerCommand as DeleteAuthorizerCommand2,
24073
24077
  GetAuthorizerCommand as GetAuthorizerCommand2,
24078
+ UpdateAuthorizerCommand as UpdateAuthorizerCommand2,
24074
24079
  GetApiCommand,
24075
24080
  GetApisCommand,
24076
24081
  NotFoundException as NotFoundException4
@@ -24145,22 +24150,59 @@ var ApiGatewayV2Provider = class {
24145
24150
  }
24146
24151
  }
24147
24152
  /**
24148
- * HTTP API resources are treated as immutable by cdkd: the deploy engine
24149
- * recreates them on property changes via the immutable-property
24150
- * replacement path. AWS does expose `UpdateApi` / `UpdateRoute` /
24151
- * `UpdateIntegration` / `UpdateStage` / `UpdateAuthorizer`, but cdkd
24152
- * does not yet plumb them through. `cdkd drift --revert` surfaces a
24153
- * clear "use --replace or re-deploy" message instead of silently
24154
- * no-op'ing the revert.
24153
+ * AWS API Gateway V2 supports in-place updates for every type cdkd
24154
+ * provisions via the matching `Update*Command`. Each command takes the
24155
+ * full Update input shape (NOT JSON Patch that's the v1 surface);
24156
+ * cdkd builds the input by selecting only the fields that differ
24157
+ * between `previousProperties` and `properties`, so unchanged fields
24158
+ * are not echoed back. The few immutable identifiers (`ProtocolType`
24159
+ * on Api; `StageName` on Stage) are not part of the Update input shape
24160
+ * and are handled by the deploy engine's immutable-property
24161
+ * replacement path.
24155
24162
  */
24156
- update(logicalId, _physicalId, resourceType, _properties, _previousProperties) {
24157
- return Promise.reject(
24158
- new ResourceUpdateNotSupportedError(
24159
- resourceType,
24160
- logicalId,
24161
- "API Gateway V2 (HTTP API) resources are recreated on property changes; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack"
24162
- )
24163
- );
24163
+ async update(logicalId, physicalId, resourceType, properties, previousProperties) {
24164
+ switch (resourceType) {
24165
+ case "AWS::ApiGatewayV2::Api":
24166
+ return this.updateApi(logicalId, physicalId, resourceType, properties, previousProperties);
24167
+ case "AWS::ApiGatewayV2::Stage":
24168
+ return this.updateStage(
24169
+ logicalId,
24170
+ physicalId,
24171
+ resourceType,
24172
+ properties,
24173
+ previousProperties
24174
+ );
24175
+ case "AWS::ApiGatewayV2::Integration":
24176
+ return this.updateIntegration(
24177
+ logicalId,
24178
+ physicalId,
24179
+ resourceType,
24180
+ properties,
24181
+ previousProperties
24182
+ );
24183
+ case "AWS::ApiGatewayV2::Route":
24184
+ return this.updateRoute(
24185
+ logicalId,
24186
+ physicalId,
24187
+ resourceType,
24188
+ properties,
24189
+ previousProperties
24190
+ );
24191
+ case "AWS::ApiGatewayV2::Authorizer":
24192
+ return this.updateAuthorizer(
24193
+ logicalId,
24194
+ physicalId,
24195
+ resourceType,
24196
+ properties,
24197
+ previousProperties
24198
+ );
24199
+ default:
24200
+ throw new ResourceUpdateNotSupportedError(
24201
+ resourceType,
24202
+ logicalId,
24203
+ "unsupported API Gateway V2 resource type for in-place update; re-deploy with cdkd deploy --replace, or destroy + redeploy the stack"
24204
+ );
24205
+ }
24164
24206
  }
24165
24207
  async delete(logicalId, physicalId, resourceType, properties, context) {
24166
24208
  switch (resourceType) {
@@ -24811,6 +24853,312 @@ var ApiGatewayV2Provider = class {
24811
24853
  } while (nextToken);
24812
24854
  return null;
24813
24855
  }
24856
+ // ─── Update implementations ───────────────────────────────────────
24857
+ /**
24858
+ * `UpdateApi` accepts the full Update input shape (not JSON Patch).
24859
+ * Mutable fields cdkd manages: `Name` / `Description` /
24860
+ * `CorsConfiguration`. `ProtocolType` is immutable — the deploy
24861
+ * engine handles changes via the replacement path; we surface a
24862
+ * `ResourceUpdateNotSupportedError` if it ever reaches us anyway.
24863
+ */
24864
+ async updateApi(logicalId, physicalId, resourceType, properties, previousProperties) {
24865
+ if (properties["ProtocolType"] !== void 0 && previousProperties["ProtocolType"] !== void 0 && properties["ProtocolType"] !== previousProperties["ProtocolType"]) {
24866
+ throw new ResourceUpdateNotSupportedError(
24867
+ resourceType,
24868
+ logicalId,
24869
+ "ProtocolType is immutable on AWS::ApiGatewayV2::Api; re-deploy with cdkd deploy --replace"
24870
+ );
24871
+ }
24872
+ const input = { ApiId: physicalId };
24873
+ let changed = false;
24874
+ if (properties["Name"] !== void 0 && properties["Name"] !== previousProperties["Name"]) {
24875
+ input.Name = properties["Name"];
24876
+ changed = true;
24877
+ }
24878
+ if (properties["Description"] !== void 0 && properties["Description"] !== previousProperties["Description"]) {
24879
+ input.Description = properties["Description"];
24880
+ changed = true;
24881
+ }
24882
+ if (properties["CorsConfiguration"] !== void 0 && !this.deepEqual(properties["CorsConfiguration"], previousProperties["CorsConfiguration"])) {
24883
+ input.CorsConfiguration = properties["CorsConfiguration"];
24884
+ changed = true;
24885
+ }
24886
+ if (!changed) {
24887
+ this.logger.debug(`No mutable Api fields changed for ${logicalId}; skipping UpdateApi`);
24888
+ return { physicalId, wasReplaced: false };
24889
+ }
24890
+ this.logger.debug(`Updating API Gateway V2 Api ${logicalId}: ${physicalId}`);
24891
+ try {
24892
+ await this.getClient().send(new UpdateApiCommand(input));
24893
+ return { physicalId, wasReplaced: false };
24894
+ } catch (error) {
24895
+ const cause = error instanceof Error ? error : void 0;
24896
+ throw new ProvisioningError(
24897
+ `Failed to update API Gateway V2 Api ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
24898
+ resourceType,
24899
+ logicalId,
24900
+ physicalId,
24901
+ cause
24902
+ );
24903
+ }
24904
+ }
24905
+ /**
24906
+ * `UpdateStage` keys on `(ApiId, StageName)` — `StageName` is the
24907
+ * physicalId and immutable. Mutable fields cdkd manages:
24908
+ * `AutoDeploy` / `Description`. `ApiId` is also immutable (a stage
24909
+ * cannot be moved between APIs).
24910
+ */
24911
+ async updateStage(logicalId, physicalId, resourceType, properties, previousProperties) {
24912
+ const apiId = properties["ApiId"] ?? previousProperties["ApiId"];
24913
+ if (!apiId) {
24914
+ throw new ProvisioningError(
24915
+ `ApiId is required to update Stage ${logicalId}`,
24916
+ resourceType,
24917
+ logicalId,
24918
+ physicalId
24919
+ );
24920
+ }
24921
+ if (properties["ApiId"] !== void 0 && previousProperties["ApiId"] !== void 0 && properties["ApiId"] !== previousProperties["ApiId"]) {
24922
+ throw new ResourceUpdateNotSupportedError(
24923
+ resourceType,
24924
+ logicalId,
24925
+ "ApiId is immutable on AWS::ApiGatewayV2::Stage; re-deploy with cdkd deploy --replace"
24926
+ );
24927
+ }
24928
+ if (properties["StageName"] !== void 0 && previousProperties["StageName"] !== void 0 && properties["StageName"] !== previousProperties["StageName"]) {
24929
+ throw new ResourceUpdateNotSupportedError(
24930
+ resourceType,
24931
+ logicalId,
24932
+ "StageName is immutable on AWS::ApiGatewayV2::Stage; re-deploy with cdkd deploy --replace"
24933
+ );
24934
+ }
24935
+ const input = { ApiId: apiId, StageName: physicalId };
24936
+ let changed = false;
24937
+ if (properties["AutoDeploy"] !== void 0 && properties["AutoDeploy"] !== previousProperties["AutoDeploy"]) {
24938
+ input.AutoDeploy = properties["AutoDeploy"];
24939
+ changed = true;
24940
+ }
24941
+ if (properties["Description"] !== void 0 && properties["Description"] !== previousProperties["Description"]) {
24942
+ input.Description = properties["Description"];
24943
+ changed = true;
24944
+ }
24945
+ if (!changed) {
24946
+ this.logger.debug(`No mutable Stage fields changed for ${logicalId}; skipping UpdateStage`);
24947
+ return { physicalId, wasReplaced: false };
24948
+ }
24949
+ this.logger.debug(`Updating API Gateway V2 Stage ${logicalId}: ${physicalId}`);
24950
+ try {
24951
+ await this.getClient().send(new UpdateStageCommand2(input));
24952
+ return { physicalId, wasReplaced: false };
24953
+ } catch (error) {
24954
+ const cause = error instanceof Error ? error : void 0;
24955
+ throw new ProvisioningError(
24956
+ `Failed to update API Gateway V2 Stage ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
24957
+ resourceType,
24958
+ logicalId,
24959
+ physicalId,
24960
+ cause
24961
+ );
24962
+ }
24963
+ }
24964
+ /**
24965
+ * `UpdateIntegration` keys on `(ApiId, IntegrationId)`. Mutable
24966
+ * fields cdkd manages: `IntegrationType` / `IntegrationUri` /
24967
+ * `IntegrationMethod` / `PayloadFormatVersion`.
24968
+ */
24969
+ async updateIntegration(logicalId, physicalId, resourceType, properties, previousProperties) {
24970
+ const apiId = properties["ApiId"] ?? previousProperties["ApiId"];
24971
+ if (!apiId) {
24972
+ throw new ProvisioningError(
24973
+ `ApiId is required to update Integration ${logicalId}`,
24974
+ resourceType,
24975
+ logicalId,
24976
+ physicalId
24977
+ );
24978
+ }
24979
+ if (properties["ApiId"] !== void 0 && previousProperties["ApiId"] !== void 0 && properties["ApiId"] !== previousProperties["ApiId"]) {
24980
+ throw new ResourceUpdateNotSupportedError(
24981
+ resourceType,
24982
+ logicalId,
24983
+ "ApiId is immutable on AWS::ApiGatewayV2::Integration; re-deploy with cdkd deploy --replace"
24984
+ );
24985
+ }
24986
+ const input = { ApiId: apiId, IntegrationId: physicalId };
24987
+ let changed = false;
24988
+ if (properties["IntegrationType"] !== void 0 && properties["IntegrationType"] !== previousProperties["IntegrationType"]) {
24989
+ input.IntegrationType = properties["IntegrationType"];
24990
+ changed = true;
24991
+ }
24992
+ if (properties["IntegrationUri"] !== void 0 && properties["IntegrationUri"] !== previousProperties["IntegrationUri"]) {
24993
+ input.IntegrationUri = properties["IntegrationUri"];
24994
+ changed = true;
24995
+ }
24996
+ if (properties["IntegrationMethod"] !== void 0 && properties["IntegrationMethod"] !== previousProperties["IntegrationMethod"]) {
24997
+ input.IntegrationMethod = properties["IntegrationMethod"];
24998
+ changed = true;
24999
+ }
25000
+ if (properties["PayloadFormatVersion"] !== void 0 && properties["PayloadFormatVersion"] !== previousProperties["PayloadFormatVersion"]) {
25001
+ input.PayloadFormatVersion = properties["PayloadFormatVersion"];
25002
+ changed = true;
25003
+ }
25004
+ if (!changed) {
25005
+ this.logger.debug(
25006
+ `No mutable Integration fields changed for ${logicalId}; skipping UpdateIntegration`
25007
+ );
25008
+ return { physicalId, wasReplaced: false };
25009
+ }
25010
+ this.logger.debug(`Updating API Gateway V2 Integration ${logicalId}: ${physicalId}`);
25011
+ try {
25012
+ await this.getClient().send(new UpdateIntegrationCommand(input));
25013
+ return { physicalId, wasReplaced: false };
25014
+ } catch (error) {
25015
+ const cause = error instanceof Error ? error : void 0;
25016
+ throw new ProvisioningError(
25017
+ `Failed to update API Gateway V2 Integration ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
25018
+ resourceType,
25019
+ logicalId,
25020
+ physicalId,
25021
+ cause
25022
+ );
25023
+ }
25024
+ }
25025
+ /**
25026
+ * `UpdateRoute` keys on `(ApiId, RouteId)`. Mutable fields cdkd
25027
+ * manages: `RouteKey` / `Target` / `AuthorizationType` /
25028
+ * `AuthorizerId` / `AuthorizationScopes`.
25029
+ */
25030
+ async updateRoute(logicalId, physicalId, resourceType, properties, previousProperties) {
25031
+ const apiId = properties["ApiId"] ?? previousProperties["ApiId"];
25032
+ if (!apiId) {
25033
+ throw new ProvisioningError(
25034
+ `ApiId is required to update Route ${logicalId}`,
25035
+ resourceType,
25036
+ logicalId,
25037
+ physicalId
25038
+ );
25039
+ }
25040
+ if (properties["ApiId"] !== void 0 && previousProperties["ApiId"] !== void 0 && properties["ApiId"] !== previousProperties["ApiId"]) {
25041
+ throw new ResourceUpdateNotSupportedError(
25042
+ resourceType,
25043
+ logicalId,
25044
+ "ApiId is immutable on AWS::ApiGatewayV2::Route; re-deploy with cdkd deploy --replace"
25045
+ );
25046
+ }
25047
+ const input = { ApiId: apiId, RouteId: physicalId };
25048
+ let changed = false;
25049
+ if (properties["RouteKey"] !== void 0 && properties["RouteKey"] !== previousProperties["RouteKey"]) {
25050
+ input.RouteKey = properties["RouteKey"];
25051
+ changed = true;
25052
+ }
25053
+ if (properties["Target"] !== void 0 && properties["Target"] !== previousProperties["Target"]) {
25054
+ input.Target = properties["Target"];
25055
+ changed = true;
25056
+ }
25057
+ if (properties["AuthorizationType"] !== void 0 && properties["AuthorizationType"] !== previousProperties["AuthorizationType"]) {
25058
+ input.AuthorizationType = properties["AuthorizationType"];
25059
+ changed = true;
25060
+ }
25061
+ if (properties["AuthorizerId"] !== void 0 && properties["AuthorizerId"] !== previousProperties["AuthorizerId"]) {
25062
+ input.AuthorizerId = properties["AuthorizerId"];
25063
+ changed = true;
25064
+ }
25065
+ if (properties["AuthorizationScopes"] !== void 0 && !this.deepEqual(properties["AuthorizationScopes"], previousProperties["AuthorizationScopes"])) {
25066
+ input.AuthorizationScopes = properties["AuthorizationScopes"];
25067
+ changed = true;
25068
+ }
25069
+ if (!changed) {
25070
+ this.logger.debug(`No mutable Route fields changed for ${logicalId}; skipping UpdateRoute`);
25071
+ return { physicalId, wasReplaced: false };
25072
+ }
25073
+ this.logger.debug(`Updating API Gateway V2 Route ${logicalId}: ${physicalId}`);
25074
+ try {
25075
+ await this.getClient().send(new UpdateRouteCommand(input));
25076
+ return { physicalId, wasReplaced: false };
25077
+ } catch (error) {
25078
+ const cause = error instanceof Error ? error : void 0;
25079
+ throw new ProvisioningError(
25080
+ `Failed to update API Gateway V2 Route ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
25081
+ resourceType,
25082
+ logicalId,
25083
+ physicalId,
25084
+ cause
25085
+ );
25086
+ }
25087
+ }
25088
+ /**
25089
+ * `UpdateAuthorizer` keys on `(ApiId, AuthorizerId)`. Mutable fields
25090
+ * cdkd manages: `AuthorizerType` / `Name` / `IdentitySource` /
25091
+ * `JwtConfiguration` / `AuthorizerUri` /
25092
+ * `AuthorizerPayloadFormatVersion`.
25093
+ */
25094
+ async updateAuthorizer(logicalId, physicalId, resourceType, properties, previousProperties) {
25095
+ const apiId = properties["ApiId"] ?? previousProperties["ApiId"];
25096
+ if (!apiId) {
25097
+ throw new ProvisioningError(
25098
+ `ApiId is required to update Authorizer ${logicalId}`,
25099
+ resourceType,
25100
+ logicalId,
25101
+ physicalId
25102
+ );
25103
+ }
25104
+ if (properties["ApiId"] !== void 0 && previousProperties["ApiId"] !== void 0 && properties["ApiId"] !== previousProperties["ApiId"]) {
25105
+ throw new ResourceUpdateNotSupportedError(
25106
+ resourceType,
25107
+ logicalId,
25108
+ "ApiId is immutable on AWS::ApiGatewayV2::Authorizer; re-deploy with cdkd deploy --replace"
25109
+ );
25110
+ }
25111
+ const input = { ApiId: apiId, AuthorizerId: physicalId };
25112
+ let changed = false;
25113
+ if (properties["AuthorizerType"] !== void 0 && properties["AuthorizerType"] !== previousProperties["AuthorizerType"]) {
25114
+ input.AuthorizerType = properties["AuthorizerType"];
25115
+ changed = true;
25116
+ }
25117
+ if (properties["Name"] !== void 0 && properties["Name"] !== previousProperties["Name"]) {
25118
+ input.Name = properties["Name"];
25119
+ changed = true;
25120
+ }
25121
+ if (properties["IdentitySource"] !== void 0) {
25122
+ const next = Array.isArray(properties["IdentitySource"]) ? properties["IdentitySource"] : [properties["IdentitySource"]];
25123
+ const prev = Array.isArray(previousProperties["IdentitySource"]) ? previousProperties["IdentitySource"] : previousProperties["IdentitySource"] !== void 0 ? [previousProperties["IdentitySource"]] : void 0;
25124
+ if (!this.deepEqual(next, prev)) {
25125
+ input.IdentitySource = next;
25126
+ changed = true;
25127
+ }
25128
+ }
25129
+ if (properties["JwtConfiguration"] !== void 0 && !this.deepEqual(properties["JwtConfiguration"], previousProperties["JwtConfiguration"])) {
25130
+ input.JwtConfiguration = properties["JwtConfiguration"];
25131
+ changed = true;
25132
+ }
25133
+ if (properties["AuthorizerUri"] !== void 0 && properties["AuthorizerUri"] !== previousProperties["AuthorizerUri"]) {
25134
+ input.AuthorizerUri = properties["AuthorizerUri"];
25135
+ changed = true;
25136
+ }
25137
+ if (properties["AuthorizerPayloadFormatVersion"] !== void 0 && properties["AuthorizerPayloadFormatVersion"] !== previousProperties["AuthorizerPayloadFormatVersion"]) {
25138
+ input.AuthorizerPayloadFormatVersion = properties["AuthorizerPayloadFormatVersion"];
25139
+ changed = true;
25140
+ }
25141
+ if (!changed) {
25142
+ this.logger.debug(
25143
+ `No mutable Authorizer fields changed for ${logicalId}; skipping UpdateAuthorizer`
25144
+ );
25145
+ return { physicalId, wasReplaced: false };
25146
+ }
25147
+ this.logger.debug(`Updating API Gateway V2 Authorizer ${logicalId}: ${physicalId}`);
25148
+ try {
25149
+ await this.getClient().send(new UpdateAuthorizerCommand2(input));
25150
+ return { physicalId, wasReplaced: false };
25151
+ } catch (error) {
25152
+ const cause = error instanceof Error ? error : void 0;
25153
+ throw new ProvisioningError(
25154
+ `Failed to update API Gateway V2 Authorizer ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
25155
+ resourceType,
25156
+ logicalId,
25157
+ physicalId,
25158
+ cause
25159
+ );
25160
+ }
25161
+ }
24814
25162
  // ─── Helpers ──────────────────────────────────────────────────────
24815
25163
  /**
24816
25164
  * Convert CloudFormation Tags (Array<{Key, Value}>) to SDK Tags (Record<string, string>).
@@ -24824,6 +25172,24 @@ var ApiGatewayV2Provider = class {
24824
25172
  }
24825
25173
  return result;
24826
25174
  }
25175
+ /**
25176
+ * Structural equality used to skip Update calls when an object /
25177
+ * array property is unchanged. Stable JSON serialization is fine
25178
+ * here because the API Gateway V2 sub-shapes (`CorsConfiguration`,
25179
+ * `JwtConfiguration`, scope arrays, identity-source arrays) are
25180
+ * small primitive maps with no key-order semantics on the AWS side.
25181
+ */
25182
+ deepEqual(a, b) {
25183
+ if (a === b)
25184
+ return true;
25185
+ if (a === void 0 || b === void 0)
25186
+ return false;
25187
+ try {
25188
+ return JSON.stringify(a) === JSON.stringify(b);
25189
+ } catch {
25190
+ return false;
25191
+ }
25192
+ }
24827
25193
  };
24828
25194
 
24829
25195
  // src/provisioning/providers/cloudfront-oai-provider.ts
@@ -27493,6 +27859,10 @@ import {
27493
27859
  DeleteLoadBalancerCommand,
27494
27860
  DescribeLoadBalancersCommand as DescribeLoadBalancersCommand2,
27495
27861
  DescribeLoadBalancerAttributesCommand,
27862
+ ModifyLoadBalancerAttributesCommand,
27863
+ SetSubnetsCommand,
27864
+ SetSecurityGroupsCommand,
27865
+ SetIpAddressTypeCommand,
27496
27866
  CreateTargetGroupCommand,
27497
27867
  DeleteTargetGroupCommand,
27498
27868
  ModifyTargetGroupCommand,
@@ -27553,7 +27923,9 @@ var ELBv2Provider = class {
27553
27923
  "DefaultActions",
27554
27924
  "Port",
27555
27925
  "Protocol",
27556
- "SslPolicy"
27926
+ "SslPolicy",
27927
+ "AlpnPolicy",
27928
+ "MutualAuthentication"
27557
27929
  ])
27558
27930
  ]
27559
27931
  ]);
@@ -27661,7 +28033,6 @@ var ELBv2Provider = class {
27661
28033
  this.logger.debug(`Successfully created LoadBalancer ${logicalId}: ${lb.LoadBalancerArn}`);
27662
28034
  const lbAttributes = properties["LoadBalancerAttributes"];
27663
28035
  if (lbAttributes && lbAttributes.length > 0) {
27664
- const { ModifyLoadBalancerAttributesCommand } = await import("@aws-sdk/client-elastic-load-balancing-v2");
27665
28036
  await this.getClient().send(
27666
28037
  new ModifyLoadBalancerAttributesCommand({
27667
28038
  LoadBalancerArn: lb.LoadBalancerArn,
@@ -27697,42 +28068,95 @@ var ELBv2Provider = class {
27697
28068
  }
27698
28069
  }
27699
28070
  async updateLoadBalancer(logicalId, physicalId, _resourceType, properties, previousProperties) {
27700
- const newAttrs = properties["LoadBalancerAttributes"] ?? [];
27701
- const oldAttrs = previousProperties["LoadBalancerAttributes"] ?? [];
27702
- const stripAttrs = (p) => {
27703
- const { LoadBalancerAttributes: _, ...rest } = p;
27704
- return rest;
28071
+ const handledKeys = /* @__PURE__ */ new Set([
28072
+ "LoadBalancerAttributes",
28073
+ "Subnets",
28074
+ "SubnetMappings",
28075
+ "SecurityGroups",
28076
+ "IpAddressType",
28077
+ "Tags"
28078
+ ]);
28079
+ const stripHandled = (p) => {
28080
+ const out = {};
28081
+ for (const [k, v] of Object.entries(p)) {
28082
+ if (!handledKeys.has(k))
28083
+ out[k] = v;
28084
+ }
28085
+ return out;
27705
28086
  };
27706
- if (JSON.stringify(stripAttrs(properties)) !== JSON.stringify(stripAttrs(previousProperties))) {
28087
+ if (JSON.stringify(stripHandled(properties)) !== JSON.stringify(stripHandled(previousProperties))) {
27707
28088
  throw new ResourceUpdateNotSupportedError(
27708
28089
  "AWS::ElasticLoadBalancingV2::LoadBalancer",
27709
28090
  logicalId,
27710
- "ELBv2 LoadBalancer in-place updates are only supported for LoadBalancerAttributes; for Name / Type / Scheme / Subnets / SecurityGroups / IpAddressType / Tags, re-deploy with cdkd deploy --replace, or destroy + redeploy the stack"
28091
+ "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"
27711
28092
  );
27712
28093
  }
27713
- const newMap = new Map(newAttrs.map((a) => [a.Key, a.Value]));
27714
- const oldMap = new Map(oldAttrs.map((a) => [a.Key, a.Value]));
27715
- const submitted = [];
27716
- for (const [k, v] of newMap) {
27717
- if (oldMap.get(k) !== v)
27718
- submitted.push({ Key: k, Value: v });
27719
- }
27720
- for (const [k] of oldMap) {
27721
- if (!newMap.has(k))
27722
- submitted.push({ Key: k, Value: "" });
27723
- }
27724
- if (submitted.length > 0) {
27725
- const { ModifyLoadBalancerAttributesCommand } = await import("@aws-sdk/client-elastic-load-balancing-v2");
28094
+ const newAttrs = properties["LoadBalancerAttributes"] ?? [];
28095
+ const oldAttrs = previousProperties["LoadBalancerAttributes"] ?? [];
28096
+ const newAttrMap = new Map(newAttrs.map((a) => [a.Key, a.Value]));
28097
+ const oldAttrMap = new Map(oldAttrs.map((a) => [a.Key, a.Value]));
28098
+ const submittedAttrs = [];
28099
+ for (const [k, v] of newAttrMap) {
28100
+ if (oldAttrMap.get(k) !== v)
28101
+ submittedAttrs.push({ Key: k, Value: v });
28102
+ }
28103
+ for (const [k] of oldAttrMap) {
28104
+ if (!newAttrMap.has(k))
28105
+ submittedAttrs.push({ Key: k, Value: "" });
28106
+ }
28107
+ if (submittedAttrs.length > 0) {
27726
28108
  await this.getClient().send(
27727
28109
  new ModifyLoadBalancerAttributesCommand({
27728
28110
  LoadBalancerArn: physicalId,
27729
- Attributes: submitted
28111
+ Attributes: submittedAttrs
27730
28112
  })
27731
28113
  );
27732
28114
  this.logger.debug(
27733
- `Applied ${submitted.length} LoadBalancerAttributes change(s) for ${logicalId}`
28115
+ `Applied ${submittedAttrs.length} LoadBalancerAttributes change(s) for ${logicalId}`
27734
28116
  );
27735
28117
  }
28118
+ const newSubnets = properties["Subnets"];
28119
+ const oldSubnets = previousProperties["Subnets"];
28120
+ const newMappings = properties["SubnetMappings"];
28121
+ const oldMappings = previousProperties["SubnetMappings"];
28122
+ const subnetsChanged = JSON.stringify(newSubnets) !== JSON.stringify(oldSubnets);
28123
+ const mappingsChanged = JSON.stringify(newMappings) !== JSON.stringify(oldMappings);
28124
+ if (subnetsChanged || mappingsChanged) {
28125
+ await this.getClient().send(
28126
+ new SetSubnetsCommand({
28127
+ LoadBalancerArn: physicalId,
28128
+ ...newMappings && newMappings.length > 0 ? { SubnetMappings: newMappings } : { Subnets: newSubnets }
28129
+ })
28130
+ );
28131
+ this.logger.debug(`Updated Subnets / SubnetMappings for ${logicalId}`);
28132
+ }
28133
+ const newSGs = properties["SecurityGroups"];
28134
+ const oldSGs = previousProperties["SecurityGroups"];
28135
+ if (JSON.stringify(newSGs) !== JSON.stringify(oldSGs)) {
28136
+ await this.getClient().send(
28137
+ new SetSecurityGroupsCommand({
28138
+ LoadBalancerArn: physicalId,
28139
+ SecurityGroups: newSGs ?? []
28140
+ })
28141
+ );
28142
+ this.logger.debug(`Updated SecurityGroups for ${logicalId}`);
28143
+ }
28144
+ const newIpType = properties["IpAddressType"];
28145
+ const oldIpType = previousProperties["IpAddressType"];
28146
+ if (newIpType !== void 0 && newIpType !== oldIpType) {
28147
+ await this.getClient().send(
28148
+ new SetIpAddressTypeCommand({
28149
+ LoadBalancerArn: physicalId,
28150
+ IpAddressType: newIpType
28151
+ })
28152
+ );
28153
+ this.logger.debug(`Updated IpAddressType for ${logicalId}`);
28154
+ }
28155
+ await this.applyTagDiff(
28156
+ physicalId,
28157
+ previousProperties["Tags"],
28158
+ properties["Tags"]
28159
+ );
27736
28160
  return { physicalId, wasReplaced: false };
27737
28161
  }
27738
28162
  async deleteLoadBalancer(logicalId, physicalId, resourceType, context) {
@@ -27904,6 +28328,8 @@ var ELBv2Provider = class {
27904
28328
  const certificates = this.convertCertificates(
27905
28329
  properties["Certificates"]
27906
28330
  );
28331
+ const alpnPolicy = properties["AlpnPolicy"];
28332
+ const mutualAuth = properties["MutualAuthentication"];
27907
28333
  const response = await this.getClient().send(
27908
28334
  new CreateListenerCommand({
27909
28335
  LoadBalancerArn: properties["LoadBalancerArn"],
@@ -27912,6 +28338,8 @@ var ELBv2Provider = class {
27912
28338
  SslPolicy: properties["SslPolicy"],
27913
28339
  DefaultActions: defaultActions ?? [],
27914
28340
  ...certificates && { Certificates: certificates },
28341
+ ...alpnPolicy && alpnPolicy.length > 0 && { AlpnPolicy: alpnPolicy },
28342
+ ...mutualAuth !== void 0 && { MutualAuthentication: mutualAuth },
27915
28343
  ...tags.length > 0 && { Tags: tags }
27916
28344
  })
27917
28345
  );
@@ -27946,6 +28374,8 @@ var ELBv2Provider = class {
27946
28374
  const certificates = this.convertCertificates(
27947
28375
  properties["Certificates"]
27948
28376
  );
28377
+ const alpnPolicy = properties["AlpnPolicy"];
28378
+ const mutualAuth = properties["MutualAuthentication"];
27949
28379
  await this.getClient().send(
27950
28380
  new ModifyListenerCommand({
27951
28381
  ListenerArn: physicalId,
@@ -27953,7 +28383,15 @@ var ELBv2Provider = class {
27953
28383
  Protocol: properties["Protocol"],
27954
28384
  SslPolicy: properties["SslPolicy"],
27955
28385
  ...defaultActions && { DefaultActions: defaultActions },
27956
- ...certificates && { Certificates: certificates }
28386
+ ...certificates && { Certificates: certificates },
28387
+ // AlpnPolicy is a TLS-listener-only field; only forward it
28388
+ // when the diff actually carries values (CFn template-side it
28389
+ // is an array of one entry). An empty array would be rejected
28390
+ // by AWS on non-TLS listeners.
28391
+ ...alpnPolicy && alpnPolicy.length > 0 && { AlpnPolicy: alpnPolicy },
28392
+ // MutualAuthentication is HTTPS-listener-only. Forward when
28393
+ // the user templated it; AWS will reject on non-HTTPS.
28394
+ ...mutualAuth !== void 0 && { MutualAuthentication: mutualAuth }
27957
28395
  })
27958
28396
  );
27959
28397
  await this.applyTagDiff(
@@ -28240,6 +28678,8 @@ var ELBv2Provider = class {
28240
28678
  result["DefaultActions"] = (listener.DefaultActions ?? []).map(
28241
28679
  (a) => a
28242
28680
  );
28681
+ result["AlpnPolicy"] = listener.AlpnPolicy ?? [];
28682
+ result["MutualAuthentication"] = listener.MutualAuthentication ?? {};
28243
28683
  await this.attachTags(result, physicalId);
28244
28684
  return result;
28245
28685
  }
@@ -45810,7 +46250,7 @@ function reorderArgs(argv) {
45810
46250
  }
45811
46251
  async function main() {
45812
46252
  const program = new Command14();
45813
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.55.0");
46253
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.57.0");
45814
46254
  program.addCommand(createBootstrapCommand());
45815
46255
  program.addCommand(createSynthCommand());
45816
46256
  program.addCommand(createListCommand());