@composurecdk/budgets 0.3.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/README.md +192 -0
- package/dist/alarm-config.d.ts +61 -0
- package/dist/alarm-config.d.ts.map +1 -0
- package/dist/alarm-config.js +2 -0
- package/dist/alarm-config.js.map +1 -0
- package/dist/budget-alarm-builder.d.ts +147 -0
- package/dist/budget-alarm-builder.d.ts.map +1 -0
- package/dist/budget-alarm-builder.js +139 -0
- package/dist/budget-alarm-builder.js.map +1 -0
- package/dist/budget-alarms.d.ts +22 -0
- package/dist/budget-alarms.d.ts.map +1 -0
- package/dist/budget-alarms.js +48 -0
- package/dist/budget-alarms.js.map +1 -0
- package/dist/budget-builder.d.ts +178 -0
- package/dist/budget-builder.d.ts.map +1 -0
- package/dist/budget-builder.js +139 -0
- package/dist/budget-builder.js.map +1 -0
- package/dist/defaults.d.ts +43 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +43 -0
- package/dist/defaults.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications.d.ts +60 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +36 -0
- package/dist/notifications.js.map +1 -0
- package/dist/topic-policy.d.ts +20 -0
- package/dist/topic-policy.d.ts.map +1 -0
- package/dist/topic-policy.js +42 -0
- package/dist/topic-policy.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# @composurecdk/budgets
|
|
2
|
+
|
|
3
|
+
AWS Budgets builder for [ComposureCDK](../../README.md).
|
|
4
|
+
|
|
5
|
+
This package provides a fluent builder for `AWS::Budgets::Budget` with well-architected defaults, percentage-threshold notification helpers, and automatic `AWS::SNS::TopicPolicy` wiring for SNS subscribers. It wraps the CDK L1 [CfnBudget](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_budgets.CfnBudget.html) construct — there is no L2 for Budgets.
|
|
6
|
+
|
|
7
|
+
## Budget Builder
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { createBudgetBuilder } from "@composurecdk/budgets";
|
|
11
|
+
|
|
12
|
+
const budget = createBudgetBuilder()
|
|
13
|
+
.budgetName("AgentBudget")
|
|
14
|
+
.limit({ amount: 50, unit: "GBP" })
|
|
15
|
+
.notifyOnActual(100, "ops@example.com")
|
|
16
|
+
.build(stack, "AgentBudget");
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Properties
|
|
20
|
+
|
|
21
|
+
Every field on [CfnBudget.BudgetDataProperty](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_budgets.CfnBudget.BudgetDataProperty.html) that tends to be set by hand is surfaced as a fluent setter:
|
|
22
|
+
|
|
23
|
+
| Setter | Purpose |
|
|
24
|
+
| ------------------- | --------------------------------------------------------------------- |
|
|
25
|
+
| `budgetName(name)` | `BudgetName` — stable identifier in the console and across regions. |
|
|
26
|
+
| `budgetType(type)` | `BudgetType` — `COST`, `USAGE`, `RI_UTILIZATION`, `RI_COVERAGE`, etc. |
|
|
27
|
+
| `timeUnit(unit)` | `TimeUnit` — `DAILY`, `MONTHLY`, `QUARTERLY`, `ANNUALLY`. |
|
|
28
|
+
| `limit({ amount })` | `BudgetLimit` — required for `COST` and `USAGE` budgets. |
|
|
29
|
+
| `costFilters(map)` | `CostFilters` — e.g. `{ Service: ["AmazonEC2"] }`. |
|
|
30
|
+
| `costTypes(types)` | `CostTypes` passthrough. |
|
|
31
|
+
|
|
32
|
+
### Notifications
|
|
33
|
+
|
|
34
|
+
Percentage-threshold helpers cover the common case; `addNotification` accepts the raw shape when you need absolute-value thresholds or a different comparison operator.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
createBudgetBuilder()
|
|
38
|
+
.limit({ amount: 100 })
|
|
39
|
+
.notifyOnActual(80, "ops@example.com") // 80% ACTUAL → email
|
|
40
|
+
.notifyOnForecasted(
|
|
41
|
+
100,
|
|
42
|
+
ref("alerts", (r) => r.topic),
|
|
43
|
+
) // 100% FORECASTED → SNS topic
|
|
44
|
+
.addNotification({
|
|
45
|
+
notificationType: "ACTUAL",
|
|
46
|
+
threshold: 120,
|
|
47
|
+
thresholdType: "ABSOLUTE_VALUE",
|
|
48
|
+
subscribers: ["oncall@example.com"],
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Subscribers may be email strings, `ITopic` instances, or `Resolvable<ITopic>` references to topics owned by sibling components.
|
|
53
|
+
|
|
54
|
+
### Recommended Thresholds
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
createBudgetBuilder().limit({ amount: 50 }).withRecommendedThresholds("ops@example.com");
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Applies the AWS Cost Optimization pillar defaults: `ACTUAL` at 80% and `FORECASTED` at 100%.
|
|
61
|
+
|
|
62
|
+
## Defaults
|
|
63
|
+
|
|
64
|
+
| Property | Default | Rationale |
|
|
65
|
+
| ----------------------------------------- | ----------- | ----------------------------------------------------------------------------- |
|
|
66
|
+
| `budgetType` | `"COST"` | Cost budgets are the most common; usage/RI/SP budgets are explicit overrides. |
|
|
67
|
+
| `timeUnit` | `"MONTHLY"` | Aligns with AWS billing cycles. |
|
|
68
|
+
| `limitUnit` | `"USD"` | Matches the AWS Billing console default. |
|
|
69
|
+
| `recommendedThresholds.actualPercent` | `80` | Early-warning threshold before breach. |
|
|
70
|
+
| `recommendedThresholds.forecastedPercent` | `100` | Trending-over-budget alert for the period. |
|
|
71
|
+
|
|
72
|
+
Exported as `BUDGET_DEFAULTS`.
|
|
73
|
+
|
|
74
|
+
## Automatic SNS Topic Policies
|
|
75
|
+
|
|
76
|
+
When at least one notification subscriber is an SNS topic, the builder creates a matching `AWS::SNS::TopicPolicy` granting `SNS:Publish` to the `budgets.amazonaws.com` service principal. Without that policy, budget notifications to SNS silently fail to deliver — one of the most common footguns when wiring Budgets by hand.
|
|
77
|
+
|
|
78
|
+
The created `TopicPolicy` constructs are returned on `result.topicPolicies`, keyed by the topic's fully-qualified node path (unique within the CDK app).
|
|
79
|
+
|
|
80
|
+
## Recommended Alarms
|
|
81
|
+
|
|
82
|
+
AWS Budgets does not publish per-budget CloudWatch metrics, but the well-architected cost-monitoring pattern combines a budget with a CloudWatch alarm on `AWS/Billing EstimatedCharges`. The builder can create that alarm for you, but it is **off by default** — pass an `estimatedCharges` config to opt in.
|
|
83
|
+
|
|
84
|
+
| Alarm | Metric | Default behaviour |
|
|
85
|
+
| ------------------ | ----------------------------------- | ----------------- |
|
|
86
|
+
| `estimatedCharges` | EstimatedCharges (Maximum, 6 hours) | off |
|
|
87
|
+
|
|
88
|
+
`treatMissingData` defaults to `notBreaching`: missing datapoints from a quiet account are not treated as a breach.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
const stack = new Stack(app, "BillingStack", { env: { region: "us-east-1" } });
|
|
92
|
+
|
|
93
|
+
createBudgetBuilder()
|
|
94
|
+
.limit({ amount: 50 })
|
|
95
|
+
.recommendedAlarms({
|
|
96
|
+
estimatedCharges: { threshold: 50, currency: "USD" },
|
|
97
|
+
})
|
|
98
|
+
.build(stack, "AccountBudget");
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The Budget itself is a global service and can be created from any region; only the alarm requires `us-east-1` (see below).
|
|
102
|
+
|
|
103
|
+
### Customising thresholds
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
createBudgetBuilder()
|
|
107
|
+
.limit({ amount: 1000 })
|
|
108
|
+
.recommendedAlarms({
|
|
109
|
+
estimatedCharges: {
|
|
110
|
+
threshold: 1000,
|
|
111
|
+
currency: "USD",
|
|
112
|
+
evaluationPeriods: 2,
|
|
113
|
+
datapointsToAlarm: 2,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Disabling alarms
|
|
119
|
+
|
|
120
|
+
Disable the recommended alarm with `recommendedAlarms({ estimatedCharges: false })`, or disable all recommended alarms with `recommendedAlarms(false)`. Custom alarms attached via `addAlarm` are unaffected by either form.
|
|
121
|
+
|
|
122
|
+
### Custom alarms
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { Metric } from "aws-cdk-lib/aws-cloudwatch";
|
|
126
|
+
|
|
127
|
+
createBudgetBuilder()
|
|
128
|
+
.limit({ amount: 1000 })
|
|
129
|
+
.addAlarm("ec2EstimatedCharges", (a) =>
|
|
130
|
+
a
|
|
131
|
+
.metric(
|
|
132
|
+
() =>
|
|
133
|
+
new Metric({
|
|
134
|
+
namespace: "AWS/Billing",
|
|
135
|
+
metricName: "EstimatedCharges",
|
|
136
|
+
dimensionsMap: { Currency: "USD", ServiceName: "AmazonEC2" },
|
|
137
|
+
statistic: "Maximum",
|
|
138
|
+
}),
|
|
139
|
+
)
|
|
140
|
+
.threshold(500)
|
|
141
|
+
.greaterThan()
|
|
142
|
+
.description("EC2 estimated charges exceeded $500."),
|
|
143
|
+
);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Applying alarm actions
|
|
147
|
+
|
|
148
|
+
No alarm actions are configured by default. Wire SNS or other actions via [`alarmActionsPolicy`](../cloudwatch/README.md#alarm-actions-policy) (or an `afterBuild` hook) — for cross-region deployments, the policy applied to the `us-east-1` monitoring stack covers both recommended and custom alarms.
|
|
149
|
+
|
|
150
|
+
### Cross-region: `AWS/Billing EstimatedCharges` lives in `us-east-1` only
|
|
151
|
+
|
|
152
|
+
The `AWS/Billing EstimatedCharges` metric is emitted in `us-east-1` only, regardless of where your budgets and resources live. CloudWatch alarms are regional, so an alarm in any other region will never receive data. The combined builder emits a synth-time warning (`@composurecdk/budgets:alarm-region`) when used outside `us-east-1`, but the better approach is to route the alarm into a `us-east-1` stack via `createBudgetAlarmBuilder` and `compose().withStacks()`:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { compose, ref } from "@composurecdk/core";
|
|
156
|
+
import {
|
|
157
|
+
createBudgetBuilder,
|
|
158
|
+
createBudgetAlarmBuilder,
|
|
159
|
+
type BudgetBuilderResult,
|
|
160
|
+
} from "@composurecdk/budgets";
|
|
161
|
+
|
|
162
|
+
compose(
|
|
163
|
+
{
|
|
164
|
+
account: createBudgetBuilder()
|
|
165
|
+
.budgetName("Account")
|
|
166
|
+
.limit({ amount: 1000 })
|
|
167
|
+
.recommendedAlarms(false), // suppress alarms in the budget's own stack
|
|
168
|
+
|
|
169
|
+
accountAlarms: createBudgetAlarmBuilder()
|
|
170
|
+
.budget(ref<BudgetBuilderResult>("account"))
|
|
171
|
+
.recommendedAlarms({ estimatedCharges: { threshold: 1000, currency: "USD" } }),
|
|
172
|
+
},
|
|
173
|
+
{ account: [], accountAlarms: ["account"] },
|
|
174
|
+
)
|
|
175
|
+
.withStacks({
|
|
176
|
+
account: appStack, // any region — AWS::Budgets::Budget is global
|
|
177
|
+
accountAlarms: monitoringStack, // us-east-1 — where AWS/Billing metrics live
|
|
178
|
+
})
|
|
179
|
+
.build(app, "App");
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
If your custom `addAlarm` definitions reference the budget construct, set `crossRegionReferences: true` on both stacks so CDK can export the budget's properties from the app stack and import them in the alarm stack. The same pattern is documented for CloudFront and Route 53 alarms, and codified in [ADR-0004](../../docs/adr/0004-split-alarm-builder-for-fixed-region-metrics.md).
|
|
183
|
+
|
|
184
|
+
## Build Result
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
interface BudgetBuilderResult {
|
|
188
|
+
budget: CfnBudget;
|
|
189
|
+
topicPolicies: Record<string, TopicPolicy>;
|
|
190
|
+
alarms: Record<string, Alarm>;
|
|
191
|
+
}
|
|
192
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { AlarmConfig } from "@composurecdk/cloudwatch";
|
|
2
|
+
/**
|
|
3
|
+
* Extended {@link AlarmConfig} for the account-level `EstimatedCharges`
|
|
4
|
+
* billing alarm.
|
|
5
|
+
*
|
|
6
|
+
* The `EstimatedCharges` metric lives in the `AWS/Billing` namespace and
|
|
7
|
+
* is **only emitted in the `us-east-1` region**, regardless of where
|
|
8
|
+
* your resources run. The builder emits a synth-time warning when the
|
|
9
|
+
* surrounding stack is not in `us-east-1`; for non-`us-east-1` stacks,
|
|
10
|
+
* suppress this alarm with `recommendedAlarms: false` and create the
|
|
11
|
+
* alarm in a `us-east-1` stack via `createBudgetAlarmBuilder` (see
|
|
12
|
+
* ADR-0004).
|
|
13
|
+
*
|
|
14
|
+
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html
|
|
15
|
+
*/
|
|
16
|
+
export interface EstimatedChargesAlarmConfig extends AlarmConfig {
|
|
17
|
+
/**
|
|
18
|
+
* The absolute cost threshold (in `currency`) at which the alarm fires.
|
|
19
|
+
* This is a hard monetary value, **not** a percentage of the budget.
|
|
20
|
+
*/
|
|
21
|
+
threshold: number;
|
|
22
|
+
/**
|
|
23
|
+
* ISO 4217 currency code that the `EstimatedCharges` metric is
|
|
24
|
+
* emitted in. AWS emits the metric with a `Currency` dimension that
|
|
25
|
+
* must match your billing currency.
|
|
26
|
+
*
|
|
27
|
+
* @default "USD"
|
|
28
|
+
*/
|
|
29
|
+
currency?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Controls which recommended CloudWatch alarms are created for an AWS
|
|
33
|
+
* Budget.
|
|
34
|
+
*
|
|
35
|
+
* AWS Budgets itself does not publish per-budget CloudWatch metrics.
|
|
36
|
+
* The recommended-alarm surface therefore mirrors the well-architected
|
|
37
|
+
* cost-monitoring pattern: a CloudWatch alarm on the account-level
|
|
38
|
+
* `AWS/Billing EstimatedCharges` metric that fires when total estimated
|
|
39
|
+
* charges cross a hard threshold.
|
|
40
|
+
*
|
|
41
|
+
* Off by default — the alarm only emits data when its stack is deployed
|
|
42
|
+
* to `us-east-1`, so callers must opt in explicitly.
|
|
43
|
+
*
|
|
44
|
+
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html
|
|
45
|
+
*/
|
|
46
|
+
export interface BudgetAlarmConfig {
|
|
47
|
+
/**
|
|
48
|
+
* Master switch.
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
enabled?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Configuration for the `EstimatedCharges` billing alarm.
|
|
54
|
+
*
|
|
55
|
+
* Pass `false` to disable, or supply an
|
|
56
|
+
* {@link EstimatedChargesAlarmConfig} to enable with a specific
|
|
57
|
+
* monetary threshold.
|
|
58
|
+
*/
|
|
59
|
+
estimatedCharges?: EstimatedChargesAlarmConfig | false;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=alarm-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alarm-config.d.ts","sourceRoot":"","sources":["../src/alarm-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,2BAA4B,SAAQ,WAAW;IAC9D;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,2BAA2B,GAAG,KAAK,CAAC;CACxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alarm-config.js","sourceRoot":"","sources":["../src/alarm-config.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { type CfnBudget } from "aws-cdk-lib/aws-budgets";
|
|
2
|
+
import { type Alarm } from "aws-cdk-lib/aws-cloudwatch";
|
|
3
|
+
import { type IConstruct } from "constructs";
|
|
4
|
+
import { type IBuilder, type Lifecycle, type Resolvable } from "@composurecdk/core";
|
|
5
|
+
import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
|
|
6
|
+
import type { BudgetAlarmConfig } from "./alarm-config.js";
|
|
7
|
+
import type { BudgetBuilderResult } from "./budget-builder.js";
|
|
8
|
+
/**
|
|
9
|
+
* Configuration properties for {@link createBudgetAlarmBuilder}.
|
|
10
|
+
*
|
|
11
|
+
* The standalone alarm builder mirrors the alarm surface that
|
|
12
|
+
* {@link createBudgetBuilder} creates by default. It exists so that
|
|
13
|
+
* billing alarms can be created in a different stack from the budget
|
|
14
|
+
* itself — specifically a `us-east-1` stack, since the
|
|
15
|
+
* `AWS/Billing EstimatedCharges` metric is only emitted in `us-east-1`
|
|
16
|
+
* regardless of where the budget is deployed.
|
|
17
|
+
*
|
|
18
|
+
* @see ADR-0004 — Split-alarm builder pattern for fixed-region metrics
|
|
19
|
+
*/
|
|
20
|
+
export interface BudgetAlarmBuilderProps {
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for AWS-recommended CloudWatch alarms.
|
|
23
|
+
*
|
|
24
|
+
* Mirrors {@link BudgetBuilderProps.recommendedAlarms}. Off by default —
|
|
25
|
+
* pass an {@link BudgetAlarmConfig.estimatedCharges} entry to enable
|
|
26
|
+
* the account-level billing alarm. Set to `false` to suppress recommended
|
|
27
|
+
* alarms entirely; custom alarms added via
|
|
28
|
+
* {@link IBudgetAlarmBuilder.addAlarm} are unaffected.
|
|
29
|
+
*
|
|
30
|
+
* No alarm actions are configured by default. Use `alarmActionsPolicy`
|
|
31
|
+
* (or an `afterBuild` hook) to wire SNS or other actions onto the
|
|
32
|
+
* resulting alarms.
|
|
33
|
+
*
|
|
34
|
+
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html
|
|
35
|
+
*/
|
|
36
|
+
recommendedAlarms?: BudgetAlarmConfig | false;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The build output of an {@link IBudgetAlarmBuilder}.
|
|
40
|
+
*/
|
|
41
|
+
export interface BudgetAlarmBuilderResult {
|
|
42
|
+
/**
|
|
43
|
+
* The CloudWatch alarms created by this builder, keyed by alarm name.
|
|
44
|
+
* Uses the same key scheme as {@link BudgetBuilderResult.alarms}.
|
|
45
|
+
*/
|
|
46
|
+
alarms: Record<string, Alarm>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A fluent builder for budget-related CloudWatch alarms, decoupled from
|
|
50
|
+
* the budget itself. Use this when the budget lives in a stack outside
|
|
51
|
+
* `us-east-1` — route this builder's component into a `us-east-1` stack
|
|
52
|
+
* via `compose().withStacks()` so the alarms land where the
|
|
53
|
+
* `AWS/Billing EstimatedCharges` metric actually emits.
|
|
54
|
+
*
|
|
55
|
+
* @see {@link createBudgetAlarmBuilder}
|
|
56
|
+
*/
|
|
57
|
+
export type IBudgetAlarmBuilder = IBuilder<BudgetAlarmBuilderProps, BudgetAlarmBuilder>;
|
|
58
|
+
/**
|
|
59
|
+
* Shared alarm-assembly used by both {@link createBudgetBuilder} (in its
|
|
60
|
+
* own stack) and {@link createBudgetAlarmBuilder} (typically in a separate
|
|
61
|
+
* `us-east-1` stack). Materialises the recommended billing alarm and any
|
|
62
|
+
* user-supplied custom alarms, emits the region warning if the resulting
|
|
63
|
+
* scope is not in `us-east-1`, and creates the alarm constructs.
|
|
64
|
+
*
|
|
65
|
+
* The `target.budget` reference is only needed for custom alarms added
|
|
66
|
+
* via `addAlarm()` — the recommended `EstimatedCharges` alarm is
|
|
67
|
+
* account-level and does not key off the budget itself, so `target` may
|
|
68
|
+
* be omitted when only the recommended alarm is being created.
|
|
69
|
+
*
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
export declare function buildBudgetAlarms(scope: IConstruct, id: string, target: Pick<BudgetBuilderResult, "budget"> | undefined, options?: {
|
|
73
|
+
recommendedAlarms?: BudgetAlarmConfig | false;
|
|
74
|
+
customAlarms?: AlarmDefinitionBuilder<CfnBudget>[];
|
|
75
|
+
}): Record<string, Alarm>;
|
|
76
|
+
declare class BudgetAlarmBuilder implements Lifecycle<BudgetAlarmBuilderResult> {
|
|
77
|
+
#private;
|
|
78
|
+
props: Partial<BudgetAlarmBuilderProps>;
|
|
79
|
+
/**
|
|
80
|
+
* Sets the budget to alarm on. Pass the result of
|
|
81
|
+
* {@link createBudgetBuilder} (or a {@link Ref} to it). The builder
|
|
82
|
+
* reads the underlying `CfnBudget` from the result so custom alarms
|
|
83
|
+
* added via {@link addAlarm} can reference it.
|
|
84
|
+
*
|
|
85
|
+
* Optional when only the recommended `EstimatedCharges` alarm is being
|
|
86
|
+
* created — that alarm is account-level and does not reference any
|
|
87
|
+
* specific budget. Required as soon as you call {@link addAlarm}.
|
|
88
|
+
*
|
|
89
|
+
* Pair with `compose().withStacks()` to route this component into a
|
|
90
|
+
* `us-east-1` stack while the budget itself lives elsewhere — set
|
|
91
|
+
* `crossRegionReferences: true` on both stacks so CDK can wire any
|
|
92
|
+
* cross-stack references automatically.
|
|
93
|
+
*/
|
|
94
|
+
budget(budget: Resolvable<BudgetBuilderResult>): this;
|
|
95
|
+
/**
|
|
96
|
+
* Adds a custom alarm against the budget. The configure callback
|
|
97
|
+
* receives a fresh {@link AlarmDefinitionBuilder} pre-set with the
|
|
98
|
+
* alarm's key; configure metric, threshold, comparison and any other
|
|
99
|
+
* options.
|
|
100
|
+
*
|
|
101
|
+
* The created alarm is materialised in this builder's stack — useful
|
|
102
|
+
* for cross-region setups where you want all billing-related alarms to
|
|
103
|
+
* live with the recommended one.
|
|
104
|
+
*/
|
|
105
|
+
addAlarm(key: string, configure: (alarm: AlarmDefinitionBuilder<CfnBudget>) => AlarmDefinitionBuilder<CfnBudget>): this;
|
|
106
|
+
build(scope: IConstruct, id: string, context?: Record<string, object>): BudgetAlarmBuilderResult;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Creates a new {@link IBudgetAlarmBuilder} for materialising AWS Budget
|
|
110
|
+
* alarms in a stack separate from the budget itself.
|
|
111
|
+
*
|
|
112
|
+
* The recommended use is multi-region deployments: the budget lives in
|
|
113
|
+
* the application's stack (in any region — `AWS::Budgets::Budget` is a
|
|
114
|
+
* global resource), and the alarms must live in a `us-east-1` stack so
|
|
115
|
+
* they can read the `AWS/Billing EstimatedCharges` metric AWS emits
|
|
116
|
+
* there.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* compose(
|
|
121
|
+
* {
|
|
122
|
+
* account: createBudgetBuilder()
|
|
123
|
+
* .budgetName("Account")
|
|
124
|
+
* .limit({ amount: 1000 })
|
|
125
|
+
* .recommendedAlarms(false), // suppress alarms in the budget's own stack
|
|
126
|
+
*
|
|
127
|
+
* accountAlarms: createBudgetAlarmBuilder()
|
|
128
|
+
* .budget(ref<BudgetBuilderResult>("account"))
|
|
129
|
+
* .recommendedAlarms({
|
|
130
|
+
* estimatedCharges: { threshold: 1000, currency: "USD" },
|
|
131
|
+
* }),
|
|
132
|
+
* },
|
|
133
|
+
* { account: [], accountAlarms: ["account"] },
|
|
134
|
+
* )
|
|
135
|
+
* .withStacks({
|
|
136
|
+
* account: appStack, // any region — Budgets is a global service
|
|
137
|
+
* accountAlarms: monitoringStack, // us-east-1 — where AWS/Billing metrics live
|
|
138
|
+
* })
|
|
139
|
+
* .build(app, "App");
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* Set `crossRegionReferences: true` on both stacks if you reference the
|
|
143
|
+
* budget from custom alarms via `.addAlarm()`.
|
|
144
|
+
*/
|
|
145
|
+
export declare function createBudgetAlarmBuilder(): IBudgetAlarmBuilder;
|
|
146
|
+
export {};
|
|
147
|
+
//# sourceMappingURL=budget-alarm-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget-alarm-builder.d.ts","sourceRoot":"","sources":["../src/budget-alarm-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAExD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,sBAAsB,EAAgB,MAAM,0BAA0B,CAAC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;;;;;;OAcG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,uBAAuB,EAAE,kBAAkB,CAAC,CAAC;AAsBxF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAC,GAAG,SAAS,EACvD,OAAO,GAAE;IACP,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAC;IAC9C,YAAY,CAAC,EAAE,sBAAsB,CAAC,SAAS,CAAC,EAAE,CAAC;CAC/C,GACL,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAoBvB;AAED,cAAM,kBAAmB,YAAW,SAAS,CAAC,wBAAwB,CAAC;;IACrE,KAAK,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAM;IAI7C;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,mBAAmB,CAAC,GAAG,IAAI;IAKrD;;;;;;;;;OASG;IACH,QAAQ,CACN,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,KAAK,EAAE,sBAAsB,CAAC,SAAS,CAAC,KAAK,sBAAsB,CAAC,SAAS,CAAC,GACzF,IAAI;IAKP,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,wBAAwB;CASjG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,wBAAwB,IAAI,mBAAmB,CAE9D"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Annotations, Stack, Token } from "aws-cdk-lib";
|
|
2
|
+
import { Builder, resolve, } from "@composurecdk/core";
|
|
3
|
+
import { AlarmDefinitionBuilder, createAlarms } from "@composurecdk/cloudwatch";
|
|
4
|
+
import { resolveBudgetAlarmDefinitions } from "./budget-alarms.js";
|
|
5
|
+
/**
|
|
6
|
+
* The `AWS/Billing EstimatedCharges` metric is emitted in `us-east-1`
|
|
7
|
+
* only. CloudWatch alarms are regional, so alarms created in any other
|
|
8
|
+
* region will never receive data. Warn (don't error) when alarms are
|
|
9
|
+
* being created outside `us-east-1`, unless the region is an unresolved
|
|
10
|
+
* token (env-agnostic stack — user knows best).
|
|
11
|
+
*/
|
|
12
|
+
function warnIfNotUsEast1(scope) {
|
|
13
|
+
const region = Stack.of(scope).region;
|
|
14
|
+
if (Token.isUnresolved(region))
|
|
15
|
+
return;
|
|
16
|
+
if (region === "us-east-1")
|
|
17
|
+
return;
|
|
18
|
+
Annotations.of(scope).addWarningV2("@composurecdk/budgets:alarm-region", `AWS/Billing EstimatedCharges is emitted in us-east-1 only, but this stack is ` +
|
|
19
|
+
`deployed in "${region}". CloudWatch alarms created here will not fire. Deploy the ` +
|
|
20
|
+
`stack in us-east-1, or use createBudgetAlarmBuilder() routed to a ` +
|
|
21
|
+
`us-east-1 stack via compose().withStacks().`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Shared alarm-assembly used by both {@link createBudgetBuilder} (in its
|
|
25
|
+
* own stack) and {@link createBudgetAlarmBuilder} (typically in a separate
|
|
26
|
+
* `us-east-1` stack). Materialises the recommended billing alarm and any
|
|
27
|
+
* user-supplied custom alarms, emits the region warning if the resulting
|
|
28
|
+
* scope is not in `us-east-1`, and creates the alarm constructs.
|
|
29
|
+
*
|
|
30
|
+
* The `target.budget` reference is only needed for custom alarms added
|
|
31
|
+
* via `addAlarm()` — the recommended `EstimatedCharges` alarm is
|
|
32
|
+
* account-level and does not key off the budget itself, so `target` may
|
|
33
|
+
* be omitted when only the recommended alarm is being created.
|
|
34
|
+
*
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export function buildBudgetAlarms(scope, id, target, options = {}) {
|
|
38
|
+
const recommended = options.recommendedAlarms;
|
|
39
|
+
const recommendedDefs = recommended === false ? [] : resolveBudgetAlarmDefinitions(recommended);
|
|
40
|
+
const customAlarms = options.customAlarms ?? [];
|
|
41
|
+
if (customAlarms.length > 0 && !target) {
|
|
42
|
+
throw new Error(`BudgetAlarmBuilder "${id}" was given addAlarm() definitions but no budget. ` +
|
|
43
|
+
`Call .budget() with a BudgetBuilderResult or a Ref to one before adding custom alarms.`);
|
|
44
|
+
}
|
|
45
|
+
const customAlarmDefs = target ? customAlarms.map((b) => b.resolve(target.budget)) : [];
|
|
46
|
+
const allAlarmDefs = [...recommendedDefs, ...customAlarmDefs];
|
|
47
|
+
if (allAlarmDefs.length > 0) {
|
|
48
|
+
warnIfNotUsEast1(scope);
|
|
49
|
+
}
|
|
50
|
+
return createAlarms(scope, id, allAlarmDefs);
|
|
51
|
+
}
|
|
52
|
+
class BudgetAlarmBuilder {
|
|
53
|
+
props = {};
|
|
54
|
+
#budget;
|
|
55
|
+
#customAlarms = [];
|
|
56
|
+
/**
|
|
57
|
+
* Sets the budget to alarm on. Pass the result of
|
|
58
|
+
* {@link createBudgetBuilder} (or a {@link Ref} to it). The builder
|
|
59
|
+
* reads the underlying `CfnBudget` from the result so custom alarms
|
|
60
|
+
* added via {@link addAlarm} can reference it.
|
|
61
|
+
*
|
|
62
|
+
* Optional when only the recommended `EstimatedCharges` alarm is being
|
|
63
|
+
* created — that alarm is account-level and does not reference any
|
|
64
|
+
* specific budget. Required as soon as you call {@link addAlarm}.
|
|
65
|
+
*
|
|
66
|
+
* Pair with `compose().withStacks()` to route this component into a
|
|
67
|
+
* `us-east-1` stack while the budget itself lives elsewhere — set
|
|
68
|
+
* `crossRegionReferences: true` on both stacks so CDK can wire any
|
|
69
|
+
* cross-stack references automatically.
|
|
70
|
+
*/
|
|
71
|
+
budget(budget) {
|
|
72
|
+
this.#budget = budget;
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Adds a custom alarm against the budget. The configure callback
|
|
77
|
+
* receives a fresh {@link AlarmDefinitionBuilder} pre-set with the
|
|
78
|
+
* alarm's key; configure metric, threshold, comparison and any other
|
|
79
|
+
* options.
|
|
80
|
+
*
|
|
81
|
+
* The created alarm is materialised in this builder's stack — useful
|
|
82
|
+
* for cross-region setups where you want all billing-related alarms to
|
|
83
|
+
* live with the recommended one.
|
|
84
|
+
*/
|
|
85
|
+
addAlarm(key, configure) {
|
|
86
|
+
this.#customAlarms.push(configure(new AlarmDefinitionBuilder(key)));
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
build(scope, id, context) {
|
|
90
|
+
const target = this.#budget ? resolve(this.#budget, context ?? {}) : undefined;
|
|
91
|
+
return {
|
|
92
|
+
alarms: buildBudgetAlarms(scope, id, target, {
|
|
93
|
+
recommendedAlarms: this.props.recommendedAlarms,
|
|
94
|
+
customAlarms: this.#customAlarms,
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Creates a new {@link IBudgetAlarmBuilder} for materialising AWS Budget
|
|
101
|
+
* alarms in a stack separate from the budget itself.
|
|
102
|
+
*
|
|
103
|
+
* The recommended use is multi-region deployments: the budget lives in
|
|
104
|
+
* the application's stack (in any region — `AWS::Budgets::Budget` is a
|
|
105
|
+
* global resource), and the alarms must live in a `us-east-1` stack so
|
|
106
|
+
* they can read the `AWS/Billing EstimatedCharges` metric AWS emits
|
|
107
|
+
* there.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* compose(
|
|
112
|
+
* {
|
|
113
|
+
* account: createBudgetBuilder()
|
|
114
|
+
* .budgetName("Account")
|
|
115
|
+
* .limit({ amount: 1000 })
|
|
116
|
+
* .recommendedAlarms(false), // suppress alarms in the budget's own stack
|
|
117
|
+
*
|
|
118
|
+
* accountAlarms: createBudgetAlarmBuilder()
|
|
119
|
+
* .budget(ref<BudgetBuilderResult>("account"))
|
|
120
|
+
* .recommendedAlarms({
|
|
121
|
+
* estimatedCharges: { threshold: 1000, currency: "USD" },
|
|
122
|
+
* }),
|
|
123
|
+
* },
|
|
124
|
+
* { account: [], accountAlarms: ["account"] },
|
|
125
|
+
* )
|
|
126
|
+
* .withStacks({
|
|
127
|
+
* account: appStack, // any region — Budgets is a global service
|
|
128
|
+
* accountAlarms: monitoringStack, // us-east-1 — where AWS/Billing metrics live
|
|
129
|
+
* })
|
|
130
|
+
* .build(app, "App");
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* Set `crossRegionReferences: true` on both stacks if you reference the
|
|
134
|
+
* budget from custom alarms via `.addAlarm()`.
|
|
135
|
+
*/
|
|
136
|
+
export function createBudgetAlarmBuilder() {
|
|
137
|
+
return Builder(BudgetAlarmBuilder);
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=budget-alarm-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget-alarm-builder.js","sourceRoot":"","sources":["../src/budget-alarm-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AlarmDefinition } from "@composurecdk/cloudwatch";
|
|
2
|
+
import type { BudgetAlarmConfig } from "./alarm-config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the recommended alarm configuration into fully-resolved
|
|
5
|
+
* {@link AlarmDefinition}s for an AWS Budget.
|
|
6
|
+
*
|
|
7
|
+
* AWS Budgets does not publish per-budget CloudWatch metrics — the only
|
|
8
|
+
* recommended alarm is the account-level `AWS/Billing EstimatedCharges`
|
|
9
|
+
* billing alarm. Off by default: callers must pass an
|
|
10
|
+
* {@link BudgetAlarmConfig.estimatedCharges} config to opt in.
|
|
11
|
+
*
|
|
12
|
+
* Period and statistic are fixed at the AWS-recommended values
|
|
13
|
+
* (6 hours, Maximum) and not exposed as configuration knobs — billing
|
|
14
|
+
* metrics only update every ~6 hours, so a shorter period would
|
|
15
|
+
* oversample. Threshold, currency, evaluation periods, datapoints and
|
|
16
|
+
* missing-data behaviour remain user-configurable via
|
|
17
|
+
* {@link EstimatedChargesAlarmConfig}.
|
|
18
|
+
*
|
|
19
|
+
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveBudgetAlarmDefinitions(config: BudgetAlarmConfig | undefined): AlarmDefinition[];
|
|
22
|
+
//# sourceMappingURL=budget-alarms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget-alarms.d.ts","sourceRoot":"","sources":["../src/budget-alarms.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,iBAAiB,GAAG,SAAS,GACpC,eAAe,EAAE,CAyBnB"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Duration } from "aws-cdk-lib";
|
|
2
|
+
import { ComparisonOperator, Metric, TreatMissingData } from "aws-cdk-lib/aws-cloudwatch";
|
|
3
|
+
const BILLING_METRIC_PERIOD = Duration.hours(6);
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the recommended alarm configuration into fully-resolved
|
|
6
|
+
* {@link AlarmDefinition}s for an AWS Budget.
|
|
7
|
+
*
|
|
8
|
+
* AWS Budgets does not publish per-budget CloudWatch metrics — the only
|
|
9
|
+
* recommended alarm is the account-level `AWS/Billing EstimatedCharges`
|
|
10
|
+
* billing alarm. Off by default: callers must pass an
|
|
11
|
+
* {@link BudgetAlarmConfig.estimatedCharges} config to opt in.
|
|
12
|
+
*
|
|
13
|
+
* Period and statistic are fixed at the AWS-recommended values
|
|
14
|
+
* (6 hours, Maximum) and not exposed as configuration knobs — billing
|
|
15
|
+
* metrics only update every ~6 hours, so a shorter period would
|
|
16
|
+
* oversample. Threshold, currency, evaluation periods, datapoints and
|
|
17
|
+
* missing-data behaviour remain user-configurable via
|
|
18
|
+
* {@link EstimatedChargesAlarmConfig}.
|
|
19
|
+
*
|
|
20
|
+
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html
|
|
21
|
+
*/
|
|
22
|
+
export function resolveBudgetAlarmDefinitions(config) {
|
|
23
|
+
if (config?.enabled === false)
|
|
24
|
+
return [];
|
|
25
|
+
if (!config?.estimatedCharges)
|
|
26
|
+
return [];
|
|
27
|
+
const cfg = config.estimatedCharges;
|
|
28
|
+
const currency = cfg.currency ?? "USD";
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
key: "estimatedCharges",
|
|
32
|
+
metric: new Metric({
|
|
33
|
+
namespace: "AWS/Billing",
|
|
34
|
+
metricName: "EstimatedCharges",
|
|
35
|
+
dimensionsMap: { Currency: currency },
|
|
36
|
+
statistic: "Maximum",
|
|
37
|
+
period: BILLING_METRIC_PERIOD,
|
|
38
|
+
}),
|
|
39
|
+
threshold: cfg.threshold,
|
|
40
|
+
comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
|
|
41
|
+
evaluationPeriods: cfg.evaluationPeriods ?? 1,
|
|
42
|
+
datapointsToAlarm: cfg.datapointsToAlarm ?? 1,
|
|
43
|
+
treatMissingData: cfg.treatMissingData ?? TreatMissingData.NOT_BREACHING,
|
|
44
|
+
description: `Account-level estimated charges exceeded ${String(cfg.threshold)} ${currency}. Billing metrics are only emitted in us-east-1.`,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=budget-alarms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget-alarms.js","sourceRoot":"","sources":["../src/budget-alarms.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAI1F,MAAM,qBAAqB,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEhD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,6BAA6B,CAC3C,MAAqC;IAErC,IAAI,MAAM,EAAE,OAAO,KAAK,KAAK;QAAE,OAAO,EAAE,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,gBAAgB;QAAE,OAAO,EAAE,CAAC;IAEzC,MAAM,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC;IACpC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,KAAK,CAAC;IAEvC,OAAO;QACL;YACE,GAAG,EAAE,kBAAkB;YACvB,MAAM,EAAE,IAAI,MAAM,CAAC;gBACjB,SAAS,EAAE,aAAa;gBACxB,UAAU,EAAE,kBAAkB;gBAC9B,aAAa,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;gBACrC,SAAS,EAAE,SAAS;gBACpB,MAAM,EAAE,qBAAqB;aAC9B,CAAC;YACF,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,kBAAkB,EAAE,kBAAkB,CAAC,sBAAsB;YAC7D,iBAAiB,EAAE,GAAG,CAAC,iBAAiB,IAAI,CAAC;YAC7C,iBAAiB,EAAE,GAAG,CAAC,iBAAiB,IAAI,CAAC;YAC7C,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,aAAa;YACxE,WAAW,EAAE,4CAA4C,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,QAAQ,kDAAkD;SAC7I;KACF,CAAC;AACJ,CAAC"}
|