@composurecdk/sns 0.7.0 → 0.8.1

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.
Files changed (83) hide show
  1. package/README.md +57 -10
  2. package/dist/commonjs/defaults.d.ts.map +1 -0
  3. package/dist/commonjs/defaults.js +17 -0
  4. package/dist/commonjs/defaults.js.map +1 -0
  5. package/dist/{index.d.ts → commonjs/index.d.ts} +1 -0
  6. package/dist/commonjs/index.d.ts.map +1 -0
  7. package/dist/commonjs/index.js +14 -0
  8. package/dist/commonjs/index.js.map +1 -0
  9. package/dist/commonjs/package.json +3 -0
  10. package/dist/{subscription-builder.d.ts → commonjs/subscription-builder.d.ts} +36 -32
  11. package/dist/commonjs/subscription-builder.d.ts.map +1 -0
  12. package/dist/commonjs/subscription-builder.js +57 -0
  13. package/dist/commonjs/subscription-builder.js.map +1 -0
  14. package/dist/commonjs/subscription-defaults.d.ts +60 -0
  15. package/dist/commonjs/subscription-defaults.d.ts.map +1 -0
  16. package/dist/commonjs/subscription-defaults.js +78 -0
  17. package/dist/commonjs/subscription-defaults.js.map +1 -0
  18. package/dist/commonjs/topic-alarm-config.d.ts.map +1 -0
  19. package/dist/commonjs/topic-alarm-config.js +3 -0
  20. package/dist/commonjs/topic-alarm-config.js.map +1 -0
  21. package/dist/commonjs/topic-alarm-defaults.d.ts.map +1 -0
  22. package/dist/commonjs/topic-alarm-defaults.js +41 -0
  23. package/dist/commonjs/topic-alarm-defaults.js.map +1 -0
  24. package/dist/commonjs/topic-alarms.d.ts.map +1 -0
  25. package/dist/commonjs/topic-alarms.js +108 -0
  26. package/dist/commonjs/topic-alarms.js.map +1 -0
  27. package/dist/commonjs/topic-builder.d.ts.map +1 -0
  28. package/dist/commonjs/topic-builder.js +97 -0
  29. package/dist/commonjs/topic-builder.js.map +1 -0
  30. package/dist/esm/defaults.d.ts +8 -0
  31. package/dist/esm/defaults.d.ts.map +1 -0
  32. package/dist/esm/defaults.js.map +1 -0
  33. package/dist/esm/index.d.ts +7 -0
  34. package/dist/esm/index.d.ts.map +1 -0
  35. package/dist/{index.js → esm/index.js} +1 -0
  36. package/dist/esm/index.js.map +1 -0
  37. package/dist/esm/package.json +3 -0
  38. package/dist/esm/subscription-builder.d.ts +104 -0
  39. package/dist/esm/subscription-builder.d.ts.map +1 -0
  40. package/dist/esm/subscription-builder.js +54 -0
  41. package/dist/esm/subscription-builder.js.map +1 -0
  42. package/dist/esm/subscription-defaults.d.ts +60 -0
  43. package/dist/esm/subscription-defaults.d.ts.map +1 -0
  44. package/dist/esm/subscription-defaults.js +74 -0
  45. package/dist/esm/subscription-defaults.js.map +1 -0
  46. package/dist/esm/topic-alarm-config.d.ts +67 -0
  47. package/dist/esm/topic-alarm-config.d.ts.map +1 -0
  48. package/dist/esm/topic-alarm-config.js.map +1 -0
  49. package/dist/esm/topic-alarm-defaults.d.ts +16 -0
  50. package/dist/esm/topic-alarm-defaults.d.ts.map +1 -0
  51. package/dist/esm/topic-alarm-defaults.js.map +1 -0
  52. package/dist/esm/topic-alarms.d.ts +26 -0
  53. package/dist/esm/topic-alarms.d.ts.map +1 -0
  54. package/dist/esm/topic-alarms.js.map +1 -0
  55. package/dist/esm/topic-builder.d.ts +136 -0
  56. package/dist/esm/topic-builder.d.ts.map +1 -0
  57. package/dist/{topic-builder.js → esm/topic-builder.js} +2 -1
  58. package/dist/esm/topic-builder.js.map +1 -0
  59. package/package.json +36 -18
  60. package/dist/defaults.d.ts.map +0 -1
  61. package/dist/defaults.js.map +0 -1
  62. package/dist/index.d.ts.map +0 -1
  63. package/dist/index.js.map +0 -1
  64. package/dist/subscription-builder.d.ts.map +0 -1
  65. package/dist/subscription-builder.js +0 -58
  66. package/dist/subscription-builder.js.map +0 -1
  67. package/dist/topic-alarm-config.d.ts.map +0 -1
  68. package/dist/topic-alarm-config.js.map +0 -1
  69. package/dist/topic-alarm-defaults.d.ts.map +0 -1
  70. package/dist/topic-alarm-defaults.js.map +0 -1
  71. package/dist/topic-alarms.d.ts.map +0 -1
  72. package/dist/topic-alarms.js.map +0 -1
  73. package/dist/topic-builder.d.ts.map +0 -1
  74. package/dist/topic-builder.js.map +0 -1
  75. /package/dist/{defaults.d.ts → commonjs/defaults.d.ts} +0 -0
  76. /package/dist/{topic-alarm-config.d.ts → commonjs/topic-alarm-config.d.ts} +0 -0
  77. /package/dist/{topic-alarm-defaults.d.ts → commonjs/topic-alarm-defaults.d.ts} +0 -0
  78. /package/dist/{topic-alarms.d.ts → commonjs/topic-alarms.d.ts} +0 -0
  79. /package/dist/{topic-builder.d.ts → commonjs/topic-builder.d.ts} +0 -0
  80. /package/dist/{defaults.js → esm/defaults.js} +0 -0
  81. /package/dist/{topic-alarm-config.js → esm/topic-alarm-config.js} +0 -0
  82. /package/dist/{topic-alarm-defaults.js → esm/topic-alarm-defaults.js} +0 -0
  83. /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"}
@@ -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,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -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"}