diff --git a/.github/actions/rust-build/action.yml b/.github/actions/rust-build/action.yml
new file mode 100644
index 00000000..85b5c0e8
--- /dev/null
+++ b/.github/actions/rust-build/action.yml
@@ -0,0 +1,26 @@
+name: "Rust builds"
+description: "Builds, tests, and formats Rust code"
+inputs:
+ package:
+ required: true
+ description: "the Rust package to test"
+ toolchain:
+ required: true
+ description: "the Rust toolchain to use"
+
+runs:
+ using: "composite"
+ steps:
+ - uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{ inputs.toolchain }}
+ components: clippy, rustfmt
+ - uses: Swatinem/rust-cache@v2
+
+ - name: Build
+ shell: bash
+ run: cargo build --all-features --verbose --package ${{ inputs.package }}
+
+ - name: Run tests
+ shell: bash
+ run: cargo test --all-features --verbose --package ${{ inputs.package }}
diff --git a/.github/workflows/build-events.yml b/.github/workflows/build-events.yml
new file mode 100644
index 00000000..dbf9a0ae
--- /dev/null
+++ b/.github/workflows/build-events.yml
@@ -0,0 +1,28 @@
+name: Check Lambda Events
+
+on:
+ push:
+ paths:
+ - 'lambda-events/**'
+ pull_request:
+ paths:
+ - 'lambda-events/**'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ toolchain:
+ - "1.62.0" # Current MSRV
+ - stable
+ env:
+ RUST_BACKTRACE: 1
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Build events
+ uses: ./.github/actions/rust-build
+ with:
+ package: aws_lambda_events
+ toolchain: ${{ matrix.toolchain}}
diff --git a/.github/workflows/build-extension.yml b/.github/workflows/build-extension.yml
new file mode 100644
index 00000000..0905f289
--- /dev/null
+++ b/.github/workflows/build-extension.yml
@@ -0,0 +1,39 @@
+name: Check Lambda Runtime
+
+on:
+ push:
+ paths:
+ - 'lambda-runtime-api-client/**'
+ - 'lambda-extension/**'
+
+ pull_request:
+ paths:
+ - 'lambda-runtime-api-client/**'
+ - 'lambda-extension/**'
+
+
+jobs:
+ build-runtime:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ toolchain:
+ - "1.62.0" # Current MSRV
+ - stable
+ env:
+ RUST_BACKTRACE: 1
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Build Runtime API Client
+ uses: ./.github/actions/rust-build
+ with:
+ package: lambda_runtime_api_client
+ toolchain: ${{ matrix.toolchain}}
+
+
+ - name: Build Extensions runtime
+ uses: ./.github/actions/rust-build
+ with:
+ package: lambda-extension
+ toolchain: ${{ matrix.toolchain}}
diff --git a/.github/workflows/build-runtime.yml b/.github/workflows/build-runtime.yml
new file mode 100644
index 00000000..68913c95
--- /dev/null
+++ b/.github/workflows/build-runtime.yml
@@ -0,0 +1,45 @@
+name: Check Lambda Runtime
+
+on:
+ push:
+ paths:
+ - 'lambda-runtime-api-client/**'
+ - 'lambda-runtime/**'
+ - 'lambda-http/**'
+
+ pull_request:
+ paths:
+ - 'lambda-runtime-api-client/**'
+ - 'lambda-runtime/**'
+ - 'lambda-http/**'
+
+jobs:
+ build-runtime:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ toolchain:
+ - "1.62.0" # Current MSRV
+ - stable
+ env:
+ RUST_BACKTRACE: 1
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Build Runtime API Client
+ uses: ./.github/actions/rust-build
+ with:
+ package: lambda_runtime_api_client
+ toolchain: ${{ matrix.toolchain}}
+
+ - name: Build Functions runtime
+ uses: ./.github/actions/rust-build
+ with:
+ package: lambda_runtime
+ toolchain: ${{ matrix.toolchain}}
+
+ - name: Build HTTP layer
+ uses: ./.github/actions/rust-build
+ with:
+ package: lambda_http
+ toolchain: ${{ matrix.toolchain}}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
deleted file mode 100644
index 370d8249..00000000
--- a/.github/workflows/build.yml
+++ /dev/null
@@ -1,93 +0,0 @@
-name: Rust
-
-on: [push, pull_request, workflow_dispatch]
-
-jobs:
- build:
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os:
- - ubuntu-latest
- - macOS-latest
- toolchain:
- - "1.62.0" # Current MSRV
- - stable
- - beta
- - nightly
- target:
- - ""
- - x86_64-unknown-linux-musl
- include:
- - rust: nightly
- allow_failure: true
- env:
- RUST_BACKTRACE: 1
- steps:
- - uses: actions/checkout@v3
- - uses: dtolnay/rust-toolchain@master
- with:
- toolchain: ${{ matrix.toolchain }}
- - uses: Swatinem/rust-cache@v2
-
- - name: Build
- run: cargo build --all --verbose
- env:
- TARGET: ${{ matrix.target }}
- continue-on-error: ${{ matrix.allow_failure }}
- - name: Run tests
- run: cargo test --all --verbose
- env:
- TARGET: ${{ matrix.target }}
- continue-on-error: ${{ matrix.allow_failure }}
- formatting:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - uses: Swatinem/rust-cache@v2
-
- - name: Run fmt check
- run: cargo fmt --all -- --check
- - name: Run clippy check
- run: cargo clippy --all-features -- -D warnings
-
- check-examples:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - uses: Swatinem/rust-cache@v2
-
- - name: Check examples
- working-directory: examples
- shell: bash
- run: ./check-examples.sh
-
- # publish rustdoc to a gh-pages branch on pushes to main
- # this can be helpful to those depending on the mainline branch
- publish-docs:
- if: github.ref == 'refs/heads/main'
- runs-on: ubuntu-latest
- needs: [build]
- steps:
- - uses: actions/checkout@v3
- - uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - uses: Swatinem/rust-cache@v2
-
- - name: Generate Docs
- run: |
- cargo doc --no-deps
- echo "" > target/doc/index.html
- - name: Publish
- uses: peaceiris/actions-gh-pages@v3
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: ./target/doc
diff --git a/.github/workflows/check-examples.yml b/.github/workflows/check-examples.yml
new file mode 100644
index 00000000..ba7bc709
--- /dev/null
+++ b/.github/workflows/check-examples.yml
@@ -0,0 +1,16 @@
+name: Check examples
+
+on: [push, pull_request]
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@stable
+ - uses: Swatinem/rust-cache@v2
+
+ - name: Check examples
+ working-directory: examples
+ shell: bash
+ run: ./check-examples.sh
\ No newline at end of file
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
new file mode 100644
index 00000000..f18d1f83
--- /dev/null
+++ b/.github/workflows/format.yml
@@ -0,0 +1,55 @@
+name: Formatting and Linting
+
+on: [push, pull_request]
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@stable
+ - uses: Swatinem/rust-cache@v2
+
+ - name: Run fmt check
+ id: cargoFmt
+ shell: bash
+ run: cargo fmt --all -- --check
+ - name: Notify fmt check
+ if: failure() && steps.cargoFmt.outcome == 'failure'
+ uses: actions/github-script@v6
+ with:
+ script: |
+ const message = `👋 It looks like your code is not formatted like we expect.
+
+ Please run \`cargo fmt\` and push the code again.`;
+
+ await github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: message,
+ });
+ core.setFailed('It looks like there are formatting errors');
+
+ - name: Run clippy check
+ id: cargoClippy
+ shell: bash
+ run: cargo clippy --workspace --all-features -- -D warnings
+ - name: Notify fmt check
+ if: failure() && steps.cargoClippy.outcome == 'failure'
+ uses: actions/github-script@v6
+ with:
+ script: |
+ const message = `👋 It looks like your code has some linting issues.
+
+ Please run \`cargo clippy --fix\` and push the code again.`;
+
+ await github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: message,
+ });
+ core.setFailed('It looks like there are linting errors');
+
+
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 7361557e..48bcd5db 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,8 @@ members = [
"lambda-integration-tests",
"lambda-runtime-api-client",
"lambda-runtime",
- "lambda-extension"
+ "lambda-extension",
+ "lambda-events"
]
exclude = ["examples"]
diff --git a/README.md b/README.md
index 8fdd232c..157c1c98 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ This package makes it easy to run AWS Lambda Functions written in Rust. This wor
- [](https://docs.rs/lambda_runtime) **`lambda-runtime`** is a library that provides a Lambda runtime for applications written in Rust.
- [](https://docs.rs/lambda_http) **`lambda-http`** is a library that makes it easy to write API Gateway proxy event focused Lambda functions in Rust.
- [](https://docs.rs/lambda-extension) **`lambda-extension`** is a library that makes it easy to write Lambda Runtime Extensions in Rust.
+- [](https://docs.rs/aws_lambda_events) **`lambda-events`** is a library with strongly-typed Lambda event structs in Rust.
- [](https://docs.rs/lambda_runtime_api_client) **`lambda-runtime-api-client`** is a shared library between the lambda runtime and lambda extension libraries that includes a common API client to talk with the AWS Lambda Runtime API.
The Rust runtime client is an experimental package. It is subject to change and intended only for evaluation purposes.
diff --git a/examples/advanced-sqs-partial-batch-failures/Cargo.toml b/examples/advanced-sqs-partial-batch-failures/Cargo.toml
index 06e56053..0dfe49d9 100644
--- a/examples/advanced-sqs-partial-batch-failures/Cargo.toml
+++ b/examples/advanced-sqs-partial-batch-failures/Cargo.toml
@@ -8,8 +8,8 @@ serde = "^1"
serde_derive = "^1"
serde_with = { version = "^2", features = ["json"], optional = true }
serde_json = "^1"
-aws_lambda_events = "0.7.3"
-lambda_runtime = "0.7"
+aws_lambda_events = { path = "../../lambda-events" }
+lambda_runtime = { path = "../../lambda-runtime" }
tokio = { version = "1", features = ["macros"] }
futures = "0.3"
tracing = { version = "0.1", features = ["log"] }
diff --git a/examples/basic-s3-thumbnail/Cargo.toml b/examples/basic-s3-thumbnail/Cargo.toml
index dfa6d69b..0ef0d463 100644
--- a/examples/basic-s3-thumbnail/Cargo.toml
+++ b/examples/basic-s3-thumbnail/Cargo.toml
@@ -15,7 +15,7 @@ edition = "2021"
# and it will keep the alphabetic ordering for you.
[dependencies]
-aws_lambda_events = "0.7.2"
+aws_lambda_events = { path = "../../lambda-events" }
lambda_runtime = { path = "../../lambda-runtime" }
serde = "1"
tokio = { version = "1", features = ["macros"] }
diff --git a/examples/basic-sqs/Cargo.toml b/examples/basic-sqs/Cargo.toml
index 086a22dc..a1b11567 100644
--- a/examples/basic-sqs/Cargo.toml
+++ b/examples/basic-sqs/Cargo.toml
@@ -15,7 +15,7 @@ edition = "2021"
# and it will keep the alphabetic ordering for you.
[dependencies]
-aws_lambda_events = "0.7.2"
+aws_lambda_events = { path = "../../lambda-events" }
lambda_runtime = { path = "../../lambda-runtime" }
serde = "1.0.136"
tokio = { version = "1", features = ["macros"] }
diff --git a/lambda-events/Cargo.toml b/lambda-events/Cargo.toml
new file mode 100644
index 00000000..225d9d8f
--- /dev/null
+++ b/lambda-events/Cargo.toml
@@ -0,0 +1,117 @@
+[package]
+name = "aws_lambda_events"
+version = "0.9.0"
+description = "AWS Lambda event definitions"
+authors = [
+ "Christian Legnitto ",
+ "Sam Rijs ",
+ "David Calavera ",
+]
+license = "MIT"
+homepage = "https://github.com/awslabs/aws-lambda-rust-runtime"
+repository = "https://github.com/awslabs/aws-lambda-rust-runtime"
+readme = "README.md"
+keywords = ["lambda", "aws", "amazon", "events", "S3"]
+categories = ["api-bindings", "encoding", "web-programming"]
+
+[dependencies]
+base64 = "0.13"
+http = "0.2"
+http-body = "0.4"
+http-serde = "^1"
+serde = "^1"
+serde_derive = "^1"
+serde_with = { version = "^2", features = ["json"], optional = true }
+serde_json = "^1"
+serde_dynamo = { version = "^4.1", optional = true }
+bytes = { version = "1", features = ["serde"] }
+chrono = { version = "0.4.23", default-features = false, features = [
+ "clock",
+ "serde",
+ "std",
+] }
+query_map = { version = "^0.6", features = ["serde", "url-query"] }
+flate2 = { version = "1.0.24", optional = true }
+
+[dev-dependencies]
+pretty_assertions = "1.3"
+
+[features]
+default = [
+ "activemq",
+ "alb",
+ "apigw",
+ "appsync",
+ "autoscaling",
+ "chime_bot",
+ "clientvpn",
+ "cloudwatch_events",
+ "cloudwatch_logs",
+ "code_commit",
+ "codebuild",
+ "codedeploy",
+ "codepipeline_cloudwatch",
+ "codepipeline_job",
+ "cognito",
+ "config",
+ "connect",
+ "dynamodb",
+ "ecr_scan",
+ "firehose",
+ "iam",
+ "iot",
+ "iot_1_click",
+ "iot_button",
+ "iot_deprecated",
+ "kafka",
+ "kinesis",
+ "kinesis_analytics",
+ "lambda_function_urls",
+ "lex",
+ "rabbitmq",
+ "s3",
+ "s3_batch_job",
+ "ses",
+ "sns",
+ "sqs",
+ "streams",
+]
+
+activemq = []
+alb = []
+apigw = []
+appsync = []
+autoscaling = []
+chime_bot = []
+clientvpn = []
+cloudwatch_events = []
+cloudwatch_logs = ["flate2"]
+code_commit = []
+codebuild = []
+codedeploy = []
+codepipeline = []
+codepipeline_cloudwatch = []
+codepipeline_job = []
+cognito = []
+config = []
+connect = []
+dynamodb = ["streams", "serde_dynamo"]
+ecr_scan = []
+firehose = []
+iam = []
+iot = ["iam"]
+iot_1_click = []
+iot_button = []
+iot_deprecated = ["iot"]
+kafka = []
+kinesis = []
+kinesis_analytics = ["kinesis"]
+lambda_function_urls = []
+lex = []
+rabbitmq = []
+s3 = []
+s3_batch_job = ["s3"]
+ses = []
+sns = ["serde_with"]
+sqs = ["serde_with"]
+streams = []
diff --git a/lambda-events/README.md b/lambda-events/README.md
new file mode 100644
index 00000000..0813c63a
--- /dev/null
+++ b/lambda-events/README.md
@@ -0,0 +1,34 @@
+# AWS Lambda Events
+
+[![crates.io][crate-image]][crate-link]
+[![Documentation][docs-image]][docs-link]
+
+This crate provides strongly-typed [AWS Lambda event structs](https://docs.aws.amazon.com/lambda/latest/dg/invoking-lambda-function.html) in Rust.
+
+## Installation
+
+Add the dependency with Cargo: `cargo add aws_lambda_events`.
+
+## Usage
+
+The crate itself has no AWS Lambda handler logic and instead exists to serialize
+and deserialize AWS Lambda events into strongly-typed Rust structs.
+
+The types
+defined in this crate are usually used with handlers / runtimes provided by the [official Rust runtime](https://github.com/awslabs/aws-lambda-rust-runtime).
+
+For a list of supported AWS Lambda events and services, see [the crate reference documentation](https://docs.rs/aws_lambda_events).
+
+## Conditional compilation of features
+
+This crate divides all Lambda Events into features named after the service that the events are generated from. By default all events are enabled when you include this crate as a dependency to your project. If you only want to import specific events from this crate, you can disable the default features, and enable only the events that you need. This will make your project to compile a little bit faster, since rustc doesn't need to compile events that you're not going to use. Here's an example on how to do that:
+
+```
+cargo add aws_lambda_events --no-default-features --features apigw,alb
+```
+
+[//]: # 'badges'
+[crate-image]: https://img.shields.io/crates/v/aws_lambda_events.svg
+[crate-link]: https://crates.io/crates/aws_lambda_events
+[docs-image]: https://docs.rs/aws_lambda_events/badge.svg
+[docs-link]: https://docs.rs/aws_lambda_events
\ No newline at end of file
diff --git a/lambda-events/src/custom_serde/codebuild_time.rs b/lambda-events/src/custom_serde/codebuild_time.rs
new file mode 100644
index 00000000..c57ccd6a
--- /dev/null
+++ b/lambda-events/src/custom_serde/codebuild_time.rs
@@ -0,0 +1,105 @@
+use chrono::{DateTime, TimeZone, Utc};
+use serde::de::{Deserialize, Deserializer, Error as DeError, Visitor};
+use serde::ser::Serializer;
+use std::fmt;
+
+// Jan 2, 2006 3:04:05 PM
+const CODEBUILD_TIME_FORMAT: &str = "%b %e, %Y %l:%M:%S %p";
+
+struct TimeVisitor;
+impl<'de> Visitor<'de> for TimeVisitor {
+ type Value = DateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "valid codebuild time: {}", CODEBUILD_TIME_FORMAT)
+ }
+
+ fn visit_str(self, val: &str) -> Result {
+ Utc.datetime_from_str(val, CODEBUILD_TIME_FORMAT)
+ .map_err(|e| DeError::custom(format!("Parse error {} for {}", e, val)))
+ }
+}
+
+pub(crate) mod str_time {
+ use super::*;
+
+ pub(crate) fn deserialize<'de, D>(d: D) -> Result, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ d.deserialize_str(TimeVisitor)
+ }
+
+ pub fn serialize(date: &DateTime, ser: S) -> Result {
+ let s = format!("{}", date.format(CODEBUILD_TIME_FORMAT));
+ ser.serialize_str(&s)
+ }
+}
+
+pub(crate) mod optional_time {
+ use super::*;
+
+ pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result