@composurecdk/sns 0.3.0 → 0.3.2

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 CHANGED
@@ -1,8 +1,8 @@
1
1
  # @composurecdk/sns
2
2
 
3
- SNS topic builder for [ComposureCDK](../../README.md).
3
+ SNS topic and subscription builders for [ComposureCDK](../../README.md).
4
4
 
5
- This package provides a fluent builder for SNS topics with secure, AWS-recommended defaults. It wraps the CDK [Topic](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sns.Topic.html) construct — refer to the CDK documentation for the full set of configurable properties.
5
+ This package provides fluent builders for SNS topics and subscriptions with secure, AWS-recommended defaults. They wrap the CDK [Topic](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sns.Topic.html) and [Subscription](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sns.Subscription.html) constructs — refer to the CDK documentation for the full set of configurable properties.
6
6
 
7
7
  ## Topic Builder
8
8
 
@@ -47,6 +47,10 @@ The builder creates [AWS-recommended CloudWatch alarms](https://docs.aws.amazon.
47
47
  | --------------------------------------------------- | --------------------------------------------------------------- | ----------------- | ------------ |
48
48
  | `numberOfNotificationsFailed` | NumberOfNotificationsFailed (Sum, 1 min) | > 0 | Always |
49
49
  | `numberOfNotificationsFilteredOutInvalidAttributes` | NumberOfNotificationsFilteredOut-InvalidAttributes (Sum, 1 min) | > 0 | Always |
50
+ | `numberOfNotificationsRedrivenToDlq` | NumberOfNotificationsRedrivenToDlq (Sum, 1 min) | > 0 | Always[^dlq] |
51
+ | `numberOfNotificationsFailedToRedriveToDlq` | NumberOfNotificationsFailedToRedriveToDlq (Sum, 1 min) | > 0 | Always[^dlq] |
52
+
53
+ [^dlq]: Metric only emits when a subscription on the topic has a dead-letter queue attached and SNS attempts redrive. `TreatMissingData` defaults to `notBreaching`, so the alarm stays quiet on topics without DLQs. Attach a DLQ via the `SubscriptionBuilder`'s `.deadLetterQueue(...)` — see [SNS DLQ docs](https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html).
50
54
 
51
55
  The defaults are exported as `TOPIC_ALARM_DEFAULTS` for visibility and testing:
52
56
 
@@ -122,6 +126,85 @@ for (const alarm of Object.values(result.alarms)) {
122
126
  }
123
127
  ```
124
128
 
129
+ ## Adding Subscriptions to a Topic
130
+
131
+ For the common case where a topic and its subscriptions are declared together, use `addSubscription` on the topic builder. It accepts any CDK [`ITopicSubscription`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sns.ITopicSubscription.html) (e.g. `EmailSubscription`, `LambdaSubscription`, `SqsSubscription`) and binds it via `ITopicSubscription.bind(topic)` — the same path CDK uses for `topic.addSubscription(...)`, so endpoint-specific wire-up (Lambda invoke permission, SQS queue policy, KMS decrypt policy) happens automatically.
132
+
133
+ ```ts
134
+ import { createTopicBuilder } from "@composurecdk/sns";
135
+ import { EmailSubscription, LambdaSubscription } from "aws-cdk-lib/aws-sns-subscriptions";
136
+
137
+ const result = createTopicBuilder()
138
+ .topicName("alerts")
139
+ .addSubscription("ops", new EmailSubscription("ops@example.com"))
140
+ .addSubscription("handler", new LambdaSubscription(alertHandler))
141
+ .build(stack, "Alerts");
142
+
143
+ result.subscriptions.ops; // AWS SNS Subscription construct
144
+ ```
145
+
146
+ Each subscription is exposed on `result.subscriptions` under the key supplied to `addSubscription`.
147
+
148
+ Cross-component subscriptions can be declared with `ref(...)` inside a [`compose`](../core/README.md) system, so the subscription's endpoint is resolved from another component's build output at build time:
149
+
150
+ ```ts
151
+ import { compose, ref } from "@composurecdk/core";
152
+ import { createTopicBuilder } from "@composurecdk/sns";
153
+ import { createFunctionBuilder, type FunctionBuilderResult } from "@composurecdk/lambda";
154
+ import { LambdaSubscription } from "aws-cdk-lib/aws-sns-subscriptions";
155
+
156
+ const system = compose(
157
+ {
158
+ handler: createFunctionBuilder()./* ... */,
159
+ alerts: createTopicBuilder().addSubscription(
160
+ "handler",
161
+ ref("handler", (r: FunctionBuilderResult) => new LambdaSubscription(r.function)),
162
+ ),
163
+ },
164
+ { handler: [], alerts: ["handler"] },
165
+ );
166
+ ```
167
+
168
+ ## Subscription Builder
169
+
170
+ ```ts
171
+ import { createSubscriptionBuilder } from "@composurecdk/sns";
172
+ import { SubscriptionProtocol } from "aws-cdk-lib/aws-sns";
173
+
174
+ const emailAlerts = createSubscriptionBuilder()
175
+ .topic(budgetTopic)
176
+ .protocol(SubscriptionProtocol.EMAIL)
177
+ .endpoint("ops@example.com")
178
+ .build(stack, "BudgetEmailSubscription");
179
+ ```
180
+
181
+ Every [SubscriptionProps](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sns.SubscriptionProps.html) property is available as a fluent setter. `topic` and `deadLetterQueue` additionally accept a `Ref` so the subscription can be composed with a `TopicBuilder` (or any other component) without post-build wiring:
182
+
183
+ ```ts
184
+ import { compose, ref } from "@composurecdk/core";
185
+ import { createTopicBuilder, createSubscriptionBuilder } from "@composurecdk/sns";
186
+ import { SubscriptionProtocol } from "aws-cdk-lib/aws-sns";
187
+
188
+ const system = compose(
189
+ {
190
+ budget: createTopicBuilder().topicName("budget-alerts"),
191
+ email: createSubscriptionBuilder()
192
+ .topic(ref("budget", (r) => r.topic))
193
+ .protocol(SubscriptionProtocol.EMAIL)
194
+ .endpoint("ops@example.com"),
195
+ },
196
+ { budget: [], email: ["budget"] },
197
+ );
198
+ ```
199
+
200
+ ### Subscription reliability
201
+
202
+ Attaching a dead-letter queue is the primary reliability control for SNS subscriptions ([AWS Well-Architected — Reliability Pillar](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/welcome.html), [SNS DLQ docs](https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html)). Pass a queue via `.deadLetterQueue(queue)` or a `ref` to one; the builder does not create a DLQ automatically because the queue resource needs to be caller-owned.
203
+
204
+ The CloudWatch metrics that surface delivery failures (`NumberOfNotificationsRedrivenToDlq`, `NumberOfNotificationsFailedToRedriveToDlq`) are topic-level, so the recommended alarms for them live on the `TopicBuilder` (see [Recommended Alarms](#recommended-alarms) above) and only report data once at least one subscription has a DLQ attached.
205
+
206
+ Also note: `SubscriptionProtocol.HTTP` is allowed for compatibility; prefer `HTTPS` for transport encryption ([SNS security best practices](https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html)).
207
+
125
208
  ## Examples
126
209
 
127
210
  - [LambdaApiStack](../examples/src/lambda-api-app.ts) — REST API with TopicBuilder for alarm actions
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { createTopicBuilder, type TopicBuilderResult, type ITopicBuilder, } from "./topic-builder.js";
2
2
  export { TOPIC_DEFAULTS } from "./defaults.js";
3
- export { type TopicAlarmConfig } from "./alarm-config.js";
4
- export { TOPIC_ALARM_DEFAULTS } from "./alarm-defaults.js";
3
+ export { type TopicAlarmConfig } from "./topic-alarm-config.js";
4
+ export { TOPIC_ALARM_DEFAULTS } from "./topic-alarm-defaults.js";
5
+ export { createSubscriptionBuilder, type ISubscriptionBuilder, type SubscriptionBuilderResult, } from "./subscription-builder.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,yBAAyB,EACzB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,GAC/B,MAAM,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { createTopicBuilder, } from "./topic-builder.js";
2
2
  export { TOPIC_DEFAULTS } from "./defaults.js";
3
- export { TOPIC_ALARM_DEFAULTS } from "./alarm-defaults.js";
3
+ export { TOPIC_ALARM_DEFAULTS } from "./topic-alarm-defaults.js";
4
+ export { createSubscriptionBuilder, } from "./subscription-builder.js";
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAGnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAGnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,yBAAyB,GAG1B,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,100 @@
1
+ import { type ITopic, Subscription, type SubscriptionProps } from "aws-cdk-lib/aws-sns";
2
+ import type { IQueue } from "aws-cdk-lib/aws-sqs";
3
+ import { type IConstruct } from "constructs";
4
+ import { type IBuilder, type Lifecycle, type Resolvable } from "@composurecdk/core";
5
+ /**
6
+ * Configuration properties for the SNS subscription builder.
7
+ *
8
+ * Extends the CDK {@link SubscriptionProps} but accepts {@link Resolvable}
9
+ * values for `topic` and `deadLetterQueue` so the builder can be wired to
10
+ * other components via {@link ref} inside a {@link compose}d system.
11
+ */
12
+ interface SubscriptionBuilderProps extends Omit<SubscriptionProps, "topic" | "deadLetterQueue"> {
13
+ /**
14
+ * The topic to subscribe to. Accepts a concrete {@link ITopic} or a
15
+ * {@link Ref} to another component's output (e.g. a `TopicBuilder`).
16
+ */
17
+ topic: Resolvable<ITopic>;
18
+ /**
19
+ * Dead-letter queue for messages that cannot be delivered to the
20
+ * subscribed endpoint. Accepts a concrete {@link IQueue} or a
21
+ * {@link Ref} to another component's output.
22
+ *
23
+ * Attaching a DLQ is the primary reliability control for SNS
24
+ * subscriptions. Redrive and redrive-failure alarms are created on the
25
+ * subscribed {@link TopicBuilder} since the underlying metrics are
26
+ * topic-level.
27
+ *
28
+ * @see https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html
29
+ * @default - no dead letter queue
30
+ */
31
+ deadLetterQueue?: Resolvable<IQueue>;
32
+ }
33
+ /**
34
+ * The build output of an {@link ISubscriptionBuilder}. Contains the CDK
35
+ * constructs created during {@link Lifecycle.build}, keyed by role.
36
+ */
37
+ export interface SubscriptionBuilderResult {
38
+ /** The SNS subscription construct created by the builder. */
39
+ subscription: Subscription;
40
+ }
41
+ /**
42
+ * A fluent builder for configuring and creating an AWS SNS subscription.
43
+ *
44
+ * Each configuration property from the CDK {@link SubscriptionProps} is
45
+ * exposed as an overloaded method: call with a value to set it (returns the
46
+ * builder for chaining), or call with no arguments to read the current
47
+ * value.
48
+ *
49
+ * The builder implements {@link Lifecycle}, so it can be used directly as a
50
+ * component in a {@link compose | composed system}. Its `topic` and
51
+ * `deadLetterQueue` properties accept {@link Resolvable} values so they can
52
+ * be supplied by another component's build output via {@link ref}.
53
+ *
54
+ * Recommended CloudWatch alarms related to subscription delivery (redrive
55
+ * to DLQ, failed redrive to DLQ) are emitted against topic-level metrics,
56
+ * so they live on {@link createTopicBuilder} rather than here.
57
+ *
58
+ * @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sns.Subscription.html
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * const emailAlerts = createSubscriptionBuilder()
63
+ * .topic(ref("topic", (r: TopicBuilderResult) => r.topic))
64
+ * .protocol(SubscriptionProtocol.EMAIL)
65
+ * .endpoint("ops@example.com");
66
+ * ```
67
+ */
68
+ export type ISubscriptionBuilder = IBuilder<SubscriptionBuilderProps, SubscriptionBuilder>;
69
+ declare class SubscriptionBuilder implements Lifecycle<SubscriptionBuilderResult> {
70
+ props: Partial<SubscriptionBuilderProps>;
71
+ build(scope: IConstruct, id: string, context?: Record<string, object>): SubscriptionBuilderResult;
72
+ }
73
+ /**
74
+ * Creates a new {@link ISubscriptionBuilder} for configuring an AWS SNS
75
+ * subscription.
76
+ *
77
+ * This is the entry point for defining an SNS subscription component. The
78
+ * returned builder exposes every {@link SubscriptionProps} property as a
79
+ * fluent setter/getter and implements {@link Lifecycle} for use with
80
+ * {@link compose}.
81
+ *
82
+ * @returns A fluent builder for an AWS SNS subscription.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const system = compose(
87
+ * {
88
+ * topic: createTopicBuilder().topicName("budget-alerts"),
89
+ * email: createSubscriptionBuilder()
90
+ * .topic(ref("topic", (r: TopicBuilderResult) => r.topic))
91
+ * .protocol(SubscriptionProtocol.EMAIL)
92
+ * .endpoint("ops@example.com"),
93
+ * },
94
+ * { topic: [], email: ["topic"] },
95
+ * );
96
+ * ```
97
+ */
98
+ export declare function createSubscriptionBuilder(): ISubscriptionBuilder;
99
+ export {};
100
+ //# sourceMappingURL=subscription-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-builder.d.ts","sourceRoot":"","sources":["../src/subscription-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;GAMG;AACH,UAAU,wBAAyB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,iBAAiB,CAAC;IAC7F;;;OAGG;IACH,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAE1B;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,6DAA6D;IAC7D,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,CAAC;AAE3F,cAAM,mBAAoB,YAAW,SAAS,CAAC,yBAAyB,CAAC;IACvE,KAAK,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAM;IAE9C,KAAK,CACH,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACnC,yBAAyB;CAmC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,yBAAyB,IAAI,oBAAoB,CAEhE"}
@@ -0,0 +1,57 @@
1
+ import { Subscription } from "aws-cdk-lib/aws-sns";
2
+ import { Builder, resolve, } from "@composurecdk/core";
3
+ class SubscriptionBuilder {
4
+ props = {};
5
+ build(scope, id, context = {}) {
6
+ const { topic, deadLetterQueue, protocol, endpoint, ...rest } = this.props;
7
+ if (topic === undefined) {
8
+ throw new Error(`SubscriptionBuilder "${id}": topic is required. Call .topic(...) with an ITopic or a Ref before building.`);
9
+ }
10
+ if (protocol === undefined) {
11
+ throw new Error(`SubscriptionBuilder "${id}": protocol is required. Call .protocol(...) with a SubscriptionProtocol before building.`);
12
+ }
13
+ if (endpoint === undefined) {
14
+ throw new Error(`SubscriptionBuilder "${id}": endpoint is required. Call .endpoint(...) with the subscriber endpoint before building.`);
15
+ }
16
+ const resolvedTopic = resolve(topic, context);
17
+ const resolvedDlq = deadLetterQueue !== undefined ? resolve(deadLetterQueue, context) : undefined;
18
+ const subscriptionProps = {
19
+ ...rest,
20
+ protocol,
21
+ endpoint,
22
+ topic: resolvedTopic,
23
+ ...(resolvedDlq !== undefined ? { deadLetterQueue: resolvedDlq } : {}),
24
+ };
25
+ const subscription = new Subscription(scope, id, subscriptionProps);
26
+ return { subscription };
27
+ }
28
+ }
29
+ /**
30
+ * Creates a new {@link ISubscriptionBuilder} for configuring an AWS SNS
31
+ * subscription.
32
+ *
33
+ * This is the entry point for defining an SNS subscription component. The
34
+ * returned builder exposes every {@link SubscriptionProps} property as a
35
+ * fluent setter/getter and implements {@link Lifecycle} for use with
36
+ * {@link compose}.
37
+ *
38
+ * @returns A fluent builder for an AWS SNS subscription.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const system = compose(
43
+ * {
44
+ * topic: createTopicBuilder().topicName("budget-alerts"),
45
+ * email: createSubscriptionBuilder()
46
+ * .topic(ref("topic", (r: TopicBuilderResult) => r.topic))
47
+ * .protocol(SubscriptionProtocol.EMAIL)
48
+ * .endpoint("ops@example.com"),
49
+ * },
50
+ * { topic: [], email: ["topic"] },
51
+ * );
52
+ * ```
53
+ */
54
+ export function createSubscriptionBuilder() {
55
+ return Builder(SubscriptionBuilder);
56
+ }
57
+ //# sourceMappingURL=subscription-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-builder.js","sourceRoot":"","sources":["../src/subscription-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAA0B,MAAM,qBAAqB,CAAC;AAGxF,OAAO,EACL,OAAO,EAIP,OAAO,GACR,MAAM,oBAAoB,CAAC;AAsE5B,MAAM,mBAAmB;IACvB,KAAK,GAAsC,EAAE,CAAC;IAE9C,KAAK,CACH,KAAiB,EACjB,EAAU,EACV,UAAkC,EAAE;QAEpC,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAE3E,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,wBAAwB,EAAE,iFAAiF,CAC5G,CAAC;QACJ,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CACb,wBAAwB,EAAE,2FAA2F,CACtH,CAAC;QACJ,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CACb,wBAAwB,EAAE,4FAA4F,CACvH,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,WAAW,GACf,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEhF,MAAM,iBAAiB,GAAsB;YAC3C,GAAG,IAAI;YACP,QAAQ;YACR,QAAQ;YACR,KAAK,EAAE,aAAa;YACpB,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvE,CAAC;QAEF,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAEpE,OAAO,EAAE,YAAY,EAAE,CAAC;IAC1B,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO,OAAO,CAAgD,mBAAmB,CAAC,CAAC;AACrF,CAAC"}
@@ -34,5 +34,34 @@ export interface TopicAlarmConfig {
34
34
  * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#SNS
35
35
  */
36
36
  numberOfNotificationsFilteredOutInvalidAttributes?: AlarmConfig | false;
37
+ /**
38
+ * Alarm when messages are moved to a subscription's dead-letter queue
39
+ * because SNS could not deliver them to the subscribed endpoint.
40
+ *
41
+ * This metric is topic-level even though DLQs are attached per subscription,
42
+ * so the recommended alarm lives on the topic. It only emits data when at
43
+ * least one subscription on the topic has a DLQ attached and SNS attempts
44
+ * redrive; {@link TreatMissingData.NOT_BREACHING} keeps it quiet otherwise.
45
+ *
46
+ * Metric: `AWS/SNS NumberOfNotificationsRedrivenToDlq`, statistic Sum,
47
+ * period 1 minute, dimension `TopicName`.
48
+ * Default threshold: > 0 redrives.
49
+ *
50
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#SNS
51
+ * @see https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html
52
+ */
53
+ numberOfNotificationsRedrivenToDlq?: AlarmConfig | false;
54
+ /**
55
+ * Alarm when messages could not even be moved to a dead-letter queue.
56
+ * Indicates a misconfiguration (e.g. missing SNS permission on the DLQ)
57
+ * that results in message loss.
58
+ *
59
+ * Metric: `AWS/SNS NumberOfNotificationsFailedToRedriveToDlq`, statistic Sum,
60
+ * period 1 minute, dimension `TopicName`.
61
+ * Default threshold: > 0 failed redrives.
62
+ *
63
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#SNS
64
+ */
65
+ numberOfNotificationsFailedToRedriveToDlq?: AlarmConfig | false;
37
66
  }
38
- //# sourceMappingURL=alarm-config.d.ts.map
67
+ //# sourceMappingURL=topic-alarm-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-alarm-config.d.ts","sourceRoot":"","sources":["../src/topic-alarm-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;OAOG;IACH,2BAA2B,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAElD;;;;;;;;;OASG;IACH,iDAAiD,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAExE;;;;;;;;;;;;;;;OAeG;IACH,kCAAkC,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAEzD;;;;;;;;;;OAUG;IACH,yCAAyC,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;CACjE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=topic-alarm-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-alarm-config.js","sourceRoot":"","sources":["../src/topic-alarm-config.ts"],"names":[],"mappings":""}
@@ -3,6 +3,8 @@ interface TopicAlarmDefaults {
3
3
  enabled: true;
4
4
  numberOfNotificationsFailed: Required<AlarmConfig>;
5
5
  numberOfNotificationsFilteredOutInvalidAttributes: Required<AlarmConfig>;
6
+ numberOfNotificationsRedrivenToDlq: Required<AlarmConfig>;
7
+ numberOfNotificationsFailedToRedriveToDlq: Required<AlarmConfig>;
6
8
  }
7
9
  /**
8
10
  * AWS-recommended default alarm configuration for SNS topics.
@@ -11,4 +13,4 @@ interface TopicAlarmDefaults {
11
13
  */
12
14
  export declare const TOPIC_ALARM_DEFAULTS: TopicAlarmDefaults;
13
15
  export {};
14
- //# sourceMappingURL=alarm-defaults.d.ts.map
16
+ //# sourceMappingURL=topic-alarm-defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-alarm-defaults.d.ts","sourceRoot":"","sources":["../src/topic-alarm-defaults.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,UAAU,kBAAkB;IAC1B,OAAO,EAAE,IAAI,CAAC;IACd,2BAA2B,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IACnD,iDAAiD,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IACzE,kCAAkC,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC1D,yCAAyC,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;CAClE;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,kBAkClC,CAAC"}
@@ -20,5 +20,19 @@ export const TOPIC_ALARM_DEFAULTS = {
20
20
  datapointsToAlarm: 1,
21
21
  treatMissingData: TreatMissingData.NOT_BREACHING,
22
22
  },
23
+ /** Any redrive to a subscription DLQ indicates a delivery failure worth investigating; threshold 0. */
24
+ numberOfNotificationsRedrivenToDlq: {
25
+ threshold: 0,
26
+ evaluationPeriods: 1,
27
+ datapointsToAlarm: 1,
28
+ treatMissingData: TreatMissingData.NOT_BREACHING,
29
+ },
30
+ /** Any failure to redrive to a DLQ means message loss; threshold 0. */
31
+ numberOfNotificationsFailedToRedriveToDlq: {
32
+ threshold: 0,
33
+ evaluationPeriods: 1,
34
+ datapointsToAlarm: 1,
35
+ treatMissingData: TreatMissingData.NOT_BREACHING,
36
+ },
23
37
  };
24
- //# sourceMappingURL=alarm-defaults.js.map
38
+ //# sourceMappingURL=topic-alarm-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-alarm-defaults.js","sourceRoot":"","sources":["../src/topic-alarm-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAW9D;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAuB;IACtD,OAAO,EAAE,IAAI;IAEb,gEAAgE;IAChE,2BAA2B,EAAE;QAC3B,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;IAED,mGAAmG;IACnG,iDAAiD,EAAE;QACjD,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;IAED,uGAAuG;IACvG,kCAAkC,EAAE;QAClC,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;IAED,uEAAuE;IACvE,yCAAyC,EAAE;QACzC,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;CACF,CAAC"}
@@ -3,7 +3,7 @@ import type { ITopic } from "aws-cdk-lib/aws-sns";
3
3
  import type { IConstruct } from "constructs";
4
4
  import type { AlarmDefinition } from "@composurecdk/cloudwatch";
5
5
  import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
6
- import type { TopicAlarmConfig } from "./alarm-config.js";
6
+ import type { TopicAlarmConfig } from "./topic-alarm-config.js";
7
7
  /**
8
8
  * Resolves the recommended alarm configuration into fully-resolved
9
9
  * {@link AlarmDefinition}s for an SNS topic.
@@ -1 +1 @@
1
- {"version":3,"file":"topic-alarms.d.ts","sourceRoot":"","sources":["../src/topic-alarms.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,KAAK,EAAsB,MAAM,4BAA4B,CAAC;AAC5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAoC,MAAM,0BAA0B,CAAC;AACpG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAM1D;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,gBAAgB,GAAG,SAAS,GACnC,eAAe,EAAE,CA0CnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,gBAAgB,GAAG,KAAK,GAAG,SAAS,EAC5C,YAAY,GAAE,sBAAsB,CAAC,MAAM,CAAC,EAAO,GAClD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAUvB"}
1
+ {"version":3,"file":"topic-alarms.d.ts","sourceRoot":"","sources":["../src/topic-alarms.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,KAAK,EAAsB,MAAM,4BAA4B,CAAC;AAC5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAoC,MAAM,0BAA0B,CAAC;AACpG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAMhE;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,gBAAgB,GAAG,SAAS,GACnC,eAAe,EAAE,CAkFnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,gBAAgB,GAAG,KAAK,GAAG,SAAS,EAC5C,YAAY,GAAE,sBAAsB,CAAC,MAAM,CAAC,EAAO,GAClD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAUvB"}
@@ -1,7 +1,7 @@
1
1
  import { Duration } from "aws-cdk-lib";
2
2
  import { ComparisonOperator } from "aws-cdk-lib/aws-cloudwatch";
3
3
  import { createAlarms, resolveAlarmConfig } from "@composurecdk/cloudwatch";
4
- import { TOPIC_ALARM_DEFAULTS } from "./alarm-defaults.js";
4
+ import { TOPIC_ALARM_DEFAULTS } from "./topic-alarm-defaults.js";
5
5
  const METRIC_PERIOD = Duration.minutes(1);
6
6
  const METRIC_PERIOD_LABEL = `${String(METRIC_PERIOD.toMinutes())} minute`;
7
7
  /**
@@ -40,6 +40,38 @@ export function resolveTopicAlarmDefinitions(topic, config) {
40
40
  description: `SNS topic messages are being filtered out due to invalid subscription filter policy attributes. Threshold: > ${String(cfg.threshold)} filtered messages in ${METRIC_PERIOD_LABEL}.`,
41
41
  });
42
42
  }
43
+ if (config?.numberOfNotificationsRedrivenToDlq !== false) {
44
+ const cfg = resolveAlarmConfig(config?.numberOfNotificationsRedrivenToDlq, TOPIC_ALARM_DEFAULTS.numberOfNotificationsRedrivenToDlq);
45
+ definitions.push({
46
+ key: "numberOfNotificationsRedrivenToDlq",
47
+ metric: topic.metric("NumberOfNotificationsRedrivenToDlq", {
48
+ period: METRIC_PERIOD,
49
+ statistic: "Sum",
50
+ }),
51
+ threshold: cfg.threshold,
52
+ comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
53
+ evaluationPeriods: cfg.evaluationPeriods,
54
+ datapointsToAlarm: cfg.datapointsToAlarm,
55
+ treatMissingData: cfg.treatMissingData,
56
+ description: `SNS topic is redriving messages to a subscription dead-letter queue, indicating delivery failures. Threshold: > ${String(cfg.threshold)} redrives in ${METRIC_PERIOD_LABEL}.`,
57
+ });
58
+ }
59
+ if (config?.numberOfNotificationsFailedToRedriveToDlq !== false) {
60
+ const cfg = resolveAlarmConfig(config?.numberOfNotificationsFailedToRedriveToDlq, TOPIC_ALARM_DEFAULTS.numberOfNotificationsFailedToRedriveToDlq);
61
+ definitions.push({
62
+ key: "numberOfNotificationsFailedToRedriveToDlq",
63
+ metric: topic.metric("NumberOfNotificationsFailedToRedriveToDlq", {
64
+ period: METRIC_PERIOD,
65
+ statistic: "Sum",
66
+ }),
67
+ threshold: cfg.threshold,
68
+ comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
69
+ evaluationPeriods: cfg.evaluationPeriods,
70
+ datapointsToAlarm: cfg.datapointsToAlarm,
71
+ treatMissingData: cfg.treatMissingData,
72
+ description: `SNS topic failed to redrive a message to a subscription dead-letter queue; messages may be lost. Threshold: > ${String(cfg.threshold)} failed redrives in ${METRIC_PERIOD_LABEL}.`,
73
+ });
74
+ }
43
75
  return definitions;
44
76
  }
45
77
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"topic-alarms.js","sourceRoot":"","sources":["../src/topic-alarms.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"topic-alarms.js","sourceRoot":"","sources":["../src/topic-alarms.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { type Alarm } from "aws-cdk-lib/aws-cloudwatch";
2
- import { type ITopic, Topic, type TopicProps } from "aws-cdk-lib/aws-sns";
2
+ import { type ITopic, type ITopicSubscription, Subscription, Topic, type TopicProps } from "aws-cdk-lib/aws-sns";
3
3
  import { type IConstruct } from "constructs";
4
- import { type IBuilder, type Lifecycle } from "@composurecdk/core";
4
+ import { type IBuilder, type Lifecycle, type Resolvable } from "@composurecdk/core";
5
5
  import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
6
- import type { TopicAlarmConfig } from "./alarm-config.js";
6
+ import type { TopicAlarmConfig } from "./topic-alarm-config.js";
7
7
  /**
8
8
  * Configuration properties for the SNS topic builder.
9
9
  *
@@ -45,6 +45,14 @@ export interface TopicBuilderResult {
45
45
  * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#SNS
46
46
  */
47
47
  alarms: Record<string, Alarm>;
48
+ /**
49
+ * Subscriptions added to the topic via
50
+ * {@link ITopicBuilder.addSubscription}, keyed by the name supplied to
51
+ * that call.
52
+ *
53
+ * Always present — `{}` when no subscriptions were added.
54
+ */
55
+ subscriptions: Record<string, Subscription>;
48
56
  }
49
57
  /**
50
58
  * A fluent builder for configuring and creating an AWS SNS topic.
@@ -75,8 +83,26 @@ export type ITopicBuilder = IBuilder<TopicBuilderProps, TopicBuilder>;
75
83
  declare class TopicBuilder implements Lifecycle<TopicBuilderResult> {
76
84
  props: Partial<TopicBuilderProps>;
77
85
  private readonly customAlarms;
86
+ private readonly _subscriptions;
78
87
  addAlarm(key: string, configure: (alarm: AlarmDefinitionBuilder<ITopic>) => AlarmDefinitionBuilder<ITopic>): this;
79
- build(scope: IConstruct, id: string): TopicBuilderResult;
88
+ /**
89
+ * Register a subscription to be attached to the topic at build time.
90
+ *
91
+ * Accepts any {@link ITopicSubscription} (e.g. `EmailSubscription`,
92
+ * `LambdaSubscription`, `SqsSubscription`) or a {@link Resolvable} so
93
+ * subscriptions wiring cross-component references (such as a Lambda
94
+ * function built by a sibling component) can be declared at configuration
95
+ * time.
96
+ *
97
+ * The subscription is bound via `ITopicSubscription.bind(topic)`, which
98
+ * performs the IAM/resource-policy wire-up required by the endpoint (for
99
+ * example, `LambdaSubscription.bind` grants the topic permission to
100
+ * invoke the function; `SqsSubscription.bind` adds the matching SQS queue
101
+ * policy). The resulting {@link Subscription} construct is exposed on
102
+ * {@link TopicBuilderResult.subscriptions} under `key`.
103
+ */
104
+ addSubscription(key: string, subscription: Resolvable<ITopicSubscription>): this;
105
+ build(scope: IConstruct, id: string, context?: Record<string, object>): TopicBuilderResult;
80
106
  }
81
107
  /**
82
108
  * Creates a new {@link ITopicBuilder} for configuring an AWS SNS topic.
@@ -1 +1 @@
1
- {"version":3,"file":"topic-builder.d.ts","sourceRoot":"","sources":["../src/topic-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAW,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAI1D;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,KAAK,EAAE,KAAK,CAAC;IAEb;;;;;;;;;;;OAWG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;AAEtE,cAAM,YAAa,YAAW,SAAS,CAAC,kBAAkB,CAAC;IACzD,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAM;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAwC;IAErE,QAAQ,CACN,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,KAAK,sBAAsB,CAAC,MAAM,CAAC,GACnF,IAAI;IAKP,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,kBAAkB;CAczD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAElD"}
1
+ {"version":3,"file":"topic-builder.d.ts","sourceRoot":"","sources":["../src/topic-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EACL,KAAK,MAAM,EACX,KAAK,kBAAkB,EACvB,YAAY,EACZ,KAAK,EACL,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAIhE;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,KAAK,EAAE,KAAK,CAAC;IAEb;;;;;;;;;;;OAWG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAE9B;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;AAOtE,cAAM,YAAa,YAAW,SAAS,CAAC,kBAAkB,CAAC;IACzD,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAM;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAwC;IACrE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA2B;IAE1D,QAAQ,CACN,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,KAAK,sBAAsB,CAAC,MAAM,CAAC,GACnF,IAAI;IAKP;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,CAAC,kBAAkB,CAAC,GAAG,IAAI;IAWhF,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,kBAAkB;CAyB3F;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAElD"}
@@ -1,16 +1,41 @@
1
- import { Topic } from "aws-cdk-lib/aws-sns";
2
- import { Builder } from "@composurecdk/core";
1
+ import { Subscription, Topic, } from "aws-cdk-lib/aws-sns";
2
+ import { Builder, resolve, } from "@composurecdk/core";
3
3
  import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
4
4
  import { createTopicAlarms } from "./topic-alarms.js";
5
5
  import { TOPIC_DEFAULTS } from "./defaults.js";
6
6
  class TopicBuilder {
7
7
  props = {};
8
8
  customAlarms = [];
9
+ _subscriptions = [];
9
10
  addAlarm(key, configure) {
10
11
  this.customAlarms.push(configure(new AlarmDefinitionBuilder(key)));
11
12
  return this;
12
13
  }
13
- build(scope, id) {
14
+ /**
15
+ * Register a subscription to be attached to the topic at build time.
16
+ *
17
+ * Accepts any {@link ITopicSubscription} (e.g. `EmailSubscription`,
18
+ * `LambdaSubscription`, `SqsSubscription`) or a {@link Resolvable} so
19
+ * subscriptions wiring cross-component references (such as a Lambda
20
+ * function built by a sibling component) can be declared at configuration
21
+ * time.
22
+ *
23
+ * The subscription is bound via `ITopicSubscription.bind(topic)`, which
24
+ * performs the IAM/resource-policy wire-up required by the endpoint (for
25
+ * example, `LambdaSubscription.bind` grants the topic permission to
26
+ * invoke the function; `SqsSubscription.bind` adds the matching SQS queue
27
+ * policy). The resulting {@link Subscription} construct is exposed on
28
+ * {@link TopicBuilderResult.subscriptions} under `key`.
29
+ */
30
+ addSubscription(key, subscription) {
31
+ if (this._subscriptions.some((s) => s.key === key)) {
32
+ throw new Error(`TopicBuilder.addSubscription: duplicate key "${key}". ` +
33
+ `Each subscription must use a unique key.`);
34
+ }
35
+ this._subscriptions.push({ key, subscription });
36
+ return this;
37
+ }
38
+ build(scope, id, context) {
14
39
  const { recommendedAlarms: alarmConfig, ...topicProps } = this.props;
15
40
  const mergedProps = {
16
41
  ...TOPIC_DEFAULTS,
@@ -18,7 +43,17 @@ class TopicBuilder {
18
43
  };
19
44
  const topic = new Topic(scope, id, mergedProps);
20
45
  const alarms = createTopicAlarms(scope, id, topic, alarmConfig, this.customAlarms);
21
- return { topic, alarms };
46
+ const subscriptions = {};
47
+ for (const entry of this._subscriptions) {
48
+ const resolvedSub = resolve(entry.subscription, context ?? {});
49
+ const subscriptionConfig = resolvedSub.bind(topic);
50
+ const subscriptionId = `${id}${entry.key[0].toUpperCase()}${entry.key.slice(1)}Subscription`;
51
+ subscriptions[entry.key] = new Subscription(scope, subscriptionId, {
52
+ topic,
53
+ ...subscriptionConfig,
54
+ });
55
+ }
56
+ return { topic, alarms, subscriptions };
22
57
  }
23
58
  }
24
59
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"topic-builder.js","sourceRoot":"","sources":["../src/topic-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAE1E,OAAO,EAAE,OAAO,EAAiC,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AA0E/C,MAAM,YAAY;IAChB,KAAK,GAA+B,EAAE,CAAC;IACtB,YAAY,GAAqC,EAAE,CAAC;IAErE,QAAQ,CACN,GAAW,EACX,SAAoF;QAEpF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,sBAAsB,CAAS,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAiB,EAAE,EAAU;QACjC,MAAM,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAErE,MAAM,WAAW,GAAG;YAClB,GAAG,cAAc;YACjB,GAAG,UAAU;SACO,CAAC;QAEvB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAEnF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAkC,YAAY,CAAC,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"topic-builder.js","sourceRoot":"","sources":["../src/topic-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,YAAY,EACZ,KAAK,GAEN,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,OAAO,EAGP,OAAO,GAER,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAwF/C,MAAM,YAAY;IAChB,KAAK,GAA+B,EAAE,CAAC;IACtB,YAAY,GAAqC,EAAE,CAAC;IACpD,cAAc,GAAwB,EAAE,CAAC;IAE1D,QAAQ,CACN,GAAW,EACX,SAAoF;QAEpF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,sBAAsB,CAAS,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,GAAW,EAAE,YAA4C;QACvE,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CACb,gDAAgD,GAAG,KAAK;gBACtD,0CAA0C,CAC7C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAiB,EAAE,EAAU,EAAE,OAAgC;QACnE,MAAM,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAErE,MAAM,WAAW,GAAG;YAClB,GAAG,cAAc;YACjB,GAAG,UAAU;SACO,CAAC;QAEvB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAEnF,MAAM,aAAa,GAAiC,EAAE,CAAC;QACvD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxC,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;YAC/D,MAAM,kBAAkB,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnD,MAAM,cAAc,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC;YAC7F,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,YAAY,CAAC,KAAK,EAAE,cAAc,EAAE;gBACjE,KAAK;gBACL,GAAG,kBAAkB;aACtB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAC1C,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAkC,YAAY,CAAC,CAAC;AAChE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@composurecdk/sns",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Composable SNS topic builder with well-architected defaults",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,10 +41,10 @@
41
41
  "constructs": "^10.0.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@types/node": "^25.5.0",
45
- "aws-cdk-lib": "^2.245.0",
44
+ "@types/node": "^25.6.0",
45
+ "aws-cdk-lib": "^2.250.0",
46
46
  "constructs": "^10.6.0",
47
- "typescript": "^6.0.2",
48
- "vitest": "^4.1.2"
47
+ "typescript": "^6.0.3",
48
+ "vitest": "^4.1.4"
49
49
  }
50
50
  }
@@ -1 +0,0 @@
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;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;OAOG;IACH,2BAA2B,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAElD;;;;;;;;;OASG;IACH,iDAAiD,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;CACzE"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=alarm-config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"alarm-config.js","sourceRoot":"","sources":["../src/alarm-config.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"alarm-defaults.d.ts","sourceRoot":"","sources":["../src/alarm-defaults.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,UAAU,kBAAkB;IAC1B,OAAO,EAAE,IAAI,CAAC;IACd,2BAA2B,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IACnD,iDAAiD,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;CAC1E;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,kBAkBlC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"alarm-defaults.js","sourceRoot":"","sources":["../src/alarm-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAS9D;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAuB;IACtD,OAAO,EAAE,IAAI;IAEb,gEAAgE;IAChE,2BAA2B,EAAE;QAC3B,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;IAED,mGAAmG;IACnG,iDAAiD,EAAE;QACjD,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;CACF,CAAC"}