@intentius/chant-lexicon-aws 0.18.16 → 0.18.17

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.
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "5add6f542b1ca426e7bd6175a4d9a373a93449986d082732ca3de1fb8d0cf1d9",
5
- "meta.json": "556e862c3f936c84ec863d3ce90822544f9580613e1c3d4bf8724b3e3409ca2e",
6
- "types/index.d.ts": "b6e4cae56f2c903c4f2690b9243cec6658d505f9e11536ff9e98ac9a15824da7",
4
+ "manifest.json": "217158f543f70284b4839d43754abbdbffa089322abc5274655c0fb6ef7ee584",
5
+ "meta.json": "956ce9e79ca7bc2b9f5169a2a4418207e8c58da478435116c25867d909209d3f",
6
+ "types/index.d.ts": "25b58838c3895ad9ba9e5f5e24af38c43df112703d5315ce0efea9bfc9aa40d5",
7
7
  "rules/hardcoded-region.ts": "5a0eaf7ab391231fe6cd51426ece29539cb4b36f31c8dd060956638fed55722a",
8
8
  "rules/iam-wildcard.ts": "135d7217d278fef50939e605c5da32603ba35674b8c4b5c4d66a06c77903e945",
9
9
  "rules/s3-encryption.ts": "c4f9f8aa8dc382ed98c7b04e820a600590cc75335a8db2e087cbfbfe4003d09e",
@@ -58,5 +58,5 @@
58
58
  "skills/chant-aws.md": "4d65eb160e001f2af42eb7c622a5b498c2fd1f5afbd6c8155615c010fb265c63",
59
59
  "skills/chant-aws-eks.md": "8789255709ff004ad0a875fd5999edcdc66fc6e33d710db058d9f42703bcfdfe"
60
60
  },
61
- "composite": "6fd40695ae9751727198eb4e8a2f343d8e9754f120af043a798663a3c7eaca74"
61
+ "composite": "fc4e487d0f9d9159f025788277385185cd9c4f9b13f6c2e2d037500e3a8dcd51"
62
62
  }
@@ -80,15 +80,16 @@ export declare class JoinIntrinsic implements Intrinsic {
80
80
  readonly [INTRINSIC_MARKER]: true;
81
81
  private delimiter;
82
82
  private values;
83
- constructor(delimiter: string, values: unknown[]);
83
+ constructor(delimiter: string, values: unknown[] | Intrinsic);
84
84
  toJSON(): {
85
- "Fn::Join": [string, unknown[]];
85
+ "Fn::Join": [string, unknown];
86
86
  };
87
87
  }
88
88
  /**
89
- * Create a Join intrinsic
89
+ * Create a Join intrinsic. `values` is a literal array, or a single
90
+ * list-returning intrinsic (e.g. `Join(",", zone.NameServers)`).
90
91
  */
91
- export declare function Join(delimiter: string, values: unknown[]): JoinIntrinsic;
92
+ export declare function Join(delimiter: string, values: unknown[] | Intrinsic): JoinIntrinsic;
92
93
  /**
93
94
  * Fn::Select intrinsic function
94
95
  * Selects a value from a list by index
@@ -1 +1 @@
1
- {"version":3,"file":"intrinsics.d.ts","sourceRoot":"","sources":["../src/intrinsics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"intrinsics.d.ts","sourceRoot":"","sources":["../src/intrinsics.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws",
3
- "version": "0.18.16",
3
+ "version": "0.18.17",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "AWS",
6
6
  "intrinsics": [
package/dist/meta.json CHANGED
@@ -5045,6 +5045,11 @@
5045
5045
  "kind": "property",
5046
5046
  "lexicon": "aws"
5047
5047
  },
5048
+ "AppConfiguration": {
5049
+ "resourceType": "AWS::EMR::InstanceGroupConfig.AppConfiguration",
5050
+ "kind": "property",
5051
+ "lexicon": "aws"
5052
+ },
5048
5053
  "AppCookieStickinessPolicy": {
5049
5054
  "resourceType": "AWS::ElasticLoadBalancing::LoadBalancer.AppCookieStickinessPolicy",
5050
5055
  "kind": "property",
@@ -48824,7 +48829,7 @@
48824
48829
  "kind": "resource",
48825
48830
  "lexicon": "aws",
48826
48831
  "attrs": {
48827
- "Id": "Id"
48832
+ "InstanceGroupId": "InstanceGroupId"
48828
48833
  },
48829
48834
  "createOnly": [
48830
48835
  "InstanceRole",
@@ -48837,17 +48842,21 @@
48837
48842
  "Market",
48838
48843
  "BidPrice"
48839
48844
  ],
48845
+ "writeOnly": [
48846
+ "EbsConfiguration/EbsBlockDeviceConfigs/*/VolumesPerInstance"
48847
+ ],
48840
48848
  "primaryIdentifier": [
48841
- "Id"
48849
+ "InstanceGroupId",
48850
+ "JobFlowId"
48842
48851
  ]
48843
48852
  },
48844
- "InstanceGroupConfig_AutoScalingPolicy": {
48845
- "resourceType": "AWS::EMR::InstanceGroupConfig.AutoScalingPolicy",
48853
+ "InstanceGroupConfig_AppConfiguration": {
48854
+ "resourceType": "AWS::EMR::InstanceGroupConfig.AppConfiguration",
48846
48855
  "kind": "property",
48847
48856
  "lexicon": "aws"
48848
48857
  },
48849
- "InstanceGroupConfig_Configuration": {
48850
- "resourceType": "AWS::EMR::InstanceGroupConfig.Configuration",
48858
+ "InstanceGroupConfig_AutoScalingPolicy": {
48859
+ "resourceType": "AWS::EMR::InstanceGroupConfig.AutoScalingPolicy",
48851
48860
  "kind": "property",
48852
48861
  "lexicon": "aws"
48853
48862
  },
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAsC,MAAM,6BAA6B,CAAC;AAsUlG;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,UAoE3B,CAAC"}
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAsC,MAAM,6BAA6B,CAAC;AA2WlG;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,UAoE3B,CAAC"}
@@ -17601,14 +17601,14 @@ export declare class InstanceGroupConfig {
17601
17601
  JobFlowId: string;
17602
17602
  AutoScalingPolicy?: InstanceGroupConfig_AutoScalingPolicy;
17603
17603
  BidPrice?: string;
17604
- Configurations?: InstanceGroupConfig_Configuration[];
17604
+ Configurations?: InstanceGroupConfig_AppConfiguration[];
17605
17605
  CustomAmiId?: string;
17606
17606
  EbsConfiguration?: InstanceGroupConfig_EbsConfiguration;
17607
- Id?: string;
17607
+ InstanceGroupId?: string;
17608
17608
  Market?: string;
17609
17609
  Name?: string;
17610
17610
  }, attributes?: CFResourceAttributes);
17611
- readonly Id: string;
17611
+ readonly InstanceGroupId: string;
17612
17612
  }
17613
17613
 
17614
17614
  export declare class InstanceProfile {
@@ -41403,6 +41403,14 @@ export declare class AppConfigResourceObject {
41403
41403
  });
41404
41404
  }
41405
41405
 
41406
+ export declare class AppConfiguration {
41407
+ constructor(props: {
41408
+ Classification?: string;
41409
+ ConfigurationProperties?: Record<string, unknown>;
41410
+ Configurations?: InstanceGroupConfig_AppConfiguration[];
41411
+ });
41412
+ }
41413
+
41406
41414
  export declare class AppCookieStickinessPolicy {
41407
41415
  constructor(props: {
41408
41416
  /** The name of the application cookie used for stickiness. */
@@ -78935,24 +78943,26 @@ export declare class InstanceFleetConfig_SpotResizingSpecification {
78935
78943
  });
78936
78944
  }
78937
78945
 
78938
- export declare class InstanceGroupConfig_AutoScalingPolicy {
78946
+ export declare class InstanceGroupConfig_AppConfiguration {
78939
78947
  constructor(props: {
78940
- Constraints: InstanceGroupConfig_ScalingConstraints;
78941
- Rules: InstanceGroupConfig_ScalingRule[];
78948
+ Classification?: string;
78949
+ ConfigurationProperties?: Record<string, unknown>;
78950
+ Configurations?: InstanceGroupConfig_AppConfiguration[];
78942
78951
  });
78943
78952
  }
78944
78953
 
78945
- export declare class InstanceGroupConfig_Configuration {
78954
+ export declare class InstanceGroupConfig_AutoScalingPolicy {
78946
78955
  constructor(props: {
78947
- Classification?: string;
78948
- ConfigurationProperties?: Record<string, unknown>;
78949
- Configurations?: InstanceGroupConfig_Configuration[];
78956
+ Constraints: InstanceGroupConfig_ScalingConstraints;
78957
+ Rules: InstanceGroupConfig_ScalingRule[];
78950
78958
  });
78951
78959
  }
78952
78960
 
78953
78961
  export declare class InstanceGroupConfig_EbsBlockDeviceConfig {
78954
78962
  constructor(props: {
78955
78963
  VolumeSpecification: InstanceGroupConfig_VolumeSpecification;
78964
+ /** Use of this property can confuse CloudFormation drift detection. The EbsBlockDeviceConfigs read from the system may return a list with one entry per volume, replacing any entry specified in the template with a VolumesPerInstance greater than one by that many entries containing only the VolumeSpecification. Thus to avoid false drift detection, it is recommended to supply repeated entries in EbsBlockDeviceConfigs for any VolumeSpecification which is intended to be repeated and not to use this property.
78965
+ */
78956
78966
  VolumesPerInstance?: number;
78957
78967
  });
78958
78968
  }
@@ -85949,10 +85959,10 @@ export declare class LogAlarm_ScheduleConfiguration {
85949
85959
  constructor(props: {
85950
85960
  /** The expression that defines when the scheduled query runs, e.g. rate(1 minute). */
85951
85961
  ScheduleExpression: string;
85952
- /** The number of seconds into the past to end the query window. */
85962
+ /** The number of seconds into the past to start the query window. Must be a positive value and cannot exceed 2592000 seconds (30 days). */
85963
+ StartTimeOffset: number;
85964
+ /** The number of seconds into the past to end the query window. Must be a non-negative value and cannot exceed 2592000 seconds (30 days). */
85953
85965
  EndTimeOffset?: number;
85954
- /** The number of seconds into the past to start the query window. */
85955
- StartTimeOffset?: number;
85956
85966
  });
85957
85967
  }
85958
85968
 
@@ -85960,14 +85970,16 @@ export declare class LogAlarm_ScheduledQueryConfiguration {
85960
85970
  constructor(props: {
85961
85971
  /** The aggregation expression for the scheduled query, e.g. count(*) or avg(latency) by host. */
85962
85972
  AggregationExpression: string;
85963
- /** The log groups to query. */
85964
- LogGroupIdentifiers: string[];
85965
85973
  /** The query string to execute against the specified log groups. */
85966
85974
  QueryString: string;
85967
85975
  /** The schedule configuration. */
85968
85976
  ScheduleConfiguration: LogAlarm_ScheduleConfiguration;
85969
85977
  /** The ARN of the IAM role that grants permissions to execute the scheduled query. */
85970
85978
  ScheduledQueryRoleARN: string;
85979
+ /** The log groups to query. */
85980
+ LogGroupIdentifiers?: string[];
85981
+ /** A list of key-value pairs to associate with the scheduled query that backs the log alarm. */
85982
+ Tags?: LogAlarm_Tag[];
85971
85983
  });
85972
85984
  }
85973
85985
 
@@ -109455,14 +109467,16 @@ export declare class ScheduledQueryConfiguration {
109455
109467
  constructor(props: {
109456
109468
  /** The aggregation expression for the scheduled query, e.g. count(*) or avg(latency) by host. */
109457
109469
  AggregationExpression: string;
109458
- /** The log groups to query. */
109459
- LogGroupIdentifiers: string[];
109460
109470
  /** The query string to execute against the specified log groups. */
109461
109471
  QueryString: string;
109462
109472
  /** The schedule configuration. */
109463
109473
  ScheduleConfiguration: LogAlarm_ScheduleConfiguration;
109464
109474
  /** The ARN of the IAM role that grants permissions to execute the scheduled query. */
109465
109475
  ScheduledQueryRoleARN: string;
109476
+ /** The log groups to query. */
109477
+ LogGroupIdentifiers?: string[];
109478
+ /** A list of key-value pairs to associate with the scheduled query that backs the log alarm. */
109479
+ Tags?: LogAlarm_Tag[];
109466
109480
  });
109467
109481
  }
109468
109482
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-aws",
3
- "version": "0.18.16",
3
+ "version": "0.18.17",
4
4
  "description": "AWS CloudFormation lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -80,7 +80,7 @@
80
80
  "typescript": "^5.9.3"
81
81
  },
82
82
  "peerDependencies": {
83
- "@intentius/chant": "^0.18.16",
83
+ "@intentius/chant": "^0.18.17",
84
84
  "typescript": "^5.9.3"
85
85
  }
86
86
  }
@@ -1,5 +1,25 @@
1
1
  import { describe, test, expect } from "vitest";
2
- import { applyAwsEndpoint, applyAwsEndpointArgv } from "./cloud-executor";
2
+ import { applyAwsEndpoint, applyAwsEndpointArgv, ecsDeploymentId, ecsServiceStable } from "./cloud-executor";
3
+
4
+ describe("ecsDeploymentId / ecsServiceStable — tolerate Floci's missing deployments (#937)", () => {
5
+ test("deployment id: real AWS shape", () => {
6
+ expect(ecsDeploymentId({ service: { deployments: [{ id: "ecs-svc/123" }] } })).toBe("ecs-svc/123");
7
+ });
8
+ test("deployment id: Floci omits `deployments` entirely → '' (no crash)", () => {
9
+ expect(ecsDeploymentId({ service: {} })).toBe("");
10
+ expect(ecsDeploymentId({ service: { deployments: [] } })).toBe("");
11
+ });
12
+
13
+ test("stable: running==desired with ≤1 deployment", () => {
14
+ expect(ecsServiceStable({ runningCount: 2, desiredCount: 2, deployments: [{}] })).toBe(true);
15
+ expect(ecsServiceStable({ runningCount: 1, desiredCount: 2, deployments: [{}] })).toBe(false);
16
+ expect(ecsServiceStable({ runningCount: 2, desiredCount: 2, deployments: [{}, {}] })).toBe(false);
17
+ });
18
+ test("stable: Floci omits `deployments` → treated as 0, no crash", () => {
19
+ expect(ecsServiceStable({ runningCount: 2, desiredCount: 2 })).toBe(true);
20
+ expect(ecsServiceStable(undefined)).toBe(true); // 0 == 0
21
+ });
22
+ });
3
23
 
4
24
  describe("applyAwsEndpoint", () => {
5
25
  const url = "http://localhost:4566";
@@ -463,6 +463,23 @@ const realCloudFormation: CloudFormationClient = {
463
463
  },
464
464
  };
465
465
 
466
+ /** Deployment id from an ECS `update-service` response. Tolerant of Floci, whose
467
+ * `service` omits `deployments` entirely (real AWS always includes it) — guards
468
+ * the index, not just `.id` (#937). Exported for testing. */
469
+ export function ecsDeploymentId(described: { service: { deployments?: Array<{ id: string }> } }): string {
470
+ return described.service.deployments?.[0]?.id ?? "";
471
+ }
472
+
473
+ /** Whether an ECS service is steady (running == desired, ≤1 active deployment).
474
+ * Tolerant of Floci's missing `deployments` field. Exported for testing. */
475
+ export function ecsServiceStable(
476
+ svc: { runningCount?: number; desiredCount?: number; deployments?: unknown[] } | undefined,
477
+ ): boolean {
478
+ const running = svc?.runningCount ?? 0;
479
+ const desired = svc?.desiredCount ?? 0;
480
+ return running === desired && (svc?.deployments?.length ?? 0) <= 1;
481
+ }
482
+
466
483
  const realEcs: EcsClient = {
467
484
  async updateService(args) {
468
485
  const parts = [`aws ecs update-service`, `--cluster ${q(args.cluster)}`, `--service ${q(args.service)}`];
@@ -470,20 +487,18 @@ const realEcs: EcsClient = {
470
487
  if (args.desiredCount !== undefined) parts.push(`--desired-count ${args.desiredCount}`);
471
488
  if (args.forceNewDeployment) parts.push(`--force-new-deployment`);
472
489
  const { stdout } = await run(parts.join(" "));
473
- const described = JSON.parse(stdout) as { service: { deployments: Array<{ id: string }> } };
474
- return { deploymentId: described.service.deployments[0]?.id ?? "" };
490
+ const described = JSON.parse(stdout) as { service: { deployments?: Array<{ id: string }> } };
491
+ return { deploymentId: ecsDeploymentId(described) };
475
492
  },
476
493
  async describeService(cluster, service) {
477
494
  const { stdout } = await run(
478
495
  `aws ecs describe-services --cluster ${q(cluster)} --services ${q(service)}`,
479
496
  );
480
497
  const described = JSON.parse(stdout) as {
481
- services: Array<{ runningCount: number; desiredCount: number; deployments: unknown[] }>;
498
+ services: Array<{ runningCount: number; desiredCount: number; deployments?: unknown[] }>;
482
499
  };
483
500
  const svc = described.services[0];
484
- const running = svc?.runningCount ?? 0;
485
- const desired = svc?.desiredCount ?? 0;
486
- return { runningCount: running, desiredCount: desired, stable: running === desired && (svc?.deployments.length ?? 0) <= 1 };
501
+ return { runningCount: svc?.runningCount ?? 0, desiredCount: svc?.desiredCount ?? 0, stable: ecsServiceStable(svc) };
487
502
  },
488
503
  async rollbackService(args) {
489
504
  await realEcs.updateService(args);
@@ -7,6 +7,7 @@ import { AttrRef } from "@intentius/chant/attrref";
7
7
  // precedent for aws-lexicon integration-style tests.
8
8
  import { resolveAttrRefs } from "../../../../packages/core/src/discovery/resolve";
9
9
  import { AgentCoreAgent } from "./agentcore-agent";
10
+ import { Split, Ref } from "../intrinsics";
10
11
  import { awsSerializer } from "../serializer";
11
12
 
12
13
  const baseProps = {
@@ -104,6 +105,17 @@ describe("AgentCoreAgent", () => {
104
105
  );
105
106
  });
106
107
 
108
+ test("VPC mode accepts a cross-stack intrinsic (Fn::Split) — checks presence, not .length (#938)", () => {
109
+ // A cross-stack value (Split of a Parameter) is a truthy intrinsic with no
110
+ // `.length`; it WAS supplied, so the composite must not reject it.
111
+ const subnets = Split(",", Ref("SubnetIdsParam")) as unknown as string[];
112
+ const sgs = Split(",", Ref("SgIdsParam")) as unknown as string[];
113
+ const instance = AgentCoreAgent({ ...baseProps, networkMode: "VPC", vpcSubnetIds: subnets, vpcSecurityGroupIds: sgs });
114
+ const vpcConfigProps = ((instance.runtime as any).props.NetworkConfiguration as any).props.NetworkModeConfig.props;
115
+ expect(vpcConfigProps.Subnets).toBe(subnets);
116
+ expect(vpcConfigProps.SecurityGroups).toBe(sgs);
117
+ });
118
+
107
119
  test("throws when memoryEventExpiryDays is out of CFN bounds (3-365)", () => {
108
120
  expect(() => AgentCoreAgent({ ...baseProps, memoryEventExpiryDays: 1 })).toThrow(
109
121
  "AgentCoreAgent memoryEventExpiryDays must be between 3 and 365",
@@ -107,7 +107,11 @@ export type AgentCoreAgentResult = {
107
107
  export const AgentCoreAgent = Composite<AgentCoreAgentProps, AgentCoreAgentResult>((props) => {
108
108
  const { defaults } = props;
109
109
  const networkMode = props.networkMode ?? "PUBLIC";
110
- if (networkMode === "VPC" && (!props.vpcSubnetIds?.length || !props.vpcSecurityGroupIds?.length)) {
110
+ // Check presence, not `.length`: a cross-stack value (Fn::Split of a Parameter,
111
+ // the shape stackOutput/Ref/Split produce) is a truthy intrinsic object with no
112
+ // `.length`, so a `.length` check wrongly rejects a value that WAS supplied
113
+ // (#938). An actually-empty list is caught by CloudFormation at deploy time.
114
+ if (networkMode === "VPC" && (props.vpcSubnetIds === undefined || props.vpcSecurityGroupIds === undefined)) {
111
115
  throw new Error("AgentCoreAgent requires vpcSubnetIds and vpcSecurityGroupIds when networkMode is \"VPC\"");
112
116
  }
113
117
  const memoryEventExpiryDays = props.memoryEventExpiryDays ?? 30;
@@ -17601,14 +17601,14 @@ export declare class InstanceGroupConfig {
17601
17601
  JobFlowId: string;
17602
17602
  AutoScalingPolicy?: InstanceGroupConfig_AutoScalingPolicy;
17603
17603
  BidPrice?: string;
17604
- Configurations?: InstanceGroupConfig_Configuration[];
17604
+ Configurations?: InstanceGroupConfig_AppConfiguration[];
17605
17605
  CustomAmiId?: string;
17606
17606
  EbsConfiguration?: InstanceGroupConfig_EbsConfiguration;
17607
- Id?: string;
17607
+ InstanceGroupId?: string;
17608
17608
  Market?: string;
17609
17609
  Name?: string;
17610
17610
  }, attributes?: CFResourceAttributes);
17611
- readonly Id: string;
17611
+ readonly InstanceGroupId: string;
17612
17612
  }
17613
17613
 
17614
17614
  export declare class InstanceProfile {
@@ -41403,6 +41403,14 @@ export declare class AppConfigResourceObject {
41403
41403
  });
41404
41404
  }
41405
41405
 
41406
+ export declare class AppConfiguration {
41407
+ constructor(props: {
41408
+ Classification?: string;
41409
+ ConfigurationProperties?: Record<string, unknown>;
41410
+ Configurations?: InstanceGroupConfig_AppConfiguration[];
41411
+ });
41412
+ }
41413
+
41406
41414
  export declare class AppCookieStickinessPolicy {
41407
41415
  constructor(props: {
41408
41416
  /** The name of the application cookie used for stickiness. */
@@ -78935,24 +78943,26 @@ export declare class InstanceFleetConfig_SpotResizingSpecification {
78935
78943
  });
78936
78944
  }
78937
78945
 
78938
- export declare class InstanceGroupConfig_AutoScalingPolicy {
78946
+ export declare class InstanceGroupConfig_AppConfiguration {
78939
78947
  constructor(props: {
78940
- Constraints: InstanceGroupConfig_ScalingConstraints;
78941
- Rules: InstanceGroupConfig_ScalingRule[];
78948
+ Classification?: string;
78949
+ ConfigurationProperties?: Record<string, unknown>;
78950
+ Configurations?: InstanceGroupConfig_AppConfiguration[];
78942
78951
  });
78943
78952
  }
78944
78953
 
78945
- export declare class InstanceGroupConfig_Configuration {
78954
+ export declare class InstanceGroupConfig_AutoScalingPolicy {
78946
78955
  constructor(props: {
78947
- Classification?: string;
78948
- ConfigurationProperties?: Record<string, unknown>;
78949
- Configurations?: InstanceGroupConfig_Configuration[];
78956
+ Constraints: InstanceGroupConfig_ScalingConstraints;
78957
+ Rules: InstanceGroupConfig_ScalingRule[];
78950
78958
  });
78951
78959
  }
78952
78960
 
78953
78961
  export declare class InstanceGroupConfig_EbsBlockDeviceConfig {
78954
78962
  constructor(props: {
78955
78963
  VolumeSpecification: InstanceGroupConfig_VolumeSpecification;
78964
+ /** Use of this property can confuse CloudFormation drift detection. The EbsBlockDeviceConfigs read from the system may return a list with one entry per volume, replacing any entry specified in the template with a VolumesPerInstance greater than one by that many entries containing only the VolumeSpecification. Thus to avoid false drift detection, it is recommended to supply repeated entries in EbsBlockDeviceConfigs for any VolumeSpecification which is intended to be repeated and not to use this property.
78965
+ */
78956
78966
  VolumesPerInstance?: number;
78957
78967
  });
78958
78968
  }
@@ -85949,10 +85959,10 @@ export declare class LogAlarm_ScheduleConfiguration {
85949
85959
  constructor(props: {
85950
85960
  /** The expression that defines when the scheduled query runs, e.g. rate(1 minute). */
85951
85961
  ScheduleExpression: string;
85952
- /** The number of seconds into the past to end the query window. */
85962
+ /** The number of seconds into the past to start the query window. Must be a positive value and cannot exceed 2592000 seconds (30 days). */
85963
+ StartTimeOffset: number;
85964
+ /** The number of seconds into the past to end the query window. Must be a non-negative value and cannot exceed 2592000 seconds (30 days). */
85953
85965
  EndTimeOffset?: number;
85954
- /** The number of seconds into the past to start the query window. */
85955
- StartTimeOffset?: number;
85956
85966
  });
85957
85967
  }
85958
85968
 
@@ -85960,14 +85970,16 @@ export declare class LogAlarm_ScheduledQueryConfiguration {
85960
85970
  constructor(props: {
85961
85971
  /** The aggregation expression for the scheduled query, e.g. count(*) or avg(latency) by host. */
85962
85972
  AggregationExpression: string;
85963
- /** The log groups to query. */
85964
- LogGroupIdentifiers: string[];
85965
85973
  /** The query string to execute against the specified log groups. */
85966
85974
  QueryString: string;
85967
85975
  /** The schedule configuration. */
85968
85976
  ScheduleConfiguration: LogAlarm_ScheduleConfiguration;
85969
85977
  /** The ARN of the IAM role that grants permissions to execute the scheduled query. */
85970
85978
  ScheduledQueryRoleARN: string;
85979
+ /** The log groups to query. */
85980
+ LogGroupIdentifiers?: string[];
85981
+ /** A list of key-value pairs to associate with the scheduled query that backs the log alarm. */
85982
+ Tags?: LogAlarm_Tag[];
85971
85983
  });
85972
85984
  }
85973
85985
 
@@ -109455,14 +109467,16 @@ export declare class ScheduledQueryConfiguration {
109455
109467
  constructor(props: {
109456
109468
  /** The aggregation expression for the scheduled query, e.g. count(*) or avg(latency) by host. */
109457
109469
  AggregationExpression: string;
109458
- /** The log groups to query. */
109459
- LogGroupIdentifiers: string[];
109460
109470
  /** The query string to execute against the specified log groups. */
109461
109471
  QueryString: string;
109462
109472
  /** The schedule configuration. */
109463
109473
  ScheduleConfiguration: LogAlarm_ScheduleConfiguration;
109464
109474
  /** The ARN of the IAM role that grants permissions to execute the scheduled query. */
109465
109475
  ScheduledQueryRoleARN: string;
109476
+ /** The log groups to query. */
109477
+ LogGroupIdentifiers?: string[];
109478
+ /** A list of key-value pairs to associate with the scheduled query that backs the log alarm. */
109479
+ Tags?: LogAlarm_Tag[];
109466
109480
  });
109467
109481
  }
109468
109482
 
@@ -688,7 +688,7 @@ export const Instance = createResource("AWS::EC2::Instance", "aws", {"InstanceId
688
688
  export const InstanceAccessControlAttributeConfiguration = createResource("AWS::SSO::InstanceAccessControlAttributeConfiguration", "aws", {});
689
689
  export const InstanceConnectEndpoint = createResource("AWS::EC2::InstanceConnectEndpoint", "aws", {"Id":"Id","AvailabilityZone":"AvailabilityZone","AvailabilityZoneId":"AvailabilityZoneId","CreatedAt":"CreatedAt","InstanceConnectEndpointArn":"InstanceConnectEndpointArn","NetworkInterfaceIds":"NetworkInterfaceIds","OwnerId":"OwnerId","PublicDnsNames":"PublicDnsNames","State":"State","StateMessage":"StateMessage","VpcId":"VpcId"});
690
690
  export const InstanceFleetConfig = createResource("AWS::EMR::InstanceFleetConfig", "aws", {"Id":"Id"});
691
- export const InstanceGroupConfig = createResource("AWS::EMR::InstanceGroupConfig", "aws", {"Id":"Id"});
691
+ export const InstanceGroupConfig = createResource("AWS::EMR::InstanceGroupConfig", "aws", {"InstanceGroupId":"InstanceGroupId"});
692
692
  export const InstanceProfile = createResource("AWS::IAM::InstanceProfile", "aws", {"Arn":"Arn"});
693
693
  export const InstanceSnapshot = createResource("AWS::Lightsail::InstanceSnapshot", "aws", {"Arn":"Arn","IsFromAutoSnapshot":"IsFromAutoSnapshot","Location":"Location","FromInstanceName":"FromInstanceName","FromInstanceArn":"FromInstanceArn","ResourceType":"ResourceType","SizeInGb":"SizeInGb","State":"State","SupportCode":"SupportCode"});
694
694
  export const InstanceStorageConfig = createResource("AWS::Connect::InstanceStorageConfig", "aws", {"AssociationId":"AssociationId"});
@@ -1985,6 +1985,7 @@ export const AppConfigDeployment_Tag = createProperty("AWS::AppConfig::Deploymen
1985
1985
  export const AppConfigEnvironment_Monitor = createProperty("AWS::AppConfig::Environment.Monitor", "aws");
1986
1986
  export const AppConfigEnvironment_Tag = createProperty("AWS::AppConfig::Environment.Tag", "aws");
1987
1987
  export const AppConfigResourceObject = createProperty("AWS::Evidently::Project.AppConfigResourceObject", "aws");
1988
+ export const AppConfiguration = createProperty("AWS::EMR::InstanceGroupConfig.AppConfiguration", "aws");
1988
1989
  export const AppCookieStickinessPolicy = createProperty("AWS::ElasticLoadBalancing::LoadBalancer.AppCookieStickinessPolicy", "aws");
1989
1990
  export const AppFlowConnector_ConnectorProvisioningConfig = createProperty("AWS::AppFlow::Connector.ConnectorProvisioningConfig", "aws");
1990
1991
  export const AppFlowConnector_LambdaConnectorProvisioningConfig = createProperty("AWS::AppFlow::Connector.LambdaConnectorProvisioningConfig", "aws");
@@ -5823,8 +5824,8 @@ export const InstanceFleetConfig_OnDemandProvisioningSpecification = createPrope
5823
5824
  export const InstanceFleetConfig_OnDemandResizingSpecification = createProperty("AWS::EMR::InstanceFleetConfig.OnDemandResizingSpecification", "aws");
5824
5825
  export const InstanceFleetConfig_SpotProvisioningSpecification = createProperty("AWS::EMR::InstanceFleetConfig.SpotProvisioningSpecification", "aws");
5825
5826
  export const InstanceFleetConfig_SpotResizingSpecification = createProperty("AWS::EMR::InstanceFleetConfig.SpotResizingSpecification", "aws");
5827
+ export const InstanceGroupConfig_AppConfiguration = createProperty("AWS::EMR::InstanceGroupConfig.AppConfiguration", "aws");
5826
5828
  export const InstanceGroupConfig_AutoScalingPolicy = createProperty("AWS::EMR::InstanceGroupConfig.AutoScalingPolicy", "aws");
5827
- export const InstanceGroupConfig_Configuration = createProperty("AWS::EMR::InstanceGroupConfig.Configuration", "aws");
5828
5829
  export const InstanceGroupConfig_EbsBlockDeviceConfig = createProperty("AWS::EMR::InstanceGroupConfig.EbsBlockDeviceConfig", "aws");
5829
5830
  export const InstanceGroupConfig_EbsConfiguration = createProperty("AWS::EMR::InstanceGroupConfig.EbsConfiguration", "aws");
5830
5831
  export const InstanceGroupConfig_ScalingAction = createProperty("AWS::EMR::InstanceGroupConfig.ScalingAction", "aws");
@@ -5045,6 +5045,11 @@
5045
5045
  "kind": "property",
5046
5046
  "lexicon": "aws"
5047
5047
  },
5048
+ "AppConfiguration": {
5049
+ "resourceType": "AWS::EMR::InstanceGroupConfig.AppConfiguration",
5050
+ "kind": "property",
5051
+ "lexicon": "aws"
5052
+ },
5048
5053
  "AppCookieStickinessPolicy": {
5049
5054
  "resourceType": "AWS::ElasticLoadBalancing::LoadBalancer.AppCookieStickinessPolicy",
5050
5055
  "kind": "property",
@@ -48824,7 +48829,7 @@
48824
48829
  "kind": "resource",
48825
48830
  "lexicon": "aws",
48826
48831
  "attrs": {
48827
- "Id": "Id"
48832
+ "InstanceGroupId": "InstanceGroupId"
48828
48833
  },
48829
48834
  "createOnly": [
48830
48835
  "InstanceRole",
@@ -48837,17 +48842,21 @@
48837
48842
  "Market",
48838
48843
  "BidPrice"
48839
48844
  ],
48845
+ "writeOnly": [
48846
+ "EbsConfiguration/EbsBlockDeviceConfigs/*/VolumesPerInstance"
48847
+ ],
48840
48848
  "primaryIdentifier": [
48841
- "Id"
48849
+ "InstanceGroupId",
48850
+ "JobFlowId"
48842
48851
  ]
48843
48852
  },
48844
- "InstanceGroupConfig_AutoScalingPolicy": {
48845
- "resourceType": "AWS::EMR::InstanceGroupConfig.AutoScalingPolicy",
48853
+ "InstanceGroupConfig_AppConfiguration": {
48854
+ "resourceType": "AWS::EMR::InstanceGroupConfig.AppConfiguration",
48846
48855
  "kind": "property",
48847
48856
  "lexicon": "aws"
48848
48857
  },
48849
- "InstanceGroupConfig_Configuration": {
48850
- "resourceType": "AWS::EMR::InstanceGroupConfig.Configuration",
48858
+ "InstanceGroupConfig_AutoScalingPolicy": {
48859
+ "resourceType": "AWS::EMR::InstanceGroupConfig.AutoScalingPolicy",
48851
48860
  "kind": "property",
48852
48861
  "lexicon": "aws"
48853
48862
  },
@@ -116,6 +116,22 @@ describe("Join intrinsic", () => {
116
116
  "Fn::Join": ["-", [{ Ref: "Prefix" }, "bucket"]],
117
117
  });
118
118
  });
119
+
120
+ test("accepts a single list-returning intrinsic (not only an array) (#517)", () => {
121
+ // Fn::Join's second arg legitimately takes a list-returning intrinsic
122
+ // (GetAtt of a list attr, Split, Ref to a List<>) — emitted as-is, no `.map`.
123
+ expect(Join(",", GetAtt("Zone", "NameServers")).toJSON()).toEqual({
124
+ "Fn::Join": [",", { "Fn::GetAtt": ["Zone", "NameServers"] }],
125
+ });
126
+ expect(Join(",", Split(",", "a,b")).toJSON()).toEqual({
127
+ "Fn::Join": [",", { "Fn::Split": [",", "a,b"] }],
128
+ });
129
+ });
130
+
131
+ test("throws a clear error for a non-array, non-intrinsic value (#517)", () => {
132
+ // @ts-expect-error — exercising the runtime guard
133
+ expect(() => Join(",", "oops")).toThrow(/array or a list-returning intrinsic/);
134
+ });
119
135
  });
120
136
 
121
137
  describe("Select intrinsic", () => {
package/src/intrinsics.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { INTRINSIC_MARKER, resolveIntrinsicValue, type Intrinsic } from "@intentius/chant/intrinsic";
1
+ import { INTRINSIC_MARKER, resolveIntrinsicValue, isIntrinsic, type Intrinsic } from "@intentius/chant/intrinsic";
2
2
  import { buildInterpolatedString, defaultInterpolationSerializer } from "@intentius/chant/intrinsic-interpolation";
3
3
  import { type Declarable } from "@intentius/chant/declarable";
4
4
  import { getLogicalName } from "@intentius/chant/utils";
@@ -129,22 +129,35 @@ export function If(conditionName: string, valueIfTrue: unknown, valueIfFalse: un
129
129
  export class JoinIntrinsic implements Intrinsic {
130
130
  readonly [INTRINSIC_MARKER] = true as const;
131
131
  private delimiter: string;
132
- private values: unknown[];
132
+ private values: unknown[] | Intrinsic;
133
133
 
134
- constructor(delimiter: string, values: unknown[]) {
134
+ constructor(delimiter: string, values: unknown[] | Intrinsic) {
135
135
  this.delimiter = delimiter;
136
136
  this.values = values;
137
137
  }
138
138
 
139
- toJSON(): { "Fn::Join": [string, unknown[]] } {
140
- return { "Fn::Join": [this.delimiter, this.values.map(resolveIntrinsicValue)] };
139
+ toJSON(): { "Fn::Join": [string, unknown] } {
140
+ // Fn::Join's second arg is either a literal list of values OR a single
141
+ // list-returning intrinsic (GetAtt of a list attr, Split, Ref to a List<>
142
+ // param). Only the array form gets `.map`; a lone intrinsic is emitted as-is
143
+ // (#517 — mapping over it dereferenced undefined and crashed the build).
144
+ const list = Array.isArray(this.values)
145
+ ? this.values.map(resolveIntrinsicValue)
146
+ : resolveIntrinsicValue(this.values);
147
+ return { "Fn::Join": [this.delimiter, list] };
141
148
  }
142
149
  }
143
150
 
144
151
  /**
145
- * Create a Join intrinsic
152
+ * Create a Join intrinsic. `values` is a literal array, or a single
153
+ * list-returning intrinsic (e.g. `Join(",", zone.NameServers)`).
146
154
  */
147
- export function Join(delimiter: string, values: unknown[]): JoinIntrinsic {
155
+ export function Join(delimiter: string, values: unknown[] | Intrinsic): JoinIntrinsic {
156
+ if (!Array.isArray(values) && !isIntrinsic(values)) {
157
+ throw new Error(
158
+ "Join(delimiter, values): values must be an array or a list-returning intrinsic (GetAtt/Split/Ref to a List)",
159
+ );
160
+ }
148
161
  return new JoinIntrinsic(delimiter, values);
149
162
  }
150
163