@composurecdk/sqs 0.8.7 → 0.9.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.
Files changed (94) hide show
  1. package/README.md +99 -13
  2. package/dist/commonjs/dlq-alarm-defaults.d.ts +53 -0
  3. package/dist/commonjs/dlq-alarm-defaults.d.ts.map +1 -0
  4. package/dist/commonjs/dlq-alarm-defaults.js +53 -0
  5. package/dist/commonjs/dlq-alarm-defaults.js.map +1 -0
  6. package/dist/commonjs/dlq-defaults.d.ts +19 -0
  7. package/dist/commonjs/dlq-defaults.d.ts.map +1 -0
  8. package/dist/commonjs/dlq-defaults.js +22 -0
  9. package/dist/commonjs/dlq-defaults.js.map +1 -0
  10. package/dist/commonjs/grants.d.ts +19 -0
  11. package/dist/commonjs/grants.d.ts.map +1 -0
  12. package/dist/commonjs/grants.js +28 -0
  13. package/dist/commonjs/grants.js.map +1 -0
  14. package/dist/commonjs/index.d.ts +6 -1
  15. package/dist/commonjs/index.d.ts.map +1 -1
  16. package/dist/commonjs/index.js +7 -1
  17. package/dist/commonjs/index.js.map +1 -1
  18. package/dist/commonjs/queue-alarm-config.d.ts +47 -11
  19. package/dist/commonjs/queue-alarm-config.d.ts.map +1 -1
  20. package/dist/commonjs/queue-alarm-defaults.d.ts +46 -11
  21. package/dist/commonjs/queue-alarm-defaults.d.ts.map +1 -1
  22. package/dist/commonjs/queue-alarm-defaults.js +11 -5
  23. package/dist/commonjs/queue-alarm-defaults.js.map +1 -1
  24. package/dist/commonjs/queue-alarm-profiles.d.ts +37 -0
  25. package/dist/commonjs/queue-alarm-profiles.d.ts.map +1 -0
  26. package/dist/commonjs/queue-alarm-profiles.js +96 -0
  27. package/dist/commonjs/queue-alarm-profiles.js.map +1 -0
  28. package/dist/commonjs/queue-alarms.d.ts +8 -2
  29. package/dist/commonjs/queue-alarms.d.ts.map +1 -1
  30. package/dist/commonjs/queue-alarms.js +49 -42
  31. package/dist/commonjs/queue-alarms.js.map +1 -1
  32. package/dist/commonjs/queue-builder.d.ts +70 -53
  33. package/dist/commonjs/queue-builder.d.ts.map +1 -1
  34. package/dist/commonjs/queue-builder.js +27 -68
  35. package/dist/commonjs/queue-builder.js.map +1 -1
  36. package/dist/commonjs/queue-props.d.ts +93 -0
  37. package/dist/commonjs/queue-props.d.ts.map +1 -0
  38. package/dist/commonjs/queue-props.js +16 -0
  39. package/dist/commonjs/queue-props.js.map +1 -0
  40. package/dist/commonjs/queue-role.d.ts +28 -0
  41. package/dist/commonjs/queue-role.d.ts.map +1 -0
  42. package/dist/commonjs/queue-role.js +13 -0
  43. package/dist/commonjs/queue-role.js.map +1 -0
  44. package/dist/commonjs/queue-validation.d.ts +12 -0
  45. package/dist/commonjs/queue-validation.d.ts.map +1 -0
  46. package/dist/commonjs/queue-validation.js +142 -0
  47. package/dist/commonjs/queue-validation.js.map +1 -0
  48. package/dist/esm/dlq-alarm-defaults.d.ts +53 -0
  49. package/dist/esm/dlq-alarm-defaults.d.ts.map +1 -0
  50. package/dist/esm/dlq-alarm-defaults.js +50 -0
  51. package/dist/esm/dlq-alarm-defaults.js.map +1 -0
  52. package/dist/esm/dlq-defaults.d.ts +19 -0
  53. package/dist/esm/dlq-defaults.d.ts.map +1 -0
  54. package/dist/esm/dlq-defaults.js +19 -0
  55. package/dist/esm/dlq-defaults.js.map +1 -0
  56. package/dist/esm/grants.d.ts +19 -0
  57. package/dist/esm/grants.d.ts.map +1 -0
  58. package/dist/esm/grants.js +25 -0
  59. package/dist/esm/grants.js.map +1 -0
  60. package/dist/esm/index.d.ts +6 -1
  61. package/dist/esm/index.d.ts.map +1 -1
  62. package/dist/esm/index.js +3 -0
  63. package/dist/esm/index.js.map +1 -1
  64. package/dist/esm/queue-alarm-config.d.ts +47 -11
  65. package/dist/esm/queue-alarm-config.d.ts.map +1 -1
  66. package/dist/esm/queue-alarm-defaults.d.ts +46 -11
  67. package/dist/esm/queue-alarm-defaults.d.ts.map +1 -1
  68. package/dist/esm/queue-alarm-defaults.js +11 -5
  69. package/dist/esm/queue-alarm-defaults.js.map +1 -1
  70. package/dist/esm/queue-alarm-profiles.d.ts +37 -0
  71. package/dist/esm/queue-alarm-profiles.d.ts.map +1 -0
  72. package/dist/esm/queue-alarm-profiles.js +92 -0
  73. package/dist/esm/queue-alarm-profiles.js.map +1 -0
  74. package/dist/esm/queue-alarms.d.ts +8 -2
  75. package/dist/esm/queue-alarms.d.ts.map +1 -1
  76. package/dist/esm/queue-alarms.js +50 -43
  77. package/dist/esm/queue-alarms.js.map +1 -1
  78. package/dist/esm/queue-builder.d.ts +70 -53
  79. package/dist/esm/queue-builder.d.ts.map +1 -1
  80. package/dist/esm/queue-builder.js +27 -68
  81. package/dist/esm/queue-builder.js.map +1 -1
  82. package/dist/esm/queue-props.d.ts +93 -0
  83. package/dist/esm/queue-props.d.ts.map +1 -0
  84. package/dist/esm/queue-props.js +13 -0
  85. package/dist/esm/queue-props.js.map +1 -0
  86. package/dist/esm/queue-role.d.ts +28 -0
  87. package/dist/esm/queue-role.d.ts.map +1 -0
  88. package/dist/esm/queue-role.js +9 -0
  89. package/dist/esm/queue-role.js.map +1 -0
  90. package/dist/esm/queue-validation.d.ts +12 -0
  91. package/dist/esm/queue-validation.d.ts.map +1 -0
  92. package/dist/esm/queue-validation.js +139 -0
  93. package/dist/esm/queue-validation.js.map +1 -0
  94. package/package.json +4 -4
@@ -4,31 +4,12 @@ import { type IConstruct } from "constructs";
4
4
  import { COPY_STATE, type Lifecycle } from "@composurecdk/core";
5
5
  import { type ITaggedBuilder } from "@composurecdk/cloudformation";
6
6
  import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
7
- import type { QueueAlarmConfig } from "./queue-alarm-config.js";
7
+ import type { QueueBuilderExtensionProps, QueueBuilderPropsByRole } from "./queue-props.js";
8
+ import { type QueueRole } from "./queue-role.js";
8
9
  /**
9
- * Configuration properties for the SQS queue builder.
10
- *
11
- * Extends the CDK {@link QueueProps} with additional builder-specific options.
12
- */
13
- export interface QueueBuilderProps extends QueueProps {
14
- /**
15
- * Configuration for AWS-recommended CloudWatch alarms.
16
- *
17
- * By default, the builder creates recommended alarms with sensible
18
- * thresholds for every applicable metric. Individual alarms can be
19
- * customized or disabled. Set to `false` to disable all alarms.
20
- *
21
- * No alarm actions are configured by default since notification
22
- * methods are user-specific. Access alarms from the build result
23
- * or use an `afterBuild` hook to apply actions.
24
- *
25
- * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#SQS
26
- */
27
- recommendedAlarms?: QueueAlarmConfig | false;
28
- }
29
- /**
30
- * The build output of an {@link IQueueBuilder}. Contains the CDK constructs
31
- * created during {@link Lifecycle.build}, keyed by role.
10
+ * The build output of {@link createQueueBuilder}, identical across every
11
+ * {@link QueueRole}. Contains the CDK constructs created during
12
+ * {@link Lifecycle.build}, keyed by role.
32
13
  */
33
14
  export interface QueueBuilderResult {
34
15
  /** The SQS queue construct created by the builder. */
@@ -37,8 +18,8 @@ export interface QueueBuilderResult {
37
18
  * CloudWatch alarms created for the queue, keyed by alarm name.
38
19
  *
39
20
  * Includes both AWS-recommended alarms and any custom alarms added
40
- * via {@link IQueueBuilder.addAlarm}. Access individual alarms
41
- * by key (e.g., `result.alarms.approximateAgeOfOldestMessage`).
21
+ * via `addAlarm`. Access individual alarms by key (e.g.,
22
+ * `result.alarms.approximateAgeOfOldestMessage`).
42
23
  *
43
24
  * No alarm actions are configured — apply them via the result or an
44
25
  * `afterBuild` hook.
@@ -48,21 +29,37 @@ export interface QueueBuilderResult {
48
29
  alarms: Record<string, Alarm>;
49
30
  }
50
31
  /**
51
- * A fluent builder for configuring and creating an AWS SQS queue.
32
+ * The builder's full internal prop store: the CDK {@link QueueProps},
33
+ * the builder-only extensions, and the queue's role. The public surface
34
+ * per role is the narrowed view in {@link QueueBuilderPropsByRole} —
35
+ * this type exists so one `QueueBuilder` implementation can back every
36
+ * role.
37
+ */
38
+ interface InternalQueueBuilderProps extends QueueProps, QueueBuilderExtensionProps {
39
+ /**
40
+ * The queue's role, set by `createQueueBuilder(role)`. Stored as a
41
+ * prop (not a private field) so it is data: `.copy()` preserves it
42
+ * for free and it is inspectable on the builder.
43
+ */
44
+ queueRole?: QueueRole;
45
+ }
46
+ /**
47
+ * A fluent builder for configuring and creating an AWS SQS queue in a
48
+ * given {@link QueueRole}.
52
49
  *
53
- * Each configuration property from the CDK {@link QueueProps} is exposed
54
- * as an overloaded method: call with a value to set it (returns the builder
50
+ * Each configuration property applicable to the role is exposed as an
51
+ * overloaded method: call with a value to set it (returns the builder
55
52
  * for chaining), or call with no arguments to read the current value.
53
+ * The prop surface is exact per role — FIFO-only props exist only on
54
+ * the FIFO roles, and `deadLetterQueue` does not exist on the
55
+ * dead-letter roles.
56
56
  *
57
- * The builder implements {@link Lifecycle}, so it can be used directly as a
58
- * component in a {@link compose | composed system}. When built, it creates
59
- * an SQS queue with the configured properties and returns a
57
+ * The builder implements {@link Lifecycle}, so it can be used directly as
58
+ * a component in a {@link compose | composed system}. When built, it
59
+ * creates an SQS queue with the configured properties, the role's
60
+ * defaults, and the role's recommended CloudWatch alarms, returning a
60
61
  * {@link QueueBuilderResult}.
61
62
  *
62
- * The builder also creates AWS-recommended CloudWatch alarms by default.
63
- * Alarms can be customized or disabled via the `recommendedAlarms` property.
64
- * Custom alarms can be added via the {@link addAlarm} method.
65
- *
66
63
  * @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sqs.Queue.html
67
64
  *
68
65
  * @example
@@ -70,42 +67,62 @@ export interface QueueBuilderResult {
70
67
  * const orders = createQueueBuilder()
71
68
  * .queueName("orders")
72
69
  * .visibilityTimeout(Duration.seconds(60));
70
+ *
71
+ * const orderEvents = createQueueBuilder("fifo")
72
+ * .queueName("order-events.fifo")
73
+ * .contentBasedDeduplication(true);
74
+ *
75
+ * const ordersDlq = createQueueBuilder("dlq").queueName("orders-dlq");
73
76
  * ```
74
77
  */
75
- export type IQueueBuilder = ITaggedBuilder<QueueBuilderProps, QueueBuilder>;
78
+ export type IQueueBuilder<R extends QueueRole = "standard"> = ITaggedBuilder<QueueBuilderPropsByRole[R], QueueBuilder>;
76
79
  declare class QueueBuilder implements Lifecycle<QueueBuilderResult> {
77
80
  #private;
78
- props: Partial<QueueBuilderProps>;
81
+ props: Partial<InternalQueueBuilderProps>;
79
82
  addAlarm(key: string, configure: (alarm: AlarmDefinitionBuilder<IQueue>) => AlarmDefinitionBuilder<IQueue>): this;
80
83
  /** @internal — see ADR-0005. */
81
84
  [COPY_STATE](target: QueueBuilder): void;
82
85
  build(scope: IConstruct, id: string): QueueBuilderResult;
83
86
  }
84
87
  /**
85
- * Creates a new {@link IQueueBuilder} for configuring an AWS SQS queue.
88
+ * Creates a new {@link IQueueBuilder} for configuring an AWS SQS queue
89
+ * in the given role.
86
90
  *
87
- * This is the entry point for defining an SQS queue component. The returned
88
- * builder exposes every {@link QueueBuilderProps} property as a fluent setter/getter
89
- * and implements {@link Lifecycle} for use with {@link compose}.
91
+ * This is the single entry point for every queue type. The role — see
92
+ * {@link QueueRole} for the full catalogue — selects the builder's
93
+ * typed prop surface, its Well-Architected defaults, its
94
+ * recommended-alarm profile, and its build-time validation:
90
95
  *
91
- * @returns A fluent builder for an AWS SQS queue.
96
+ * - `createQueueBuilder()` / `createQueueBuilder("standard")` — primary
97
+ * standard queue.
98
+ * - `createQueueBuilder("fifo")` — primary FIFO queue.
99
+ * - `createQueueBuilder("dlq")` — standard dead-letter queue.
100
+ * - `createQueueBuilder("fifo-dlq")` — FIFO dead-letter queue (the DLQ
101
+ * for a FIFO source must itself be FIFO).
92
102
  *
93
- * @example
94
- * ```ts
95
- * const orders = createQueueBuilder()
96
- * .queueName("orders")
97
- * .visibilityTimeout(Duration.seconds(60));
103
+ * The returned builder exposes every prop applicable to the role as a
104
+ * fluent setter/getter and implements {@link Lifecycle} for use with
105
+ * {@link compose}.
98
106
  *
99
- * // Use standalone:
100
- * const result = orders.build(stack, "Orders");
107
+ * @param role - The queue's role. Defaults to `"standard"`.
108
+ * @returns A fluent builder for an AWS SQS queue in that role.
101
109
  *
102
- * // Or compose into a system:
110
+ * @example
111
+ * ```ts
112
+ * // A FIFO primary queue redriving to a FIFO dead-letter queue:
103
113
  * const system = compose(
104
- * { orders, alerts: createTopicBuilder() },
105
- * { orders: [], alerts: [] },
114
+ * {
115
+ * orderEventsDlq: createQueueBuilder("fifo-dlq").queueName("order-events-dlq.fifo"),
116
+ * orderEvents: createQueueBuilder("fifo")
117
+ * .queueName("order-events.fifo")
118
+ * .contentBasedDeduplication(true)
119
+ * .deadLetterQueue(ref("orderEventsDlq", (r) => ({ queue: r.queue, maxReceiveCount: 5 }))),
120
+ * },
121
+ * { orderEventsDlq: [], orderEvents: ["orderEventsDlq"] },
106
122
  * );
107
123
  * ```
108
124
  */
109
125
  export declare function createQueueBuilder(): IQueueBuilder;
126
+ export declare function createQueueBuilder<R extends QueueRole>(role: R): IQueueBuilder<R>;
110
127
  export {};
111
128
  //# sourceMappingURL=queue-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"queue-builder.d.ts","sourceRoot":"","sources":["../../src/queue-builder.ts"],"names":[],"mappings":"AACA,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,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,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;AAehE;;;;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,cAAc,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;AAE5E,cAAM,YAAa,YAAW,SAAS,CAAC,kBAAkB,CAAC;;IACzD,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAM;IAGvC,QAAQ,CACN,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,KAAK,sBAAsB,CAAC,MAAM,CAAC,GACnF,IAAI;IAKP,gCAAgC;IAChC,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAIxC,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,kBAAkB;CAgBzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAElD"}
1
+ {"version":3,"file":"queue-builder.d.ts","sourceRoot":"","sources":["../../src/queue-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,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,KAAK,cAAc,EAAiB,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAOxE;;;;GAIG;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;;;;;;GAMG;AACH,UAAU,yBAA0B,SAAQ,UAAU,EAAE,0BAA0B;IAChF;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,SAAS,GAAG,UAAU,IAAI,cAAc,CAC1E,uBAAuB,CAAC,CAAC,CAAC,EAC1B,YAAY,CACb,CAAC;AAEF,cAAM,YAAa,YAAW,SAAS,CAAC,kBAAkB,CAAC;;IACzD,KAAK,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAM;IAG/C,QAAQ,CACN,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,KAAK,sBAAsB,CAAC,MAAM,CAAC,GACnF,IAAI;IAKP,gCAAgC;IAChC,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAIxC,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,kBAAkB;CA+BzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAAC;AACpD,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC"}
@@ -1,20 +1,13 @@
1
- import { Annotations, Token } from "aws-cdk-lib";
2
1
  import { Queue } from "aws-cdk-lib/aws-sqs";
3
2
  import { COPY_STATE } from "@composurecdk/core";
4
3
  import { taggedBuilder } from "@composurecdk/cloudformation";
5
4
  import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
6
- import { createQueueAlarms } from "./queue-alarms.js";
5
+ import { isDlqRole, isFifoRole } from "./queue-role.js";
7
6
  import { QUEUE_DEFAULTS } from "./defaults.js";
8
- /**
9
- * AWS-recommended minimum for `maxReceiveCount` on an SQS redrive
10
- * policy. A consumer needs a few retries before SQS gives up and
11
- * forwards the message to the dead-letter queue; anything below this
12
- * tends to surface as a flood of "poison" messages from transient
13
- * errors that would have succeeded on retry.
14
- *
15
- * @see https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html
16
- */
17
- const RECOMMENDED_MIN_MAX_RECEIVE_COUNT = 5;
7
+ import { DLQ_QUEUE_DEFAULTS } from "./dlq-defaults.js";
8
+ import { dlqAlarmProfile, PRIMARY_ALARM_PROFILE } from "./queue-alarm-profiles.js";
9
+ import { createQueueAlarms } from "./queue-alarms.js";
10
+ import { validateQueueProps } from "./queue-validation.js";
18
11
  class QueueBuilder {
19
12
  props = {};
20
13
  #customAlarms = [];
@@ -27,67 +20,33 @@ class QueueBuilder {
27
20
  target.#customAlarms.push(...this.#customAlarms);
28
21
  }
29
22
  build(scope, id) {
30
- const { recommendedAlarms: alarmConfig, ...queueProps } = this.props;
23
+ const { queueRole: role = "standard", ...configured } = this.props;
24
+ const fifo = isFifoRole(role);
25
+ const dlq = isDlqRole(role);
31
26
  const mergedProps = {
32
27
  ...QUEUE_DEFAULTS,
33
- ...queueProps,
28
+ ...(dlq ? DLQ_QUEUE_DEFAULTS : {}),
29
+ ...configured,
30
+ ...(fifo ? { fifo: true } : {}),
34
31
  };
35
- warnIfLowMaxReceiveCount(scope, id, mergedProps);
36
- const queue = new Queue(scope, id, mergedProps);
37
- const alarms = createQueueAlarms(scope, id, queue, alarmConfig, this.#customAlarms);
32
+ validateQueueProps(scope, id, role, mergedProps);
33
+ const { recommendedAlarms, ...queueProps } = mergedProps;
34
+ const queue = new Queue(scope, id, queueProps);
35
+ const profile = dlq
36
+ ? dlqAlarmProfile(scope, mergedProps.retentionPeriod)
37
+ : PRIMARY_ALARM_PROFILE;
38
+ const alarms = createQueueAlarms(scope, id, queue, recommendedAlarms, this.#customAlarms, profile);
38
39
  return { queue, alarms };
39
40
  }
40
41
  }
41
- /**
42
- * Creates a new {@link IQueueBuilder} for configuring an AWS SQS queue.
43
- *
44
- * This is the entry point for defining an SQS queue component. The returned
45
- * builder exposes every {@link QueueBuilderProps} property as a fluent setter/getter
46
- * and implements {@link Lifecycle} for use with {@link compose}.
47
- *
48
- * @returns A fluent builder for an AWS SQS queue.
49
- *
50
- * @example
51
- * ```ts
52
- * const orders = createQueueBuilder()
53
- * .queueName("orders")
54
- * .visibilityTimeout(Duration.seconds(60));
55
- *
56
- * // Use standalone:
57
- * const result = orders.build(stack, "Orders");
58
- *
59
- * // Or compose into a system:
60
- * const system = compose(
61
- * { orders, alerts: createTopicBuilder() },
62
- * { orders: [], alerts: [] },
63
- * );
64
- * ```
65
- */
66
- export function createQueueBuilder() {
67
- return taggedBuilder(QueueBuilder);
68
- }
69
- /**
70
- * Annotates `scope` with a non-fatal warning when a redrive policy is
71
- * configured with `maxReceiveCount` below the AWS-recommended floor
72
- * of {@link RECOMMENDED_MIN_MAX_RECEIVE_COUNT}.
73
- *
74
- * The builder owns the redrive policy directly, so this is a true
75
- * check rather than a contextual reminder — the actual configured
76
- * value is compared. Short-circuits on unresolved tokens so stacks
77
- * that thread `maxReceiveCount` through CFN parameters aren't spammed.
78
- */
79
- function warnIfLowMaxReceiveCount(scope, id, props) {
80
- const dlq = props.deadLetterQueue;
81
- if (!dlq)
82
- return;
83
- const maxReceiveCount = dlq.maxReceiveCount;
84
- if (Token.isUnresolved(maxReceiveCount))
85
- return;
86
- if (maxReceiveCount >= RECOMMENDED_MIN_MAX_RECEIVE_COUNT)
87
- return;
88
- Annotations.of(scope).addWarningV2("@composurecdk/sqs:redrive-low-max-receive-count", `QueueBuilder "${id}": redrive policy maxReceiveCount is ${String(maxReceiveCount)}; ` +
89
- `AWS recommends >= ${String(RECOMMENDED_MIN_MAX_RECEIVE_COUNT)} so the consumer ` +
90
- `has room to retry before messages hit the dead-letter queue. ` +
91
- `See https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html`);
42
+ // Callers only ever see the overloads above, which return the exact
43
+ // per-role `IQueueBuilder<R>`. The `unknown` here types the implementation
44
+ // body alone (the internal builder carries the full prop surface, not the
45
+ // narrowed per-role one) and is never observed at a call site — so it does
46
+ // not weaken the type of a builder passed to `compose`.
47
+ export function createQueueBuilder(role = "standard") {
48
+ const builder = taggedBuilder(QueueBuilder);
49
+ builder.queueRole(role);
50
+ return builder;
92
51
  }
93
52
  //# sourceMappingURL=queue-builder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"queue-builder.js","sourceRoot":"","sources":["../../src/queue-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAe,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAE1E,OAAO,EAAE,UAAU,EAAkB,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAuB,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,iCAAiC,GAAG,CAAC,CAAC;AA0E5C,MAAM,YAAY;IAChB,KAAK,GAA+B,EAAE,CAAC;IAC9B,aAAa,GAAqC,EAAE,CAAC;IAE9D,QAAQ,CACN,GAAW,EACX,SAAoF;QAEpF,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,sBAAsB,CAAS,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gCAAgC;IAChC,CAAC,UAAU,CAAC,CAAC,MAAoB;QAC/B,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;IACnD,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,wBAAwB,CAAC,KAAK,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;QAEjD,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,aAAa,CAAC,CAAC;QAEpF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,aAAa,CAAkC,YAAY,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,wBAAwB,CAC/B,KAAiB,EACjB,EAAU,EACV,KAAiC;IAEjC,MAAM,GAAG,GAAG,KAAK,CAAC,eAAe,CAAC;IAClC,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,MAAM,eAAe,GAAG,GAAG,CAAC,eAAe,CAAC;IAC5C,IAAI,KAAK,CAAC,YAAY,CAAC,eAAe,CAAC;QAAE,OAAO;IAChD,IAAI,eAAe,IAAI,iCAAiC;QAAE,OAAO;IACjE,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,CAChC,iDAAiD,EACjD,iBAAiB,EAAE,wCAAwC,MAAM,CAAC,eAAe,CAAC,IAAI;QACpF,qBAAqB,MAAM,CAAC,iCAAiC,CAAC,mBAAmB;QACjF,+DAA+D;QAC/D,gEAAgE,CACnE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"queue-builder.js","sourceRoot":"","sources":["../../src/queue-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAE1E,OAAO,EAAE,UAAU,EAAkB,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAuB,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AA+E3D,MAAM,YAAY;IAChB,KAAK,GAAuC,EAAE,CAAC;IACtC,aAAa,GAAqC,EAAE,CAAC;IAE9D,QAAQ,CACN,GAAW,EACX,SAAoF;QAEpF,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,sBAAsB,CAAS,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gCAAgC;IAChC,CAAC,UAAU,CAAC,CAAC,MAAoB;QAC/B,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,KAAiB,EAAE,EAAU;QACjC,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,UAAU,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QACnE,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAE5B,MAAM,WAAW,GAAG;YAClB,GAAG,cAAc;YACjB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;YAClC,GAAG,UAAU;YACb,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChC,CAAC;QAEF,kBAAkB,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAEjD,MAAM,EAAE,iBAAiB,EAAE,GAAG,UAAU,EAAE,GAAG,WAAW,CAAC;QACzD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC;QAE/C,MAAM,OAAO,GAAG,GAAG;YACjB,CAAC,CAAC,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,eAAe,CAAC;YACrD,CAAC,CAAC,qBAAqB,CAAC;QAC1B,MAAM,MAAM,GAAG,iBAAiB,CAC9B,KAAK,EACL,EAAE,EACF,KAAK,EACL,iBAAiB,EACjB,IAAI,CAAC,aAAa,EAClB,OAAO,CACR,CAAC;QAEF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,CAAC;CACF;AA0CD,oEAAoE;AACpE,2EAA2E;AAC3E,0EAA0E;AAC1E,2EAA2E;AAC3E,wDAAwD;AACxD,MAAM,UAAU,kBAAkB,CAAC,OAAkB,UAAU;IAC7D,MAAM,OAAO,GAAG,aAAa,CAA0C,YAAY,CAAC,CAAC;IACpF,OAA8D,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAChF,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,93 @@
1
+ import type { QueueProps } from "aws-cdk-lib/aws-sqs";
2
+ import type { QueueAlarmConfig } from "./queue-alarm-config.js";
3
+ /**
4
+ * A queue name for a FIFO queue. AWS requires the name of a FIFO queue to
5
+ * end in `.fifo`, so the constraint is expressed in the type — a
6
+ * non-conforming literal is a compile error at the call site rather than
7
+ * a synth failure. (Unresolved tokens are not supported as FIFO queue
8
+ * names by the CDK `Queue` construct itself.)
9
+ *
10
+ * @see https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html
11
+ */
12
+ export type FifoQueueName = `${string}.fifo`;
13
+ /**
14
+ * The {@link QueueProps} keys that only have meaning on a FIFO queue.
15
+ * These are omitted from the standard queue builder's prop surface and
16
+ * guarded at build time, so a queue with FIFO behaviour is always an
17
+ * explicit choice of the FIFO-aware entry points.
18
+ */
19
+ export declare const FIFO_ONLY_PROP_KEYS: readonly ["fifo", "contentBasedDeduplication", "deduplicationScope", "fifoThroughputLimit"];
20
+ /** Union of the FIFO-only {@link QueueProps} keys. */
21
+ export type FifoOnlyPropKey = (typeof FIFO_ONLY_PROP_KEYS)[number];
22
+ /**
23
+ * Builder-only props every queue builder in this package layers on top
24
+ * of the CDK {@link QueueProps}. Defined once so the builders and the
25
+ * shared build core agree on what must be stripped before the props
26
+ * reach the `Queue` construct.
27
+ */
28
+ export interface QueueBuilderExtensionProps {
29
+ /**
30
+ * Configuration for AWS-recommended CloudWatch alarms.
31
+ *
32
+ * By default, the builder creates recommended alarms with sensible
33
+ * thresholds for every applicable metric — which alarms apply depends
34
+ * on the queue's role (primary vs. dead-letter). Individual alarms can
35
+ * be customized or disabled. Set to `false` to disable all alarms.
36
+ *
37
+ * No alarm actions are configured by default since notification
38
+ * methods are user-specific. Access alarms from the build result
39
+ * or use an `afterBuild` hook to apply actions.
40
+ *
41
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#SQS
42
+ */
43
+ recommendedAlarms?: QueueAlarmConfig | false;
44
+ }
45
+ /**
46
+ * Prop surface of `createQueueBuilder()` / `createQueueBuilder("standard")`:
47
+ * every CDK {@link QueueProps} property except the FIFO-only ones — a
48
+ * queue with FIFO behaviour is an explicit role choice
49
+ * (`createQueueBuilder("fifo")`), not a prop.
50
+ */
51
+ export interface QueueBuilderProps extends Omit<QueueProps, FifoOnlyPropKey>, QueueBuilderExtensionProps {
52
+ }
53
+ /**
54
+ * Prop surface of `createQueueBuilder("fifo")`. `fifo` itself is not
55
+ * settable — the role is the switch — and `queueName` is typed as
56
+ * {@link FifoQueueName}, so a name missing the AWS-required `.fifo`
57
+ * suffix is a compile error rather than a synth failure.
58
+ */
59
+ export interface FifoQueueBuilderProps extends Omit<QueueProps, "fifo" | "queueName">, QueueBuilderExtensionProps {
60
+ /**
61
+ * Physical name of the FIFO queue. Must end in `.fifo` (AWS
62
+ * requirement, enforced by the type and validated at build for
63
+ * untyped callers). Omit to let CloudFormation generate a valid name.
64
+ */
65
+ queueName?: FifoQueueName;
66
+ }
67
+ /**
68
+ * Prop surface of `createQueueBuilder("dlq")`: the standard surface (no
69
+ * FIFO-only props — a FIFO dead-letter queue is its own role,
70
+ * `"fifo-dlq"`) minus `deadLetterQueue`, because a dead-letter queue is
71
+ * the terminal destination for failed messages and must not carry its
72
+ * own redrive policy.
73
+ */
74
+ export type DlqQueueBuilderProps = Omit<QueueBuilderProps, "deadLetterQueue">;
75
+ /**
76
+ * Prop surface of `createQueueBuilder("fifo-dlq")`: the FIFO surface
77
+ * (suffix-typed `queueName`, no settable `fifo`) minus
78
+ * `deadLetterQueue`, for the dead-letter queue of a FIFO source — AWS
79
+ * requires it to itself be FIFO.
80
+ */
81
+ export type FifoDlqQueueBuilderProps = Omit<FifoQueueBuilderProps, "deadLetterQueue">;
82
+ /**
83
+ * Maps each {@link QueueRole} to its prop surface. `createQueueBuilder`
84
+ * uses this to give every role an exact fluent API — props that don't
85
+ * apply to a role simply don't exist on its builder type.
86
+ */
87
+ export interface QueueBuilderPropsByRole {
88
+ standard: QueueBuilderProps;
89
+ fifo: FifoQueueBuilderProps;
90
+ dlq: DlqQueueBuilderProps;
91
+ "fifo-dlq": FifoDlqQueueBuilderProps;
92
+ }
93
+ //# sourceMappingURL=queue-props.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-props.d.ts","sourceRoot":"","sources":["../../src/queue-props.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,GAAG,MAAM,OAAO,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,6FAKkB,CAAC;AAEnD,sDAAsD;AACtD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;;;;;;OAaG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;CAC9C;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBACf,SAAQ,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,EAAE,0BAA0B;CAAG;AAE1E;;;;;GAKG;AACH,MAAM,WAAW,qBACf,SAAQ,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAAC,EAAE,0BAA0B;IAC1E;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,CAAC;AAEtF;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,GAAG,EAAE,oBAAoB,CAAC;IAC1B,UAAU,EAAE,wBAAwB,CAAC;CACtC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The {@link QueueProps} keys that only have meaning on a FIFO queue.
3
+ * These are omitted from the standard queue builder's prop surface and
4
+ * guarded at build time, so a queue with FIFO behaviour is always an
5
+ * explicit choice of the FIFO-aware entry points.
6
+ */
7
+ export const FIFO_ONLY_PROP_KEYS = [
8
+ "fifo",
9
+ "contentBasedDeduplication",
10
+ "deduplicationScope",
11
+ "fifoThroughputLimit",
12
+ ];
13
+ //# sourceMappingURL=queue-props.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-props.js","sourceRoot":"","sources":["../../src/queue-props.ts"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,MAAM;IACN,2BAA2B;IAC3B,oBAAoB;IACpB,qBAAqB;CAC2B,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The role a queue plays in its system, chosen at the factory:
3
+ * `createQueueBuilder(role)`. The role selects the builder's prop
4
+ * surface (each role exposes only the props that apply to it), its
5
+ * defaults, its recommended-alarm profile, and its validation:
6
+ *
7
+ * - `"standard"` — a primary, consumer-fed standard queue (the
8
+ * default). FIFO-only props are excluded.
9
+ * - `"fifo"` — a primary FIFO queue: `fifo: true` always, `queueName`
10
+ * typed to require the `.fifo` suffix, high-throughput coherence
11
+ * validated.
12
+ * - `"dlq"` — a standard dead-letter queue: 14-day retention, inverted
13
+ * alarm set (any visible message alerts), no `deadLetterQueue` — a
14
+ * DLQ is a terminal destination.
15
+ * - `"fifo-dlq"` — a FIFO dead-letter queue for a FIFO source (AWS
16
+ * requires the DLQ of a FIFO queue to be FIFO): combines the FIFO
17
+ * surface with the DLQ defaults and alarms.
18
+ *
19
+ * Modeled as data rather than separate factories so that roles compose
20
+ * (`"fifo-dlq"` is a role, not a fourth entry point) and the choice is
21
+ * copy-safe, inspectable state on the builder.
22
+ */
23
+ export type QueueRole = "standard" | "fifo" | "dlq" | "fifo-dlq";
24
+ /** Whether the role builds a FIFO queue. */
25
+ export declare function isFifoRole(role: QueueRole): boolean;
26
+ /** Whether the role builds a dead-letter queue. */
27
+ export declare function isDlqRole(role: QueueRole): boolean;
28
+ //# sourceMappingURL=queue-role.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-role.d.ts","sourceRoot":"","sources":["../../src/queue-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC;AAEjE,4CAA4C;AAC5C,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAEnD;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAElD"}
@@ -0,0 +1,9 @@
1
+ /** Whether the role builds a FIFO queue. */
2
+ export function isFifoRole(role) {
3
+ return role === "fifo" || role === "fifo-dlq";
4
+ }
5
+ /** Whether the role builds a dead-letter queue. */
6
+ export function isDlqRole(role) {
7
+ return role === "dlq" || role === "fifo-dlq";
8
+ }
9
+ //# sourceMappingURL=queue-role.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-role.js","sourceRoot":"","sources":["../../src/queue-role.ts"],"names":[],"mappings":"AAwBA,4CAA4C;AAC5C,MAAM,UAAU,UAAU,CAAC,IAAe;IACxC,OAAO,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,UAAU,CAAC;AAChD,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,SAAS,CAAC,IAAe;IACvC,OAAO,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,UAAU,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { QueueProps } from "aws-cdk-lib/aws-sqs";
2
+ import type { IConstruct } from "constructs";
3
+ import { type QueueRole } from "./queue-role.js";
4
+ /**
5
+ * Runs every build-time check for a queue in the given role against its
6
+ * merged props. This is the single validation entry point — each guard
7
+ * owns its own applicability (self-gating on the role or on the props),
8
+ * so a new role or a new invariant is entirely a change to this module,
9
+ * never new branching in the builder.
10
+ */
11
+ export declare function validateQueueProps(scope: IConstruct, id: string, role: QueueRole, props: Partial<QueueProps>): void;
12
+ //# sourceMappingURL=queue-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-validation.d.ts","sourceRoot":"","sources":["../../src/queue-validation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAExE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,GACzB,IAAI,CASN"}
@@ -0,0 +1,139 @@
1
+ import { Annotations, Token } from "aws-cdk-lib";
2
+ import { DeduplicationScope, FifoThroughputLimit } from "aws-cdk-lib/aws-sqs";
3
+ import { FIFO_ONLY_PROP_KEYS } from "./queue-props.js";
4
+ import { isDlqRole, isFifoRole } from "./queue-role.js";
5
+ /**
6
+ * Runs every build-time check for a queue in the given role against its
7
+ * merged props. This is the single validation entry point — each guard
8
+ * owns its own applicability (self-gating on the role or on the props),
9
+ * so a new role or a new invariant is entirely a change to this module,
10
+ * never new branching in the builder.
11
+ */
12
+ export function validateQueueProps(scope, id, role, props) {
13
+ if (!isFifoRole(role))
14
+ throwIfFifoPropsOnNonFifoRole(id, role, props);
15
+ validateFifoQueueProps(id, props);
16
+ if (isDlqRole(role)) {
17
+ throwIfRedriveOnDlqRole(id, role, props);
18
+ }
19
+ else {
20
+ throwIfRedriveTargetFifoMismatch(id, isFifoRole(role), props.deadLetterQueue);
21
+ warnIfLowMaxReceiveCount(scope, id, props);
22
+ }
23
+ }
24
+ /**
25
+ * AWS-recommended minimum for `maxReceiveCount` on an SQS redrive
26
+ * policy. A consumer needs a few retries before SQS gives up and
27
+ * forwards the message to the dead-letter queue; anything below this
28
+ * tends to surface as a flood of "poison" messages from transient
29
+ * errors that would have succeeded on retry.
30
+ *
31
+ * @see https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html
32
+ */
33
+ const RECOMMENDED_MIN_MAX_RECEIVE_COUNT = 5;
34
+ /**
35
+ * Annotates `scope` with a non-fatal warning when a redrive policy is
36
+ * configured with `maxReceiveCount` below the AWS-recommended floor
37
+ * of {@link RECOMMENDED_MIN_MAX_RECEIVE_COUNT}.
38
+ *
39
+ * The builder owns the redrive policy directly, so this is a true
40
+ * check rather than a contextual reminder — the actual configured
41
+ * value is compared. Short-circuits on unresolved tokens so stacks
42
+ * that thread `maxReceiveCount` through CFN parameters aren't spammed.
43
+ */
44
+ function warnIfLowMaxReceiveCount(scope, id, props) {
45
+ const dlq = props.deadLetterQueue;
46
+ if (!dlq)
47
+ return;
48
+ const maxReceiveCount = dlq.maxReceiveCount;
49
+ if (Token.isUnresolved(maxReceiveCount))
50
+ return;
51
+ if (maxReceiveCount >= RECOMMENDED_MIN_MAX_RECEIVE_COUNT)
52
+ return;
53
+ Annotations.of(scope).addWarningV2("@composurecdk/sqs:redrive-low-max-receive-count", `QueueBuilder "${id}": redrive policy maxReceiveCount is ${String(maxReceiveCount)}; ` +
54
+ `AWS recommends >= ${String(RECOMMENDED_MIN_MAX_RECEIVE_COUNT)} so the consumer ` +
55
+ `has room to retry before messages hit the dead-letter queue. ` +
56
+ `See https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html`);
57
+ }
58
+ /**
59
+ * Throws when a FIFO-only prop reaches a non-FIFO role — the role's
60
+ * typed surface omits them, so this catches untyped (JavaScript)
61
+ * callers and points them at the FIFO roles instead of letting the
62
+ * queue synth with primary-queue alarm defaults that don't fit a FIFO
63
+ * queue.
64
+ */
65
+ function throwIfFifoPropsOnNonFifoRole(id, role, props) {
66
+ for (const key of FIFO_ONLY_PROP_KEYS) {
67
+ if (props[key] === undefined)
68
+ continue;
69
+ throw new Error(`QueueBuilder "${id}": "${key}" is FIFO-specific and not supported on role ` +
70
+ `"${role}". Create the builder with ` +
71
+ `createQueueBuilder("${isDlqRole(role) ? "fifo-dlq" : "fifo"}") instead.`);
72
+ }
73
+ }
74
+ /**
75
+ * Validates the FIFO-specific configuration invariants that would
76
+ * otherwise surface as a synth or deploy failure:
77
+ *
78
+ * - A non-token `queueName` must end in `.fifo` (AWS requirement).
79
+ * - High-throughput mode (`fifoThroughputLimit: PER_MESSAGE_GROUP_ID`)
80
+ * requires `deduplicationScope: MESSAGE_GROUP`.
81
+ *
82
+ * No-op unless `props.fifo` is set (the FIFO roles merge `fifo: true`
83
+ * before calling), so every role calls it unconditionally — the
84
+ * validator owns both the invariants and their applicability.
85
+ *
86
+ * These are configuration errors, not advisory best practice, so they
87
+ * throw (unlike the `maxReceiveCount` warning).
88
+ *
89
+ * @see https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/high-throughput-fifo.html
90
+ */
91
+ function validateFifoQueueProps(id, props) {
92
+ const { fifo, queueName, fifoThroughputLimit, deduplicationScope } = props;
93
+ if (!fifo)
94
+ return;
95
+ if (queueName !== undefined && !Token.isUnresolved(queueName) && !queueName.endsWith(".fifo")) {
96
+ throw new Error(`QueueBuilder "${id}": FIFO queues require a queueName ending in ".fifo"; ` +
97
+ `got "${queueName}". Omit queueName to let CloudFormation generate one.`);
98
+ }
99
+ if (fifoThroughputLimit === FifoThroughputLimit.PER_MESSAGE_GROUP_ID &&
100
+ deduplicationScope !== DeduplicationScope.MESSAGE_GROUP) {
101
+ throw new Error(`QueueBuilder "${id}": fifoThroughputLimit=PER_MESSAGE_GROUP_ID (high-throughput ` +
102
+ `FIFO) requires deduplicationScope=MESSAGE_GROUP. ` +
103
+ `See https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/high-throughput-fifo.html`);
104
+ }
105
+ }
106
+ /**
107
+ * Throws when a queue's redrive target does not match its own FIFO-ness.
108
+ * AWS requires the dead-letter queue of a FIFO queue to be FIFO and the
109
+ * dead-letter queue of a standard queue to be standard; the mismatch
110
+ * otherwise fails at deploy time, after a successful synth.
111
+ *
112
+ * @see https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html
113
+ */
114
+ function throwIfRedriveTargetFifoMismatch(id, fifo, deadLetterQueue) {
115
+ if (!deadLetterQueue)
116
+ return;
117
+ if (deadLetterQueue.queue.fifo === fifo)
118
+ return;
119
+ const [queueKind, targetKind] = fifo ? ["FIFO", "standard"] : ["standard", "FIFO"];
120
+ throw new Error(`QueueBuilder "${id}": a ${queueKind} queue cannot redrive to the ${targetKind} ` +
121
+ `dead-letter queue "${deadLetterQueue.queue.node.id}" — AWS requires the ` +
122
+ `dead-letter queue to match the source queue's type. ` +
123
+ `See https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html`);
124
+ }
125
+ /**
126
+ * Throws when a dead-letter-role queue is given its own
127
+ * `deadLetterQueue` redrive policy — a DLQ is the terminal destination
128
+ * for failed messages; a queue that redrives elsewhere is a primary
129
+ * queue and belongs to the `"standard"` or `"fifo"` role.
130
+ */
131
+ function throwIfRedriveOnDlqRole(id, role, props) {
132
+ if (!props.deadLetterQueue)
133
+ return;
134
+ throw new Error(`QueueBuilder "${id}": deadLetterQueue is not supported on role "${role}" — a ` +
135
+ `dead-letter queue is the terminal destination for failed messages. If this queue ` +
136
+ `needs its own redrive policy it is a primary queue: create the builder with ` +
137
+ `createQueueBuilder("${isFifoRole(role) ? "fifo" : "standard"}").`);
138
+ }
139
+ //# sourceMappingURL=queue-validation.js.map