lambda_loadout 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: de1d78c715119ebec2046c1cb5e16d8bdae6c33058f86c879186b172cb8d0118
4
+ data.tar.gz: 7f18ba031fafe3230594917e841bc22b4c24ca4fd02c50bb4daf1b60b2b6b6b0
5
+ SHA512:
6
+ metadata.gz: 105685b48b4d49732fc10ebf173792812d3ef25d638c46fde658edec4662114773d0aacee3e3c3896dcb22342f6e8762e25a2db84d0d89ee9bbc95dedb9d0969
7
+ data.tar.gz: 554ef9161c2aea601fbf8f9019d507ab05cbce82e606b516e0590718ced36ee764cf9650c1184de0fc9d771af9739afb93e212ac349612eea235e8729705694f
checksums.yaml.gz.sig ADDED
Binary file
data/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.0.1] - 2026-06-09
11
+
12
+ ### Added
13
+ - Initial RubyGems release of Lambda Loadout
14
+ - CloudWatch Metrics with EMF (Embedded Metric Format) support
15
+ - Metric creation with units and dimensions
16
+ - High-resolution metrics (1-second granularity)
17
+ - Metadata support for searchable fields
18
+ - Custom timestamp support
19
+ - Automatic metric batching (up to 100 metrics per EMF object)
20
+ - Structured JSON logging
21
+ - Multiple log levels (debug, info, warn, error, fatal)
22
+ - Lambda context injection
23
+ - Persistent fields support
24
+ - Exception logging with stack traces
25
+ - Sampling support for debug logs
26
+ - Error Notification System via SNS
27
+ - Rich email notifications with error details, stack traces, and request context
28
+ - Deep links to CloudWatch Logs Insights and Log streams
29
+ - Support for API Gateway, SQS, SNS, DynamoDB Streams, and EventBridge events
30
+ - Graceful fallback if notification sending fails
31
+ - Error handling and alerting
32
+ - ErrorHandler class for automatic error capture
33
+ - AlarmConfig for generating CloudWatch Alarm definitions
34
+ - CloudFormation and Terraform export support
35
+ - Lambda middleware pattern
36
+ - `with_observability` helper method
37
+ - `LambdaLoadout::Handler` DSL for simplified integration
38
+ - Cold start tracking
39
+ - Automatic cold start metric capture
40
+ - Per-function cold start tracking
41
+ - Rake tasks for Lambda layer management
42
+ - `rake layer:build` — builds lambda-loadout-layer.zip
43
+ - `rake layer:publish` — builds + publishes to AWS Lambda
44
+ - `rake layer:clean` — removes build artifacts
45
+ - Gem signing with Stowzilla cert chain
46
+ - GitHub Actions CI (test matrix Ruby 3.2/3.3/3.4, lint, security, auto-tag release)
47
+ - Comprehensive documentation and examples
48
+
49
+ [Unreleased]: https://github.com/stowzilla/lambda-loadout/compare/v0.0.1...HEAD
50
+ [0.0.1]: https://github.com/stowzilla/lambda-loadout/releases/tag/v0.0.1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stowzilla Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,499 @@
1
+ # Lambda Loadout
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/lambda_loadout.svg)](https://rubygems.org/gems/lambda_loadout)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D3.2-ruby.svg)](https://www.ruby-lang.org/)
6
+
7
+ **AWS Lambda Powertools for Ruby** — A developer toolkit to implement serverless best practices and increase developer velocity.
8
+
9
+ Lambda Loadout provides structured logging, CloudWatch metrics via Embedded Metric Format (EMF), error handling, error notifications via SNS, and alerting for AWS Lambda functions. Inspired by [AWS Lambda Powertools for Python](https://github.com/aws-powertools/powertools-lambda-python).
10
+
11
+ ## Features
12
+
13
+ - **CloudWatch Metrics (EMF)** — Custom metrics via CloudWatch Embedded Metric Format (zero API calls, zero latency overhead)
14
+ - **Structured Logging** — JSON structured logging with automatic Lambda context enrichment
15
+ - **Error Notifications** — Detailed error alerts via SNS with CloudWatch deep links and event source detection
16
+ - **Error Handling & Alerting** — Automatic error capture with CloudWatch alarm configuration helpers (CloudFormation & Terraform)
17
+ - **Cold Start Tracking** — Built-in cold start metric capture
18
+ - **Middleware Pattern** — Clean `with_observability` wrapper and `Handler` DSL for Ruby Lambda handlers
19
+ - **Global Configuration** — Module-level API for shared logger/metrics instances
20
+ - **Lambda Layer Support** — Build and publish as a Lambda layer via Rake tasks
21
+
22
+ ## Installation
23
+
24
+ Add to your Lambda function's Gemfile:
25
+
26
+ ```ruby
27
+ gem 'lambda_loadout'
28
+ ```
29
+
30
+ Or install directly:
31
+
32
+ ```bash
33
+ gem install lambda_loadout
34
+ ```
35
+
36
+ ### Dependencies
37
+
38
+ - `json` (~> 2.0) — JSON serialization (Ruby stdlib)
39
+ - `aws-sdk-sns` (~> 1.0) — SNS error notifications
40
+
41
+ ## Quick Start
42
+
43
+ ### Basic Usage
44
+
45
+ ```ruby
46
+ require 'lambda_loadout'
47
+
48
+ LOGGER = LambdaLoadout::Logger.new(service: "payment")
49
+ METRICS = LambdaLoadout::Metrics.new(namespace: "MyApp", service: "payment")
50
+
51
+ def lambda_handler(event:, context:)
52
+ LambdaLoadout.with_logging_and_metrics(LOGGER, METRICS, context) do
53
+ LOGGER.info("Processing payment", order_id: event['orderId'])
54
+ METRICS.add_metric(name: "PaymentProcessed", unit: "Count", value: 1)
55
+ METRICS.add_dimension(name: "payment_type", value: event['type'])
56
+
57
+ { statusCode: 200, body: "Payment processed" }
58
+ end
59
+ end
60
+ ```
61
+
62
+ ### With Error Notifications
63
+
64
+ ```ruby
65
+ def lambda_handler(event:, context:)
66
+ LambdaLoadout.with_logging_and_metrics(
67
+ LOGGER, METRICS, context,
68
+ event: event,
69
+ error_notification_config: { sns_topic_arn: ENV['ERROR_NOTIFICATION_TOPIC_ARN'] }
70
+ ) do
71
+ process_payment(event)
72
+ { statusCode: 200, body: "Success" }
73
+ end
74
+ end
75
+ ```
76
+
77
+ When an error occurs, the `ErrorNotifier` sends a detailed SNS message including:
78
+ - Error class, message, and stack trace (first 15 lines)
79
+ - Lambda request context (function name, request ID, memory, remaining time)
80
+ - Event source detection (API Gateway, SQS, SNS, DynamoDB Streams, EventBridge)
81
+ - Deep links to CloudWatch Logs Insights (pre-filtered query) and log streams
82
+ - JSON-formatted error data for programmatic consumption
83
+
84
+ Notification failures are caught and logged — they won't break your Lambda execution.
85
+
86
+ ### Using Middleware Pattern
87
+
88
+ ```ruby
89
+ require 'lambda_loadout'
90
+
91
+ class PaymentHandler
92
+ include LambdaLoadout::Middleware
93
+
94
+ def initialize
95
+ @logger = LambdaLoadout::Logger.new(service: "payment")
96
+ @metrics = LambdaLoadout::Metrics.new(namespace: "MyApp", service: "payment")
97
+ end
98
+
99
+ def call(event:, context:)
100
+ with_observability(context) do
101
+ @logger.info("Processing payment", event: event)
102
+ result = process_payment(event)
103
+ @metrics.add_metric(name: "PaymentProcessed", unit: "Count", value: 1)
104
+ { statusCode: 200, body: result.to_json }
105
+ end
106
+ end
107
+ end
108
+
109
+ HANDLER = PaymentHandler.new
110
+
111
+ def lambda_handler(event:, context:)
112
+ HANDLER.call(event: event, context: context)
113
+ end
114
+ ```
115
+
116
+ ### Using Handler DSL
117
+
118
+ ```ruby
119
+ require 'lambda_loadout'
120
+
121
+ LambdaLoadout::Handler.configure do |config|
122
+ config.service = "payment"
123
+ config.namespace = "MyApp"
124
+ config.log_level = :info
125
+ config.capture_cold_start = true
126
+ end
127
+
128
+ def lambda_handler(event:, context:)
129
+ LambdaLoadout::Handler.call(event, context) do |logger, metrics|
130
+ logger.info("Processing event", event_type: event['type'])
131
+ metrics.add_metric(name: "EventProcessed", unit: "Count", value: 1)
132
+ { statusCode: 200, body: "OK" }
133
+ end
134
+ end
135
+ ```
136
+
137
+ ### Global Configuration
138
+
139
+ ```ruby
140
+ require 'lambda_loadout'
141
+
142
+ LambdaLoadout.configure do |config|
143
+ config.service = "payment-api"
144
+ config.namespace = "MyApp"
145
+ config.log_level = :debug
146
+ end
147
+
148
+ # Access global instances anywhere
149
+ LambdaLoadout.logger.info("Starting up")
150
+ LambdaLoadout.metrics.add_metric(name: "Boot", unit: "Count", value: 1)
151
+ ```
152
+
153
+ ## CloudWatch Metrics (EMF)
154
+
155
+ Metrics are published via CloudWatch Embedded Metric Format — structured JSON written to stdout that CloudWatch automatically extracts. No `PutMetricData` API calls, no additional latency.
156
+
157
+ ### Creating Metrics
158
+
159
+ ```ruby
160
+ metrics = LambdaLoadout::Metrics.new(namespace: "MyApp", service: "payment")
161
+
162
+ metrics.add_metric(name: "BookingConfirmation", unit: "Count", value: 1)
163
+ metrics.add_metric(name: "ResponseTime", unit: "Milliseconds", value: 145.5)
164
+ metrics.add_dimension(name: "environment", value: "production")
165
+ metrics.add_metadata(key: "booking_id", value: "abc-123")
166
+ metrics.flush
167
+ ```
168
+
169
+ ### High-Resolution Metrics
170
+
171
+ ```ruby
172
+ metrics.add_metric(name: "HighPrecisionMetric", unit: "Count", value: 1, resolution: 1)
173
+ ```
174
+
175
+ ### Default Dimensions
176
+
177
+ ```ruby
178
+ metrics.set_default_dimensions(environment: "production", region: "us-east-1")
179
+ # These persist across flushes
180
+ ```
181
+
182
+ ### Custom Timestamps
183
+
184
+ ```ruby
185
+ metrics.set_timestamp(Time.now) # Time object
186
+ metrics.set_timestamp(1699876543000) # Epoch milliseconds
187
+ # Validates within CloudWatch limits (14 days past, 2 hours future)
188
+ ```
189
+
190
+ ### Auto-Flush
191
+
192
+ Metrics automatically flush when the 100-metric limit is reached. You can also call `metrics.flush` manually or rely on the `with_logging_and_metrics` / `with_observability` wrappers to flush in their `ensure` block.
193
+
194
+ ### Supported Units
195
+
196
+ `Count`, `Seconds`, `Milliseconds`, `Microseconds`, `Bytes`, `Kilobytes`, `Megabytes`, `Gigabytes`, `Terabytes`, `Bits`, `Kilobits`, `Megabits`, `Gigabits`, `Terabits`, `Percent`, `Count/Second`, `Bytes/Second`, `Kilobytes/Second`, `Megabytes/Second`, `Gigabytes/Second`, `Terabytes/Second`, `Bits/Second`, `Kilobits/Second`, `Megabits/Second`, `Gigabits/Second`, `Terabits/Second`, `None`
197
+
198
+ ### EMF Output Example
199
+
200
+ ```json
201
+ {
202
+ "_aws": {
203
+ "Timestamp": 1699876543000,
204
+ "CloudWatchMetrics": [{
205
+ "Namespace": "MyApp",
206
+ "Dimensions": [["service", "environment"]],
207
+ "Metrics": [
208
+ {"Name": "PaymentProcessed", "Unit": "Count"},
209
+ {"Name": "ResponseTime", "Unit": "Milliseconds"}
210
+ ]
211
+ }]
212
+ },
213
+ "service": "payment",
214
+ "environment": "production",
215
+ "PaymentProcessed": 1.0,
216
+ "ResponseTime": 145.5,
217
+ "booking_id": "abc-123"
218
+ }
219
+ ```
220
+
221
+ ## Structured Logging
222
+
223
+ ### Basic Logging
224
+
225
+ ```ruby
226
+ logger = LambdaLoadout::Logger.new(service: "payment", level: :info)
227
+
228
+ logger.info("Payment processed", order_id: "12345", amount: 99.99)
229
+ # => {"level":"INFO","timestamp":"2025-11-13T12:00:00.000Z","message":"Payment processed","service":"payment","order_id":"12345","amount":99.99}
230
+ ```
231
+
232
+ ### Lambda Context Injection
233
+
234
+ ```ruby
235
+ def lambda_handler(event:, context:)
236
+ logger.inject_lambda_context(context)
237
+ logger.info("Processing request")
238
+ # Output includes: function_name, function_version, function_request_id, function_memory_size, cold_start
239
+ end
240
+ ```
241
+
242
+ ### Exception Logging
243
+
244
+ ```ruby
245
+ begin
246
+ risky_operation()
247
+ rescue StandardError => e
248
+ logger.error("Operation failed", e, order_id: order_id)
249
+ # Automatically includes error message, error_class, and backtrace (first 10 lines)
250
+
251
+ # Or use the dedicated exception method
252
+ logger.exception(e, message: "Operation failed", order_id: order_id)
253
+ end
254
+ ```
255
+
256
+ ### Persistent Fields
257
+
258
+ ```ruby
259
+ logger.append_keys(correlation_id: "abc-123", tenant_id: "tenant-1")
260
+ logger.info("Event 1") # Includes correlation_id and tenant_id
261
+
262
+ logger.remove_keys(:tenant_id)
263
+ logger.info("Event 2") # Only includes correlation_id
264
+ ```
265
+
266
+ ### Debug Log Sampling
267
+
268
+ ```ruby
269
+ logger = LambdaLoadout::Logger.new(service: "payment", level: :debug, sampling_rate: 0.1)
270
+ # Only 10% of debug logs will be emitted
271
+ ```
272
+
273
+ ### Log Levels
274
+
275
+ `debug`, `info`, `warn`, `error`, `fatal`
276
+
277
+ ## Error Notifications via SNS
278
+
279
+ Sends rich error alerts when Lambda functions fail.
280
+
281
+ ### Standalone Usage
282
+
283
+ ```ruby
284
+ notifier = LambdaLoadout::ErrorNotifier.new(
285
+ sns_topic_arn: ENV['ERROR_NOTIFICATION_TOPIC_ARN'],
286
+ logger: logger,
287
+ region: 'us-east-1' # optional, defaults to AWS_REGION env var
288
+ )
289
+
290
+ notifier.notify(error: e, context: context, event: event)
291
+ ```
292
+
293
+ ### Integrated Usage
294
+
295
+ Pass `error_notification_config` to `with_logging_and_metrics` (see Quick Start above). Notifications are sent automatically on unhandled exceptions.
296
+
297
+ ### What's Included in Each Notification
298
+
299
+ - Error class, message, and stack trace (first 15 lines)
300
+ - Lambda request context (function name, request ID, memory, remaining time)
301
+ - Event source detection (API Gateway, SQS, SNS, DynamoDB Streams, EventBridge)
302
+ - Deep links to CloudWatch Logs Insights (pre-filtered query) and log streams
303
+ - JSON-formatted error data for programmatic consumption
304
+
305
+ ## Error Handling & Alarms
306
+
307
+ ### Automatic Error Capture
308
+
309
+ ```ruby
310
+ handler = LambdaLoadout::ErrorHandler.new(
311
+ logger: logger,
312
+ metrics: metrics,
313
+ capture_stack_trace: true,
314
+ error_metric_name: "LambdaError" # default
315
+ )
316
+
317
+ def lambda_handler(event:, context:)
318
+ handler.handle(context) do
319
+ process_event(event)
320
+ end
321
+ end
322
+ ```
323
+
324
+ ### CloudWatch Alarm Configuration
325
+
326
+ Generate CloudFormation or Terraform for alarms:
327
+
328
+ ```ruby
329
+ alarm = LambdaLoadout::AlarmConfig.new(
330
+ metric_name: "LambdaError",
331
+ namespace: "MyApp",
332
+ threshold: 1,
333
+ evaluation_periods: 1,
334
+ period: 60,
335
+ statistic: "Sum",
336
+ comparison_operator: "GreaterThanOrEqualToThreshold"
337
+ )
338
+
339
+ puts alarm.to_cloudformation(
340
+ alarm_name: "PaymentErrorAlarm",
341
+ sns_topic_arn: "arn:aws:sns:us-east-1:123456789012:alerts",
342
+ dimensions: { service: "payment" }
343
+ )
344
+
345
+ puts alarm.to_terraform(
346
+ resource_name: "payment_error_alarm",
347
+ sns_topic_arn: "arn:aws:sns:us-east-1:123456789012:alerts",
348
+ dimensions: { service: "payment" }
349
+ )
350
+ ```
351
+
352
+ ## Lambda Layer
353
+
354
+ Lambda Loadout can be published as a Lambda layer so your functions don't need to bundle it in their deployment packages. This is the recommended approach for teams sharing the gem across multiple Lambda functions.
355
+
356
+ ### Rake Tasks
357
+
358
+ ```bash
359
+ # Build the layer zip
360
+ bundle exec rake layer:build
361
+
362
+ # Build and publish to AWS (requires configured AWS CLI)
363
+ bundle exec rake layer:publish
364
+
365
+ # Clean build artifacts
366
+ bundle exec rake layer:clean
367
+ ```
368
+
369
+ The layer targets the `ruby3.4` runtime. After publishing, add the returned `LayerVersionArn` to your Lambda function configuration.
370
+
371
+ ### Shell Scripts (alternative)
372
+
373
+ ```bash
374
+ ./scripts/build_layer.sh # Build only
375
+ ./scripts/publish_layer.sh # Publish (requires prior build)
376
+ ./scripts/release.sh # Build + publish interactively
377
+ ```
378
+
379
+ ### Using the Layer in Your Lambda
380
+
381
+ **Terraform:**
382
+
383
+ ```hcl
384
+ resource "aws_lambda_function" "my_function" {
385
+ # ...
386
+ layers = ["arn:aws:lambda:us-east-1:ACCOUNT:layer:lambda-loadout:VERSION"]
387
+ }
388
+ ```
389
+
390
+ **CloudFormation / SAM:**
391
+
392
+ ```yaml
393
+ MyFunction:
394
+ Type: AWS::Lambda::Function
395
+ Properties:
396
+ Layers:
397
+ - arn:aws:lambda:us-east-1:ACCOUNT:layer:lambda-loadout:VERSION
398
+ ```
399
+
400
+ ## Environment Variables
401
+
402
+ | Variable | Description |
403
+ |----------|-------------|
404
+ | `POWERTOOLS_SERVICE_NAME` | Default service name for Logger and Metrics |
405
+ | `POWERTOOLS_METRICS_NAMESPACE` | Default metrics namespace |
406
+ | `ERROR_NOTIFICATION_TOPIC_ARN` | SNS topic ARN for error notifications |
407
+ | `ENVIRONMENT` / `STAGE` | Environment name (included in error notifications) |
408
+ | `AWS_REGION` | AWS region (used by ErrorNotifier, defaults to `us-east-1`) |
409
+
410
+ ## Testing
411
+
412
+ ### Testing with Metrics
413
+
414
+ ```ruby
415
+ output = StringIO.new
416
+ metrics = LambdaLoadout::Metrics.new(namespace: "MyApp", output: output)
417
+
418
+ metrics.add_metric(name: "TestMetric", unit: "Count", value: 1)
419
+ metrics.flush
420
+
421
+ emf_output = JSON.parse(output.string)
422
+ expect(emf_output['TestMetric']).to eq(1)
423
+ ```
424
+
425
+ ### Testing with Logger
426
+
427
+ ```ruby
428
+ output = StringIO.new
429
+ logger = LambdaLoadout::Logger.new(service: "test", output: output)
430
+
431
+ logger.info("Test message", data: "value")
432
+
433
+ log_entry = JSON.parse(output.string)
434
+ expect(log_entry['message']).to eq("Test message")
435
+ ```
436
+
437
+ Both `Logger` and `Metrics` accept an `output:` parameter, making it easy to capture and assert on output in tests without mocking stdout.
438
+
439
+ ## Development
440
+
441
+ ```bash
442
+ # Install dependencies
443
+ bundle install
444
+
445
+ # Run tests
446
+ bundle exec rake spec
447
+
448
+ # Run linter
449
+ bundle exec rake rubocop
450
+
451
+ # Run both (default task)
452
+ bundle exec rake
453
+
454
+ # List all available tasks
455
+ bundle exec rake -T
456
+ ```
457
+
458
+ ## Project Structure
459
+
460
+ ```
461
+ lambda-loadout/
462
+ ├── lib/lambda_loadout/
463
+ │ ├── version.rb # Gem version
464
+ │ ├── logger.rb # Structured JSON logging
465
+ │ ├── metrics.rb # CloudWatch EMF metrics
466
+ │ ├── errors.rb # ErrorHandler, AlarmConfig, custom error classes
467
+ │ ├── error_notifier.rb # SNS error notifications with CloudWatch deep links
468
+ │ ├── middleware.rb # Middleware module + Handler DSL
469
+ │ └── global.rb # Module-level API & global config
470
+ ├── examples/ # Working Lambda handler examples
471
+ ├── spec/ # RSpec test suite
472
+ ├── scripts/ # Layer build & publish scripts
473
+ └── docs/ # Integration guide, alarm templates
474
+ ```
475
+
476
+ ## Roadmap
477
+
478
+ - [x] CloudWatch Metrics (EMF)
479
+ - [x] Structured Logging
480
+ - [x] Error Handling & Alarm Config (CloudFormation + Terraform)
481
+ - [x] Cold Start Tracking
482
+ - [x] Error Notifications via SNS
483
+ - [x] Middleware Pattern & Handler DSL
484
+ - [x] Global Configuration API
485
+ - [ ] X-Ray Tracing Integration
486
+ - [ ] Parameter Store / Secrets Manager Integration
487
+ - [ ] Idempotency Support
488
+ - [ ] Batch Processing Utilities
489
+ - [ ] Event Source Data Classes
490
+
491
+ ## Related Projects
492
+
493
+ - [AWS Lambda Powertools Python](https://github.com/aws-powertools/powertools-lambda-python)
494
+ - [AWS Lambda Powertools TypeScript](https://github.com/aws-powertools/powertools-lambda-typescript)
495
+ - [AWS Lambda Powertools Java](https://github.com/aws-powertools/powertools-lambda-java)
496
+
497
+ ## License
498
+
499
+ MIT — see [LICENSE.txt](LICENSE.txt) for details.
@@ -0,0 +1,26 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEdDCCAtygAwIBAgIBATANBgkqhkiG9w0BAQsFADBAMQ4wDAYDVQQDDAVhZ2Vu
3
+ dDEZMBcGCgmSJomT8ixkARkWCXN0b3d6aWxsYTETMBEGCgmSJomT8ixkARkWA2Nv
4
+ bTAeFw0yNjA2MDgxOTExNTlaFw0yNzA2MDgxOTExNTlaMEAxDjAMBgNVBAMMBWFn
5
+ ZW50MRkwFwYKCZImiZPyLGQBGRYJc3Rvd3ppbGxhMRMwEQYKCZImiZPyLGQBGRYD
6
+ Y29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAupBquKI/4WvXOgND
7
+ pXyqH2GllZs1wG4TWWdn/DoMg45UoCwD+AWEuGrIdInBCpPN8vEJNJWPoM/RrU+b
8
+ xRBZT4uUk00bnZRW2SYh5GJSqBoBR+rWc2DGkXyGfdRU2sQvkB0+is6ChgQ61WMM
9
+ 33LE9+loBlVsZ6EVtrc18Uh2OW0mJpe0hN2nmBrxZqqOZigxC4DKRMFHvpRkxSb6
10
+ mD4kit1AcwX9NEWJsXxrPaetL/SB/VbXaEZX93XAvp6USaXvCWt4slkDS2mIvqtn
11
+ 9DtGC43LFC7SDGbnsG9PVenQgVCi8UWFPUAab0PqZSlmi3Qlbhw8qTGPp5Cbv4vz
12
+ qjC2UGPOQigA/7lbbGRhCohMrjOVHMAQwkcgiIqtolUoYlnvPMIy+m3pdvgDv/PH
13
+ bsZGvXQ7i0458xsmp1vaKthZocVAR+GboHbuIiYPUnO45ccXUQ00x6365tTe7mZi
14
+ NvmUYdAGbQmVvFqyxF7IYA6sF74L2Lstu0knSfss557bAe1HAgMBAAGjeTB3MAkG
15
+ A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSnxTL/lNBCeLqpeVIX6AUY
16
+ kel4zjAeBgNVHREEFzAVgRNhZ2VudEBzdG93emlsbGEuY29tMB4GA1UdEgQXMBWB
17
+ E2FnZW50QHN0b3d6aWxsYS5jb20wDQYJKoZIhvcNAQELBQADggGBACm9Fjit/UCv
18
+ FxlKqeiCTIG94cIx+QrWAOJSx9knKydwUec1u04D/DbfZjTn3C2Bj227QgxeUn+6
19
+ if3e2v7zAk1896hLmGYzML0+nxQPb0vmtdLR7HETUlSKTVabcv1fbwLyjsuGrBvk
20
+ y51vOEzUEZ508a9yepLYqrQu1kOju4d57c9oA5l3H0mMKWz7av9tFj0B+STvuaWk
21
+ HRYDWc5HgOEVTyV+w0uFt2Kw4OCb8C42uSvC5RfYYtw78MSP+5Ru+LXJ7XOtmuN0
22
+ E6GVmofQ17ig9O3rgfFbMendSInrRmvPIGswvM1yivq9NOllFbdck2OJKPx6FCJF
23
+ 7SJIkXQfc9P4B5iASIV1d1FsE0YX+g3jHXPJK/4mGL5bAyBKzpMfQB/mg6vQBzkh
24
+ aOKPwcreFj7TznBl89R5tNS9wZQfPVR98zgPyocddWhK18eQNMSBUnv4eeJ8PPbk
25
+ DovL+G8ajHDZ9fjH/+GVYHEMuiVdLarXrKJpHC1VfGTTUAp4NSEpUQ==
26
+ -----END CERTIFICATE-----