@intentius/chant-lexicon-aws 0.18.15 → 0.18.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8347,8 +8347,7 @@
8347
8347
  "KmsKeyArn": "KmsKeyArn"
8348
8348
  },
8349
8349
  "createOnly": [
8350
- "KmsKeyId",
8351
- "ForceDelete"
8350
+ "KmsKeyId"
8352
8351
  ],
8353
8352
  "writeOnly": [
8354
8353
  "KmsKeyId",
@@ -49451,6 +49450,92 @@
49451
49450
  "kind": "property",
49452
49451
  "lexicon": "aws"
49453
49452
  },
49453
+ "IntermediateTable": {
49454
+ "resourceType": "AWS::CleanRooms::IntermediateTable",
49455
+ "kind": "resource",
49456
+ "lexicon": "aws",
49457
+ "attrs": {
49458
+ "IntermediateTableIdentifier": "IntermediateTableIdentifier",
49459
+ "Arn": "Arn",
49460
+ "MembershipArn": "MembershipArn",
49461
+ "CollaborationIdentifier": "CollaborationIdentifier",
49462
+ "CollaborationArn": "CollaborationArn",
49463
+ "Status": "Status"
49464
+ },
49465
+ "propertyConstraints": {
49466
+ "Arn": {
49467
+ "maxLength": 256
49468
+ },
49469
+ "MembershipArn": {
49470
+ "maxLength": 100
49471
+ },
49472
+ "CollaborationArn": {
49473
+ "maxLength": 100
49474
+ },
49475
+ "Name": {
49476
+ "pattern": "^(?!\\s*$)[\\u0020-\\uD7FF\\uE000-\\uFFFD\\uD800\\uDBFF-\\uDC00\\uDFFF\\t]*$",
49477
+ "minLength": 1,
49478
+ "maxLength": 100
49479
+ },
49480
+ "Description": {
49481
+ "pattern": "^[\\u0020-\\uD7FF\\uE000-\\uFFFD\\uD800\\uDBFF-\\uDC00\\uDFFF\\t\\r\\n]*$",
49482
+ "maxLength": 255
49483
+ },
49484
+ "KmsKeyArn": {
49485
+ "minLength": 4,
49486
+ "maxLength": 2048
49487
+ }
49488
+ },
49489
+ "createOnly": [
49490
+ "MembershipIdentifier",
49491
+ "Name",
49492
+ "PopulationAnalysisConfiguration"
49493
+ ],
49494
+ "primaryIdentifier": [
49495
+ "IntermediateTableIdentifier",
49496
+ "MembershipIdentifier"
49497
+ ],
49498
+ "tagging": {
49499
+ "taggable": true,
49500
+ "tagOnCreate": true,
49501
+ "tagUpdatable": true
49502
+ }
49503
+ },
49504
+ "IntermediateTableAnalysisRule": {
49505
+ "resourceType": "AWS::CleanRooms::IntermediateTable.IntermediateTableAnalysisRule",
49506
+ "kind": "property",
49507
+ "lexicon": "aws"
49508
+ },
49509
+ "IntermediateTableAnalysisRulePolicy": {
49510
+ "resourceType": "AWS::CleanRooms::IntermediateTable.IntermediateTableAnalysisRulePolicy",
49511
+ "kind": "property",
49512
+ "lexicon": "aws"
49513
+ },
49514
+ "IntermediateTable_IntermediateTableAnalysisRule": {
49515
+ "resourceType": "AWS::CleanRooms::IntermediateTable.IntermediateTableAnalysisRule",
49516
+ "kind": "property",
49517
+ "lexicon": "aws"
49518
+ },
49519
+ "IntermediateTable_IntermediateTableAnalysisRulePolicy": {
49520
+ "resourceType": "AWS::CleanRooms::IntermediateTable.IntermediateTableAnalysisRulePolicy",
49521
+ "kind": "property",
49522
+ "lexicon": "aws"
49523
+ },
49524
+ "IntermediateTable_PopulationAnalysisConfiguration": {
49525
+ "resourceType": "AWS::CleanRooms::IntermediateTable.PopulationAnalysisConfiguration",
49526
+ "kind": "property",
49527
+ "lexicon": "aws"
49528
+ },
49529
+ "IntermediateTable_PopulationAnalysisSqlParameters": {
49530
+ "resourceType": "AWS::CleanRooms::IntermediateTable.PopulationAnalysisSqlParameters",
49531
+ "kind": "property",
49532
+ "lexicon": "aws"
49533
+ },
49534
+ "IntermediateTable_Tag": {
49535
+ "resourceType": "AWS::CleanRooms::IntermediateTable.Tag",
49536
+ "kind": "property",
49537
+ "lexicon": "aws"
49538
+ },
49454
49539
  "InternetGateway": {
49455
49540
  "resourceType": "AWS::EC2::InternetGateway",
49456
49541
  "kind": "resource",
@@ -54791,7 +54876,12 @@
54791
54876
  ],
54792
54877
  "primaryIdentifier": [
54793
54878
  "ListenerArn"
54794
- ]
54879
+ ],
54880
+ "tagging": {
54881
+ "taggable": true,
54882
+ "tagOnCreate": true,
54883
+ "tagUpdatable": true
54884
+ }
54795
54885
  },
54796
54886
  "ListenerAttribute": {
54797
54887
  "resourceType": "AWS::ElasticLoadBalancingV2::Listener.ListenerAttribute",
@@ -55022,6 +55112,11 @@
55022
55112
  "kind": "property",
55023
55113
  "lexicon": "aws"
55024
55114
  },
55115
+ "Listener_Tag": {
55116
+ "resourceType": "AWS::ElasticLoadBalancingV2::Listener.Tag",
55117
+ "kind": "property",
55118
+ "lexicon": "aws"
55119
+ },
55025
55120
  "Listener_TargetGroupStickinessConfig": {
55026
55121
  "resourceType": "AWS::ElasticLoadBalancingV2::Listener.TargetGroupStickinessConfig",
55027
55122
  "kind": "property",
@@ -71684,6 +71779,16 @@
71684
71779
  "kind": "property",
71685
71780
  "lexicon": "aws"
71686
71781
  },
71782
+ "PopulationAnalysisConfiguration": {
71783
+ "resourceType": "AWS::CleanRooms::IntermediateTable.PopulationAnalysisConfiguration",
71784
+ "kind": "property",
71785
+ "lexicon": "aws"
71786
+ },
71787
+ "PopulationAnalysisSqlParameters": {
71788
+ "resourceType": "AWS::CleanRooms::IntermediateTable.PopulationAnalysisSqlParameters",
71789
+ "kind": "property",
71790
+ "lexicon": "aws"
71791
+ },
71687
71792
  "Port": {
71688
71793
  "resourceType": "AWS::Lightsail::Instance.Port",
71689
71794
  "kind": "property",
@@ -41,14 +41,24 @@ describe("aws exportResources I/O glue (#160)", () => {
41
41
  expect(ir.resources.map((r) => r.logicalId)).toEqual(["MyBucket"]);
42
42
  });
43
43
 
44
- test("a non-zero exit throws with the stderr surfaced", async () => {
44
+ test("a not-yet-deployed stack returns empty live state (pre-first-apply), not an error", async () => {
45
45
  spawnMock.mockResolvedValue({
46
46
  stdout: "",
47
- stderr: "Stack with id ghost does not exist",
47
+ stderr: "An error occurred (ValidationError) …: Stack with id ghost does not exist",
48
48
  exitCode: 254,
49
49
  });
50
- await expect(awsPlugin.exportResources!({ environment: "ghost" })).rejects.toThrow(
51
- /Failed to get template for stack "ghost".*does not exist/,
50
+ const ir = await awsPlugin.exportResources!({ environment: "ghost" });
51
+ expect(ir.resources).toEqual([]);
52
+ });
53
+
54
+ test("a genuine failure (not 'does not exist') still throws with the stderr surfaced", async () => {
55
+ spawnMock.mockResolvedValue({
56
+ stdout: "",
57
+ stderr: "An error occurred (AccessDenied) …: not authorized",
58
+ exitCode: 254,
59
+ });
60
+ await expect(awsPlugin.exportResources!({ environment: "prod" })).rejects.toThrow(
61
+ /Failed to get template for stack "prod".*AccessDenied/,
52
62
  );
53
63
  });
54
64
 
@@ -1,7 +1,19 @@
1
1
  import { describe, test, expect } from "vitest";
2
- import { awsPlugin } from "./plugin";
2
+ import { awsPlugin, stackDoesNotExist } from "./plugin";
3
3
  import { isLexiconPlugin } from "@intentius/chant/lexicon";
4
4
 
5
+ describe("stackDoesNotExist (pre-first-apply live state)", () => {
6
+ test("true for the CloudFormation 'does not exist' error", () => {
7
+ expect(stackDoesNotExist(
8
+ "An error occurred (ValidationError) when calling the DescribeStackResources operation: Stack with id prod does not exist",
9
+ )).toBe(true);
10
+ });
11
+ test("false for other failures (auth, network) — those still throw", () => {
12
+ expect(stackDoesNotExist("An error occurred (InvalidClientTokenId) ...")).toBe(false);
13
+ expect(stackDoesNotExist("Could not connect to the endpoint URL")).toBe(false);
14
+ });
15
+ });
16
+
5
17
  describe("awsPlugin", () => {
6
18
  // -----------------------------------------------------------------------
7
19
  // Basic interface
package/src/plugin.ts CHANGED
@@ -24,6 +24,13 @@ import { parseStackTemplate } from "./import/live-export";
24
24
  import { awsCompletions } from "./lsp/completions";
25
25
  import { awsHover } from "./lsp/hover";
26
26
 
27
+ /** True when a CloudFormation CLI error means the stack simply isn't there yet
28
+ * (`ValidationError … does not exist`) — the pre-first-apply state, which live
29
+ * queries should treat as "nothing deployed", not a failure. Exported for testing. */
30
+ export function stackDoesNotExist(stderr: string): boolean {
31
+ return /does not exist/i.test(stderr);
32
+ }
33
+
27
34
  /**
28
35
  * AWS CloudFormation lexicon plugin.
29
36
  *
@@ -497,6 +504,13 @@ aws cloudformation wait stack-update-complete --stack-name my-app-prod`,
497
504
  ], process.env.AWS_ENDPOINT_URL));
498
505
 
499
506
  if (listResult.exitCode !== 0) {
507
+ // A stack that doesn't exist yet is the pre-first-apply state: nothing is
508
+ // deployed for this env, so there are no live resources (every declared
509
+ // resource is "pending") — not an error. Returning empty lets `lifecycle
510
+ // diff --live` / the overlay show pending nodes instead of failing hard.
511
+ if (stackDoesNotExist(listResult.stderr)) {
512
+ return resources;
513
+ }
500
514
  throw new Error(`Failed to describe stack "${stackName}": ${listResult.stderr}`);
501
515
  }
502
516
 
@@ -579,6 +593,12 @@ aws cloudformation wait stack-update-complete --stack-name my-app-prod`,
579
593
  "--output", "json",
580
594
  ], process.env.AWS_ENDPOINT_URL));
581
595
  if (result.exitCode !== 0) {
596
+ // Not deployed yet → no template to export (nothing live), not an error.
597
+ // Keeps `chant graph --live` edge enrichment and `import --from` quiet
598
+ // before the first apply.
599
+ if (stackDoesNotExist(result.stderr)) {
600
+ return parseStackTemplate({ Resources: {} }, options.selector, options.owned);
601
+ }
582
602
  throw new Error(`Failed to get template for stack "${stackName}": ${result.stderr}`);
583
603
  }
584
604