@composurecdk/sns 0.6.0 → 0.8.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 +57 -10
- package/dist/commonjs/defaults.d.ts.map +1 -0
- package/dist/commonjs/defaults.js +17 -0
- package/dist/commonjs/defaults.js.map +1 -0
- package/dist/{index.d.ts → commonjs/index.d.ts} +1 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/commonjs/index.js +14 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/{subscription-builder.d.ts → commonjs/subscription-builder.d.ts} +36 -32
- package/dist/commonjs/subscription-builder.d.ts.map +1 -0
- package/dist/commonjs/subscription-builder.js +57 -0
- package/dist/commonjs/subscription-builder.js.map +1 -0
- package/dist/commonjs/subscription-defaults.d.ts +60 -0
- package/dist/commonjs/subscription-defaults.d.ts.map +1 -0
- package/dist/commonjs/subscription-defaults.js +78 -0
- package/dist/commonjs/subscription-defaults.js.map +1 -0
- package/dist/commonjs/topic-alarm-config.d.ts.map +1 -0
- package/dist/commonjs/topic-alarm-config.js +3 -0
- package/dist/commonjs/topic-alarm-config.js.map +1 -0
- package/dist/commonjs/topic-alarm-defaults.d.ts.map +1 -0
- package/dist/commonjs/topic-alarm-defaults.js +41 -0
- package/dist/commonjs/topic-alarm-defaults.js.map +1 -0
- package/dist/commonjs/topic-alarms.d.ts.map +1 -0
- package/dist/commonjs/topic-alarms.js +108 -0
- package/dist/commonjs/topic-alarms.js.map +1 -0
- package/dist/{topic-builder.d.ts → commonjs/topic-builder.d.ts} +5 -2
- package/dist/commonjs/topic-builder.d.ts.map +1 -0
- package/dist/commonjs/topic-builder.js +97 -0
- package/dist/commonjs/topic-builder.js.map +1 -0
- package/dist/esm/defaults.d.ts +8 -0
- package/dist/esm/defaults.d.ts.map +1 -0
- package/dist/esm/defaults.js.map +1 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/{index.js → esm/index.js} +1 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/subscription-builder.d.ts +104 -0
- package/dist/esm/subscription-builder.d.ts.map +1 -0
- package/dist/esm/subscription-builder.js +54 -0
- package/dist/esm/subscription-builder.js.map +1 -0
- package/dist/esm/subscription-defaults.d.ts +60 -0
- package/dist/esm/subscription-defaults.d.ts.map +1 -0
- package/dist/esm/subscription-defaults.js +74 -0
- package/dist/esm/subscription-defaults.js.map +1 -0
- package/dist/esm/topic-alarm-config.d.ts +67 -0
- package/dist/esm/topic-alarm-config.d.ts.map +1 -0
- package/dist/esm/topic-alarm-config.js.map +1 -0
- package/dist/esm/topic-alarm-defaults.d.ts +16 -0
- package/dist/esm/topic-alarm-defaults.d.ts.map +1 -0
- package/dist/esm/topic-alarm-defaults.js.map +1 -0
- package/dist/esm/topic-alarms.d.ts +26 -0
- package/dist/esm/topic-alarms.d.ts.map +1 -0
- package/dist/esm/topic-alarms.js.map +1 -0
- package/dist/esm/topic-builder.d.ts +136 -0
- package/dist/esm/topic-builder.d.ts.map +1 -0
- package/dist/{topic-builder.js → esm/topic-builder.js} +10 -3
- package/dist/esm/topic-builder.js.map +1 -0
- package/package.json +35 -16
- package/dist/defaults.d.ts.map +0 -1
- package/dist/defaults.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/subscription-builder.d.ts.map +0 -1
- package/dist/subscription-builder.js +0 -57
- package/dist/subscription-builder.js.map +0 -1
- package/dist/topic-alarm-config.d.ts.map +0 -1
- package/dist/topic-alarm-config.js.map +0 -1
- package/dist/topic-alarm-defaults.d.ts.map +0 -1
- package/dist/topic-alarm-defaults.js.map +0 -1
- package/dist/topic-alarms.d.ts.map +0 -1
- package/dist/topic-alarms.js.map +0 -1
- package/dist/topic-builder.d.ts.map +0 -1
- package/dist/topic-builder.js.map +0 -1
- /package/dist/{defaults.d.ts → commonjs/defaults.d.ts} +0 -0
- /package/dist/{topic-alarm-config.d.ts → commonjs/topic-alarm-config.d.ts} +0 -0
- /package/dist/{topic-alarm-defaults.d.ts → commonjs/topic-alarm-defaults.d.ts} +0 -0
- /package/dist/{topic-alarms.d.ts → commonjs/topic-alarms.d.ts} +0 -0
- /package/dist/{defaults.js → esm/defaults.js} +0 -0
- /package/dist/{topic-alarm-config.js → esm/topic-alarm-config.js} +0 -0
- /package/dist/{topic-alarm-defaults.js → esm/topic-alarm-defaults.js} +0 -0
- /package/dist/{topic-alarms.js → esm/topic-alarms.js} +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveTopicAlarmDefinitions = resolveTopicAlarmDefinitions;
|
|
4
|
+
exports.createTopicAlarms = createTopicAlarms;
|
|
5
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
|
+
const aws_cloudwatch_1 = require("aws-cdk-lib/aws-cloudwatch");
|
|
7
|
+
const cloudwatch_1 = require("@composurecdk/cloudwatch");
|
|
8
|
+
const topic_alarm_defaults_js_1 = require("./topic-alarm-defaults.js");
|
|
9
|
+
const METRIC_PERIOD = aws_cdk_lib_1.Duration.minutes(1);
|
|
10
|
+
const METRIC_PERIOD_LABEL = `${String(METRIC_PERIOD.toMinutes())} minute`;
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the recommended alarm configuration into fully-resolved
|
|
13
|
+
* {@link AlarmDefinition}s for an SNS topic.
|
|
14
|
+
*/
|
|
15
|
+
function resolveTopicAlarmDefinitions(topic, config) {
|
|
16
|
+
if (config?.enabled === false)
|
|
17
|
+
return [];
|
|
18
|
+
const definitions = [];
|
|
19
|
+
if (config?.numberOfNotificationsFailed !== false) {
|
|
20
|
+
const cfg = (0, cloudwatch_1.resolveAlarmConfig)(config?.numberOfNotificationsFailed, topic_alarm_defaults_js_1.TOPIC_ALARM_DEFAULTS.numberOfNotificationsFailed);
|
|
21
|
+
definitions.push({
|
|
22
|
+
key: "numberOfNotificationsFailed",
|
|
23
|
+
alarmName: cfg.alarmName,
|
|
24
|
+
metric: topic.metricNumberOfNotificationsFailed({ period: METRIC_PERIOD }),
|
|
25
|
+
threshold: cfg.threshold,
|
|
26
|
+
comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_THRESHOLD,
|
|
27
|
+
evaluationPeriods: cfg.evaluationPeriods,
|
|
28
|
+
datapointsToAlarm: cfg.datapointsToAlarm,
|
|
29
|
+
treatMissingData: cfg.treatMissingData,
|
|
30
|
+
description: `SNS topic is failing to deliver notifications. Threshold: > ${String(cfg.threshold)} failures in ${METRIC_PERIOD_LABEL}.`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (config?.numberOfNotificationsFilteredOutInvalidAttributes !== false) {
|
|
34
|
+
const cfg = (0, cloudwatch_1.resolveAlarmConfig)(config?.numberOfNotificationsFilteredOutInvalidAttributes, topic_alarm_defaults_js_1.TOPIC_ALARM_DEFAULTS.numberOfNotificationsFilteredOutInvalidAttributes);
|
|
35
|
+
definitions.push({
|
|
36
|
+
key: "numberOfNotificationsFilteredOutInvalidAttributes",
|
|
37
|
+
alarmName: cfg.alarmName,
|
|
38
|
+
metric: topic.metricNumberOfNotificationsFilteredOutInvalidAttributes({
|
|
39
|
+
period: METRIC_PERIOD,
|
|
40
|
+
}),
|
|
41
|
+
threshold: cfg.threshold,
|
|
42
|
+
comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_THRESHOLD,
|
|
43
|
+
evaluationPeriods: cfg.evaluationPeriods,
|
|
44
|
+
datapointsToAlarm: cfg.datapointsToAlarm,
|
|
45
|
+
treatMissingData: cfg.treatMissingData,
|
|
46
|
+
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}.`,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (config?.numberOfNotificationsRedrivenToDlq !== false) {
|
|
50
|
+
const cfg = (0, cloudwatch_1.resolveAlarmConfig)(config?.numberOfNotificationsRedrivenToDlq, topic_alarm_defaults_js_1.TOPIC_ALARM_DEFAULTS.numberOfNotificationsRedrivenToDlq);
|
|
51
|
+
definitions.push({
|
|
52
|
+
key: "numberOfNotificationsRedrivenToDlq",
|
|
53
|
+
alarmName: cfg.alarmName,
|
|
54
|
+
metric: topic.metric("NumberOfNotificationsRedrivenToDlq", {
|
|
55
|
+
period: METRIC_PERIOD,
|
|
56
|
+
statistic: "Sum",
|
|
57
|
+
}),
|
|
58
|
+
threshold: cfg.threshold,
|
|
59
|
+
comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_THRESHOLD,
|
|
60
|
+
evaluationPeriods: cfg.evaluationPeriods,
|
|
61
|
+
datapointsToAlarm: cfg.datapointsToAlarm,
|
|
62
|
+
treatMissingData: cfg.treatMissingData,
|
|
63
|
+
description: `SNS topic is redriving messages to a subscription dead-letter queue, indicating delivery failures. Threshold: > ${String(cfg.threshold)} redrives in ${METRIC_PERIOD_LABEL}.`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (config?.numberOfNotificationsFailedToRedriveToDlq !== false) {
|
|
67
|
+
const cfg = (0, cloudwatch_1.resolveAlarmConfig)(config?.numberOfNotificationsFailedToRedriveToDlq, topic_alarm_defaults_js_1.TOPIC_ALARM_DEFAULTS.numberOfNotificationsFailedToRedriveToDlq);
|
|
68
|
+
definitions.push({
|
|
69
|
+
key: "numberOfNotificationsFailedToRedriveToDlq",
|
|
70
|
+
alarmName: cfg.alarmName,
|
|
71
|
+
metric: topic.metric("NumberOfNotificationsFailedToRedriveToDlq", {
|
|
72
|
+
period: METRIC_PERIOD,
|
|
73
|
+
statistic: "Sum",
|
|
74
|
+
}),
|
|
75
|
+
threshold: cfg.threshold,
|
|
76
|
+
comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_THRESHOLD,
|
|
77
|
+
evaluationPeriods: cfg.evaluationPeriods,
|
|
78
|
+
datapointsToAlarm: cfg.datapointsToAlarm,
|
|
79
|
+
treatMissingData: cfg.treatMissingData,
|
|
80
|
+
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}.`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return definitions;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Creates AWS-recommended CloudWatch alarms for an SNS topic,
|
|
87
|
+
* merging recommended definitions with any custom alarm builders.
|
|
88
|
+
*
|
|
89
|
+
* @param scope - CDK construct scope for creating alarm constructs.
|
|
90
|
+
* @param id - Base identifier for alarm construct ids.
|
|
91
|
+
* @param topic - The SNS topic to create alarms for.
|
|
92
|
+
* @param config - User-provided alarm configuration, or `false` to disable all.
|
|
93
|
+
* @param customAlarms - Custom alarm builders added via `addAlarm()`.
|
|
94
|
+
* @returns A record mapping alarm keys to their created Alarm constructs.
|
|
95
|
+
*
|
|
96
|
+
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#SNS
|
|
97
|
+
*/
|
|
98
|
+
function createTopicAlarms(scope, id, topic, config, customAlarms = []) {
|
|
99
|
+
if (config === false)
|
|
100
|
+
return {};
|
|
101
|
+
const enabled = config?.enabled ?? topic_alarm_defaults_js_1.TOPIC_ALARM_DEFAULTS.enabled;
|
|
102
|
+
if (!enabled)
|
|
103
|
+
return {};
|
|
104
|
+
const recommended = resolveTopicAlarmDefinitions(topic, config);
|
|
105
|
+
const custom = customAlarms.map((b) => b.resolve(topic));
|
|
106
|
+
return (0, cloudwatch_1.createAlarms)(scope, id, [...recommended, ...custom]);
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=topic-alarms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-alarms.js","sourceRoot":"","sources":["../../src/topic-alarms.ts"],"names":[],"mappings":";;AAgBA,oEAyFC;AAeD,8CAgBC;AAxID,6CAAuC;AACvC,+DAA4E;AAI5E,yDAAoG;AAEpG,uEAAiE;AAEjE,MAAM,aAAa,GAAG,sBAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC1C,MAAM,mBAAmB,GAAG,GAAG,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;AAE1E;;;GAGG;AACH,SAAgB,4BAA4B,CAC1C,KAAa,EACb,MAAoC;IAEpC,IAAI,MAAM,EAAE,OAAO,KAAK,KAAK;QAAE,OAAO,EAAE,CAAC;IAEzC,MAAM,WAAW,GAAsB,EAAE,CAAC;IAE1C,IAAI,MAAM,EAAE,2BAA2B,KAAK,KAAK,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,IAAA,+BAAkB,EAC5B,MAAM,EAAE,2BAA2B,EACnC,8CAAoB,CAAC,2BAA2B,CACjD,CAAC;QACF,WAAW,CAAC,IAAI,CAAC;YACf,GAAG,EAAE,6BAA6B;YAClC,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,KAAK,CAAC,iCAAiC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;YAC1E,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,kBAAkB,EAAE,mCAAkB,CAAC,sBAAsB;YAC7D,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;YACtC,WAAW,EAAE,+DAA+D,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,mBAAmB,GAAG;SACxI,CAAC,CAAC;IACL,CAAC;IAED,IAAI,MAAM,EAAE,iDAAiD,KAAK,KAAK,EAAE,CAAC;QACxE,MAAM,GAAG,GAAG,IAAA,+BAAkB,EAC5B,MAAM,EAAE,iDAAiD,EACzD,8CAAoB,CAAC,iDAAiD,CACvE,CAAC;QACF,WAAW,CAAC,IAAI,CAAC;YACf,GAAG,EAAE,mDAAmD;YACxD,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,KAAK,CAAC,uDAAuD,CAAC;gBACpE,MAAM,EAAE,aAAa;aACtB,CAAC;YACF,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,kBAAkB,EAAE,mCAAkB,CAAC,sBAAsB;YAC7D,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;YACtC,WAAW,EAAE,gHAAgH,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,yBAAyB,mBAAmB,GAAG;SAClM,CAAC,CAAC;IACL,CAAC;IAED,IAAI,MAAM,EAAE,kCAAkC,KAAK,KAAK,EAAE,CAAC;QACzD,MAAM,GAAG,GAAG,IAAA,+BAAkB,EAC5B,MAAM,EAAE,kCAAkC,EAC1C,8CAAoB,CAAC,kCAAkC,CACxD,CAAC;QACF,WAAW,CAAC,IAAI,CAAC;YACf,GAAG,EAAE,oCAAoC;YACzC,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,oCAAoC,EAAE;gBACzD,MAAM,EAAE,aAAa;gBACrB,SAAS,EAAE,KAAK;aACjB,CAAC;YACF,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,kBAAkB,EAAE,mCAAkB,CAAC,sBAAsB;YAC7D,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;YACtC,WAAW,EAAE,mHAAmH,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,mBAAmB,GAAG;SAC5L,CAAC,CAAC;IACL,CAAC;IAED,IAAI,MAAM,EAAE,yCAAyC,KAAK,KAAK,EAAE,CAAC;QAChE,MAAM,GAAG,GAAG,IAAA,+BAAkB,EAC5B,MAAM,EAAE,yCAAyC,EACjD,8CAAoB,CAAC,yCAAyC,CAC/D,CAAC;QACF,WAAW,CAAC,IAAI,CAAC;YACf,GAAG,EAAE,2CAA2C;YAChD,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,2CAA2C,EAAE;gBAChE,MAAM,EAAE,aAAa;gBACrB,SAAS,EAAE,KAAK;aACjB,CAAC;YACF,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,kBAAkB,EAAE,mCAAkB,CAAC,sBAAsB;YAC7D,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;YACtC,WAAW,EAAE,iHAAiH,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,uBAAuB,mBAAmB,GAAG;SACjM,CAAC,CAAC;IACL,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,iBAAiB,CAC/B,KAAiB,EACjB,EAAU,EACV,KAAa,EACb,MAA4C,EAC5C,eAAiD,EAAE;IAEnD,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,8CAAoB,CAAC,OAAO,CAAC;IAChE,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAExB,MAAM,WAAW,GAAG,4BAA4B,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAEzD,OAAO,IAAA,yBAAY,EAAC,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,WAAW,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type Alarm } from "aws-cdk-lib/aws-cloudwatch";
|
|
2
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 {
|
|
4
|
+
import { COPY_STATE, type Lifecycle, type Resolvable } from "@composurecdk/core";
|
|
5
|
+
import { type ITaggedBuilder } from "@composurecdk/cloudformation";
|
|
5
6
|
import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
|
|
6
7
|
import type { TopicAlarmConfig } from "./topic-alarm-config.js";
|
|
7
8
|
/**
|
|
@@ -79,7 +80,7 @@ export interface TopicBuilderResult {
|
|
|
79
80
|
* .displayName("My Alert Topic");
|
|
80
81
|
* ```
|
|
81
82
|
*/
|
|
82
|
-
export type ITopicBuilder =
|
|
83
|
+
export type ITopicBuilder = ITaggedBuilder<TopicBuilderProps, TopicBuilder>;
|
|
83
84
|
declare class TopicBuilder implements Lifecycle<TopicBuilderResult> {
|
|
84
85
|
#private;
|
|
85
86
|
props: Partial<TopicBuilderProps>;
|
|
@@ -101,6 +102,8 @@ declare class TopicBuilder implements Lifecycle<TopicBuilderResult> {
|
|
|
101
102
|
* {@link TopicBuilderResult.subscriptions} under `key`.
|
|
102
103
|
*/
|
|
103
104
|
addSubscription(key: string, subscription: Resolvable<ITopicSubscription>): this;
|
|
105
|
+
/** @internal — see ADR-0005. */
|
|
106
|
+
[COPY_STATE](target: TopicBuilder): void;
|
|
104
107
|
build(scope: IConstruct, id: string, context?: Record<string, object>): TopicBuilderResult;
|
|
105
108
|
}
|
|
106
109
|
/**
|
|
@@ -0,0 +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,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,EAAE,UAAU,EAAE,KAAK,SAAS,EAAW,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,KAAK,cAAc,EAAiB,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAKhE;;;;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,cAAc,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;AAO5E,cAAM,YAAa,YAAW,SAAS,CAAC,kBAAkB,CAAC;;IACzD,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAM;IAIvC,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,gCAAgC;IAChC,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAKxC,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,kBAAkB;CA6B3F;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAElD"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTopicBuilder = createTopicBuilder;
|
|
4
|
+
const aws_sns_1 = require("aws-cdk-lib/aws-sns");
|
|
5
|
+
const core_1 = require("@composurecdk/core");
|
|
6
|
+
const cloudformation_1 = require("@composurecdk/cloudformation");
|
|
7
|
+
const cloudwatch_1 = require("@composurecdk/cloudwatch");
|
|
8
|
+
const topic_alarms_js_1 = require("./topic-alarms.js");
|
|
9
|
+
const defaults_js_1 = require("./defaults.js");
|
|
10
|
+
const subscription_defaults_js_1 = require("./subscription-defaults.js");
|
|
11
|
+
class TopicBuilder {
|
|
12
|
+
props = {};
|
|
13
|
+
#customAlarms = [];
|
|
14
|
+
#subscriptions = [];
|
|
15
|
+
addAlarm(key, configure) {
|
|
16
|
+
this.#customAlarms.push(configure(new cloudwatch_1.AlarmDefinitionBuilder(key)));
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Register a subscription to be attached to the topic at build time.
|
|
21
|
+
*
|
|
22
|
+
* Accepts any {@link ITopicSubscription} (e.g. `EmailSubscription`,
|
|
23
|
+
* `LambdaSubscription`, `SqsSubscription`) or a {@link Resolvable} so
|
|
24
|
+
* subscriptions wiring cross-component references (such as a Lambda
|
|
25
|
+
* function built by a sibling component) can be declared at configuration
|
|
26
|
+
* time.
|
|
27
|
+
*
|
|
28
|
+
* The subscription is bound via `ITopicSubscription.bind(topic)`, which
|
|
29
|
+
* performs the IAM/resource-policy wire-up required by the endpoint (for
|
|
30
|
+
* example, `LambdaSubscription.bind` grants the topic permission to
|
|
31
|
+
* invoke the function; `SqsSubscription.bind` adds the matching SQS queue
|
|
32
|
+
* policy). The resulting {@link Subscription} construct is exposed on
|
|
33
|
+
* {@link TopicBuilderResult.subscriptions} under `key`.
|
|
34
|
+
*/
|
|
35
|
+
addSubscription(key, subscription) {
|
|
36
|
+
if (this.#subscriptions.some((s) => s.key === key)) {
|
|
37
|
+
throw new Error(`TopicBuilder.addSubscription: duplicate key "${key}". ` +
|
|
38
|
+
`Each subscription must use a unique key.`);
|
|
39
|
+
}
|
|
40
|
+
this.#subscriptions.push({ key, subscription });
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
/** @internal — see ADR-0005. */
|
|
44
|
+
[core_1.COPY_STATE](target) {
|
|
45
|
+
target.#customAlarms.push(...this.#customAlarms);
|
|
46
|
+
target.#subscriptions.push(...this.#subscriptions);
|
|
47
|
+
}
|
|
48
|
+
build(scope, id, context) {
|
|
49
|
+
const { recommendedAlarms: alarmConfig, ...topicProps } = this.props;
|
|
50
|
+
const mergedProps = {
|
|
51
|
+
...defaults_js_1.TOPIC_DEFAULTS,
|
|
52
|
+
...topicProps,
|
|
53
|
+
};
|
|
54
|
+
const topic = new aws_sns_1.Topic(scope, id, mergedProps);
|
|
55
|
+
const alarms = (0, topic_alarms_js_1.createTopicAlarms)(scope, id, topic, alarmConfig, this.#customAlarms);
|
|
56
|
+
const subscriptions = {};
|
|
57
|
+
for (const entry of this.#subscriptions) {
|
|
58
|
+
const resolvedSub = (0, core_1.resolve)(entry.subscription, context ?? {});
|
|
59
|
+
const subscriptionId = `${id}${entry.key[0].toUpperCase()}${entry.key.slice(1)}Subscription`;
|
|
60
|
+
const subscriptionConfig = (0, subscription_defaults_js_1.applySubscriptionDefaults)(scope, subscriptionId, resolvedSub.bind(topic));
|
|
61
|
+
subscriptions[entry.key] = new aws_sns_1.Subscription(scope, subscriptionId, {
|
|
62
|
+
topic,
|
|
63
|
+
...subscriptionConfig,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return { topic, alarms, subscriptions };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Creates a new {@link ITopicBuilder} for configuring an AWS SNS topic.
|
|
71
|
+
*
|
|
72
|
+
* This is the entry point for defining an SNS topic component. The returned
|
|
73
|
+
* builder exposes every {@link TopicBuilderProps} property as a fluent setter/getter
|
|
74
|
+
* and implements {@link Lifecycle} for use with {@link compose}.
|
|
75
|
+
*
|
|
76
|
+
* @returns A fluent builder for an AWS SNS topic.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* const alerts = createTopicBuilder()
|
|
81
|
+
* .topicName("my-alerts")
|
|
82
|
+
* .displayName("My Alert Topic");
|
|
83
|
+
*
|
|
84
|
+
* // Use standalone:
|
|
85
|
+
* const result = alerts.build(stack, "AlertTopic");
|
|
86
|
+
*
|
|
87
|
+
* // Or compose into a system:
|
|
88
|
+
* const system = compose(
|
|
89
|
+
* { alerts, handler: createFunctionBuilder() },
|
|
90
|
+
* { alerts: [], handler: [] },
|
|
91
|
+
* );
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
function createTopicBuilder() {
|
|
95
|
+
return (0, cloudformation_1.taggedBuilder)(TopicBuilder);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=topic-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-builder.js","sourceRoot":"","sources":["../../src/topic-builder.ts"],"names":[],"mappings":";;AA6MA,gDAEC;AA9MD,iDAM6B;AAE7B,6CAA0F;AAC1F,iEAAkF;AAClF,yDAAkE;AAElE,uDAAsD;AACtD,+CAA+C;AAC/C,yEAAuE;AAwFvE,MAAM,YAAY;IAChB,KAAK,GAA+B,EAAE,CAAC;IAC9B,aAAa,GAAqC,EAAE,CAAC;IACrD,cAAc,GAAwB,EAAE,CAAC;IAElD,QAAQ,CACN,GAAW,EACX,SAAoF;QAEpF,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,mCAAsB,CAAS,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5E,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,gCAAgC;IAChC,CAAC,iBAAU,CAAC,CAAC,MAAoB;QAC/B,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;IACrD,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,4BAAc;YACjB,GAAG,UAAU;SACO,CAAC;QAEvB,MAAM,KAAK,GAAG,IAAI,eAAK,CAAC,KAAK,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,IAAA,mCAAiB,EAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAEpF,MAAM,aAAa,GAAiC,EAAE,CAAC;QACvD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxC,MAAM,WAAW,GAAG,IAAA,cAAO,EAAC,KAAK,CAAC,YAAY,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;YAC/D,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,MAAM,kBAAkB,GAAG,IAAA,oDAAyB,EAClD,KAAK,EACL,cAAc,EACd,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CACxB,CAAC;YACF,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,sBAAY,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,SAAgB,kBAAkB;IAChC,OAAO,IAAA,8BAAa,EAAkC,YAAY,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TopicProps } from "aws-cdk-lib/aws-sns";
|
|
2
|
+
/**
|
|
3
|
+
* Secure, AWS-recommended defaults applied to every SNS topic built
|
|
4
|
+
* with {@link createTopicBuilder}. Each property can be individually
|
|
5
|
+
* overridden via the builder's fluent API.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TOPIC_DEFAULTS: Partial<TopicProps>;
|
|
8
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,UAAU,CAO9C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/defaults.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAwB;IACjD;;;;OAIG;IACH,UAAU,EAAE,IAAI;CACjB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createTopicBuilder, type TopicBuilderProps, type TopicBuilderResult, type ITopicBuilder, } from "./topic-builder.js";
|
|
2
|
+
export { TOPIC_DEFAULTS } from "./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 SubscriptionBuilderProps, type SubscriptionBuilderResult, } from "./subscription-builder.js";
|
|
6
|
+
export { SUBSCRIPTION_DEFAULTS, type SubscriptionDefaults } from "./subscription-defaults.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,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,wBAAwB,EAC7B,KAAK,yBAAyB,GAC/B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -2,4 +2,5 @@ export { createTopicBuilder, } from "./topic-builder.js";
|
|
|
2
2
|
export { TOPIC_DEFAULTS } from "./defaults.js";
|
|
3
3
|
export { TOPIC_ALARM_DEFAULTS } from "./topic-alarm-defaults.js";
|
|
4
4
|
export { createSubscriptionBuilder, } from "./subscription-builder.js";
|
|
5
|
+
export { SUBSCRIPTION_DEFAULTS } from "./subscription-defaults.js";
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAInB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,yBAAyB,GAI1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAA6B,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { type ITopic, type ITopicSubscription, Subscription } from "aws-cdk-lib/aws-sns";
|
|
2
|
+
import { type IConstruct } from "constructs";
|
|
3
|
+
import { type IBuilder, type Lifecycle, type Resolvable } from "@composurecdk/core";
|
|
4
|
+
/**
|
|
5
|
+
* Configuration properties for the SNS subscription builder.
|
|
6
|
+
*
|
|
7
|
+
* Both fields are required at build time. Both accept {@link Resolvable}
|
|
8
|
+
* values so the subscription can be wired to other components via
|
|
9
|
+
* {@link ref} inside a {@link compose}d system.
|
|
10
|
+
*/
|
|
11
|
+
export interface SubscriptionBuilderProps {
|
|
12
|
+
/**
|
|
13
|
+
* The topic to subscribe to. Accepts a concrete {@link ITopic} or a
|
|
14
|
+
* {@link Ref} to another component's output (e.g. a `TopicBuilder`).
|
|
15
|
+
*/
|
|
16
|
+
topic: Resolvable<ITopic>;
|
|
17
|
+
/**
|
|
18
|
+
* The subscription to attach. Accepts any CDK
|
|
19
|
+
* {@link ITopicSubscription} (e.g. `EmailSubscription`,
|
|
20
|
+
* `LambdaSubscription`, `SqsSubscription`) or a {@link Ref} to one.
|
|
21
|
+
*
|
|
22
|
+
* The subscription is bound via `ITopicSubscription.bind(topic)`, which
|
|
23
|
+
* performs the endpoint-specific IAM/resource-policy wire-up (Lambda
|
|
24
|
+
* invoke permission, SQS queue policy, KMS decrypt grant, etc.).
|
|
25
|
+
* Subscription-specific options — dead-letter queue, filter policy, raw
|
|
26
|
+
* message delivery — are configured on the `ITopicSubscription` itself,
|
|
27
|
+
* matching CDK's own subscription API.
|
|
28
|
+
*/
|
|
29
|
+
subscription: Resolvable<ITopicSubscription>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The build output of an {@link ISubscriptionBuilder}. Contains the CDK
|
|
33
|
+
* constructs created during {@link Lifecycle.build}, keyed by role.
|
|
34
|
+
*/
|
|
35
|
+
export interface SubscriptionBuilderResult {
|
|
36
|
+
/** The SNS subscription construct created by the builder. */
|
|
37
|
+
subscription: Subscription;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A fluent builder for configuring and creating an AWS SNS subscription.
|
|
41
|
+
*
|
|
42
|
+
* The builder implements {@link Lifecycle}, so it can be used directly as a
|
|
43
|
+
* component in a {@link compose | composed system}. Its `topic` and
|
|
44
|
+
* `subscription` properties accept {@link Resolvable} values so they can be
|
|
45
|
+
* supplied by another component's build output via {@link ref}.
|
|
46
|
+
*
|
|
47
|
+
* At build time, the configured `ITopicSubscription` is bound to the topic
|
|
48
|
+
* via `ITopicSubscription.bind(topic)` — the same path CDK uses for
|
|
49
|
+
* `topic.addSubscription(...)`. This ensures endpoint-specific wire-up
|
|
50
|
+
* (Lambda invoke permission, SQS queue policy, etc.) happens correctly.
|
|
51
|
+
*
|
|
52
|
+
* Recommended CloudWatch alarms related to subscription delivery (redrive
|
|
53
|
+
* to DLQ, failed redrive to DLQ) are emitted against topic-level metrics,
|
|
54
|
+
* so they live on {@link createTopicBuilder} rather than here.
|
|
55
|
+
*
|
|
56
|
+
* Use this builder when subscribing to a *foreign* topic — one not built in
|
|
57
|
+
* the same `compose` system. For the common case where a topic and its
|
|
58
|
+
* subscriptions are declared together, use `TopicBuilder.addSubscription`.
|
|
59
|
+
*
|
|
60
|
+
* @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sns.Subscription.html
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { EmailSubscription } from "aws-cdk-lib/aws-sns-subscriptions";
|
|
65
|
+
*
|
|
66
|
+
* const emailAlerts = createSubscriptionBuilder()
|
|
67
|
+
* .topic(ref("topic", (r: TopicBuilderResult) => r.topic))
|
|
68
|
+
* .subscription(new EmailSubscription("ops@example.com"));
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export type ISubscriptionBuilder = IBuilder<SubscriptionBuilderProps, SubscriptionBuilder>;
|
|
72
|
+
declare class SubscriptionBuilder implements Lifecycle<SubscriptionBuilderResult> {
|
|
73
|
+
props: Partial<SubscriptionBuilderProps>;
|
|
74
|
+
build(scope: IConstruct, id: string, context?: Record<string, object>): SubscriptionBuilderResult;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Creates a new {@link ISubscriptionBuilder} for configuring an AWS SNS
|
|
78
|
+
* subscription.
|
|
79
|
+
*
|
|
80
|
+
* The returned builder exposes `topic` and `subscription` as fluent
|
|
81
|
+
* setter/getters and implements {@link Lifecycle} for use with
|
|
82
|
+
* {@link compose}. Subscription-specific options (DLQ, filter policy, raw
|
|
83
|
+
* message delivery) are configured on the `ITopicSubscription` itself.
|
|
84
|
+
*
|
|
85
|
+
* @returns A fluent builder for an AWS SNS subscription.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* import { EmailSubscription } from "aws-cdk-lib/aws-sns-subscriptions";
|
|
90
|
+
*
|
|
91
|
+
* const system = compose(
|
|
92
|
+
* {
|
|
93
|
+
* topic: createTopicBuilder().topicName("budget-alerts"),
|
|
94
|
+
* email: createSubscriptionBuilder()
|
|
95
|
+
* .topic(ref("topic", (r: TopicBuilderResult) => r.topic))
|
|
96
|
+
* .subscription(new EmailSubscription("ops@example.com")),
|
|
97
|
+
* },
|
|
98
|
+
* { topic: [], email: ["topic"] },
|
|
99
|
+
* );
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function createSubscriptionBuilder(): ISubscriptionBuilder;
|
|
103
|
+
export {};
|
|
104
|
+
//# 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,KAAK,kBAAkB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAG5B;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAE1B;;;;;;;;;;;OAWG;IACH,YAAY,EAAE,UAAU,CAAC,kBAAkB,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,6DAA6D;IAC7D,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,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;CA6B7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,yBAAyB,IAAI,oBAAoB,CAGhE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Subscription } from "aws-cdk-lib/aws-sns";
|
|
2
|
+
import { Builder, resolve, } from "@composurecdk/core";
|
|
3
|
+
import { applySubscriptionDefaults } from "./subscription-defaults.js";
|
|
4
|
+
class SubscriptionBuilder {
|
|
5
|
+
props = {};
|
|
6
|
+
build(scope, id, context = {}) {
|
|
7
|
+
const { topic, subscription } = this.props;
|
|
8
|
+
if (topic === undefined) {
|
|
9
|
+
throw new Error(`SubscriptionBuilder "${id}": topic is required. Call .topic(...) with an ITopic or a Ref before building.`);
|
|
10
|
+
}
|
|
11
|
+
if (subscription === undefined) {
|
|
12
|
+
throw new Error(`SubscriptionBuilder "${id}": subscription is required. Call .subscription(...) with an ITopicSubscription (e.g. EmailSubscription, LambdaSubscription, SqsSubscription) or a Ref before building.`);
|
|
13
|
+
}
|
|
14
|
+
const resolvedTopic = resolve(topic, context);
|
|
15
|
+
const resolvedSubscription = resolve(subscription, context);
|
|
16
|
+
const subscriptionConfig = applySubscriptionDefaults(scope, id, resolvedSubscription.bind(resolvedTopic));
|
|
17
|
+
const built = new Subscription(scope, id, {
|
|
18
|
+
topic: resolvedTopic,
|
|
19
|
+
...subscriptionConfig,
|
|
20
|
+
});
|
|
21
|
+
return { subscription: built };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new {@link ISubscriptionBuilder} for configuring an AWS SNS
|
|
26
|
+
* subscription.
|
|
27
|
+
*
|
|
28
|
+
* The returned builder exposes `topic` and `subscription` as fluent
|
|
29
|
+
* setter/getters and implements {@link Lifecycle} for use with
|
|
30
|
+
* {@link compose}. Subscription-specific options (DLQ, filter policy, raw
|
|
31
|
+
* message delivery) are configured on the `ITopicSubscription` itself.
|
|
32
|
+
*
|
|
33
|
+
* @returns A fluent builder for an AWS SNS subscription.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { EmailSubscription } from "aws-cdk-lib/aws-sns-subscriptions";
|
|
38
|
+
*
|
|
39
|
+
* const system = compose(
|
|
40
|
+
* {
|
|
41
|
+
* topic: createTopicBuilder().topicName("budget-alerts"),
|
|
42
|
+
* email: createSubscriptionBuilder()
|
|
43
|
+
* .topic(ref("topic", (r: TopicBuilderResult) => r.topic))
|
|
44
|
+
* .subscription(new EmailSubscription("ops@example.com")),
|
|
45
|
+
* },
|
|
46
|
+
* { topic: [], email: ["topic"] },
|
|
47
|
+
* );
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function createSubscriptionBuilder() {
|
|
51
|
+
// eslint-disable-next-line composurecdk/builder-must-be-tagged -- AWS::SNS::Subscription has no Tags property
|
|
52
|
+
return Builder(SubscriptionBuilder);
|
|
53
|
+
}
|
|
54
|
+
//# 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,EAAwC,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEzF,OAAO,EACL,OAAO,EAIP,OAAO,GACR,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AA2EvE,MAAM,mBAAmB;IACvB,KAAK,GAAsC,EAAE,CAAC;IAE9C,KAAK,CACH,KAAiB,EACjB,EAAU,EACV,UAAkC,EAAE;QAEpC,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAE3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,wBAAwB,EAAE,iFAAiF,CAC5G,CAAC;QACJ,CAAC;QACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,wBAAwB,EAAE,yKAAyK,CACpM,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,oBAAoB,GAAG,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC5D,MAAM,kBAAkB,GAAG,yBAAyB,CAClD,KAAK,EACL,EAAE,EACF,oBAAoB,CAAC,IAAI,CAAC,aAAa,CAAC,CACzC,CAAC;QAEF,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE;YACxC,KAAK,EAAE,aAAa;YACpB,GAAG,kBAAkB;SACtB,CAAC,CAAC;QAEH,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACjC,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,yBAAyB;IACvC,8GAA8G;IAC9G,OAAO,OAAO,CAAgD,mBAAmB,CAAC,CAAC;AACrF,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { SubscriptionProtocol, type TopicSubscriptionConfig } from "aws-cdk-lib/aws-sns";
|
|
2
|
+
import type { IConstruct } from "constructs";
|
|
3
|
+
/**
|
|
4
|
+
* Per-protocol overrides applied to a {@link TopicSubscriptionConfig}.
|
|
5
|
+
*
|
|
6
|
+
* Only fields relevant to delivery semantics are included; `protocol`,
|
|
7
|
+
* `endpoint`, `subscriberId`, etc. are determined by the
|
|
8
|
+
* {@link aws-cdk-lib.aws_sns.ITopicSubscription | ITopicSubscription} and
|
|
9
|
+
* are never defaulted here.
|
|
10
|
+
*/
|
|
11
|
+
export type SubscriptionDefaults = Pick<TopicSubscriptionConfig, "rawMessageDelivery">;
|
|
12
|
+
/**
|
|
13
|
+
* AWS-recommended defaults applied per `SubscriptionProtocol` when a
|
|
14
|
+
* subscription is bound through either `createSubscriptionBuilder` or
|
|
15
|
+
* `TopicBuilder.addSubscription`.
|
|
16
|
+
*
|
|
17
|
+
* Defaults are merged into the {@link TopicSubscriptionConfig} returned by
|
|
18
|
+
* `ITopicSubscription.bind(topic)`: any field the `ITopicSubscription`
|
|
19
|
+
* itself set to a defined value wins, and the default only fills the gap
|
|
20
|
+
* when the bound config left the field `undefined`. This keeps every
|
|
21
|
+
* default individually overridable through the `ITopicSubscription`
|
|
22
|
+
* constructor options.
|
|
23
|
+
*
|
|
24
|
+
* Only the protocols on which SNS actually supports raw message delivery
|
|
25
|
+
* (SQS and Firehose) receive a default — applying it elsewhere would
|
|
26
|
+
* trigger CDK's own raw-delivery validation at synth time. Lambda is
|
|
27
|
+
* intentionally absent: SNS does not support raw delivery to Lambda
|
|
28
|
+
* subscriptions, and Lambda handlers always receive the SNS envelope.
|
|
29
|
+
*
|
|
30
|
+
* @see https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html
|
|
31
|
+
*/
|
|
32
|
+
export declare const SUBSCRIPTION_DEFAULTS: Partial<Record<SubscriptionProtocol, SubscriptionDefaults>>;
|
|
33
|
+
/**
|
|
34
|
+
* Merge {@link SUBSCRIPTION_DEFAULTS} into the result of
|
|
35
|
+
* `ITopicSubscription.bind(topic)` and emit transport-security warnings.
|
|
36
|
+
*
|
|
37
|
+
* Both `createSubscriptionBuilder` and `TopicBuilder.addSubscription`
|
|
38
|
+
* route through this helper so SNS subscriptions get the same defaults
|
|
39
|
+
* regardless of which builder created them.
|
|
40
|
+
*
|
|
41
|
+
* - Defaults are gap-filling: any field the `ITopicSubscription`
|
|
42
|
+
* explicitly set wins, and the default only applies when the bound
|
|
43
|
+
* config left the field `undefined`. Many `ITopicSubscription`
|
|
44
|
+
* implementations propagate `undefined` from their props, so a naive
|
|
45
|
+
* `{ ...defaults, ...config }` spread would clobber the defaults —
|
|
46
|
+
* this helper filters undefined entries before merging.
|
|
47
|
+
* - Emits a synth-time warning when subscribing over plain `HTTP` to
|
|
48
|
+
* nudge callers toward `HTTPS` for transport encryption. Other invalid
|
|
49
|
+
* protocol/option combinations (e.g. `rawMessageDelivery` on EMAIL)
|
|
50
|
+
* are surfaced by CDK's own `Subscription` validation.
|
|
51
|
+
*
|
|
52
|
+
* @param scope - The construct scope used to attach annotations.
|
|
53
|
+
* @param id - The subscription's logical id, used in warning text.
|
|
54
|
+
* @param config - The `TopicSubscriptionConfig` returned by
|
|
55
|
+
* `ITopicSubscription.bind(topic)`.
|
|
56
|
+
*
|
|
57
|
+
* @see https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html
|
|
58
|
+
*/
|
|
59
|
+
export declare function applySubscriptionDefaults(scope: IConstruct, id: string, config: TopicSubscriptionConfig): TopicSubscriptionConfig;
|
|
60
|
+
//# sourceMappingURL=subscription-defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-defaults.d.ts","sourceRoot":"","sources":["../../src/subscription-defaults.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,uBAAuB,EAAE,oBAAoB,CAAC,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,qBAAqB,EAAE,OAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,oBAAoB,CAAC,CAe7F,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,uBAAuB,GAC9B,uBAAuB,CAgBzB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Annotations } from "aws-cdk-lib";
|
|
2
|
+
import { SubscriptionProtocol } from "aws-cdk-lib/aws-sns";
|
|
3
|
+
/**
|
|
4
|
+
* AWS-recommended defaults applied per `SubscriptionProtocol` when a
|
|
5
|
+
* subscription is bound through either `createSubscriptionBuilder` or
|
|
6
|
+
* `TopicBuilder.addSubscription`.
|
|
7
|
+
*
|
|
8
|
+
* Defaults are merged into the {@link TopicSubscriptionConfig} returned by
|
|
9
|
+
* `ITopicSubscription.bind(topic)`: any field the `ITopicSubscription`
|
|
10
|
+
* itself set to a defined value wins, and the default only fills the gap
|
|
11
|
+
* when the bound config left the field `undefined`. This keeps every
|
|
12
|
+
* default individually overridable through the `ITopicSubscription`
|
|
13
|
+
* constructor options.
|
|
14
|
+
*
|
|
15
|
+
* Only the protocols on which SNS actually supports raw message delivery
|
|
16
|
+
* (SQS and Firehose) receive a default — applying it elsewhere would
|
|
17
|
+
* trigger CDK's own raw-delivery validation at synth time. Lambda is
|
|
18
|
+
* intentionally absent: SNS does not support raw delivery to Lambda
|
|
19
|
+
* subscriptions, and Lambda handlers always receive the SNS envelope.
|
|
20
|
+
*
|
|
21
|
+
* @see https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html
|
|
22
|
+
*/
|
|
23
|
+
export const SUBSCRIPTION_DEFAULTS = {
|
|
24
|
+
/**
|
|
25
|
+
* Deliver raw payloads to SQS so downstream consumers don't have to
|
|
26
|
+
* unwrap the SNS envelope. Halves payload size and removes a parse step
|
|
27
|
+
* — the typical choice for SNS → SQS fan-out.
|
|
28
|
+
* @see https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html
|
|
29
|
+
*/
|
|
30
|
+
[SubscriptionProtocol.SQS]: { rawMessageDelivery: true },
|
|
31
|
+
/**
|
|
32
|
+
* Deliver raw payloads to Firehose so records are stored as the
|
|
33
|
+
* publisher sent them rather than wrapped in an SNS envelope.
|
|
34
|
+
* @see https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html
|
|
35
|
+
*/
|
|
36
|
+
[SubscriptionProtocol.FIREHOSE]: { rawMessageDelivery: true },
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Merge {@link SUBSCRIPTION_DEFAULTS} into the result of
|
|
40
|
+
* `ITopicSubscription.bind(topic)` and emit transport-security warnings.
|
|
41
|
+
*
|
|
42
|
+
* Both `createSubscriptionBuilder` and `TopicBuilder.addSubscription`
|
|
43
|
+
* route through this helper so SNS subscriptions get the same defaults
|
|
44
|
+
* regardless of which builder created them.
|
|
45
|
+
*
|
|
46
|
+
* - Defaults are gap-filling: any field the `ITopicSubscription`
|
|
47
|
+
* explicitly set wins, and the default only applies when the bound
|
|
48
|
+
* config left the field `undefined`. Many `ITopicSubscription`
|
|
49
|
+
* implementations propagate `undefined` from their props, so a naive
|
|
50
|
+
* `{ ...defaults, ...config }` spread would clobber the defaults —
|
|
51
|
+
* this helper filters undefined entries before merging.
|
|
52
|
+
* - Emits a synth-time warning when subscribing over plain `HTTP` to
|
|
53
|
+
* nudge callers toward `HTTPS` for transport encryption. Other invalid
|
|
54
|
+
* protocol/option combinations (e.g. `rawMessageDelivery` on EMAIL)
|
|
55
|
+
* are surfaced by CDK's own `Subscription` validation.
|
|
56
|
+
*
|
|
57
|
+
* @param scope - The construct scope used to attach annotations.
|
|
58
|
+
* @param id - The subscription's logical id, used in warning text.
|
|
59
|
+
* @param config - The `TopicSubscriptionConfig` returned by
|
|
60
|
+
* `ITopicSubscription.bind(topic)`.
|
|
61
|
+
*
|
|
62
|
+
* @see https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html
|
|
63
|
+
*/
|
|
64
|
+
export function applySubscriptionDefaults(scope, id, config) {
|
|
65
|
+
const protocolDefaults = SUBSCRIPTION_DEFAULTS[config.protocol] ?? {};
|
|
66
|
+
const definedConfig = Object.fromEntries(Object.entries(config).filter(([, value]) => value !== undefined));
|
|
67
|
+
const merged = { ...protocolDefaults, ...definedConfig };
|
|
68
|
+
if (merged.protocol === SubscriptionProtocol.HTTP) {
|
|
69
|
+
Annotations.of(scope).addWarningV2("@composurecdk/sns:http-subscription-insecure", `SNS subscription "${id}": delivering over plain HTTP — messages and any signed-confirmation tokens travel unencrypted. ` +
|
|
70
|
+
`Prefer SubscriptionProtocol.HTTPS for transport encryption.`);
|
|
71
|
+
}
|
|
72
|
+
return merged;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=subscription-defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-defaults.js","sourceRoot":"","sources":["../../src/subscription-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAgC,MAAM,qBAAqB,CAAC;AAazF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAgE;IAChG;;;;;OAKG;IACH,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE;IAExD;;;;OAIG;IACH,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE;CAC9D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAiB,EACjB,EAAU,EACV,MAA+B;IAE/B,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACtE,MAAM,aAAa,GAAG,MAAM,CAAC,WAAW,CACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAClE,CAAC;IACF,MAAM,MAAM,GAAG,EAAE,GAAG,gBAAgB,EAAE,GAAG,aAAa,EAA6B,CAAC;IAEpF,IAAI,MAAM,CAAC,QAAQ,KAAK,oBAAoB,CAAC,IAAI,EAAE,CAAC;QAClD,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,CAChC,8CAA8C,EAC9C,qBAAqB,EAAE,kGAAkG;YACvH,6DAA6D,CAChE,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|