vybekiit 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/bin.js +1697 -562
  2. package/dist/global-skills/add-ai/SKILL.md +1 -1
  3. package/dist/global-skills/add-analytics/SKILL.md +1 -1
  4. package/dist/global-skills/add-blog/SKILL.md +1 -1
  5. package/dist/global-skills/add-crud/SKILL.md +1 -1
  6. package/dist/global-skills/add-files/SKILL.md +1 -1
  7. package/dist/global-skills/add-images/SKILL.md +1 -1
  8. package/dist/global-skills/add-language/SKILL.md +1 -1
  9. package/dist/global-skills/add-notifications/SKILL.md +1 -1
  10. package/dist/global-skills/add-realtime/SKILL.md +1 -1
  11. package/dist/global-skills/add-route/SKILL.md +1 -1
  12. package/dist/global-skills/add-search/SKILL.md +1 -1
  13. package/dist/global-skills/add-signin/SKILL.md +1 -1
  14. package/dist/global-skills/add-teams/SKILL.md +1 -1
  15. package/dist/global-skills/add-upload/SKILL.md +1 -1
  16. package/dist/global-skills/aws-serverless/SKILL.md +44 -44
  17. package/dist/global-skills/aws-serverless/assets/powertools-handler.py +1 -2
  18. package/dist/global-skills/aws-serverless/references/api-gateway.md +470 -50
  19. package/dist/global-skills/aws-serverless/references/architecture.md +186 -47
  20. package/dist/global-skills/aws-serverless/references/concurrency.md +158 -44
  21. package/dist/global-skills/aws-serverless/references/deployment.md +1 -1
  22. package/dist/global-skills/aws-serverless/references/event-sources.md +391 -72
  23. package/dist/global-skills/aws-serverless/references/lambda.md +428 -69
  24. package/dist/global-skills/aws-serverless/references/orchestration.md +384 -65
  25. package/dist/global-skills/aws-serverless/references/production.md +415 -78
  26. package/dist/global-skills/aws-serverless/references/troubleshooting.md +626 -79
  27. package/dist/global-skills/back-up-my-code/SKILL.md +1 -1
  28. package/dist/global-skills/buy-domain/SKILL.md +1 -1
  29. package/dist/global-skills/check-safety/SKILL.md +1 -1
  30. package/dist/global-skills/configure-capabilities/SKILL.md +1 -1
  31. package/dist/global-skills/connect-account/SKILL.md +1 -1
  32. package/dist/global-skills/connect-account-backend/SKILL.md +1 -1
  33. package/dist/global-skills/design-my-data/SKILL.md +1 -1
  34. package/dist/global-skills/doctor/SKILL.md +1 -1
  35. package/dist/global-skills/feedback/SKILL.md +63 -0
  36. package/dist/global-skills/go-live/SKILL.md +1 -1
  37. package/dist/global-skills/harden/SKILL.md +1 -1
  38. package/dist/global-skills/instrument-feature-flags/references/usage.md +0 -35
  39. package/dist/global-skills/instrument-product-analytics/SKILL.md +1 -1
  40. package/dist/global-skills/instrument-product-analytics/references/android.md +0 -36
  41. package/dist/global-skills/instrument-product-analytics/references/configuration.md +0 -1
  42. package/dist/global-skills/instrument-product-analytics/references/flutter.md +0 -37
  43. package/dist/global-skills/instrument-product-analytics/references/posthog-python.md +2 -3
  44. package/dist/global-skills/instrument-product-analytics/references/usage.md +0 -35
  45. package/dist/global-skills/manifest.json +2 -1
  46. package/dist/global-skills/neon/SKILL.md +20 -27
  47. package/dist/global-skills/neon-ai-gateway/SKILL.md +2 -68
  48. package/dist/global-skills/neon-functions/SKILL.md +7 -7
  49. package/dist/global-skills/neon-object-storage/SKILL.md +2 -2
  50. package/dist/global-skills/neon-postgres/SKILL.md +5 -5
  51. package/dist/global-skills/neon-postgres-branches/SKILL.md +1 -1
  52. package/dist/global-skills/onboarding/SKILL.md +1 -1
  53. package/dist/global-skills/plan-my-idea/SKILL.md +1 -1
  54. package/dist/global-skills/publish-app/SKILL.md +1 -1
  55. package/dist/global-skills/publish-extension/SKILL.md +1 -1
  56. package/dist/global-skills/reset-password/SKILL.md +1 -1
  57. package/dist/global-skills/save-data/SKILL.md +1 -1
  58. package/dist/global-skills/setup-email/SKILL.md +1 -1
  59. package/dist/global-skills/setup-payments/SKILL.md +1 -1
  60. package/dist/global-skills/setup-sms/SKILL.md +1 -1
  61. package/dist/global-skills/sign-in-with-email-link/SKILL.md +1 -1
  62. package/dist/global-skills/sign-in-with-google/SKILL.md +1 -1
  63. package/dist/global-skills/sign-in-with-phone/SKILL.md +1 -1
  64. package/dist/global-skills/stripe-best-practices/SKILL.md +6 -11
  65. package/dist/global-skills/stripe-best-practices/references/billing.md +0 -5
  66. package/dist/global-skills/stripe-best-practices/references/payments.md +2 -4
  67. package/dist/global-skills/stripe-best-practices/references/tax.md +8 -78
  68. package/dist/global-skills/track-errors/SKILL.md +1 -1
  69. package/dist/global-skills/update-kit/SKILL.md +1 -1
  70. package/dist/global-skills/wire-auth/SKILL.md +1 -1
  71. package/dist/global-skills/wire-database/SKILL.md +1 -1
  72. package/dist/global-skills/wire-email/SKILL.md +1 -1
  73. package/dist/global-skills/wire-payments/SKILL.md +1 -1
  74. package/package.json +8 -8
  75. package/dist/global-skills/email-best-practices/.github/workflows/sync-skills.yml +0 -30
  76. package/dist/global-skills/email-best-practices/README.md +0 -63
  77. package/dist/global-skills/email-best-practices/references/accessibility.md +0 -189
  78. package/dist/global-skills/email-best-practices/references/compliance.md +0 -125
  79. package/dist/global-skills/email-best-practices/references/deliverability.md +0 -121
  80. package/dist/global-skills/email-best-practices/references/email-capture.md +0 -129
  81. package/dist/global-skills/email-best-practices/references/email-types.md +0 -173
  82. package/dist/global-skills/email-best-practices/references/list-management.md +0 -157
  83. package/dist/global-skills/email-best-practices/references/marketing-emails.md +0 -115
  84. package/dist/global-skills/email-best-practices/references/sending-reliability.md +0 -155
  85. package/dist/global-skills/email-best-practices/references/transactional-email-catalog.md +0 -418
  86. package/dist/global-skills/email-best-practices/references/transactional-emails.md +0 -92
  87. package/dist/global-skills/email-best-practices/references/webhooks-events.md +0 -167
  88. package/dist/global-skills/email-best-practices/tests/README.md +0 -35
  89. package/dist/global-skills/email-best-practices/tests/scenarios/01-spam-deliverability.md +0 -46
  90. package/dist/global-skills/email-best-practices/tests/scenarios/02-multi-region-compliance.md +0 -48
  91. package/dist/global-skills/email-best-practices/tests/scenarios/03-retry-idempotency.md +0 -36
  92. package/dist/global-skills/email-best-practices/tests/scenarios/04-webhook-bounce-handling.md +0 -52
  93. package/dist/global-skills/email-best-practices/tests/scenarios/05-new-saas-email-plan.md +0 -51
  94. package/dist/global-skills/neon-postgres/references/neon-sdk.md +0 -262
@@ -1,165 +1,484 @@
1
1
  # Lambda Event Sources Reference
2
2
 
3
- Event source mapping (ESM) config parameters, scaling numbers, and filtering gotchas. Assumes you know the basics (SNS pushes asynchronously and is a direct trigger not an ESM; `ReportBatchItemFailures` returns `{batchItemFailures: [{itemIdentifier}]}`; unmatched SQS filter messages are permanently deleted; SQS visibility timeout ≥ 6× function timeout) — this file focuses on the exact values and edge cases.
3
+ Quick reference for Lambda event source mappings (ESMs), direct triggers, filtering, and error handling.
4
4
 
5
5
  ## Contents
6
6
 
7
7
  - [SQS event source mapping](#sqs-event-source-mapping)
8
8
  - [DynamoDB Streams triggers](#dynamodb-streams-triggers)
9
+ - [SNS subscriptions](#sns-subscriptions)
9
10
  - [Event filtering](#event-filtering)
10
11
  - [Partial batch failure reporting](#partial-batch-failure-reporting)
11
- - [Error handling and concurrency](#error-handling-and-concurrency)
12
+ - [Error handling strategies](#error-handling-strategies)
12
13
 
13
14
  ---
14
15
 
15
16
  ## SQS event source mapping
16
17
 
17
- Lambda long-polls SQS and invokes your function **synchronously** with a batch.
18
+ Lambda polls SQS using long polling and invokes your function **synchronously** with a batch of messages.
19
+
20
+ ### Configuration parameters
18
21
 
19
22
  | Parameter | Default | Range / Notes |
20
23
  |-----------|---------|---------------|
21
24
  | `BatchSize` | 10 | Standard: max 10,000. FIFO: max 10 |
22
- | `MaximumBatchingWindowInSeconds` | 0 | 0–300. Not for FIFO. Requires ≥ 1s when BatchSize > 10 |
23
- | `MaximumConcurrency` | — | 2–1,000. Per-ESM cap |
25
+ | `MaximumBatchingWindowInSeconds` | 0 | 0–300. Not supported for FIFO. Requires ≥ 1s when BatchSize > 10 |
26
+ | `MaximumConcurrency` | — | 2–1,000. Per-ESM concurrency cap |
24
27
  | `ProvisionedPollerConfig.MinimumPollers` | 2 | 2–200 |
25
- | `ProvisionedPollerConfig.MaximumPollers` | 200 | 1–2,000 |
28
+ | `ProvisionedPollerConfig.MaximumPollers` | 200 | 2–2,000 |
26
29
  | `FilterCriteria` | — | Filters on `body` key only |
27
30
  | `FunctionResponseTypes` | — | Set to `ReportBatchItemFailures` |
28
31
 
29
- > **MaximumConcurrency and Provisioned Mode are mutually exclusive** on the same ESM.
32
+ > **MaximumConcurrency and Provisioned Mode are mutually exclusive.** You cannot set both on the same ESM.
33
+
34
+ ### Batching behavior
35
+
36
+ Lambda invokes when **any** condition is met:
37
+
38
+ 1. Batching window expires
39
+ 2. Batch size reached
40
+ 3. Payload reaches 6 MB
41
+
42
+ ### Scaling behavior
43
+
44
+ **Standard queues:**
45
+
46
+ - Starts with **5** concurrent invocations
47
+ - Scales up by **300/min**
48
+ - Default maximum: **1,250** concurrent invocations
49
+ - Provisioned mode: up to **20,000** (scales 3× faster at 1,000/min)
50
+
51
+ **FIFO queues:**
30
52
 
31
- Lambda invokes when **any** of: batching window expires, batch size reached, or payload hits 6 MB.
53
+ - Concurrency capped by the **lower** of: number of message group IDs or `MaximumConcurrency`
54
+ - Messages delivered in order per message group ID
32
55
 
33
- ### Scaling
56
+ ### Error handling
34
57
 
35
- **Standard queues:** concurrency **starts at 5** concurrent invocations and scales up by **~300 per minute** to a **default maximum of 1,250** — so a sudden burst (e.g. a backlog of 10,000 messages) is not absorbed immediately; it takes several minutes to ramp. For high scale-out or high-throughput workloads, use **Provisioned Mode**, which starts higher, ramps significantly faster, and reaches a much larger ceiling. The 1,250 default is also bounded by account concurrency; confirm current account limits with `aws service-quotas get-service-quota --service-code lambda`.
58
+ - Use the **SQS redrive policy** (native dead-letter queue (DLQ) on the queue) not an ESM-level DLQ
59
+ - Set visibility timeout to **≥ 6× function timeout** to prevent premature retry
60
+ - On function error, entire batch becomes visible again after visibility timeout
61
+ - On throttle, Lambda backs off; messages reappear after visibility timeout
36
62
 
37
- **FIFO queues:** concurrency capped by the **lower** of (number of message group IDs, `MaximumConcurrency`); order preserved per group ID.
63
+ ### SAM template
38
64
 
39
65
  ```yaml
40
- # SAM
41
- Events:
42
- SQSEvent:
43
- Type: SQS
44
- Properties:
45
- Queue: !GetAtt MyQueue.Arn
46
- BatchSize: 10
47
- MaximumBatchingWindowInSeconds: 5
48
- FunctionResponseTypes: [ReportBatchItemFailures]
49
- ScalingConfig:
50
- MaximumConcurrency: 50
51
- FilterCriteria:
52
- Filters:
53
- - Pattern: '{"body": {"status": ["PENDING"]}}'
66
+ MyFunction:
67
+ Type: AWS::Serverless::Function
68
+ Properties:
69
+ Handler: index.handler
70
+ Runtime: nodejs22.x
71
+ Events:
72
+ SQSEvent:
73
+ Type: SQS
74
+ Properties:
75
+ Queue: !GetAtt MyQueue.Arn
76
+ BatchSize: 10
77
+ MaximumBatchingWindowInSeconds: 5
78
+ FunctionResponseTypes:
79
+ - ReportBatchItemFailures
80
+ ScalingConfig:
81
+ MaximumConcurrency: 50
82
+ FilterCriteria:
83
+ Filters:
84
+ - Pattern: '{"body": {"status": ["PENDING"]}}'
54
85
  ```
55
86
 
56
- CDK: `fn.addEventSource(new SqsEventSource(queue, { batchSize, maxBatchingWindow, reportBatchItemFailures: true, maxConcurrency }))`. Harden the queue: `new sqs.Queue(this, 'MyQueue', { encryption: sqs.QueueEncryption.SQS_MANAGED, enforceSSL: true, ... })` (set the same on the DLQ).
87
+ ### CDK example
88
+
89
+ ```typescript
90
+ import { SqsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
91
+ import * as sqs from 'aws-cdk-lib/aws-sqs';
92
+
93
+ const dlq = new sqs.Queue(this, 'DLQ');
94
+ const queue = new sqs.Queue(this, 'MyQueue', {
95
+ visibilityTimeout: Duration.seconds(300), // 6× function timeout
96
+ deadLetterQueue: { queue: dlq, maxReceiveCount: 3 },
97
+ });
98
+
99
+ fn.addEventSource(new SqsEventSource(queue, {
100
+ batchSize: 10,
101
+ maxBatchingWindow: Duration.seconds(5),
102
+ reportBatchItemFailures: true,
103
+ maxConcurrency: 50,
104
+ }));
105
+ ```
57
106
 
58
107
  ---
59
108
 
60
109
  ## DynamoDB Streams triggers
61
110
 
62
- Lambda polls stream shards **4×/second**; invokes synchronously, in-order per partition key.
111
+ Lambda polls DynamoDB stream shards at **4 times per second**. Invokes synchronously with in-order processing at the partition-key level.
112
+
113
+ ### Configuration parameters
63
114
 
64
115
  | Parameter | Default | Range / Notes |
65
116
  |-----------|---------|---------------|
66
117
  | `BatchSize` | 100 | Max 10,000 |
118
+ | `MaximumBatchingWindowInSeconds` | 0 | 0–300 |
67
119
  | `StartingPosition` | — | `TRIM_HORIZON` (recommended) or `LATEST` |
68
120
  | `ParallelizationFactor` | 1 | 1–10. Concurrent batches per shard |
69
- | `BisectBatchOnFunctionError` | false | Split failed batch in half; does NOT consume retry quota |
121
+ | `BisectBatchOnFunctionError` | false | Split failed batch in half |
70
122
  | `MaximumRetryAttempts` | -1 (infinite) | 0–10,000 |
71
- | `MaximumRecordAgeInSeconds` | -1 (infinite) | -1 (infinite), or 60–604,800 (7 days); 0–59 rejected |
123
+ | `MaximumRecordAgeInSeconds` | -1 (infinite) | -1 to 604,800 (7 days) |
72
124
  | `DestinationConfig.OnFailure` | — | SQS, SNS, S3, or Kafka topic |
73
- | `TumblingWindowInSeconds` | — | 0–900, for stateful aggregation |
125
+ | `FilterCriteria` | — | Filters on `dynamodb` key and metadata fields (e.g., `eventName`) |
126
+ | `FunctionResponseTypes` | — | `ReportBatchItemFailures` |
127
+ | `TumblingWindowInSeconds` | — | 0–900 for stateful aggregation |
74
128
 
75
129
  ### Key behaviors
76
130
 
77
- - **Max 2 Lambda readers per shard** (single-region tables). Global tables: limit to **1**.
78
- - **TRIM_HORIZON** recommended `LATEST` may miss events during ESM creation.
79
- - 100 shards × ParallelizationFactor 10 = up to **1,000 concurrent invocations** (order maintained at partition-key level).
80
- - **Stream retention is 24 hours** a poison record can block a shard for that entire window if retries aren't bounded. Set `MaximumRetryAttempts` / `MaximumRecordAgeInSeconds` / `BisectBatchOnFunctionError`.
131
+ - **TRIM_HORIZON** recommended `LATEST` may miss events during ESM creation
132
+ - **Max 2 Lambda readers per shard** (single-region tables). Global tables: limit to 1
133
+ - **ParallelizationFactor**: 100 shards × factor 10 = up to 1,000 concurrent invocations. Order maintained at partition-key level
134
+ - **BisectBatchOnFunctionError** does NOT consume retry quota
135
+ - DynamoDB stream retention is **24 hours** — a poison record can block a shard for that entire window without retry limits
136
+
137
+ ### SAM template
81
138
 
82
139
  ```yaml
83
- # SAM
84
- Events:
85
- DynamoDBStream:
86
- Type: DynamoDB
87
- Properties:
88
- Stream: !GetAtt MyTable.StreamArn
89
- StartingPosition: TRIM_HORIZON
90
- ParallelizationFactor: 5
91
- BisectBatchOnFunctionError: true
92
- MaximumRetryAttempts: 3
93
- FunctionResponseTypes: [ReportBatchItemFailures]
94
- DestinationConfig:
95
- OnFailure:
96
- Destination: !GetAtt FailureQueue.Arn
140
+ MyFunction:
141
+ Type: AWS::Serverless::Function
142
+ Properties:
143
+ Handler: index.handler
144
+ Runtime: nodejs22.x
145
+ Events:
146
+ DDBStream:
147
+ Type: DynamoDB
148
+ Properties:
149
+ Stream: !GetAtt MyTable.StreamArn
150
+ StartingPosition: TRIM_HORIZON
151
+ BatchSize: 100
152
+ MaximumBatchingWindowInSeconds: 5
153
+ ParallelizationFactor: 5
154
+ BisectBatchOnFunctionError: true
155
+ MaximumRetryAttempts: 3
156
+ MaximumRecordAgeInSeconds: 3600
157
+ FunctionResponseTypes:
158
+ - ReportBatchItemFailures
159
+ DestinationConfig:
160
+ OnFailure:
161
+ Destination: !GetAtt FailureQueue.Arn
162
+ FilterCriteria:
163
+ Filters:
164
+ - Pattern: '{"eventName": ["INSERT"]}'
165
+ ```
166
+
167
+ ### CDK example
168
+
169
+ ```typescript
170
+ import { DynamoEventSource, SqsDlq } from 'aws-cdk-lib/aws-lambda-event-sources';
171
+ import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
172
+
173
+ const table = new dynamodb.Table(this, 'MyTable', {
174
+ partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
175
+ stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
176
+ });
177
+
178
+ fn.addEventSource(new DynamoEventSource(table, {
179
+ startingPosition: lambda.StartingPosition.TRIM_HORIZON,
180
+ batchSize: 100,
181
+ maxBatchingWindow: Duration.seconds(5),
182
+ parallelizationFactor: 5,
183
+ bisectBatchOnError: true,
184
+ retryAttempts: 3,
185
+ maxRecordAge: Duration.hours(1),
186
+ reportBatchItemFailures: true,
187
+ onFailure: new SqsDlq(dlq),
188
+ }));
97
189
  ```
98
190
 
99
- Encrypt the source table at rest — CDK `new dynamodb.Table(this, 'MyTable', { encryption: dynamodb.TableEncryption.AWS_MANAGED, ... })`, or a customer managed KMS key when compliance requires key control.
191
+ ---
192
+
193
+ ## SNS subscriptions
194
+
195
+ SNS invokes Lambda **asynchronously** — it is a **direct trigger, NOT an event source mapping**. No polling involved; SNS pushes events to Lambda.
196
+
197
+ ### Key characteristics
198
+
199
+ - **Standard topics only** (not FIFO)
200
+ - At-least-once delivery — make functions idempotent
201
+ - SNS retries at increasing intervals over several hours if Lambda is unreachable
202
+ - Cross-account subscriptions supported
203
+
204
+ ### Filter policies
205
+
206
+ Filter policies are managed by **SNS** (not Lambda `FilterCriteria`). Set `FilterPolicyScope` to control what is filtered:
207
+
208
+ | Scope | Filters on |
209
+ |-------|-----------|
210
+ | `MessageAttributes` (default) | SNS message attributes |
211
+ | `MessageBody` | JSON body content |
100
212
 
101
- SNS filter policies (not Lambda `FilterCriteria`) are SNS-managed; set `FilterPolicyScope` to `MessageAttributes` (default) or `MessageBody`.
213
+ ```json
214
+ {
215
+ "event_type": ["order_placed"],
216
+ "price_usd": [{"numeric": [">=", 100]}],
217
+ "store": [{"anything-but": "test_store"}]
218
+ }
219
+ ```
220
+
221
+ ### SAM template
222
+
223
+ ```yaml
224
+ ProcessorFunction:
225
+ Type: AWS::Serverless::Function
226
+ Properties:
227
+ Handler: processor.handler
228
+ Runtime: nodejs22.x
229
+ Events:
230
+ SNSEvent:
231
+ Type: SNS
232
+ Properties:
233
+ Topic: !Ref MyTopic
234
+ FilterPolicy:
235
+ event_type:
236
+ - order_placed
237
+ FilterPolicyScope: MessageAttributes
238
+ ```
239
+
240
+ ### CDK example
241
+
242
+ ```typescript
243
+ import * as sns from 'aws-cdk-lib/aws-sns';
244
+ import * as subscriptions from 'aws-cdk-lib/aws-sns-subscriptions';
245
+
246
+ topic.addSubscription(new subscriptions.LambdaSubscription(fn, {
247
+ filterPolicy: {
248
+ event_type: sns.SubscriptionFilter.stringFilter({
249
+ allowlist: ['order_placed'],
250
+ }),
251
+ price: sns.SubscriptionFilter.numericFilter({
252
+ greaterThanOrEqualTo: 100,
253
+ }),
254
+ },
255
+ }));
256
+ ```
102
257
 
103
258
  ---
104
259
 
105
260
  ## Event filtering
106
261
 
107
- `FilterCriteria` applies to ESMs only (not SNS/push triggers).
262
+ Lambda `FilterCriteria` applies to event source mappings only (not SNS or other push triggers).
263
+
264
+ ### Supported sources and filter keys
108
265
 
109
266
  | Source | Filter key | Notes |
110
267
  |--------|-----------|-------|
111
- | SQS | `body` | Unmatched messages **automatically (permanently) deleted** |
112
- | DynamoDB Streams | `dynamodb` + metadata (e.g. `eventName`) | **Does NOT support numeric operators** |
268
+ | SQS | `body` | Unmatched messages **automatically deleted** |
269
+ | DynamoDB Streams | `dynamodb` and metadata fields | Does **NOT** support numeric operators |
113
270
  | Kinesis | `data` | Base64-decoded before filtering |
114
271
  | MSK / Kafka | `value` | — |
272
+ | Amazon MQ | `data` | — |
115
273
 
116
- - Up to **5 filters** per ESM (request increase to 10). Multiple filters are **OR**'d; fields within one filter are **AND**'d.
117
- - **DynamoDB numeric filtering is unsupported** — numbers are stored as strings in the DynamoDB stream JSON. Use `{"S": [...]}`/`{"N": ["123"]}` string matches, not `{"numeric": [...]}`.
118
- - Format mismatch drops the record: if the incoming body is plain string but the filter is JSON (or vice versa), Lambda drops the message.
274
+ ### Filter rules
119
275
 
120
- Operators: `["value"]`, `{"equals-ignore-case"}`, `[null]`, `[""]`, `{"anything-but"}`, `{"numeric": [">", 10, "<=", 20]}`, `{"exists": true}`, `{"prefix"}`, `{"suffix"}`, `"$or": [...]`.
276
+ - Up to **5 filters** per ESM (can request increase to 10)
277
+ - Multiple filters are **ORed** — record matches if any filter matches
278
+ - Fields within a single filter are **ANDed**
279
+
280
+ ### Filter rule operators
281
+
282
+ | Operator | Syntax | Example |
283
+ |----------|--------|---------|
284
+ | Equals | `["value"]` | `"City": ["Seattle"]` |
285
+ | Equals (ignore case) | `[{"equals-ignore-case": "value"}]` | `"City": [{"equals-ignore-case": "seattle"}]` |
286
+ | Null | `[null]` | `"UserID": [null]` |
287
+ | Empty | `[""]` | `"Name": [""]` |
288
+ | Not | `[{"anything-but": ["value"]}]` | `"Weather": [{"anything-but": ["Raining"]}]` |
289
+ | Numeric equals | `[{"numeric": ["=", 100]}]` | `"Price": [{"numeric": ["=", 100]}]` |
290
+ | Numeric range | `[{"numeric": [">", 10, "<=", 20]}]` | `"Price": [{"numeric": [">", 10, "<=", 20]}]` |
291
+ | Exists | `[{"exists": true}]` | `"Field": [{"exists": true}]` |
292
+ | Prefix | `[{"prefix": "us-"}]` | `"Region": [{"prefix": "us-"}]` |
293
+ | Suffix | `[{"suffix": ".png"}]` | `"FileName": [{"suffix": ".png"}]` |
294
+ | Or (fields) | `"$or": [{...}, {...}]` | `"$or": [{"City": ["NY"]}, {"Day": ["Mon"]}]` |
295
+
296
+ > **DynamoDB filtering does NOT support numeric operators.** Numbers are stored as strings in the DynamoDB JSON record.
297
+
298
+ ### Body/data format matching
299
+
300
+ | Incoming format | Filter format | Result |
301
+ |----------------|---------------|--------|
302
+ | Plain string | Plain string | Filters normally |
303
+ | Plain string | Valid JSON | Lambda drops the message |
304
+ | Valid JSON | Plain string | Lambda drops the message |
305
+ | Valid JSON | Valid JSON | Filters normally |
306
+
307
+ ### Filter examples
121
308
 
122
309
  ```yaml
123
- # DynamoDBINSERT events only / by NewImage attribute (string match, not numeric)
310
+ # SQSfilter on body field
311
+ FilterCriteria:
312
+ Filters:
313
+ - Pattern: '{"body": {"RequestCode": ["BBBB"]}}'
314
+
315
+ # DynamoDB — INSERT events only
124
316
  FilterCriteria:
125
317
  Filters:
126
318
  - Pattern: '{"eventName": ["INSERT"]}'
319
+
320
+ # DynamoDB — filter by NewImage attribute
321
+ FilterCriteria:
322
+ Filters:
127
323
  - Pattern: '{"dynamodb": {"NewImage": {"status": {"S": ["ACTIVE"]}}}}'
324
+
325
+ # Kinesis — filter decoded data
326
+ FilterCriteria:
327
+ Filters:
328
+ - Pattern: '{"data": {"status": ["ACTIVE"]}}'
128
329
  ```
129
330
 
130
331
  ---
131
332
 
132
333
  ## Partial batch failure reporting
133
334
 
134
- Set `FunctionResponseTypes: [ReportBatchItemFailures]` and return the failed identifiers.
335
+ Enable by setting `FunctionResponseTypes` to `["ReportBatchItemFailures"]`.
336
+
337
+ ### SQS — return failed messageId values
338
+
339
+ ```javascript
340
+ export const handler = async (event) => {
341
+ const batchItemFailures = [];
342
+ for (const record of event.Records) {
343
+ try {
344
+ await processMessage(record);
345
+ } catch (error) {
346
+ batchItemFailures.push({ itemIdentifier: record.messageId });
347
+ }
348
+ }
349
+ return { batchItemFailures };
350
+ };
351
+ ```
352
+
353
+ ### Streams — return failed SequenceNumber values
354
+
355
+ For DynamoDB Streams and Kinesis, Lambda uses the **lowest sequence number** as the checkpoint and retries everything from that point.
356
+
357
+ ```javascript
358
+ export const handler = async (event) => {
359
+ for (const record of event.Records) {
360
+ try {
361
+ await processRecord(record);
362
+ } catch (e) {
363
+ return {
364
+ batchItemFailures: [
365
+ { itemIdentifier: record.dynamodb.SequenceNumber },
366
+ // Kinesis: { itemIdentifier: record.kinesis.sequenceNumber }
367
+ ],
368
+ };
369
+ }
370
+ }
371
+ return { batchItemFailures: [] };
372
+ };
373
+ ```
374
+
375
+ ### Python with Powertools Batch Processor
376
+
377
+ ```python
378
+ from aws_lambda_powertools.utilities.batch import (
379
+ BatchProcessor, EventType, process_partial_response,
380
+ )
381
+
382
+ processor = BatchProcessor(event_type=EventType.SQS)
383
+
384
+ def record_handler(record):
385
+ payload = record.body
386
+ # process payload...
387
+
388
+ def lambda_handler(event, context):
389
+ return process_partial_response(
390
+ event=event, record_handler=record_handler,
391
+ processor=processor, context=context,
392
+ )
393
+ ```
394
+
395
+ ### FIFO queue behavior
396
+
397
+ - **Stop processing after the first failure**
398
+ - Return all failed and unprocessed messages in `batchItemFailures`
399
+ - This preserves message ordering within the group
135
400
 
136
- - **SQS:** return failed `messageId` values in `batchItemFailures`.
137
- - **Streams (DynamoDB/Kinesis):** return the failed `SequenceNumber`; Lambda checkpoints at the **lowest** returned sequence number and retries everything from that point.
138
- - **FIFO:** stop after the first failure; return that message plus all unprocessed ones (preserves ordering).
401
+ ### Success/failure conditions
139
402
 
140
- Response edge cases that cause a **complete batch retry**: `itemIdentifier` empty/null, a bad key name, or any unhandled exception. An empty/null `batchItemFailures` = complete success.
403
+ | Response | Interpretation |
404
+ |----------|---------------|
405
+ | Empty `batchItemFailures` list | Complete success |
406
+ | Null `batchItemFailures` or empty `EventResponse` | Complete success |
407
+ | `itemIdentifier` is empty string or null | **Complete failure** (entire batch retried) |
408
+ | Bad key name in `itemIdentifier` | **Complete failure** |
409
+ | Unhandled exception | **Complete failure** |
141
410
 
142
- Streams interaction: an unhandled **exception** triggers `BisectBatchOnFunctionError` (no response returned, so `ReportBatchItemFailures` has no effect); a **success with `batchItemFailures`** checkpoints at the lowest failed sequence number.
411
+ ### Interaction with BisectBatchOnFunctionError (streams)
143
412
 
144
- The Powertools Batch Processor (`process_partial_response`) handles all of this prefer it over hand-rolled loops. See [assets/powertools-handler.py](../assets/powertools-handler.py).
413
+ - Function **errors** (unhandled exception): `BisectBatchOnFunctionError` splits the batch in half for retry. `ReportBatchItemFailures` has no effect since no response was returned.
414
+ - Function **succeeds** with `batchItemFailures`: Lambda checkpoints at the lowest failed sequence number and retries from that point. If `BisectBatchOnFunctionError` is also enabled, the batch is bisected at the returned sequence number.
145
415
 
146
416
  ---
147
417
 
148
- ## Error handling and concurrency
418
+ ## Error handling strategies
419
+
420
+ ### SQS
421
+
422
+ | Strategy | Configuration | When to use |
423
+ |----------|--------------|-------------|
424
+ | SQS redrive policy (DLQ) | `maxReceiveCount` on the queue | Always — catches poison messages |
425
+ | Partial batch failures | `ReportBatchItemFailures` | Batches with mix of good/bad messages |
426
+ | Visibility timeout | Set to ≥ 6× function timeout | Always — prevents premature retry |
427
+ | MaximumConcurrency | `ScalingConfig` on ESM | Protect downstream resources |
149
428
 
150
- | Source | Key strategies |
151
- |--------|---------------|
152
- | SQS | Redrive policy / DLQ (`maxReceiveCount`) always; `ReportBatchItemFailures`; visibility ≥ 6× timeout; `MaximumConcurrency` to protect downstream |
153
- | DynamoDB/Kinesis | `BisectBatchOnFunctionError`; `ReportBatchItemFailures`; `MaximumRetryAttempts` + `MaximumRecordAgeInSeconds` (prevent shard blocking); `OnFailure` destination; `ParallelizationFactor` to reduce blast radius |
429
+ ### DynamoDB Streams / Kinesis
430
+
431
+ | Strategy | Configuration | When to use |
432
+ |----------|--------------|-------------|
433
+ | BisectBatchOnFunctionError | `true` | Isolate bad records in large batches |
434
+ | Partial batch failures | `ReportBatchItemFailures` | Avoid reprocessing successful records |
435
+ | Maximum retry attempts | `MaximumRetryAttempts` | Limit retries to prevent shard blocking |
436
+ | Maximum record age | `MaximumRecordAgeInSeconds` | Skip stale records |
437
+ | On-failure destination | `DestinationConfig.OnFailure` | Capture failed records for analysis |
438
+ | Parallelization factor | `ParallelizationFactor` | Reduce blast radius per shard |
439
+
440
+ ### ESM (polling) vs direct trigger (push)
441
+
442
+ | Aspect | ESM (SQS, DDB, Kinesis) | Async push (SNS, S3) | Sync push (API Gateway) |
443
+ |--------|--------------------------|----------------------|-------------------------|
444
+ | Invocation | Synchronous (Lambda polls) | Asynchronous (service pushes) | Synchronous (service pushes) |
445
+ | Batching | Yes (configurable) | No (single event) | No (single event) |
446
+ | Event filtering | Lambda `FilterCriteria` | SNS filter policies (SNS-managed) | N/A |
447
+ | Error handling | Partial batch, bisect, retry config | 2 automatic retries, DLQ/destination | Error returned directly to caller, no automatic retry |
448
+ | Ordering | Supported (streams, FIFO) | Not guaranteed | N/A (request/response) |
154
449
 
155
450
  ### Concurrency formulas
156
451
 
157
452
  ```
158
453
  SQS (default): min(1250, MaximumConcurrency, ReservedConcurrency)
159
454
  SQS (provisioned): MaximumPollers × 10
160
- DynamoDB/Kinesis: number_of_shards × ParallelizationFactor
455
+ DDB/Kinesis: number_of_shards × ParallelizationFactor
161
456
  ```
162
457
 
163
458
  ### Idempotency
164
459
 
165
- All event sources deliver at-least-once — duplicates happen. Make handlers idempotent (Powertools Idempotency utility, keyed e.g. on SQS `messageId`). See [production.md](production.md#idempotency).
460
+ All event sources deliver at least once — duplicates can occur. Use Powertools idempotency utility:
461
+
462
+ ```python
463
+ from aws_lambda_powertools.utilities.batch import (
464
+ BatchProcessor, EventType, process_partial_response,
465
+ )
466
+ from aws_lambda_powertools.utilities.idempotency import (
467
+ IdempotencyConfig, DynamoDBPersistenceLayer, idempotent_function,
468
+ )
469
+
470
+ processor = BatchProcessor(event_type=EventType.SQS)
471
+ persistence_layer = DynamoDBPersistenceLayer(table_name="IdempotencyTable")
472
+ config = IdempotencyConfig(event_key_jmespath="messageId")
473
+
474
+ @idempotent_function(config=config, persistence_store=persistence_layer, data_keyword_argument="record")
475
+ def record_handler(record):
476
+ # process record...
477
+ pass
478
+
479
+ def lambda_handler(event, context):
480
+ return process_partial_response(
481
+ event=event, record_handler=record_handler,
482
+ processor=processor, context=context,
483
+ )
484
+ ```