├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── ossf-scorecard.yml │ ├── release.yml │ ├── test-dast.yml │ ├── test-dco.yml │ ├── test-lint.yml │ ├── test-pref.yml │ ├── test-sast.yml │ ├── test-types.yml │ ├── test-unit.yml │ ├── website-publish.yml │ └── website-test.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── CNAME ├── LICENSE ├── README.md ├── SECURITY.md ├── biome.json ├── commitlint.config.cjs ├── docs ├── CNAME ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── GOVERNANCE.md ├── RELEASE.md ├── chart-market-downloads.html ├── chart-monorepo-downloads.html └── img │ ├── middy-logo-scooter.svg │ ├── middy-logo.ai │ ├── middy-logo.png │ ├── middy-logo.svg │ ├── middy-middleware-engine.sketch │ ├── repository-open-graph.png │ └── repository-open-graph.sketch ├── llrt ├── .gitignore ├── index.js └── package.json ├── package-lock.json ├── package.json ├── packages ├── appconfig │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── cloudformation-response │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── cloudformation-router │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── cloudwatch-metrics │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── core │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── do-not-wait-for-empty-event-loop │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── dynamodb │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── error-logger │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── event-normalizer │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-content-encoding │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-content-negotiation │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-cors │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-error-handler │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-event-normalizer │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-header-normalizer │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-json-body-parser │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-multipart-body-parser │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-partial-response │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-response-serializer │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-router │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-security-headers │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.test-d.ts │ ├── index.test.js │ ├── package.json │ └── test.index.js ├── http-urlencode-body-parser │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── http-urlencode-path-parser │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── input-output-logger │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── rds-signer │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── s3-object-response │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── s3 │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── secrets-manager │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── service-discovery │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── sqs-partial-batch-failure │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── ssm │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── sts │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── util │ ├── README.md │ ├── index.d.ts │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ ├── package.json │ ├── type-utils.d.ts │ └── type-utils.test-d.ts ├── validator │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ ├── package.json │ ├── transpile.d.ts │ ├── transpile.js │ └── transpile.test-d.ts ├── warmup │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── ws-json-body-parser │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.perf.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── ws-response │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json └── ws-router │ ├── README.md │ ├── index.d.ts │ ├── index.fuzz.js │ ├── index.js │ ├── index.pref.js │ ├── index.test-d.ts │ ├── index.test.js │ └── package.json ├── plugin ├── __tests__ │ └── index.js ├── hrtime.js ├── memory.js ├── multi.js ├── package.json ├── promise.js └── time.js ├── tsconfig.json └── website ├── .gitignore ├── README.md ├── babel.config.js ├── docs ├── best-practices │ ├── 01-intro.md │ ├── 02-connection-reuse.md │ ├── 03-internal-context.md │ ├── 05-bundling.md │ ├── 06-small-node-modules.md │ ├── 07-profiling.md │ └── _category_.yml ├── events │ ├── 01-intro.md │ ├── _category_.yml │ ├── alexa.md │ ├── api-gateway-authorizer.md │ ├── api-gateway-http.md │ ├── api-gateway-rest.md │ ├── api-gateway-ws.md │ ├── application-load-balancer.md │ ├── appsync.md │ ├── cloud-formation.md │ ├── cloud-front.md │ ├── cloud-trail.md │ ├── cloud-watch-alarm.md │ ├── cloud-watch-logs.md │ ├── code-commit.md │ ├── code-pipeline.md │ ├── cognito.md │ ├── config.md │ ├── connect.md │ ├── documentdb.md │ ├── dynamodb.md │ ├── ec2.md │ ├── event-bridge.md │ ├── function-url.md │ ├── iot-events.md │ ├── iot.md │ ├── kafka-managed-streaming.md │ ├── kafka-self-managed.md │ ├── kinesis-firehose.md │ ├── kinesis-streams.md │ ├── lex.md │ ├── mq.md │ ├── rds.md │ ├── s3-batch.md │ ├── s3-object.md │ ├── s3.md │ ├── secrets-manager.md │ ├── ses.md │ ├── sns.md │ ├── sqs.md │ ├── vpc-lattice.md │ └── workmail.md ├── faq.md ├── integrations │ ├── 01-intro.md │ ├── RDS.md │ ├── _category_.yml │ ├── apollo-server.md │ ├── lambda-powertools.md │ ├── pino.md │ ├── serverless-framework.md │ └── serverless-stack.md ├── intro │ ├── 01-intro.md │ ├── 02-getting-started.md │ ├── 03-how-it-works.md │ ├── 04-early-interrupt.md │ ├── 05-handling-errors.md │ ├── 06-streamify-response.md │ ├── 06-testing.md │ ├── 06-typescript.md │ ├── 07-hooks.md │ ├── 08-history.md │ ├── 08-influence.md │ ├── 08-utilities.md │ ├── 09-release-cycle.md │ ├── 10-contributing.md │ ├── 11-sponsoring.md │ └── _category_.yml ├── middlewares │ ├── 00-intro.md │ ├── _category_.yml │ ├── appconfig.md │ ├── cloudformation-response.md │ ├── cloudwatch-metrics.md │ ├── do-not-wait-for-empty-event-loop.md │ ├── dynamodb.md │ ├── error-logger.md │ ├── event-normalizer.md │ ├── http-content-encoding.md │ ├── http-content-negotiation.md │ ├── http-cors.md │ ├── http-error-handler.md │ ├── http-event-normalizer.md │ ├── http-header-normalizer.md │ ├── http-json-body-parser.md │ ├── http-multipart-body-parser.md │ ├── http-partial-response.md │ ├── http-response-serializer.md │ ├── http-security-headers.md │ ├── http-urlencode-body-parser.md │ ├── http-urlencode-path-parser.md │ ├── input-output-logger.md │ ├── rds-signer.md │ ├── s3-object-response.md │ ├── s3.md │ ├── secrets-manager.md │ ├── service-discovery.md │ ├── sqs-partial-batch-failure.md │ ├── ssm.md │ ├── sts.md │ ├── third-party.md │ ├── validator.md │ ├── warmup.md │ ├── ws-json-body-parser.md │ └── ws-response.md ├── routers │ ├── _category_.yml │ ├── cloudformation-router.md │ ├── http-router.md │ └── ws-router.md ├── upgrade │ ├── 0-1.md │ ├── 1-2.md │ ├── 2-3.md │ ├── 3-4.md │ ├── 4-5.md │ ├── 5-6.md │ └── _category_.yml └── writing-middlewares │ ├── 01-intro.md │ ├── 02-configurable-middlewares.md │ ├── 03-inline-middlewares.md │ ├── 04-internal-storage.md │ ├── 05-timeouts.md │ ├── 06-more-examples.md │ ├── 07-with-typescript.md │ └── _category_.yml ├── docusaurus.config.js ├── package-lock.json ├── package.json ├── sidebars.js ├── src ├── components │ ├── Example.js │ ├── Example.module.css │ ├── GetStartedHero.js │ ├── GetStartedHero.module.css │ ├── HomepageFeatures.js │ ├── HomepageFeatures.module.css │ ├── HomepageSponsors.js │ ├── HomepageSponsors.module.css │ ├── HomepageWhatUsersSay.js │ └── HomepageWhoUses.js ├── css │ └── custom.css ├── pages │ ├── index.js │ ├── index.module.css │ └── markdown-page.md └── theme │ └── NotFound.js └── static ├── .nojekyll ├── CNAME ├── img ├── batteries-included.svg ├── blazing-fast.svg ├── extensible.svg ├── favicon.svg ├── focus.svg ├── logo │ ├── amazon-web-services.svg │ ├── fourtheorem.svg │ └── reserved.svg ├── middy-404.gif ├── middy-logo-horizontal.svg ├── middy-logo-icon.svg ├── middy-logo-name.svg ├── middy-logo.svg ├── middy-middleware-engine.png ├── middy-og-image.png ├── powerful.svg └── small-core.svg └── robots.txt /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @middyjs/owners 2 | * @middyjs/reviewers 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [willfarrell, lmammino] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | How to reproduce the behaviour: 14 | 15 | 1. Sample code '...' 16 | 2. Input '....' 17 | 3. Unit test '....' 18 | 4. Thrown error 19 | 20 | **Expected behaviour** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Environment (please complete the following information):** 24 | 25 | - Node.js: [e.g. 20] 26 | - Middy: [e.g. 5.0.0] 27 | - AWS SDK [e.g. 3.0.0] 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature request 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pull request 3 | about: Pull request 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | **What does this implement/fix? Explain your changes.** 13 | 14 | **Does this close any currently open issues?** 15 | 16 | **Any relevant logs, error output, etc?** 17 | 18 | **Environment:** 19 | - Node.js: [e.g. 22] 20 | - Middy: [e.g. 6.0.0] 21 | - AWS SDK [e.g. 3.999.0] 22 | 23 | **Any other comments?** 24 | 25 | **Todo List:** 26 | - [ ] All commits are cryptographically signed 27 | - [ ] Feature/Fix fully implemented 28 | - [ ] Updated relevant types 29 | - [ ] Added tests (if applicable) 30 | - [ ] Unit tests 31 | - [ ] Fuzz tests 32 | - [ ] Type tests 33 | - [ ] Benchmark tests 34 | - [ ] Updated relevant documentation 35 | - [ ] Updated relevant examples 36 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | - package-ecosystem: npm 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/test-dast.yml: -------------------------------------------------------------------------------- 1 | name: Tests (dast) 2 | 3 | on: 4 | pull_request: 5 | 6 | env: 7 | NODE_VERSION: 23.x 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | fuzz: 14 | name: Tests (fuzz) 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | - name: Setup Node.js ${{ env.NODE_VERSION }} 21 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 22 | with: 23 | node-version: ${{ env.NODE_VERSION }} 24 | registry-url: https://registry.npmjs.org 25 | - name: Cache npm 26 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 27 | with: 28 | path: ~/.npm 29 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 30 | restore-keys: | 31 | ${{ runner.os }}-node- 32 | - name: Install dependencies 33 | run: | 34 | npm ci 35 | - name: Build 36 | run: | 37 | npm run build --if-present 38 | - name: Fuzzing tests 39 | run: | 40 | npm run test:dast:fuzz 41 | -------------------------------------------------------------------------------- /.github/workflows/test-dco.yml: -------------------------------------------------------------------------------- 1 | name: Tests (dco) 2 | 3 | on: 4 | pull_request: 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | dco: 11 | name: Tests (dco) 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Check for Developer Certificate of Origin (DCO) compiance 15 | uses: KineticCafe/actions-dco@416cafbc9c07f26219d09981d9ac49ce29b5bfea # v1.3.4 16 | -------------------------------------------------------------------------------- /.github/workflows/test-lint.yml: -------------------------------------------------------------------------------- 1 | name: Tests (lint) 2 | 3 | on: 4 | pull_request: 5 | 6 | env: 7 | NODE_VERSION: 23.x 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | lint: 14 | name: Tests (lint) 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | - name: Setup Node.js ${{ env.NODE_VERSION }} 21 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 22 | with: 23 | node-version: ${{ env.NODE_VERSION }} 24 | registry-url: https://registry.npmjs.org 25 | - name: Cache npm 26 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 27 | with: 28 | path: ~/.npm 29 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 30 | restore-keys: | 31 | ${{ runner.os }}-node- 32 | - name: Install dependencies 33 | run: | 34 | npm ci 35 | - name: Linting 36 | run: | 37 | ./node_modules/.bin/biome ci --no-errors-on-unmatched 38 | -------------------------------------------------------------------------------- /.github/workflows/test-pref.yml: -------------------------------------------------------------------------------- 1 | name: Tests (perf) 2 | 3 | on: 4 | pull_request: 5 | 6 | env: 7 | NODE_VERSION: 23.x 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | unit: 14 | name: Tests (perf) 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | - name: Setup Node.js ${{ env.NODE_VERSION }} 21 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 22 | with: 23 | node-version: ${{ env.NODE_VERSION }} 24 | registry-url: https://registry.npmjs.org 25 | - name: Cache npm 26 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 27 | with: 28 | path: ~/.npm 29 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 30 | restore-keys: | 31 | ${{ runner.os }}-node- 32 | - name: Install dependencies 33 | run: | 34 | npm ci 35 | - name: Build 36 | run: | 37 | npm run build --if-present 38 | - name: Benchmarking tests 39 | run: | 40 | npm run test:perf 41 | -------------------------------------------------------------------------------- /.github/workflows/test-types.yml: -------------------------------------------------------------------------------- 1 | name: Test (types) 2 | 3 | on: 4 | pull_request: 5 | 6 | env: 7 | NODE_VERSION: 23.x 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | types: 14 | name: Tests (types) 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | - name: Setup Node.js ${{ env.NODE_VERSION }} 21 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 22 | with: 23 | node-version: ${{ env.NODE_VERSION }} 24 | registry-url: https://registry.npmjs.org 25 | - name: Cache npm 26 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 27 | with: 28 | path: ~/.npm 29 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 30 | restore-keys: | 31 | ${{ runner.os }}-node- 32 | - name: Install dependencies 33 | run: | 34 | npm ci 35 | - name: Check typings 36 | run: npm run test:types 37 | -------------------------------------------------------------------------------- /.github/workflows/test-unit.yml: -------------------------------------------------------------------------------- 1 | name: Tests (unit) 2 | 3 | on: 4 | pull_request: 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | unit: 11 | name: Tests (unit) 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [20.x, 22.x] 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | - name: Setup Node.js ${{ matrix.node-version }} 22 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | registry-url: https://registry.npmjs.org 26 | - name: Cache npm 27 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 28 | with: 29 | path: ~/.npm 30 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 31 | restore-keys: | 32 | ${{ runner.os }}-node- 33 | - name: Install dependencies 34 | run: | 35 | npm ci 36 | - name: Build 37 | run: | 38 | npm run build --if-present 39 | - name: Unit tests 40 | run: | 41 | npm run test:unit 42 | -------------------------------------------------------------------------------- /.github/workflows/website-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Website 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - 'website/*' 8 | branches: 9 | - main 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | website: 16 | name: Publish website 17 | runs-on: ubuntu-latest 18 | permissions: 19 | contents: write 20 | 21 | strategy: 22 | matrix: 23 | node-version: [20.x] 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | - name: Set up Node.js 29 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 30 | with: 31 | node-version: ${{ matrix.node-version }} 32 | - name: Install dependencies 33 | working-directory: website 34 | run: | 35 | npm ci 36 | - name: Build website 37 | working-directory: website 38 | run: | 39 | npm run build 40 | - name: Publish website 41 | uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 42 | with: 43 | github_token: ${{ secrets.GITHUB_TOKEN }} 44 | publish_dir: ./website/build 45 | -------------------------------------------------------------------------------- /.github/workflows/website-test.yml: -------------------------------------------------------------------------------- 1 | name: Test Website 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | paths: 7 | - 'website/*' 8 | branches: 9 | - 'main' 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | website: 16 | name: Test website 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | - name: Set up Node.js 22 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 23 | with: 24 | node-version: 20.x 25 | - name: Install dependencies 26 | working-directory: website 27 | run: | 28 | npm ci 29 | - name: Build website 30 | working-directory: website 31 | run: | 32 | npm run build 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | *.pid.lock 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # Bower dependency directory (https://bower.io/) 28 | bower_components 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (http://nodejs.org/api/addons.html) 34 | build/Release 35 | 36 | # Dependency directories 37 | node_modules/ 38 | jspm_packages/ 39 | 40 | # Typescript v1 declaration files 41 | typings/ 42 | 43 | # Optional npm cache directory 44 | .npm 45 | 46 | # Optional eslint cache 47 | .eslintcache 48 | 49 | # Optional REPL history 50 | .node_repl_history 51 | 52 | # Output of 'npm pack' 53 | *.tgz 54 | 55 | # Yarn Integrity file 56 | .yarn-integrity 57 | 58 | # dotenv environment variables file 59 | .env 60 | 61 | .tern-port 62 | .DS_Store 63 | 64 | # SAST 65 | .scannerwork 66 | 67 | # IDE 68 | *.iml 69 | .idea/ 70 | .vscode/ 71 | .nova/ 72 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | npm run git:commit-msg 3 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | npm run git:pre-commit 3 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | middy.js.org -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2025 [Luciano Mammino](https://github.com/lmammino), [will Farrell](https://github.com/willfarrell) and the [Middy team](https://github.com/middyjs/middy/graphs/contributors) 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. 22 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { 4 | "enabled": false, 5 | "clientKind": "git", 6 | "useIgnoreFile": false 7 | }, 8 | "files": { 9 | "ignoreUnknown": false, 10 | "ignore": [] 11 | }, 12 | "formatter": { 13 | "enabled": true, 14 | "indentStyle": "tab" 15 | }, 16 | "organizeImports": { 17 | "enabled": true 18 | }, 19 | "linter": { 20 | "enabled": true, 21 | "rules": { 22 | "recommended": true, 23 | "complexity": { 24 | "noBannedTypes": "off" 25 | }, 26 | "suspicious": { 27 | "noExplicitAny": "off" 28 | } 29 | } 30 | }, 31 | "javascript": { 32 | "formatter": { 33 | "quoteStyle": "double" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /commitlint.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@commitlint/config-conventional"], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | middy.js.org -------------------------------------------------------------------------------- /docs/GOVERNANCE.md: -------------------------------------------------------------------------------- 1 | # Governance 2 | 3 | ## Roles 4 | 5 | ### [Owner](https://github.com/orgs/middyjs/teams/owners) 6 | 7 | Also known as a core maintainer. Have a long history with the project, have a deep understanding of the codebase, and decide the direction of the project. 8 | 9 | ### [Security](https://github.com/orgs/middyjs/teams/security) 10 | 11 | Are responsible to respond and remediate security disclosures. 12 | 13 | ### [Reviewer](https://github.com/orgs/middyjs/teams/reviewers) 14 | 15 | Group of people responsible for reviewing pull requests. 16 | 17 | ## Decisions 18 | 19 | All discussion and decisions are documented in a GitHub Issue to allow transparency and community feedback. Video calls to go over larger decisions and those that relate to governance may happen periodically. 20 | 21 | ## Maintainers 22 | 23 | - Project must maintain a minimum of 3 maintainers with at least two unassociated significant contributors 24 | - All maintainers are required to have WebAuthn MFA enable on their account. 25 | - Required to know secure design principals. 26 | -------------------------------------------------------------------------------- /docs/img/middy-logo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/docs/img/middy-logo.ai -------------------------------------------------------------------------------- /docs/img/middy-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/docs/img/middy-logo.png -------------------------------------------------------------------------------- /docs/img/middy-middleware-engine.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/docs/img/middy-middleware-engine.sketch -------------------------------------------------------------------------------- /docs/img/repository-open-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/docs/img/repository-open-graph.png -------------------------------------------------------------------------------- /docs/img/repository-open-graph.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/docs/img/repository-open-graph.sketch -------------------------------------------------------------------------------- /llrt/.gitignore: -------------------------------------------------------------------------------- 1 | index.mjs 2 | llrt 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /llrt/index.js: -------------------------------------------------------------------------------- 1 | import middy from "@middy/core"; 2 | // import appconfigMiddleware from '@middy/appconfig' 3 | // import cloudwatchMetricsMiddleware from '@middy/cloudwatch-metrics' 4 | // import doNotWaitForEmptyEventLoopMiddleware from '@middy/do-not-wait-for-empty-event-loop' 5 | // import dynamodbMiddleware from '@middy/dynamodb' 6 | // import errorLoggerMiddleware from '@middy/error-logger' 7 | // import eventNormalizerMiddleware from '@middy/event-normalizer' 8 | // import httpContentEncodingMiddleware from '@middy/http-content-encoding' 9 | // import httpContentNegotiationMiddleware from '@middy/http-content-negotiation' 10 | // import httpCorsMiddleware from '@middy/http-cors' 11 | // import httpErrorHandlerMiddleware from '@middy/http-error-handler' 12 | // import httpEventNormalizerMiddleware from '@middy/http-event-normalizer' 13 | // TODO add in all 14 | 15 | const baseHandler = async (event, context, { signal }) => { 16 | return {}; 17 | }; 18 | export const handler = middy() 19 | // .use(appconfigMiddleware()) 20 | // .use(cloudwatchMetricsMiddleware()) 21 | // .use(doNotWaitForEmptyEventLoopMiddleware()) 22 | // .use(dynamodbMiddleware()) 23 | // .use(errorLoggerMiddleware()) 24 | // .use(validatorMiddleware()) 25 | .handler(baseHandler); 26 | -------------------------------------------------------------------------------- /llrt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "llrt", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "esbuild index.js --platform=node --target=es2020 --format=esm --bundle --minify --external:@aws-sdk --external:@smithy --external:uuid --outfile=index.mjs", 8 | "test": "npm run build && ./llrt index.mjs", 9 | "download:ci": "curl -L https://github.com/awslabs/llrt/releases/download/v0.1.14-beta/llrt-linux-x64.zip | bsdtar -xvf - -C ./ && chmod +x llrt", 10 | "download:macos": "curl -L https://github.com/awslabs/llrt/releases/download/v0.1.14-beta/llrt-darwin-arm64.zip | bsdtar -xvf - -C ./ && chmod +x llrt" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "dependencies": { 15 | "@middy/core": "file:../packages/core", 16 | "@middy/do-not-wait-for-empty-event-loop": "file:../packages/core", 17 | "@middy/validator": "file:../packages/core" 18 | }, 19 | "devDependencies": { 20 | "esbuild": "0.21.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/appconfig/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/cloudformation-response/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | declare function cloudformationResponse(): middy.MiddlewareObj; 4 | 5 | export default cloudformationResponse; 6 | -------------------------------------------------------------------------------- /packages/cloudformation-response/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/cloudformation-response/index.js: -------------------------------------------------------------------------------- 1 | const cloudformationCustomResourceMiddleware = () => { 2 | const cloudformationCustomResourceMiddlewareAfter = (request) => { 3 | let { response } = request; 4 | response ??= {}; 5 | response.Status ??= "SUCCESS"; 6 | response.RequestId ??= request.event.RequestId; 7 | response.LogicalResourceId ??= request.event.LogicalResourceId; 8 | response.StackId ??= request.event.StackId; 9 | request.response = response; 10 | }; 11 | const cloudformationCustomResourceMiddlewareOnError = (request) => { 12 | const response = { 13 | Status: "FAILED", 14 | Reason: request.error.message, 15 | }; 16 | request.response = response; 17 | cloudformationCustomResourceMiddlewareAfter(request); 18 | }; 19 | return { 20 | after: cloudformationCustomResourceMiddlewareAfter, 21 | onError: cloudformationCustomResourceMiddlewareOnError, 22 | }; 23 | }; 24 | 25 | export default cloudformationCustomResourceMiddleware; 26 | -------------------------------------------------------------------------------- /packages/cloudformation-response/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const coldHandler = setupHandler(); 16 | 17 | const event = {}; 18 | await bench 19 | .add("without cache", async () => { 20 | try { 21 | await coldHandler(event, context); 22 | } catch (e) {} 23 | }) 24 | 25 | .run(); 26 | 27 | console.table(bench.table()); 28 | -------------------------------------------------------------------------------- /packages/cloudformation-response/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | 4 | import cloudformationResponse from "."; 5 | 6 | // use with default options 7 | const middleware = cloudformationResponse(); 8 | expectType(middleware); 9 | -------------------------------------------------------------------------------- /packages/cloudformation-router/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { CloudFormationCustomResourceHandler } from "aws-lambda"; 3 | 4 | interface Route { 5 | requestType: string; 6 | handler: CloudFormationCustomResourceHandler; 7 | } 8 | 9 | declare function cloudformationRouterHandler( 10 | routes: Route[], 11 | ): middy.MiddyfiedHandler; 12 | 13 | export default cloudformationRouterHandler; 14 | -------------------------------------------------------------------------------- /packages/cloudformation-router/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import router from "./index.js"; 5 | 6 | const handler = middy(router()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | try { 15 | await handler(event, context); 16 | } catch (e) { 17 | if (e.cause?.package !== "@middy/cloudformation-router") { 18 | throw e; 19 | } 20 | } 21 | }), 22 | { 23 | numRuns: 100_000, 24 | verbose: 2, 25 | 26 | examples: [], 27 | }, 28 | ); 29 | }); 30 | 31 | test("fuzz `event` w/ `record`", async () => { 32 | await fc.assert( 33 | fc.asyncProperty( 34 | fc.record({ 35 | RequestType: fc.string(), 36 | RequestId: fc.string(), 37 | LogicalResourceId: fc.string(), 38 | StackId: fc.string(), 39 | }), 40 | async (event) => { 41 | try { 42 | await handler(event, context); 43 | } catch (e) { 44 | if (e.cause?.package !== "@middy/cloudformation-router") { 45 | throw e; 46 | } 47 | } 48 | }, 49 | ), 50 | { 51 | numRuns: 100_000, 52 | verbose: 2, 53 | examples: [[{ requestContext: { routeKey: "valueOf" } }]], 54 | }, 55 | ); 56 | }); 57 | -------------------------------------------------------------------------------- /packages/cloudformation-router/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import router from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => true; 12 | return middy( 13 | router([ 14 | { 15 | requestType: "Create", 16 | handler: baseHandler, 17 | }, 18 | ]), 19 | ); 20 | }; 21 | 22 | const coldHandler = setupHandler(); 23 | 24 | const event = {}; 25 | await bench 26 | .add("without cache", async () => { 27 | try { 28 | await coldHandler(event, context); 29 | } catch (e) {} 30 | }) 31 | 32 | .run(); 33 | 34 | console.table(bench.table()); 35 | -------------------------------------------------------------------------------- /packages/cloudformation-router/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | // import { CloudFormationCustomResourceHandler } from 'aws-lambda' 3 | import { expectType } from "tsd"; 4 | import cloudformationRouterHandler from "."; 5 | 6 | const createLambdaHandler: any = async () => { 7 | return { 8 | Status: "SUCCESS", 9 | }; 10 | }; 11 | 12 | const deleteLambdaHandler: any = async () => { 13 | return { 14 | Status: "SUCCESS", 15 | }; 16 | }; 17 | 18 | const middleware = cloudformationRouterHandler([ 19 | { 20 | requestType: "Create", 21 | handler: createLambdaHandler, 22 | }, 23 | { 24 | requestType: "Delete", 25 | handler: deleteLambdaHandler, 26 | }, 27 | ]); 28 | expectType(middleware); 29 | -------------------------------------------------------------------------------- /packages/cloudwatch-metrics/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { MetricsLogger } from "aws-embedded-metrics"; 3 | import type { Context as LambdaContext } from "aws-lambda"; 4 | export { MetricsLogger } from "aws-embedded-metrics"; 5 | 6 | interface Options { 7 | namespace?: string; 8 | dimensions?: Array>; 9 | } 10 | 11 | export type Context = LambdaContext & { 12 | metrics: MetricsLogger; 13 | }; 14 | 15 | declare function cloudwatchMetrics( 16 | options?: Options, 17 | ): middy.MiddlewareObj; 18 | 19 | export default cloudwatchMetrics; 20 | -------------------------------------------------------------------------------- /packages/cloudwatch-metrics/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | // import middleware from '../index.js' // TODO needs mocking 5 | 6 | const handler = middy((event) => event); // .use(middleware()) 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/cloudwatch-metrics/index.js: -------------------------------------------------------------------------------- 1 | import awsEmbeddedMetrics from "aws-embedded-metrics"; 2 | 3 | const defaults = {}; 4 | 5 | const cloudwatchMetricsMiddleware = (opts = {}) => { 6 | const { namespace, dimensions } = { ...defaults, ...opts }; 7 | const cloudwatchMetricsBefore = (request) => { 8 | const metrics = awsEmbeddedMetrics.createMetricsLogger(); 9 | 10 | // If not set, defaults to aws-embedded-metrics 11 | if (namespace) { 12 | metrics.setNamespace(namespace); 13 | } 14 | 15 | // If not set, keeps defaults as defined here https://github.com/awslabs/aws-embedded-metrics-node/#configuration 16 | if (dimensions) { 17 | metrics.setDimensions(dimensions); 18 | } 19 | Object.assign(request.context, { metrics }); 20 | }; 21 | 22 | const cloudwatchMetricsAfter = async (request) => { 23 | await request.context.metrics.flush(); 24 | }; 25 | const cloudwatchMetricsOnError = async (request) => { 26 | try { 27 | await cloudwatchMetricsAfter(request); 28 | } catch (e) {} 29 | }; 30 | 31 | return { 32 | before: cloudwatchMetricsBefore, 33 | after: cloudwatchMetricsAfter, 34 | onError: cloudwatchMetricsOnError, 35 | }; 36 | }; 37 | 38 | export default cloudwatchMetricsMiddleware; 39 | -------------------------------------------------------------------------------- /packages/cloudwatch-metrics/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = (options = {}) => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware({ namespace: "namespace" })); 13 | }; 14 | 15 | const coldHandler = setupHandler({ cacheExpiry: 0 }); 16 | const warmHandler = setupHandler(); 17 | 18 | const event = {}; 19 | await bench 20 | .add("without cache", async () => { 21 | try { 22 | await coldHandler(event, context); 23 | } catch (e) {} 24 | }) 25 | .add("with cache", async () => { 26 | try { 27 | await warmHandler(event, context); 28 | } catch (e) {} 29 | }) 30 | 31 | .run(); 32 | 33 | console.table(bench.table()); 34 | -------------------------------------------------------------------------------- /packages/cloudwatch-metrics/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import cloudwatchMetrics, { type Context } from "."; 4 | 5 | // use with default options 6 | let middleware = cloudwatchMetrics(); 7 | expectType>(middleware); 8 | 9 | // use with all options 10 | middleware = cloudwatchMetrics({ 11 | namespace: "myApp", 12 | dimensions: [{ Action: "Buy" }], 13 | }); 14 | expectType>(middleware); 15 | -------------------------------------------------------------------------------- /packages/core/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "./index.js"; 4 | 5 | const handler = middy((event) => event); 6 | const context = { 7 | getRemainingTimeInMillis: () => 1000, 8 | }; 9 | 10 | test("fuzz `event` w/ `object`", async () => { 11 | await fc.assert( 12 | fc.asyncProperty(fc.object(), async (event) => { 13 | await handler(event, context); 14 | }), 15 | { 16 | numRuns: 100_000, 17 | verbose: 2, 18 | 19 | examples: [], 20 | }, 21 | ); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/do-not-wait-for-empty-event-loop/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | runOnBefore?: boolean; 5 | runOnAfter?: boolean; 6 | runOnError?: boolean; 7 | } 8 | 9 | declare function doNotWaitForEmptyEventLoop( 10 | options?: Options, 11 | ): middy.MiddlewareObj; 12 | 13 | export default doNotWaitForEmptyEventLoop; 14 | -------------------------------------------------------------------------------- /packages/do-not-wait-for-empty-event-loop/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/do-not-wait-for-empty-event-loop/index.js: -------------------------------------------------------------------------------- 1 | const defaults = { 2 | runOnBefore: true, 3 | runOnAfter: false, 4 | runOnError: false, 5 | }; 6 | 7 | const doNotWaitForEmptyEventLoopMiddleware = (opts = {}) => { 8 | const options = { ...defaults, ...opts }; 9 | 10 | const doNotWaitForEmptyEventLoop = async (request) => { 11 | request.context.callbackWaitsForEmptyEventLoop = false; 12 | }; 13 | 14 | return { 15 | before: options.runOnBefore ? doNotWaitForEmptyEventLoop : undefined, 16 | after: options.runOnAfter ? doNotWaitForEmptyEventLoop : undefined, 17 | onError: options.runOnError ? doNotWaitForEmptyEventLoop : undefined, 18 | }; 19 | }; 20 | export default doNotWaitForEmptyEventLoopMiddleware; 21 | -------------------------------------------------------------------------------- /packages/do-not-wait-for-empty-event-loop/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const warmHandler = setupHandler(); 16 | 17 | const event = {}; 18 | await bench 19 | .add("Change Context", async () => { 20 | try { 21 | await warmHandler(event, context); 22 | } catch (e) {} 23 | }) 24 | 25 | .run(); 26 | 27 | console.table(bench.table()); 28 | -------------------------------------------------------------------------------- /packages/do-not-wait-for-empty-event-loop/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import doNotWaitForEmptyEventLoop from "."; 4 | 5 | // use with default options 6 | let middleware = doNotWaitForEmptyEventLoop(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = doNotWaitForEmptyEventLoop({ 11 | runOnBefore: true, 12 | runOnAfter: true, 13 | runOnError: true, 14 | }); 15 | expectType(middleware); 16 | -------------------------------------------------------------------------------- /packages/dynamodb/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/dynamodb/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb"; 6 | import { mockClient } from "aws-sdk-client-mock"; 7 | 8 | const bench = new Bench({ time: 1_000 }); 9 | 10 | const context = { 11 | getRemainingTimeInMillis: () => 30000, 12 | }; 13 | const setupHandler = (options = {}) => { 14 | mockClient(DynamoDBClient) 15 | .on(GetItemCommand) 16 | .resolvesOnce({ 17 | Item: { 18 | value: { 19 | S: "value", 20 | }, 21 | }, 22 | }); 23 | const baseHandler = () => {}; 24 | return middy(baseHandler).use( 25 | middleware({ 26 | ...options, 27 | AwsClient: DynamoDBClient, 28 | }), 29 | ); 30 | }; 31 | 32 | const coldHandler = setupHandler({ cacheExpiry: 0 }); 33 | const warmHandler = setupHandler(); 34 | 35 | const event = {}; 36 | await bench 37 | .add("without cache", async () => { 38 | try { 39 | await coldHandler(event, context); 40 | } catch (e) {} 41 | }) 42 | .add("with cache", async () => { 43 | try { 44 | await warmHandler(event, context); 45 | } catch (e) {} 46 | }) 47 | 48 | .run(); 49 | 50 | console.table(bench.table()); 51 | -------------------------------------------------------------------------------- /packages/error-logger/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | logger?: (request: any) => void; 5 | } 6 | 7 | declare function errorLogger(options?: Options): middy.MiddlewareObj; 8 | 9 | export default errorLogger; 10 | -------------------------------------------------------------------------------- /packages/error-logger/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/error-logger/index.js: -------------------------------------------------------------------------------- 1 | const defaults = { 2 | logger: ({ error }) => console.error(error), 3 | }; 4 | 5 | const errorLoggerMiddleware = (opts = {}) => { 6 | let { logger } = { ...defaults, ...opts }; 7 | if (typeof logger !== "function") logger = null; 8 | 9 | const errorLoggerMiddlewareOnError = async (request) => { 10 | logger(request); 11 | }; 12 | return { 13 | onError: logger ? errorLoggerMiddlewareOnError : null, 14 | }; 15 | }; 16 | export default errorLoggerMiddleware; 17 | -------------------------------------------------------------------------------- /packages/error-logger/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => { 12 | throw new Error(); 13 | }; 14 | return middy(baseHandler).use(middleware({ logger: () => {} })); 15 | }; 16 | 17 | const warmHandler = setupHandler(); 18 | 19 | const event = {}; 20 | await bench 21 | .add("Catch Error", async () => { 22 | try { 23 | await warmHandler(event, context); 24 | } catch (e) {} 25 | }) 26 | 27 | .run(); 28 | 29 | console.table(bench.table()); 30 | -------------------------------------------------------------------------------- /packages/error-logger/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import errorLogger from "."; 4 | 5 | // use with default options 6 | let middleware = errorLogger(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = errorLogger({ 11 | logger: ({ error }) => { 12 | console.log(error); 13 | }, 14 | }); 15 | expectType(middleware); 16 | -------------------------------------------------------------------------------- /packages/event-normalizer/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | declare function eventNormalizer(): middy.MiddlewareObj; 4 | 5 | export default eventNormalizer; 6 | -------------------------------------------------------------------------------- /packages/event-normalizer/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/event-normalizer/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import eventNormalizer from "."; 4 | 5 | // use with default options 6 | let middleware = eventNormalizer(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = eventNormalizer(); 11 | expectType(middleware); 12 | -------------------------------------------------------------------------------- /packages/http-content-encoding/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | br?: any; 5 | gzip?: any; 6 | deflate?: any; 7 | overridePreferredEncoding?: string[]; 8 | } 9 | 10 | declare function httpContentEncoding(options?: Options): middy.MiddlewareObj; 11 | 12 | export default httpContentEncoding; 13 | -------------------------------------------------------------------------------- /packages/http-content-encoding/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | preferredEncoding: "br", 10 | }; 11 | 12 | test("fuzz `event` w/ `object`", async () => { 13 | await fc.assert( 14 | fc.asyncProperty(fc.object(), async (event) => { 15 | await handler(event, context); 16 | }), 17 | { 18 | numRuns: 100_000, 19 | verbose: 2, 20 | 21 | examples: [], 22 | }, 23 | ); 24 | }); 25 | 26 | test("fuzz `event` w/ `record`", async () => { 27 | await fc.assert( 28 | fc.asyncProperty( 29 | fc.record({ 30 | body: fc.anything(), 31 | }), 32 | async (event) => { 33 | await handler(event, context); 34 | }, 35 | ), 36 | { 37 | numRuns: 100_000, 38 | verbose: 2, 39 | 40 | examples: [], 41 | }, 42 | ); 43 | }); 44 | -------------------------------------------------------------------------------- /packages/http-content-encoding/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = (options) => { 11 | const response = JSON.stringify(new Array(100000).fill(0)); 12 | const baseHandler = () => response; 13 | return middy(baseHandler).use(middleware(options)); 14 | }; 15 | 16 | const gzHandler = setupHandler({ preferredEncoding: "gz" }); 17 | const brHandler = setupHandler({ preferredEncoding: "br" }); 18 | 19 | const event = {}; 20 | await bench 21 | .add("gzip Response", async () => { 22 | await gzHandler(event, context); 23 | }) 24 | .add("brotli Response", async () => { 25 | await brHandler(event, context); 26 | }) 27 | .run(); 28 | 29 | console.table(bench.table()); 30 | -------------------------------------------------------------------------------- /packages/http-content-encoding/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import httpContentEncodingMiddleware from "."; 4 | 5 | // use with default options 6 | let middleware = httpContentEncodingMiddleware(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = httpContentEncodingMiddleware({ 11 | br: {}, 12 | gzip: {}, 13 | deflate: {}, 14 | overridePreferredEncoding: ["br", "gzip", "deflate"], 15 | }); 16 | expectType(middleware); 17 | -------------------------------------------------------------------------------- /packages/http-content-negotiation/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | parseCharsets?: boolean; 5 | availableCharsets?: string[]; 6 | parseEncodings?: boolean; 7 | availableEncodings?: string[]; 8 | parseLanguages?: boolean; 9 | availableLanguages?: string[]; 10 | parseMediaTypes?: boolean; 11 | availableMediaTypes?: string[]; 12 | failOnMismatch?: boolean; 13 | } 14 | 15 | // eslint-disable-next-line @typescript-eslint/no-empty-interface 16 | export type Event = {}; 17 | 18 | export interface Context { 19 | preferredCharsets: string[]; 20 | preferredCharset: string; 21 | preferredEncodings: string[]; 22 | preferredEncoding: string; 23 | preferredLanguages: string[]; 24 | preferredLanguage: string; 25 | preferredMediaTypes: string[]; 26 | preferredMediaType: string; 27 | } 28 | 29 | declare function httpContentNegotiation( 30 | options?: Options, 31 | ): middy.MiddlewareObj; 32 | 33 | export default httpContentNegotiation; 34 | -------------------------------------------------------------------------------- /packages/http-content-negotiation/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use( 7 | middleware({ failOnMismatch: false }), 8 | ); 9 | const context = { 10 | getRemainingTimeInMillis: () => 1000, 11 | }; 12 | 13 | test("fuzz `event` w/ `object`", async () => { 14 | await fc.assert( 15 | fc.asyncProperty(fc.object(), async (event) => { 16 | await handler(event, context); 17 | }), 18 | { 19 | numRuns: 100_000, 20 | verbose: 2, 21 | 22 | examples: [], 23 | }, 24 | ); 25 | }); 26 | 27 | test("fuzz `event` w/ `record`", async () => { 28 | await fc.assert( 29 | fc.asyncProperty( 30 | fc.record({ 31 | headers: fc.record({ 32 | "Accept-Charset": fc.string(), 33 | "Accept-Encoding": fc.string(), 34 | "Accept-Language": fc.string(), 35 | Accept: fc.string(), 36 | }), 37 | }), 38 | async (event) => { 39 | await handler(event, context); 40 | }, 41 | ), 42 | { 43 | numRuns: 100_000, 44 | verbose: 2, 45 | 46 | examples: [], 47 | }, 48 | ); 49 | }); 50 | -------------------------------------------------------------------------------- /packages/http-content-negotiation/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use( 13 | middleware({ 14 | availableCharsets: ["utf-8"], 15 | availableEncodings: ["br", "gz"], 16 | availableLanguages: ["en-CA"], 17 | availableMediaTypes: ["text/plain", "application/json"], 18 | }), 19 | ); 20 | }; 21 | 22 | const warmHandler = setupHandler(); 23 | 24 | await bench 25 | .add( 26 | "Parse headers", 27 | async ( 28 | event = { 29 | headers: { 30 | "Accept-Charset": "utf-8, iso-8859-5, unicode-1-1;q=0.8", 31 | "Accept-Encoding": "gzip, deflate, br", 32 | "Accept-Language": "da, en-gb;q=0.8, en;q=0.7", 33 | Accept: "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c", 34 | }, 35 | }, 36 | ) => { 37 | try { 38 | await warmHandler(event, context); 39 | } catch (e) {} 40 | }, 41 | ) 42 | 43 | .run(); 44 | 45 | console.table(bench.table()); 46 | -------------------------------------------------------------------------------- /packages/http-content-negotiation/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import httpContentNegotiationMiddleware, { type Event } from "."; 4 | 5 | // use with default options 6 | let middleware = httpContentNegotiationMiddleware(); 7 | expectType>(middleware); 8 | 9 | // use with all options 10 | middleware = httpContentNegotiationMiddleware({ 11 | parseCharsets: true, 12 | availableCharsets: ["utf-8", "iso-8859-1"], 13 | parseEncodings: true, 14 | availableEncodings: ["gzip", "deflate"], 15 | parseLanguages: true, 16 | availableLanguages: ["it_IT", "en_GB"], 17 | parseMediaTypes: true, 18 | availableMediaTypes: ["application/xml", "application/json"], 19 | failOnMismatch: true, 20 | }); 21 | expectType>(middleware); 22 | -------------------------------------------------------------------------------- /packages/http-cors/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | export interface Options { 4 | getOrigin?: (incomingOrigin: string, options: Options) => string; 5 | credentials?: boolean | string; 6 | disableBeforePreflightResponse?: boolean; 7 | headers?: string; 8 | methods?: string; 9 | origin?: string; 10 | origins?: string[]; 11 | exposeHeaders?: string; 12 | maxAge?: number | string; 13 | requestHeaders?: string; 14 | requestMethods?: string; 15 | cacheControl?: string; 16 | } 17 | 18 | declare function httpCors(options?: Options): middy.MiddlewareObj; 19 | 20 | export default httpCors; 21 | -------------------------------------------------------------------------------- /packages/http-cors/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | 25 | test("fuzz `event` w/ `record`", async () => { 26 | await fc.assert( 27 | fc.asyncProperty( 28 | fc.record({ 29 | headers: fc.object(), 30 | }), 31 | async (event) => { 32 | await handler(event, context); 33 | }, 34 | ), 35 | { 36 | numRuns: 100_000, 37 | verbose: 2, 38 | 39 | examples: [], 40 | }, 41 | ); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/http-cors/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const warmHandler = setupHandler(); 16 | 17 | await bench 18 | .add("Add Headers", async (event = { httpMethod: "OPTIONS" }) => { 19 | try { 20 | await warmHandler(event, context); 21 | } catch (e) {} 22 | }) 23 | 24 | .run(); 25 | 26 | console.table(bench.table()); 27 | -------------------------------------------------------------------------------- /packages/http-cors/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import httpCors, { type Options } from "."; 4 | 5 | // use with default options 6 | let middleware = httpCors(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = httpCors({ 11 | credentials: true, // Access-Control-Allow-Credentials 12 | disableBeforePreflightResponse: true, // answer preflight requests accordingly 13 | headers: "X-Custom-Header, Upgrade-Insecure-Requests", // 'Access-Control-Allow-Headers', 14 | methods: "POST, GET, OPTIONS", // 'Access-Control-Allow-Methods' 15 | origin: "foo.bar.com", 16 | origins: ["foo.bar.com", "foo.baz.com"], 17 | exposeHeaders: "Content-Length, X-Kuma-Revision", // Access-Control-Expose-Headers 18 | maxAge: 600, // Access-Control-Max-Age 19 | requestHeaders: "X-PINGOTHER, Content-Type", // Access-Control-Request-Headers 20 | requestMethods: "POST", // Access-Control-Request-Methods 21 | cacheControl: "proxy-revalidate", // Cache-Control, 22 | getOrigin: (incomingOrigin: string, options: Options) => { 23 | return "foo.bar.com"; 24 | }, 25 | }); 26 | expectType(middleware); 27 | -------------------------------------------------------------------------------- /packages/http-error-handler/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | logger?: ((error: any) => void) | boolean; 5 | fallbackMessage?: string; 6 | } 7 | 8 | declare function httpErrorHandler(options?: Options): middy.MiddlewareObj; 9 | 10 | export default httpErrorHandler; 11 | -------------------------------------------------------------------------------- /packages/http-error-handler/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/http-error-handler/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => { 12 | throw new Error(); 13 | }; 14 | return middy(baseHandler).use(middleware({ logger: () => {} })); 15 | }; 16 | 17 | const warmHandler = setupHandler(); 18 | 19 | const event = {}; 20 | await bench 21 | .add("Handle Error", async () => { 22 | try { 23 | await warmHandler(event, context); 24 | } catch (e) {} 25 | }) 26 | 27 | .run(); 28 | 29 | console.table(bench.table()); 30 | -------------------------------------------------------------------------------- /packages/http-error-handler/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { HttpError } from "http-errors"; 3 | import { expectType } from "tsd"; 4 | import httpErrorHandler from "."; 5 | 6 | // use with default options 7 | let middleware = httpErrorHandler(); 8 | expectType(middleware); 9 | 10 | // use with all options 11 | middleware = httpErrorHandler({ 12 | logger: (error: HttpError) => { 13 | console.error(error); 14 | }, 15 | fallbackMessage: "whoopsiedoosie!", 16 | }); 17 | expectType(middleware); 18 | -------------------------------------------------------------------------------- /packages/http-event-normalizer/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { 3 | APIGatewayEvent, 4 | APIGatewayProxyEventMultiValueQueryStringParameters, 5 | APIGatewayProxyEventPathParameters, 6 | APIGatewayProxyEventQueryStringParameters, 7 | // TODO add in VPC Lattice event 8 | } from "aws-lambda"; 9 | 10 | export type Event = APIGatewayEvent & { 11 | multiValueQueryStringParameters: APIGatewayProxyEventMultiValueQueryStringParameters; 12 | pathParameters: APIGatewayProxyEventPathParameters; 13 | queryStringParameters: APIGatewayProxyEventQueryStringParameters; 14 | }; 15 | 16 | declare function httpEventNormalizer(): middy.MiddlewareObj; 17 | 18 | export default httpEventNormalizer; 19 | -------------------------------------------------------------------------------- /packages/http-event-normalizer/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/http-event-normalizer/index.js: -------------------------------------------------------------------------------- 1 | const httpEventNormalizerMiddleware = () => { 2 | const httpEventNormalizerMiddlewareBefore = async (request) => { 3 | const { event } = request; 4 | 5 | const version = pickVersion(event); 6 | // VPC Lattice is an http event, however uses a different notation 7 | // - query_string_parameters 8 | // - is_base64_encoded 9 | 10 | if (version === "1.0") { 11 | event.multiValueQueryStringParameters ??= {}; 12 | } else if (version === "vpc") { 13 | event.queryStringParameters = event.query_string_parameters; 14 | event.isBase64Encoded = event.is_base64_encoded; 15 | } 16 | 17 | // event.headers ??= {} // Will always have at least one header 18 | event.pathParameters ??= {}; 19 | event.queryStringParameters ??= {}; 20 | }; 21 | 22 | return { 23 | before: httpEventNormalizerMiddlewareBefore, 24 | }; 25 | }; 26 | 27 | const pickVersion = (event) => { 28 | // '1.0' is a safer default 29 | return event.version ?? (event.method ? "vpc" : "1.0"); 30 | }; 31 | 32 | export default httpEventNormalizerMiddleware; 33 | -------------------------------------------------------------------------------- /packages/http-event-normalizer/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const warmHandler = setupHandler(); 16 | 17 | const event = {}; 18 | await bench 19 | .add("Normalize Event", async () => { 20 | try { 21 | await warmHandler(event, context); 22 | } catch (e) {} 23 | }) 24 | 25 | .run(); 26 | 27 | console.table(bench.table()); 28 | -------------------------------------------------------------------------------- /packages/http-event-normalizer/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import httpEventNormalizer, { type Event } from "."; 4 | 5 | // use with default options 6 | let middleware = httpEventNormalizer(); 7 | expectType>(middleware); 8 | 9 | // use with all options 10 | middleware = httpEventNormalizer(); 11 | expectType>(middleware); 12 | -------------------------------------------------------------------------------- /packages/http-header-normalizer/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | canonical?: boolean; 5 | defaultHeaders?: Record; 6 | normalizeHeaderKey?: (key: string) => string; 7 | } 8 | 9 | // eslint-disable-next-line @typescript-eslint/no-empty-interface 10 | export type Event = {}; 11 | 12 | declare function httpHeaderNormalizer( 13 | options?: Options, 14 | ): middy.MiddlewareObj; 15 | 16 | export default httpHeaderNormalizer; 17 | -------------------------------------------------------------------------------- /packages/http-header-normalizer/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | 25 | test("fuzz `event` w/ `record`", async () => { 26 | await fc.assert( 27 | fc.asyncProperty( 28 | fc.record({ 29 | headers: fc.object(), 30 | }), 31 | async (event) => { 32 | await handler(event, context); 33 | }, 34 | ), 35 | { 36 | numRuns: 100_000, 37 | verbose: 2, 38 | 39 | examples: [], 40 | }, 41 | ); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/http-header-normalizer/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | return middy().use(middleware()); 12 | }; 13 | 14 | const warmHandler = setupHandler(); 15 | 16 | await bench 17 | .add( 18 | "Normalize Headers", 19 | async ( 20 | event = { 21 | headers: { 22 | accept: "*/*", 23 | "accept-encoding": "gzip, deflate, br", 24 | "content-type": "application/json", 25 | Host: "", 26 | "User-Agent": "", 27 | "X-Amzn-Trace-Id": "", 28 | }, 29 | }, 30 | ) => { 31 | try { 32 | await warmHandler(event, context); 33 | } catch (e) {} 34 | }, 35 | ) 36 | 37 | .run(); 38 | 39 | console.table(bench.table()); 40 | -------------------------------------------------------------------------------- /packages/http-header-normalizer/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import httpHeaderNormalizer, { type Event } from "."; 4 | 5 | // use with default options 6 | let middleware = httpHeaderNormalizer(); 7 | expectType>(middleware); 8 | 9 | // use with all options 10 | middleware = httpHeaderNormalizer({ 11 | normalizeHeaderKey: (key: string) => key.toLowerCase(), 12 | canonical: false, 13 | }); 14 | expectType>(middleware); 15 | -------------------------------------------------------------------------------- /packages/http-json-body-parser/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { 3 | ALBEvent, 4 | APIGatewayEvent, 5 | APIGatewayProxyEventV2, 6 | } from "aws-lambda"; 7 | 8 | interface Options { 9 | reviver?: (key: string, value: any) => any; 10 | disableContentTypeError?: boolean; 11 | } 12 | 13 | export type RequestEvent = APIGatewayEvent | APIGatewayProxyEventV2 | ALBEvent; 14 | 15 | declare function jsonBodyParser( 16 | options?: Options, 17 | ): middy.MiddlewareObj; 18 | 19 | export default jsonBodyParser; 20 | -------------------------------------------------------------------------------- /packages/http-json-body-parser/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | try { 15 | await handler(event, context); 16 | } catch (e) { 17 | if (e.cause?.package !== "@middy/http-json-body-parser") { 18 | throw e; 19 | } 20 | } 21 | }), 22 | { 23 | numRuns: 100_000, 24 | verbose: 2, 25 | 26 | examples: [], 27 | }, 28 | ); 29 | }); 30 | 31 | test("fuzz `event` w/ `record`", async () => { 32 | await fc.assert( 33 | fc.asyncProperty( 34 | fc.record({ 35 | headers: fc.record({ 36 | "content-type": fc.constant("application/json"), 37 | }), 38 | body: fc.string(), 39 | }), 40 | async (event) => { 41 | try { 42 | await handler(event, context); 43 | } catch (e) { 44 | if (e.cause?.package !== "@middy/http-json-body-parser") { 45 | throw e; 46 | } 47 | } 48 | }, 49 | ), 50 | { 51 | numRuns: 100_000, 52 | verbose: 2, 53 | 54 | examples: [], 55 | }, 56 | ); 57 | }); 58 | -------------------------------------------------------------------------------- /packages/http-json-body-parser/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | return middy().use(middleware()); 12 | }; 13 | 14 | const warmHandler = setupHandler(); 15 | 16 | await bench 17 | .add( 18 | "Parse body", 19 | async ( 20 | event = { 21 | headers: { 22 | "Content-Type": "application/json", 23 | }, 24 | body: '{ "foo": "bar" }', 25 | }, 26 | ) => { 27 | try { 28 | await warmHandler(event, context); 29 | } catch (e) {} 30 | }, 31 | ) 32 | 33 | .run(); 34 | 35 | console.table(bench.table()); 36 | -------------------------------------------------------------------------------- /packages/http-multipart-body-parser/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { APIGatewayEvent } from "aws-lambda"; 3 | import type { JsonValue } from "type-fest"; 4 | 5 | interface Options { 6 | busboy?: { 7 | headers?: any; 8 | highWaterMark?: number; 9 | fileHwm?: number; 10 | defCharset?: string; 11 | preservePath?: boolean; 12 | limits?: { 13 | fieldNameSize?: number; 14 | fieldSize?: number; 15 | fields?: number; 16 | fileSize?: number; 17 | files?: number; 18 | parts?: number; 19 | headerPairs?: number; 20 | }; 21 | }; 22 | charset?: string; 23 | disableContentTypeError?: boolean; 24 | } 25 | 26 | export type Event = Omit & { 27 | body: JsonValue; 28 | }; 29 | 30 | declare function multipartBodyParser( 31 | options?: Options, 32 | ): middy.MiddlewareObj; 33 | 34 | export default multipartBodyParser; 35 | -------------------------------------------------------------------------------- /packages/http-multipart-body-parser/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | try { 15 | await handler(event, context); 16 | } catch (e) { 17 | if (e.cause?.package !== "@middy/http-multipart-body-parser") { 18 | throw e; 19 | } 20 | } 21 | }), 22 | { 23 | numRuns: 100_000, 24 | verbose: 2, 25 | 26 | examples: [], 27 | }, 28 | ); 29 | }); 30 | 31 | test("fuzz `event` w/ `record`", async () => { 32 | await fc.assert( 33 | fc.asyncProperty( 34 | fc.record({ 35 | headers: fc.record({ 36 | "content-type": fc.constant("multipart/form-data; boundary="), 37 | }), 38 | body: fc.string(), 39 | }), 40 | async (event) => { 41 | try { 42 | await handler(event, context); 43 | } catch (e) { 44 | if (e.cause?.package !== "@middy/http-multipart-body-parser") { 45 | throw e; 46 | } 47 | } 48 | }, 49 | ), 50 | { 51 | numRuns: 100_000, 52 | verbose: 2, 53 | 54 | examples: [], 55 | }, 56 | ); 57 | }); 58 | -------------------------------------------------------------------------------- /packages/http-multipart-body-parser/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const warmHandler = setupHandler(); 16 | 17 | await bench 18 | .add( 19 | "Parse body", 20 | async ( 21 | event = { 22 | headers: { 23 | "Content-Type": 24 | "multipart/form-data; boundary=----WebKitFormBoundaryppsQEwf2BVJeCe0M", 25 | }, 26 | body: "LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5cHBzUUV3ZjJCVkplQ2UwTQ0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJmb28iDQoNCmJhcg0KLS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5cHBzUUV3ZjJCVkplQ2UwTS0t", 27 | isBase64Encoded: true, 28 | }, 29 | ) => { 30 | try { 31 | await warmHandler(event, context); 32 | } catch (e) {} 33 | }, 34 | ) 35 | 36 | .run(); 37 | 38 | console.table(bench.table()); 39 | -------------------------------------------------------------------------------- /packages/http-multipart-body-parser/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import multipartBodyParser, { type Event } from "."; 4 | 5 | // use with default options 6 | let middleware = multipartBodyParser(); 7 | expectType>(middleware); 8 | 9 | // use with all options 10 | middleware = multipartBodyParser({ 11 | busboy: { 12 | headers: { "x-foo": "bar" }, 13 | highWaterMark: 1024, 14 | fileHwm: 1024, 15 | defCharset: "utf-8", 16 | preservePath: false, 17 | limits: { 18 | fieldNameSize: 256, 19 | fieldSize: 1024 * 1024 * 10, 20 | fields: 100, 21 | fileSize: 1024 * 1024 * 10, 22 | files: 3, 23 | parts: 100, 24 | headerPairs: 100, 25 | }, 26 | }, 27 | charset: "utf8", 28 | }); 29 | expectType>(middleware); 30 | -------------------------------------------------------------------------------- /packages/http-partial-response/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | filteringKeyName?: string; 5 | } 6 | 7 | declare function httpPartialResponse(options?: Options): middy.MiddlewareObj; 8 | 9 | export default httpPartialResponse; 10 | -------------------------------------------------------------------------------- /packages/http-partial-response/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/http-partial-response/index.js: -------------------------------------------------------------------------------- 1 | import { jsonSafeParse, normalizeHttpResponse } from "@middy/util"; 2 | import mask from "json-mask"; 3 | 4 | const defaults = { 5 | filteringKeyName: "fields", 6 | }; 7 | 8 | const httpPartialResponseMiddleware = (opts = {}) => { 9 | const options = { ...defaults, ...opts }; 10 | const { filteringKeyName } = options; 11 | 12 | const httpPartialResponseMiddlewareAfter = async (request) => { 13 | const fields = request.event?.queryStringParameters?.[filteringKeyName]; 14 | if (!fields) return; 15 | 16 | normalizeHttpResponse(request); 17 | const body = request.response.body; 18 | const bodyIsString = typeof body === "string"; 19 | 20 | const parsedBody = jsonSafeParse(body); 21 | if (typeof parsedBody !== "object") return; 22 | 23 | const filteredBody = mask(parsedBody, fields); 24 | 25 | request.response.body = bodyIsString 26 | ? JSON.stringify(filteredBody) 27 | : filteredBody; 28 | }; 29 | 30 | return { 31 | after: httpPartialResponseMiddlewareAfter, 32 | }; 33 | }; 34 | export default httpPartialResponseMiddleware; 35 | -------------------------------------------------------------------------------- /packages/http-partial-response/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => ({ 12 | body: JSON.stringify({ 13 | foo: "bar", 14 | bar: "foo", 15 | }), 16 | }); 17 | return middy(baseHandler).use(middleware()); 18 | }; 19 | 20 | const warmHandler = setupHandler(); 21 | 22 | await bench 23 | .add( 24 | "Normalize Headers", 25 | async ( 26 | event = { 27 | queryStringParameters: { 28 | fields: "foo", 29 | }, 30 | }, 31 | ) => { 32 | try { 33 | await warmHandler(event, context); 34 | } catch (e) {} 35 | }, 36 | ) 37 | 38 | .run(); 39 | 40 | console.table(bench.table()); 41 | -------------------------------------------------------------------------------- /packages/http-partial-response/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import httpPartialResponse from "."; 4 | 5 | // use with default options 6 | let middleware = httpPartialResponse(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = httpPartialResponse({ 11 | filteringKeyName: "something", 12 | }); 13 | expectType(middleware); 14 | -------------------------------------------------------------------------------- /packages/http-response-serializer/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface SerializerHandler { 4 | regex: RegExp; 5 | serializer: (response: any) => string | { body: any; [key: string]: any }; 6 | } 7 | 8 | interface Options { 9 | serializers: SerializerHandler[]; 10 | defaultContentType?: string; 11 | } 12 | 13 | declare function httpResponseSerializer(options?: Options): middy.MiddlewareObj; 14 | 15 | export default httpResponseSerializer; 16 | -------------------------------------------------------------------------------- /packages/http-response-serializer/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/http-response-serializer/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => ({ 12 | body: JSON.stringify({ 13 | foo: "bar", 14 | bar: "foo", 15 | }), 16 | }); 17 | return middy(baseHandler).use( 18 | middleware({ 19 | serializers: [ 20 | { 21 | regex: /^application\/xml$/, 22 | serializer: ({ body }) => `${body}`, 23 | }, 24 | { 25 | regex: /^application\/json$/, 26 | serializer: ({ body }) => JSON.stringify(body), 27 | }, 28 | { 29 | regex: /^text\/plain$/, 30 | serializer: ({ body }) => body, 31 | }, 32 | ], 33 | default: "application/json", 34 | }), 35 | ); 36 | }; 37 | 38 | const warmHandler = setupHandler(); 39 | 40 | const event = {}; 41 | await bench 42 | .add("Serialize Response", async () => { 43 | try { 44 | await warmHandler(event, context); 45 | } catch (e) {} 46 | }) 47 | 48 | .run(); 49 | 50 | console.table(bench.table()); 51 | -------------------------------------------------------------------------------- /packages/http-response-serializer/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import httpResponseSerializer from "."; 4 | 5 | // use with default options 6 | let middleware = httpResponseSerializer(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = httpResponseSerializer({ 11 | defaultContentType: "application/json", 12 | serializers: [ 13 | { 14 | regex: /^application\/xml$/, 15 | serializer: (data) => data, 16 | }, 17 | ], 18 | }); 19 | expectType(middleware); 20 | -------------------------------------------------------------------------------- /packages/http-router/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { MiddyfiedHandler } from "@middy/core"; 3 | import type { 4 | ALBEvent, 5 | ALBResult, 6 | APIGatewayProxyEvent, 7 | APIGatewayProxyEventV2, 8 | APIGatewayProxyResult, 9 | APIGatewayProxyResultV2, 10 | Handler as LambdaHandler, 11 | } from "aws-lambda"; 12 | 13 | export type Method = 14 | | "GET" 15 | | "POST" 16 | | "PUT" 17 | | "PATCH" 18 | | "DELETE" 19 | | "OPTIONS" 20 | | "HEAD" 21 | | "ANY"; 22 | 23 | export interface Route { 24 | method: Method; 25 | path: string; 26 | handler: 27 | | LambdaHandler 28 | | MiddyfiedHandler; 29 | } 30 | 31 | export type RouteNotFoundResponseFn = (input: { 32 | method: string; 33 | path: string; 34 | }) => never; 35 | 36 | declare function httpRouterHandler< 37 | TEvent extends 38 | | ALBEvent 39 | | APIGatewayProxyEvent 40 | | APIGatewayProxyEventV2 = APIGatewayProxyEvent, 41 | TResult extends 42 | | ALBResult 43 | | APIGatewayProxyResult 44 | | APIGatewayProxyResultV2 = APIGatewayProxyResult, 45 | >( 46 | routes: 47 | | Array> 48 | | { 49 | routes: Array>; 50 | notFoundResponse: RouteNotFoundResponseFn; 51 | }, 52 | ): middy.MiddyfiedHandler; 53 | 54 | export default httpRouterHandler; 55 | -------------------------------------------------------------------------------- /packages/http-security-headers/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | dnsPrefetchControl?: { 5 | allow?: boolean; 6 | }; 7 | frameOptions?: { 8 | action?: string; 9 | }; 10 | poweredBy?: { 11 | server: string; 12 | }; 13 | strictTransportSecurity?: { 14 | maxAge?: number; 15 | includeSubDomains?: boolean; 16 | preload?: boolean; 17 | }; 18 | downloadOptions?: { 19 | action?: string; 20 | }; 21 | contentTypeOptions?: { 22 | action?: string; 23 | }; 24 | originAgentCluster?: boolean; 25 | referrerPolicy?: { 26 | policy?: string; 27 | }; 28 | xssProtection?: { 29 | reportUri?: string; 30 | }; 31 | contentSecurityPolicy?: Record; 32 | contentSecurityPolicyReportOnly?: boolean; 33 | crossOriginEmbedderPolicy?: { 34 | policy?: string; 35 | }; 36 | crossOriginOpenerPolicy?: { 37 | policy?: string; 38 | }; 39 | crossOriginResourcePolicy?: { 40 | policy?: string; 41 | }; 42 | permissionsPolicy?: Record; 43 | permittedCrossDomainPolicies?: { 44 | policy?: string; 45 | }; 46 | reportTo?: { 47 | maxAge?: number; 48 | default?: string; 49 | includeSubdomains?: boolean; 50 | csp?: string; 51 | staple?: string; 52 | xss?: string; 53 | }; 54 | } 55 | 56 | type WithBoolValues = { [K in keyof T]: T[K] | boolean }; 57 | 58 | declare function httpSecurityHeaders( 59 | options?: WithBoolValues, 60 | ): middy.MiddlewareObj; 61 | 62 | export default httpSecurityHeaders; 63 | -------------------------------------------------------------------------------- /packages/http-security-headers/test.index.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const warmHandler = setupHandler(); 16 | 17 | const event = {}; 18 | await bench 19 | .add("Add Headers", async () => { 20 | try { 21 | await warmHandler(event, context); 22 | } catch (e) {} 23 | }) 24 | 25 | .run(); 26 | 27 | console.table(bench.table()); 28 | -------------------------------------------------------------------------------- /packages/http-urlencode-body-parser/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { APIGatewayEvent } from "aws-lambda"; 3 | import type { JsonValue } from "type-fest"; 4 | 5 | interface Options { 6 | disableContentTypeError?: boolean; 7 | } 8 | 9 | export type Event = APIGatewayEvent & { 10 | body: JsonValue; 11 | }; 12 | 13 | declare function urlEncodeBodyParser( 14 | options?: Options, 15 | ): middy.MiddlewareObj; 16 | 17 | export default urlEncodeBodyParser; 18 | -------------------------------------------------------------------------------- /packages/http-urlencode-body-parser/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | try { 15 | await handler(event, context); 16 | } catch (e) { 17 | if (e.cause?.package !== "@middy/http-urlencode-body-parser") { 18 | throw e; 19 | } 20 | } 21 | }), 22 | { 23 | numRuns: 100_000, 24 | verbose: 2, 25 | 26 | examples: [], 27 | }, 28 | ); 29 | }); 30 | 31 | test("fuzz `event` w/ `record`", async () => { 32 | await fc.assert( 33 | fc.asyncProperty( 34 | fc.record({ 35 | headers: fc.record({ 36 | "content-type": fc.constant("application/x-www-form-urlencoded"), 37 | }), 38 | body: fc.string(), 39 | }), 40 | async (event) => { 41 | try { 42 | await handler(event, context); 43 | } catch (e) { 44 | if (e.cause?.package !== "@middy/http-urlencode-body-parser") { 45 | throw e; 46 | } 47 | } 48 | }, 49 | ), 50 | { 51 | numRuns: 100_000, 52 | verbose: 2, 53 | 54 | examples: [], 55 | }, 56 | ); 57 | }); 58 | -------------------------------------------------------------------------------- /packages/http-urlencode-body-parser/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const warmHandler = setupHandler(); 16 | 17 | await bench 18 | .add( 19 | "Parse body", 20 | async ( 21 | event = { 22 | headers: { 23 | "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", 24 | }, 25 | body: "a[b][c][d]=i", 26 | }, 27 | ) => { 28 | try { 29 | await warmHandler(event, context); 30 | } catch (e) {} 31 | }, 32 | ) 33 | 34 | .run(); 35 | 36 | console.table(bench.table()); 37 | -------------------------------------------------------------------------------- /packages/http-urlencode-body-parser/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import urlEncodeBodyParser, { type Event } from "."; 4 | 5 | // use with default options 6 | const middleware = urlEncodeBodyParser(); 7 | expectType>(middleware); 8 | -------------------------------------------------------------------------------- /packages/http-urlencode-path-parser/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { APIGatewayEvent } from "aws-lambda"; 3 | import type { JsonValue } from "type-fest"; 4 | 5 | export type Event = APIGatewayEvent & { 6 | body: JsonValue; 7 | }; 8 | 9 | declare function urlEncodePathParser(): middy.MiddlewareObj; 10 | 11 | export default urlEncodePathParser; 12 | -------------------------------------------------------------------------------- /packages/http-urlencode-path-parser/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/http-urlencode-path-parser/index.js: -------------------------------------------------------------------------------- 1 | const httpUrlencodePathParserMiddlewareBefore = async (request) => { 2 | if (!request.event.pathParameters) return; 3 | for (const key in request.event.pathParameters) { 4 | request.event.pathParameters[key] = decodeURIComponent( 5 | request.event.pathParameters[key], 6 | ); 7 | } 8 | }; 9 | 10 | const httpUrlencodePathParserMiddleware = () => ({ 11 | before: httpUrlencodePathParserMiddlewareBefore, 12 | }); 13 | export default httpUrlencodePathParserMiddleware; 14 | -------------------------------------------------------------------------------- /packages/http-urlencode-path-parser/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const warmHandler = setupHandler(); 16 | 17 | await bench 18 | .add( 19 | "Parse body", 20 | async ( 21 | event = { 22 | pathParameters: { 23 | char: "M%C3%AEddy", 24 | }, 25 | }, 26 | ) => { 27 | try { 28 | await warmHandler(event, context); 29 | } catch (e) {} 30 | }, 31 | ) 32 | 33 | .run(); 34 | 35 | console.table(bench.table()); 36 | -------------------------------------------------------------------------------- /packages/http-urlencode-path-parser/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import urlEncodePathParser, { type Event } from "."; 4 | 5 | // use with default options 6 | const middleware = urlEncodePathParser(); 7 | expectType>(middleware); 8 | -------------------------------------------------------------------------------- /packages/input-output-logger/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | logger?: (message: any) => void; 5 | awsContext?: boolean; 6 | omitPaths?: string[]; 7 | mask?: string; 8 | } 9 | 10 | declare function inputOutputLogger(options?: Options): middy.MiddlewareObj; 11 | 12 | export default inputOutputLogger; 13 | -------------------------------------------------------------------------------- /packages/input-output-logger/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware({ logger: () => {} })); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/input-output-logger/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import inputOutputLogger from "."; 4 | 5 | // use with default options 6 | let middleware = inputOutputLogger(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = inputOutputLogger({ 11 | logger: (...args) => { 12 | console.log(...args); 13 | }, 14 | awsContext: true, 15 | omitPaths: ["a", "b", "c"], 16 | }); 17 | expectType(middleware); 18 | -------------------------------------------------------------------------------- /packages/rds-signer/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { Signer, SignerConfig } from "@aws-sdk/rds-signer"; 2 | import type middy from "@middy/core"; 3 | import type { Options as MiddyOptions } from "@middy/util"; 4 | import type { Context as LambdaContext } from "aws-lambda"; 5 | 6 | export type RdsSignerOptions = Omit< 7 | MiddyOptions, 8 | "fetchData" 9 | > & { 10 | fetchData?: { 11 | [key: string]: SignerConfig; 12 | }; 13 | }; 14 | 15 | export type Context = 16 | TOptions extends { setToContext: true } 17 | ? TOptions extends { fetchData: infer TFetchData } 18 | ? LambdaContext & { 19 | [Key in keyof TFetchData]: string; 20 | } 21 | : LambdaContext 22 | : LambdaContext; 23 | 24 | export type Internal = 25 | TOptions extends RdsSignerOptions 26 | ? TOptions extends { fetchData: infer TFetchData } 27 | ? { 28 | [Key in keyof TFetchData]: string; 29 | } 30 | : {} 31 | : {}; 32 | 33 | declare function rdsSigner( 34 | options?: TOptions, 35 | ): middy.MiddlewareObj< 36 | unknown, 37 | any, 38 | Error, 39 | Context, 40 | Internal 41 | >; 42 | 43 | export default rdsSigner; 44 | -------------------------------------------------------------------------------- /packages/rds-signer/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/s3-object-response/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { ClientRequest } from "node:http"; 2 | import type { S3Client, S3ClientConfig } from "@aws-sdk/client-s3"; 3 | import type middy from "@middy/core"; 4 | import type { Options as MiddyOptions } from "@middy/util"; 5 | import type { Context as LambdaContext } from "aws-lambda"; 6 | 7 | export interface S3ObjectResponseOptions 8 | extends Pick< 9 | MiddyOptions, 10 | | "AwsClient" 11 | | "awsClientOptions" 12 | | "awsClientAssumeRole" 13 | | "awsClientCapture" 14 | | "disablePrefetch" 15 | > { 16 | bodyType?: "stream" | "promise"; 17 | } 18 | 19 | export type Context = 20 | LambdaContext & { 21 | s3Object: TOptions extends { bodyType: "stream" } 22 | ? ClientRequest 23 | : TOptions extends { bodyType: "promise" } 24 | ? Promise 25 | : never; 26 | } & { 27 | s3ObjectFetch: Promise; 28 | }; 29 | 30 | export interface Internal extends Record { 31 | s3ObjectResponse: { 32 | RequestRoute: string; 33 | RequestToken: string; 34 | }; 35 | } 36 | 37 | declare function s3ObjectResponse< 38 | TOptions extends S3ObjectResponseOptions | undefined, 39 | >( 40 | options?: TOptions, 41 | ): middy.MiddlewareObj, Internal>; 42 | 43 | export default s3ObjectResponse; 44 | -------------------------------------------------------------------------------- /packages/s3-object-response/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | import { S3Client, WriteGetObjectResponseCommand } from "@aws-sdk/client-s3"; 6 | import { mockClient } from "aws-sdk-client-mock"; 7 | 8 | const bench = new Bench({ time: 1_000 }); 9 | 10 | const context = { 11 | getRemainingTimeInMillis: () => 30000, 12 | }; 13 | 14 | globalThis.fetch = () => Promise.resolve(); 15 | const setupHandler = (options = {}) => { 16 | mockClient(S3Client) 17 | .on(WriteGetObjectResponseCommand) 18 | .resolves({ statusCode: 200 }); 19 | const baseHandler = () => {}; 20 | return middy(baseHandler).use( 21 | middleware({ 22 | ...options, 23 | AwsClient: S3Client, 24 | }), 25 | ); 26 | }; 27 | 28 | const coldHandler = setupHandler({ disablePrefetch: true }); 29 | const warmHandler = setupHandler(); 30 | 31 | const event = { 32 | getObjectContext: { 33 | inputS3Url: "http://localhost", 34 | }, 35 | }; 36 | await bench 37 | .add("without cache", async () => { 38 | try { 39 | await coldHandler(event, context); 40 | } catch (e) {} 41 | }) 42 | .add("with cache", async () => { 43 | try { 44 | await warmHandler(event, context); 45 | } catch (e) {} 46 | }) 47 | 48 | .run(); 49 | 50 | console.table(bench.table()); 51 | -------------------------------------------------------------------------------- /packages/s3/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/s3/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3"; 6 | import { mockClient } from "aws-sdk-client-mock"; 7 | 8 | const bench = new Bench({ time: 1_000 }); 9 | 10 | const context = { 11 | getRemainingTimeInMillis: () => 30000, 12 | }; 13 | const setupHandler = (options = {}) => { 14 | const s3Response = (content) => { 15 | return { 16 | transformToString: async () => content, 17 | }; 18 | }; 19 | mockClient(S3Client) 20 | .on(GetObjectCommand) 21 | .resolvesOnce({ 22 | ContentType: "application/json", 23 | Body: s3Response('{"option":"value"}'), 24 | }); 25 | const baseHandler = () => {}; 26 | return middy(baseHandler).use( 27 | middleware({ 28 | ...options, 29 | AwsClient: S3Client, 30 | }), 31 | ); 32 | }; 33 | 34 | const coldHandler = setupHandler({ cacheExpiry: 0 }); 35 | const warmHandler = setupHandler(); 36 | 37 | const event = {}; 38 | await bench 39 | .add("without cache", async () => { 40 | try { 41 | await coldHandler(event, context); 42 | } catch (e) {} 43 | }) 44 | .add("with cache", async () => { 45 | try { 46 | await warmHandler(event, context); 47 | } catch (e) {} 48 | }) 49 | 50 | .run(); 51 | 52 | console.table(bench.table()); 53 | -------------------------------------------------------------------------------- /packages/secrets-manager/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/secrets-manager/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | import { 6 | GetSecretValueCommand, 7 | SecretsManagerClient, 8 | } from "@aws-sdk/client-secrets-manager"; 9 | import { mockClient } from "aws-sdk-client-mock"; 10 | 11 | const bench = new Bench({ time: 1_000 }); 12 | 13 | const context = { 14 | getRemainingTimeInMillis: () => 30000, 15 | }; 16 | const setupHandler = (options = {}) => { 17 | mockClient(SecretsManagerClient) 18 | .on(GetSecretValueCommand) 19 | .resolves({ SecretString: "token" }); 20 | const baseHandler = () => {}; 21 | return middy(baseHandler).use( 22 | middleware({ 23 | ...options, 24 | AwsClient: SecretsManagerClient, 25 | }), 26 | ); 27 | }; 28 | 29 | const coldHandler = setupHandler({ cacheExpiry: 0 }); 30 | const warmHandler = setupHandler(); 31 | 32 | const event = {}; 33 | await bench 34 | .add("without cache", async () => { 35 | try { 36 | await coldHandler(event, context); 37 | } catch (e) {} 38 | }) 39 | .add("with cache", async () => { 40 | try { 41 | await warmHandler(event, context); 42 | } catch (e) {} 43 | }) 44 | 45 | .run(); 46 | 47 | console.table(bench.table()); 48 | -------------------------------------------------------------------------------- /packages/service-discovery/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/service-discovery/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | import { 6 | DiscoverInstancesCommand, 7 | ServiceDiscoveryClient, 8 | } from "@aws-sdk/client-servicediscovery"; 9 | import { mockClient } from "aws-sdk-client-mock"; 10 | 11 | const bench = new Bench({ time: 1_000 }); 12 | 13 | const context = { 14 | getRemainingTimeInMillis: () => 30000, 15 | }; 16 | const setupHandler = (options = {}) => { 17 | mockClient(ServiceDiscoveryClient) 18 | .on(DiscoverInstancesCommand) 19 | .resolves({ 20 | Instances: [ 21 | { 22 | Attributes: { 23 | AWS_INSTANCE_IPV4: "172.2.1.3", 24 | AWS_INSTANCE_PORT: "808", 25 | }, 26 | HealthStatus: "UNKNOWN", 27 | InstanceId: "myservice-53", 28 | NamespaceName: "example.com", 29 | ServiceName: "myservice", 30 | }, 31 | ], 32 | }); 33 | const baseHandler = () => {}; 34 | return middy(baseHandler).use( 35 | middleware({ 36 | ...options, 37 | AwsClient: ServiceDiscoveryClient, 38 | }), 39 | ); 40 | }; 41 | 42 | const coldHandler = setupHandler({ cacheExpiry: 0 }); 43 | const warmHandler = setupHandler(); 44 | 45 | const event = {}; 46 | await bench 47 | .add("without cache", async () => { 48 | try { 49 | await coldHandler(event, context); 50 | } catch (e) {} 51 | }) 52 | .add("with cache", async () => { 53 | try { 54 | await warmHandler(event, context); 55 | } catch (e) {} 56 | }) 57 | 58 | .run(); 59 | 60 | console.table(bench.table()); 61 | -------------------------------------------------------------------------------- /packages/sqs-partial-batch-failure/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | logger?: (reason: any, record: any) => void; 5 | } 6 | 7 | declare function sqsPartialBatchFailure(options?: Options): middy.MiddlewareObj; 8 | 9 | export default sqsPartialBatchFailure; 10 | -------------------------------------------------------------------------------- /packages/sqs-partial-batch-failure/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware({ logger: false })); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | 25 | test("fuzz `event` w/ `record`", async () => { 26 | await fc.assert( 27 | fc.asyncProperty( 28 | fc.record({ 29 | Records: fc.array(fc.object()), 30 | response: fc.array( 31 | fc.record({ 32 | status: fc.constantFrom("pending", "fulfilled", "rejected"), 33 | reason: fc.string(), 34 | }), 35 | ), 36 | }), 37 | async (event) => { 38 | await handler(event, context); 39 | }, 40 | ), 41 | { 42 | numRuns: 100_000, 43 | verbose: 2, 44 | 45 | examples: [], 46 | }, 47 | ); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/sqs-partial-batch-failure/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = (event) => { 12 | const recordPromises = event.Records.map((record, index) => { 13 | return Promise.resolve(record); 14 | }); 15 | return Promise.allSettled(recordPromises); 16 | }; 17 | return middy(baseHandler).use(middleware()); 18 | }; 19 | 20 | const warmHandler = setupHandler(); 21 | 22 | const event = { 23 | Records: [{}], 24 | }; 25 | await bench 26 | .add("process failures", async () => { 27 | try { 28 | await warmHandler(event, context); 29 | } catch (e) {} 30 | }) 31 | .run(); 32 | 33 | console.table(bench.table()); 34 | -------------------------------------------------------------------------------- /packages/sqs-partial-batch-failure/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import sqsPartialBatchFailure from "."; 4 | 5 | // use with default options 6 | let middleware = sqsPartialBatchFailure(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = sqsPartialBatchFailure({ 11 | logger: (...args) => { 12 | console.error(...args); 13 | }, 14 | }); 15 | expectType(middleware); 16 | -------------------------------------------------------------------------------- /packages/ssm/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { SSMClient, SSMClientConfig } from "@aws-sdk/client-ssm"; 2 | import type middy from "@middy/core"; 3 | import type { Options as MiddyOptions } from "@middy/util"; 4 | import type { Context as LambdaContext } from "aws-lambda"; 5 | 6 | export type ParamType = string & { __returnType?: T }; 7 | export declare function ssmParam(path: string): ParamType; 8 | 9 | export interface SSMOptions 10 | extends Omit, "fetchData"> { 11 | fetchData?: { [key: string]: string | ParamType }; 12 | } 13 | 14 | export type Context = 15 | TOptions extends { setToContext: true } 16 | ? TOptions extends { fetchData: infer TFetchData } 17 | ? LambdaContext & { 18 | [Key in keyof TFetchData]: TFetchData[Key] extends ParamType 19 | ? T 20 | : unknown; 21 | } 22 | : never 23 | : LambdaContext; 24 | 25 | export type Internal = 26 | TOptions extends SSMOptions 27 | ? TOptions extends { fetchData: infer TFetchData } 28 | ? { 29 | [Key in keyof TFetchData]: TFetchData[Key] extends ParamType 30 | ? T 31 | : unknown; 32 | } 33 | : {} 34 | : {}; 35 | 36 | declare function ssm( 37 | options?: TOptions, 38 | ): middy.MiddlewareObj< 39 | unknown, 40 | any, 41 | Error, 42 | Context, 43 | Internal 44 | >; 45 | 46 | export default ssm; 47 | -------------------------------------------------------------------------------- /packages/ssm/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/ssm/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | import { 6 | GetParametersByPathCommand, 7 | GetParametersCommand, 8 | SSMClient, 9 | } from "@aws-sdk/client-ssm"; 10 | import { mockClient } from "aws-sdk-client-mock"; 11 | 12 | const bench = new Bench({ time: 1_000 }); 13 | 14 | const context = { 15 | getRemainingTimeInMillis: () => 30000, 16 | }; 17 | const setupHandler = (options = {}) => { 18 | mockClient(SSMClient) 19 | .on(GetParametersCommand) 20 | .resolves({ Parameters: [{ Name: "/key", Value: "value" }] }) 21 | .on(GetParametersByPathCommand) 22 | .resolves({ Parameters: [{ Name: "/key", Value: "value" }] }); 23 | const baseHandler = () => {}; 24 | return middy(baseHandler).use( 25 | middleware({ 26 | ...options, 27 | AwsClient: SSMClient, 28 | }), 29 | ); 30 | }; 31 | 32 | const coldHandler = setupHandler({ cacheExpiry: 0 }); 33 | const warmHandler = setupHandler(); 34 | 35 | const event = {}; 36 | await bench 37 | .add("without cache", async () => { 38 | try { 39 | await coldHandler(event, context); 40 | } catch (e) {} 41 | }) 42 | .add("with cache", async () => { 43 | try { 44 | await warmHandler(event, context); 45 | } catch (e) {} 46 | }) 47 | 48 | .run(); 49 | 50 | console.table(bench.table()); 51 | -------------------------------------------------------------------------------- /packages/sts/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/sts/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | import { AssumeRoleCommand, STSClient } from "@aws-sdk/client-sts"; 6 | import { mockClient } from "aws-sdk-client-mock"; 7 | 8 | const bench = new Bench({ time: 1_000 }); 9 | 10 | const context = { 11 | getRemainingTimeInMillis: () => 30000, 12 | }; 13 | const setupHandler = (options = {}) => { 14 | mockClient(STSClient) 15 | .on(AssumeRoleCommand) 16 | .resolves({ 17 | Credentials: { 18 | AccessKeyId: "accessKeyId", 19 | SecretAccessKey: "secretAccessKey", 20 | SessionToken: "sessionToken", 21 | }, 22 | }); 23 | const baseHandler = () => {}; 24 | return middy(baseHandler).use( 25 | middleware({ 26 | ...options, 27 | AwsClient: STSClient, 28 | }), 29 | ); 30 | }; 31 | 32 | const coldHandler = setupHandler({ cacheExpiry: 0 }); 33 | const warmHandler = setupHandler(); 34 | 35 | const event = {}; 36 | await bench 37 | .add("without cache", async () => { 38 | try { 39 | await coldHandler(event, context); 40 | } catch (e) {} 41 | }) 42 | .add("with cache", async () => { 43 | try { 44 | await warmHandler(event, context); 45 | } catch (e) {} 46 | }) 47 | 48 | .run(); 49 | 50 | console.table(bench.table()); 51 | -------------------------------------------------------------------------------- /packages/sts/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import { STSClient } from "@aws-sdk/client-sts"; 2 | import middy from "@middy/core"; 3 | import { getInternal } from "@middy/util"; 4 | import type { Context as LambdaContext } from "aws-lambda"; 5 | import { captureAWSv3Client } from "aws-xray-sdk"; 6 | import { expectType } from "tsd"; 7 | import sts, { type AssumedRoleCredentials, type Context } from "."; 8 | 9 | // use with default options 10 | expectType>>(sts()); 11 | 12 | // use with all options 13 | const options = { 14 | AwsClient: STSClient, 15 | awsClientCapture: captureAWSv3Client, 16 | disablePrefetch: true, 17 | }; 18 | expectType>>( 19 | sts(options), 20 | ); 21 | 22 | const handler = middy(async (event: {}, context: LambdaContext) => { 23 | return await Promise.resolve({}); 24 | }); 25 | 26 | // setToContext: true 27 | handler 28 | .use( 29 | sts({ 30 | ...options, 31 | fetchData: { foo: { RoleArn: "foo" } }, 32 | setToContext: true, 33 | }), 34 | ) 35 | .before(async (request) => { 36 | expectType(request.context.foo); 37 | 38 | const data = await getInternal("foo", request); 39 | expectType(data.foo); 40 | }); 41 | 42 | // setToContext: false 43 | handler 44 | .use( 45 | sts({ 46 | ...options, 47 | fetchData: { foo: { RoleArn: "foo" } }, 48 | setToContext: false, 49 | }), 50 | ) 51 | .before(async (request) => { 52 | const data = await getInternal("foo", request); 53 | expectType(data.foo); 54 | }); 55 | -------------------------------------------------------------------------------- /packages/util/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | 3 | import { 4 | getInternal, 5 | jsonSafeParse, 6 | normalizeHttpResponse, 7 | processCache, 8 | } from "./index.js"; 9 | 10 | const bench = new Bench({ time: 1_000 }); 11 | 12 | await bench 13 | .add("getInternal", async () => { 14 | await getInternal(true, { 15 | internal: { 16 | key: Promise.resolve("value"), 17 | }, 18 | }); 19 | }) 20 | .add("processCache w/ { cacheExpiry: 0 }", async () => { 21 | await processCache({ cacheExpiry: 0, cacheKey: "key" }); 22 | }) 23 | .add("processCache w/ { cacheExpiry: -1 }", async () => { 24 | await processCache({ cacheExpiry: -1, cacheKey: "key" }); 25 | }) 26 | .add("jsonSafeParse", async () => { 27 | await jsonSafeParse('{"key":"value"}'); 28 | }) 29 | .add("normalizeHttpResponse", async () => { 30 | await normalizeHttpResponse({}); 31 | }) 32 | .run(); 33 | 34 | console.table(bench.table()); 35 | -------------------------------------------------------------------------------- /packages/validator/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | eventSchema?: Function | any; 5 | contextSchema?: Function | any; 6 | responseSchema?: Function | any; 7 | defaultLanguage?: string; 8 | languages?: object | any; 9 | } 10 | 11 | declare function validator(options?: Options): middy.MiddlewareObj; 12 | 13 | export default validator; 14 | -------------------------------------------------------------------------------- /packages/validator/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | import { transpileSchema } from "./transpile.js"; 6 | 7 | const eventSchema = transpileSchema({ 8 | type: "object", 9 | properties: {}, 10 | maxProperties: 1, 11 | }); 12 | const handler = middy((event) => event).use(middleware({ eventSchema })); 13 | const context = { 14 | getRemainingTimeInMillis: () => 1000, 15 | }; 16 | 17 | test("fuzz `event` w/ `object`", async () => { 18 | await fc.assert( 19 | fc.asyncProperty(fc.object(), async (event) => { 20 | try { 21 | await handler(event, context); 22 | } catch (e) { 23 | if (e.cause?.package !== "@middy/validator") { 24 | throw e; 25 | } 26 | } 27 | }), 28 | { 29 | numRuns: 100_000, 30 | verbose: 2, 31 | 32 | examples: [], 33 | }, 34 | ); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/validator/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | import { transpileSchema } from "./transpile.js"; 5 | 6 | const bench = new Bench({ time: 1_000 }); 7 | 8 | const context = { 9 | getRemainingTimeInMillis: () => 30000, 10 | }; 11 | const setupHandler = () => { 12 | const baseHandler = () => {}; 13 | return middy(baseHandler).use( 14 | middleware({ 15 | eventSchema: transpileSchema({ type: "object" }), 16 | responseSchema: transpileSchema({ type: "object" }), 17 | }), 18 | ); 19 | }; 20 | 21 | const warmHandler = setupHandler(); 22 | 23 | const event = {}; 24 | await bench 25 | .add("type check input & output", async () => { 26 | try { 27 | await warmHandler(event, context); 28 | } catch (e) {} 29 | }) 30 | 31 | .run(); 32 | 33 | console.table(bench.table()); 34 | -------------------------------------------------------------------------------- /packages/validator/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import validator from "."; 4 | 5 | // use with default options 6 | let middleware = validator(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = validator({ 11 | eventSchema: () => {}, 12 | contextSchema: () => {}, 13 | responseSchema: () => {}, 14 | defaultLanguage: "en", 15 | languages: {}, 16 | }); 17 | expectType(middleware); 18 | -------------------------------------------------------------------------------- /packages/validator/transpile.d.ts: -------------------------------------------------------------------------------- 1 | import type Ajv from "ajv"; 2 | import type { Options as AjvOptions } from "ajv"; 3 | 4 | export function transpileSchema( 5 | schema: object, 6 | ajvOptions?: Partial, 7 | ): Ajv; 8 | 9 | export function transpileLocale(src: string, options?: object | any): Function; 10 | -------------------------------------------------------------------------------- /packages/validator/transpile.test-d.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from "tsd"; 2 | import type { transpileLocale, transpileSchema } from "./transpile.t.ds"; 3 | 4 | const schema = transpileSchema({ type: "object" }, {}); 5 | expectType(schema); 6 | 7 | const locale = transpileLocale("", {}); 8 | expectType(locale); 9 | -------------------------------------------------------------------------------- /packages/warmup/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | 3 | interface Options { 4 | isWarmingUp?: (event: any) => boolean; 5 | onWarmup?: (event: any) => void; 6 | } 7 | 8 | declare function warmup(options?: Options): middy.MiddlewareObj; 9 | 10 | export default warmup; 11 | -------------------------------------------------------------------------------- /packages/warmup/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(middleware()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | await handler(event, context); 15 | }), 16 | { 17 | numRuns: 100_000, 18 | verbose: 2, 19 | 20 | examples: [], 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/warmup/index.js: -------------------------------------------------------------------------------- 1 | const defaults = { 2 | isWarmingUp: (event) => event.source === "serverless-plugin-warmup", 3 | }; 4 | 5 | const warmupMiddleware = (opt) => { 6 | const options = { ...defaults, ...opt }; 7 | 8 | const warmupMiddlewareBefore = (request) => { 9 | if (options.isWarmingUp(request.event)) { 10 | return "warmup"; 11 | } 12 | }; 13 | 14 | return { 15 | before: warmupMiddlewareBefore, 16 | }; 17 | }; 18 | 19 | export default warmupMiddleware; 20 | -------------------------------------------------------------------------------- /packages/warmup/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const baseHandler = () => {}; 12 | return middy(baseHandler).use(middleware()); 13 | }; 14 | 15 | const warmHandler = setupHandler(); 16 | 17 | await bench 18 | .add( 19 | "Change Context", 20 | async ( 21 | event = { 22 | source: "serverless-plugin-warmup", 23 | }, 24 | ) => { 25 | try { 26 | await warmHandler(event, context); 27 | } catch (e) {} 28 | }, 29 | ) 30 | 31 | .run(); 32 | 33 | console.table(bench.table()); 34 | -------------------------------------------------------------------------------- /packages/warmup/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import warmup from "."; 4 | 5 | // use with default options 6 | let middleware = warmup(); 7 | expectType(middleware); 8 | 9 | // use with all options 10 | middleware = warmup({ 11 | isWarmingUp: () => true, 12 | }); 13 | expectType(middleware); 14 | -------------------------------------------------------------------------------- /packages/ws-json-body-parser/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { APIGatewayProxyWebsocketEventV2 } from "aws-lambda"; 3 | import type { JsonValue } from "type-fest"; 4 | 5 | interface Options { 6 | reviver?: (key: string, value: any) => any; 7 | } 8 | 9 | export type Event = Omit & { 10 | body: JsonValue; 11 | }; 12 | 13 | declare function jsonBodyParser(options?: Options): middy.MiddlewareObj; 14 | 15 | export default jsonBodyParser; 16 | -------------------------------------------------------------------------------- /packages/ws-json-body-parser/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import jsonBodyParser from "./index.js"; 5 | 6 | const handler = middy((event) => event).use(jsonBodyParser()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | try { 15 | await handler(event, context); 16 | } catch (e) { 17 | if (e.cause?.package !== "@middy/ws-json-body-parser") { 18 | throw e; 19 | } 20 | } 21 | }), 22 | { 23 | numRuns: 100_000, 24 | verbose: 2, 25 | 26 | examples: [], 27 | }, 28 | ); 29 | }); 30 | 31 | test("fuzz `event` w/ `record`", async () => { 32 | await fc.assert( 33 | fc.asyncProperty( 34 | fc.record({ 35 | body: fc.string(), 36 | }), 37 | async (event) => { 38 | try { 39 | await handler(event, context); 40 | } catch (e) { 41 | if (e.cause?.package !== "@middy/ws-json-body-parser") { 42 | throw e; 43 | } 44 | } 45 | }, 46 | ), 47 | { 48 | numRuns: 100_000, 49 | verbose: 2, 50 | 51 | examples: [], 52 | }, 53 | ); 54 | }); 55 | -------------------------------------------------------------------------------- /packages/ws-json-body-parser/index.js: -------------------------------------------------------------------------------- 1 | import { createError } from "@middy/util"; 2 | 3 | const defaults = { 4 | reviver: undefined, 5 | }; 6 | 7 | const wsJsonBodyParserMiddleware = (opts = {}) => { 8 | const options = { ...defaults, ...opts }; 9 | const wsJsonBodyParserMiddlewareBefore = async (request) => { 10 | const { body } = request.event; 11 | if (typeof body === "undefined") { 12 | throw createError(422, "Invalid or malformed JSON was provided", { 13 | cause: { package: "@middy/ws-json-body-parser", data: body }, 14 | }); 15 | } 16 | 17 | try { 18 | const data = request.event.isBase64Encoded 19 | ? Buffer.from(body, "base64").toString() 20 | : body; 21 | 22 | request.event.body = JSON.parse(data, options.reviver); 23 | } catch (err) { 24 | // UnprocessableEntity 25 | throw createError(422, "Invalid or malformed JSON was provided", { 26 | cause: { 27 | package: "@middy/ws-json-body-parser", 28 | data: body, 29 | message: err.message, 30 | }, 31 | }); 32 | } 33 | }; 34 | 35 | return { 36 | before: wsJsonBodyParserMiddlewareBefore, 37 | }; 38 | }; 39 | export default wsJsonBodyParserMiddleware; 40 | -------------------------------------------------------------------------------- /packages/ws-json-body-parser/index.perf.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | return middy().use(middleware()); 12 | }; 13 | 14 | const warmHandler = setupHandler(); 15 | 16 | await bench 17 | .add( 18 | "Parse body", 19 | async ( 20 | event = { 21 | body: '{ "action": "message", "message":"hello" }', 22 | }, 23 | ) => { 24 | try { 25 | await warmHandler(event, context); 26 | } catch (e) {} 27 | }, 28 | ) 29 | 30 | .run(); 31 | 32 | console.table(bench.table()); 33 | -------------------------------------------------------------------------------- /packages/ws-json-body-parser/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import { expectType } from "tsd"; 3 | import jsonBodyParser, { type Event } from "."; 4 | 5 | // use with default options 6 | expectType>(jsonBodyParser()); 7 | 8 | // use with all options 9 | const options = { 10 | reviver: (key: string, value: any) => Boolean(value), 11 | }; 12 | expectType>(jsonBodyParser(options)); 13 | -------------------------------------------------------------------------------- /packages/ws-response/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ApiGatewayManagementApiClient, 3 | ApiGatewayManagementApiClientConfig, 4 | } from "@aws-sdk/client-apigatewaymanagementapi"; 5 | import type middy from "@middy/core"; 6 | import type { Options as MiddyOptions } from "@middy/util"; 7 | 8 | interface Options< 9 | AwsApiGatewayManagementApiClient = ApiGatewayManagementApiClient, 10 | > extends Pick< 11 | MiddyOptions< 12 | AwsApiGatewayManagementApiClient, 13 | ApiGatewayManagementApiClientConfig 14 | >, 15 | | "AwsClient" 16 | | "awsClientOptions" 17 | | "awsClientAssumeRole" 18 | | "awsClientCapture" 19 | | "disablePrefetch" 20 | > {} 21 | 22 | declare function wsResponse(options?: Options): middy.MiddlewareObj; 23 | 24 | export default wsResponse; 25 | -------------------------------------------------------------------------------- /packages/ws-response/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import middleware from "./index.js"; 5 | 6 | import { 7 | ApiGatewayManagementApiClient, 8 | PostToConnectionCommand, 9 | } from "@aws-sdk/client-apigatewaymanagementapi"; 10 | import { mockClient } from "aws-sdk-client-mock"; 11 | mockClient(ApiGatewayManagementApiClient) 12 | .on(PostToConnectionCommand) 13 | .resolves({ statusCode: 200 }); 14 | 15 | const handler = middy((event) => event).use( 16 | middleware({ 17 | AwsClient: ApiGatewayManagementApiClient, 18 | }), 19 | ); 20 | const context = { 21 | getRemainingTimeInMillis: () => 1000, 22 | }; 23 | 24 | test("fuzz `event` w/ `object`", async () => { 25 | await fc.assert( 26 | fc.asyncProperty(fc.object(), async (event) => { 27 | await handler(event, context); 28 | }), 29 | { 30 | numRuns: 100_000, 31 | verbose: 2, 32 | 33 | examples: [], 34 | }, 35 | ); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/ws-response/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import middleware from "./index.js"; 4 | 5 | import { 6 | ApiGatewayManagementApiClient, 7 | PostToConnectionCommand, 8 | } from "@aws-sdk/client-apigatewaymanagementapi"; 9 | import { mockClient } from "aws-sdk-client-mock"; 10 | 11 | const bench = new Bench({ time: 1_000 }); 12 | 13 | const context = { 14 | getRemainingTimeInMillis: () => 30000, 15 | }; 16 | const setupHandler = (options = {}) => { 17 | mockClient(ApiGatewayManagementApiClient) 18 | .on(PostToConnectionCommand) 19 | .resolves({ statusCode: 200 }); 20 | const baseHandler = () => {}; 21 | return middy(baseHandler).use( 22 | middleware({ 23 | ...options, 24 | AwsClient: ApiGatewayManagementApiClient, 25 | }), 26 | ); 27 | }; 28 | 29 | const coldHandler = setupHandler({ cacheExpiry: 0 }); 30 | const warmHandler = setupHandler(); 31 | 32 | const event = {}; 33 | await bench 34 | .add("without cache", async () => { 35 | try { 36 | await coldHandler(event, context); 37 | } catch (e) {} 38 | }) 39 | .add("with cache", async () => { 40 | try { 41 | await warmHandler(event, context); 42 | } catch (e) {} 43 | }) 44 | 45 | .run(); 46 | 47 | console.table(bench.table()); 48 | -------------------------------------------------------------------------------- /packages/ws-response/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import { ApiGatewayManagementApiClient } from "@aws-sdk/client-apigatewaymanagementapi"; 2 | import type middy from "@middy/core"; 3 | import { captureAWSv3Client } from "aws-xray-sdk"; 4 | import { expectType } from "tsd"; 5 | import wsResponse from "."; 6 | 7 | // use with default options 8 | let middleware = wsResponse(); 9 | expectType(middleware); 10 | 11 | // use with all options 12 | middleware = wsResponse({ 13 | AwsClient: ApiGatewayManagementApiClient, 14 | awsClientCapture: captureAWSv3Client, 15 | disablePrefetch: true, 16 | }); 17 | expectType(middleware); 18 | -------------------------------------------------------------------------------- /packages/ws-router/index.d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { APIGatewayProxyWebsocketHandlerV2 } from "aws-lambda"; 3 | 4 | interface Route { 5 | routeKey: string; 6 | handler: APIGatewayProxyWebsocketHandlerV2; 7 | } 8 | 9 | declare function wsRouterHandler(routes: Route[]): middy.MiddyfiedHandler; 10 | 11 | export default wsRouterHandler; 12 | -------------------------------------------------------------------------------- /packages/ws-router/index.fuzz.js: -------------------------------------------------------------------------------- 1 | import { test } from "node:test"; 2 | import fc from "fast-check"; 3 | import middy from "../core/index.js"; 4 | import router from "./index.js"; 5 | 6 | const handler = middy(router()); 7 | const context = { 8 | getRemainingTimeInMillis: () => 1000, 9 | }; 10 | 11 | test("fuzz `event` w/ `object`", async () => { 12 | await fc.assert( 13 | fc.asyncProperty(fc.object(), async (event) => { 14 | try { 15 | await handler(event, context); 16 | } catch (e) { 17 | if (e.cause?.package !== "@middy/ws-router") { 18 | throw e; 19 | } 20 | } 21 | }), 22 | { 23 | numRuns: 100_000, 24 | verbose: 2, 25 | 26 | examples: [], 27 | }, 28 | ); 29 | }); 30 | 31 | test("fuzz `event` w/ `record`", async () => { 32 | await fc.assert( 33 | fc.asyncProperty( 34 | fc.record({ 35 | requestContext: fc.record({ 36 | routeKey: fc.string(), 37 | }), 38 | }), 39 | async (event) => { 40 | try { 41 | await handler(event, context); 42 | } catch (e) { 43 | if (e.cause?.package !== "@middy/ws-router") { 44 | throw e; 45 | } 46 | } 47 | }, 48 | ), 49 | { 50 | numRuns: 100_000, 51 | verbose: 2, 52 | examples: [[{ requestContext: { routeKey: "valueOf" } }]], 53 | }, 54 | ); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/ws-router/index.js: -------------------------------------------------------------------------------- 1 | import { createError } from "@middy/util"; 2 | const defaults = { 3 | routes: [], 4 | notFoundResponse: ({ routeKey }) => { 5 | const err = createError(404, "Route does not exist", { 6 | cause: { package: "@middy/ws-router", data: { routeKey } }, 7 | }); 8 | throw err; 9 | }, 10 | }; 11 | const wsRouteHandler = (opts = {}) => { 12 | let options; 13 | if (Array.isArray(opts)) { 14 | options = { routes: opts }; 15 | } 16 | options ??= opts; 17 | const { routes, notFoundResponse } = { ...defaults, ...options }; 18 | 19 | const routesStatic = {}; 20 | for (const route of routes) { 21 | const { routeKey, handler } = route; 22 | 23 | // Static 24 | routesStatic[routeKey] = handler; 25 | } 26 | 27 | return (event, context, abort) => { 28 | const { routeKey } = event.requestContext ?? {}; 29 | if (!routeKey) { 30 | throw createError(400, "Unknown WebSocket event format", { 31 | cause: { package: "@middy/ws-router", data: { routeKey } }, 32 | }); 33 | } 34 | 35 | // Static 36 | if (Object.hasOwnProperty.call(routesStatic, routeKey)) { 37 | const handler = routesStatic[routeKey]; 38 | return handler(event, context, abort); 39 | } 40 | 41 | // Not Found 42 | return notFoundResponse({ routeKey }); 43 | }; 44 | }; 45 | 46 | export default wsRouteHandler; 47 | -------------------------------------------------------------------------------- /packages/ws-router/index.pref.js: -------------------------------------------------------------------------------- 1 | import { Bench } from "tinybench"; 2 | import middy from "../core/index.js"; 3 | import router from "./index.js"; 4 | 5 | const bench = new Bench({ time: 1_000 }); 6 | 7 | const context = { 8 | getRemainingTimeInMillis: () => 30000, 9 | }; 10 | const setupHandler = () => { 11 | const handler = () => {}; 12 | return middy( 13 | router([ 14 | { routeKey: "$connect", handler }, 15 | { routeKey: "$disconnect", handler }, 16 | { routeKey: "$default", handler }, 17 | ]), 18 | ); 19 | }; 20 | 21 | const warmHandler = setupHandler(); 22 | 23 | await bench 24 | .add( 25 | "short static", 26 | async (event = { requestContext: { routeKey: "$connect" } }) => { 27 | try { 28 | await warmHandler(event, context); 29 | } catch (e) {} 30 | }, 31 | ) 32 | 33 | .run(); 34 | 35 | console.table(bench.table()); 36 | -------------------------------------------------------------------------------- /packages/ws-router/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import type middy from "@middy/core"; 2 | import type { APIGatewayProxyWebsocketHandlerV2 } from "aws-lambda"; 3 | import { expectType } from "tsd"; 4 | import wsRouterHandler from "."; 5 | 6 | const connectLambdaHandler: APIGatewayProxyWebsocketHandlerV2 = async () => { 7 | return { 8 | statusCode: 200, 9 | body: "Connected to websocket", 10 | }; 11 | }; 12 | 13 | const disconnectLambdaHandler: APIGatewayProxyWebsocketHandlerV2 = async () => { 14 | return { 15 | statusCode: 200, 16 | body: "Disconnected to websocket", 17 | }; 18 | }; 19 | 20 | const middleware = wsRouterHandler([ 21 | { 22 | routeKey: "$connect", 23 | handler: connectLambdaHandler, 24 | }, 25 | { 26 | routeKey: "$disconnect", 27 | handler: disconnectLambdaHandler, 28 | }, 29 | ]); 30 | expectType(middleware); 31 | -------------------------------------------------------------------------------- /plugin/hrtime.js: -------------------------------------------------------------------------------- 1 | const defaults = { 2 | logger: console.log, 3 | enabled: true, 4 | }; 5 | 6 | const timePlugin = (opts = {}) => { 7 | const { logger, enabled } = { ...defaults, ...opts }; 8 | if (!enabled) { 9 | return {}; 10 | } 11 | 12 | let cold = true; 13 | const store = {}; 14 | 15 | const start = (id) => { 16 | store[id] = process.hrtime.bigint(); 17 | }; 18 | const stop = (id) => { 19 | if (!enabled) return; 20 | logger( 21 | id, 22 | Number.parseInt((process.hrtime.bigint() - store[id]).toString()) / 23 | 1_000_000, 24 | "ms", 25 | ); 26 | }; 27 | 28 | // Only run during cold start 29 | const beforePrefetch = () => start("prefetch"); 30 | const requestStart = () => { 31 | if (cold) { 32 | cold = false; 33 | stop("prefetch"); 34 | } 35 | start("request"); 36 | }; 37 | const beforeMiddleware = start; 38 | const afterMiddleware = stop; 39 | const beforeHandler = () => start("handler"); 40 | const afterHandler = () => stop("handler"); 41 | const requestEnd = () => stop("request"); 42 | 43 | return { 44 | beforePrefetch, 45 | requestStart, 46 | beforeMiddleware, 47 | afterMiddleware, 48 | beforeHandler, 49 | afterHandler, 50 | requestEnd, 51 | }; 52 | }; 53 | export default timePlugin; 54 | -------------------------------------------------------------------------------- /plugin/memory.js: -------------------------------------------------------------------------------- 1 | import memwatch from "@airbnb/node-memwatch"; 2 | 3 | const defaults = { 4 | logger: console.log, 5 | enabled: true, 6 | }; 7 | 8 | const memoryPlugin = (opts = {}) => { 9 | const { logger, enabled } = { ...defaults, ...opts }; 10 | if (!enabled) { 11 | return {}; 12 | } 13 | 14 | let cold = true; 15 | const store = {}; 16 | 17 | const start = (id) => { 18 | store[id] = new memwatch.HeapDiff(); 19 | }; 20 | const stop = (id) => { 21 | logger(id, store[id].end()); 22 | }; 23 | 24 | const beforePrefetch = () => start("prefetch"); 25 | const requestStart = () => { 26 | if (cold) { 27 | cold = false; 28 | stop("prefetch"); 29 | } 30 | start("request"); 31 | }; 32 | const beforeMiddleware = start; 33 | const afterMiddleware = stop; 34 | const beforeHandler = () => start("handler"); 35 | const afterHandler = () => stop("handler"); 36 | const requestEnd = () => stop("request"); 37 | 38 | return { 39 | beforePrefetch, 40 | requestStart, 41 | beforeMiddleware, 42 | afterMiddleware, 43 | beforeHandler, 44 | afterHandler, 45 | requestEnd, 46 | }; 47 | }; 48 | export default memoryPlugin; 49 | -------------------------------------------------------------------------------- /plugin/multi.js: -------------------------------------------------------------------------------- 1 | const defaults = { 2 | plugins: [], 3 | enabled: true, 4 | }; 5 | 6 | const multiPlugin = (opts = {}) => { 7 | const { plugins, enabled } = { ...defaults, ...opts }; 8 | if (!enabled) { 9 | return {}; 10 | } 11 | 12 | const hooks = { 13 | beforePrefetch: [], 14 | requestStart: [], 15 | beforeMiddleware: [], 16 | afterMiddleware: [], // reveresed 17 | beforeHandler: [], 18 | afterHandler: [], // reveresed 19 | requestEnd: [], // reveresed 20 | }; 21 | 22 | const push = (id, plugin) => { 23 | if (plugin[id]) { 24 | hooks[id].push(plugin[id]); 25 | } 26 | }; 27 | for (let i = 0, l = plugins.length; i < l; i++) { 28 | const plugin = plugins[i]; 29 | push("beforePrefetch", plugin); 30 | push("requestStart", plugin); 31 | push("beforeMiddleware", plugin); 32 | push("afterMiddleware", plugin); 33 | push("beforeHandler", plugin); 34 | push("afterHandler", plugin); 35 | push("requestEnd", plugin); 36 | } 37 | 38 | hooks.afterMiddleware.reverse(); 39 | hooks.afterHandler.reverse(); 40 | hooks.requestEnd.reverse(); 41 | 42 | const run = (id) => { 43 | for (let i = 0, l = hooks[id].length; i < l; i++) { 44 | hooks[id](); 45 | } 46 | }; 47 | return { 48 | beforePrefetch: () => run("beforePrefetch"), 49 | requestStart: () => run("requestStart"), 50 | beforeMiddleware: () => run("beforeMiddleware"), 51 | afterMiddleware: () => run("afterMiddleware"), 52 | beforeHandler: () => run("beforeHandler"), 53 | afterHandler: () => run("afterHandler"), 54 | requestEnd: () => run("requestEnd"), 55 | }; 56 | }; 57 | export default multiPlugin; 58 | -------------------------------------------------------------------------------- /plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@middy/plugin", 3 | "version": "2.0.0", 4 | "description": "Performance profiling plugins for middy", 5 | "type": "module", 6 | "engines": { 7 | "node": ">=20" 8 | }, 9 | "engineStrict": true, 10 | "publishConfig": { 11 | "access": "public" 12 | }, 13 | "scripts": { 14 | "test": "npm run test:unit && npm run test:fuzz", 15 | "test:unit": "node --test", 16 | "test:fuzz": "node --test index.fuzz.js", 17 | "test:perf": "node --test index.perf.js" 18 | }, 19 | "license": "MIT", 20 | "keywords": [ 21 | "Lambda", 22 | "Middleware", 23 | "Serverless", 24 | "Framework", 25 | "AWS", 26 | "AWS Lambda" 27 | ], 28 | "author": { 29 | "name": "Middy contributors", 30 | "url": "https://github.com/middyjs/middy/graphs/contributors" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "git+https://github.com/middyjs/middy.git" 35 | }, 36 | "bugs": { 37 | "url": "https://github.com/middyjs/middy/issues" 38 | }, 39 | "homepage": "https://middy.js.org", 40 | "funding": { 41 | "type": "github", 42 | "url": "https://github.com/sponsors/willfarrell" 43 | }, 44 | "dependencies": { 45 | "@airbnb/node-memwatch": "2.0.0" 46 | }, 47 | "devDependencies": {}, 48 | "gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431" 49 | } 50 | -------------------------------------------------------------------------------- /plugin/promise.js: -------------------------------------------------------------------------------- 1 | import { createHook } from "node:async_hooks"; 2 | const defaults = { 3 | logger: console.log, 4 | enabled: true, 5 | }; 6 | 7 | let count = 0; 8 | const hook = createHook({ 9 | init(asyncId, type) { 10 | if (type === "PROMISE") { 11 | count++; 12 | } 13 | }, 14 | }); 15 | 16 | const promisePlugin = (opts = {}) => { 17 | const { logger, enabled } = { ...defaults, ...opts }; 18 | if (!enabled) { 19 | return {}; 20 | } 21 | hook.enable(); 22 | 23 | let cold = true; 24 | const store = {}; 25 | const start = (id) => { 26 | store[id] = count; 27 | }; 28 | const stop = (id) => { 29 | logger(id, count - store[id]); 30 | }; 31 | 32 | const beforePrefetch = () => start("prefetch"); 33 | const requestStart = () => { 34 | if (cold) { 35 | cold = false; 36 | stop("prefetch"); 37 | } 38 | start("request"); 39 | }; 40 | const beforeMiddleware = start; 41 | const afterMiddleware = stop; 42 | const beforeHandler = () => start("handler"); 43 | const afterHandler = () => stop("handler"); 44 | const requestEnd = () => stop("request"); 45 | 46 | return { 47 | beforePrefetch, 48 | requestStart, 49 | beforeMiddleware, 50 | afterMiddleware, 51 | beforeHandler, 52 | afterHandler, 53 | requestEnd, 54 | }; 55 | }; 56 | export default promisePlugin; 57 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ npm i 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ npm start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ npm run build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | 28 | 29 | 30 | ### Deployment 31 | 32 | Automatically managed through GitHub actions when merging to `main`. 33 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve("@docusaurus/core/lib/babel/preset")], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docs/best-practices/01-intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Intro 3 | sidebar_position: 1 4 | --- 5 | 6 | In this section you will find some common tips and tricks to ensure you don't hit any performance or security issues. 7 | 8 | Did we miss something? Let us know. 9 | -------------------------------------------------------------------------------- /website/docs/best-practices/02-connection-reuse.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Connection reuse 3 | sidebar_position: 2 4 | --- 5 | 6 | Be sure to set the following environment variable when connecting to AWS services: 7 | 8 | ```plain 9 | AWS_NODEJS_CONNECTION_REUSE_ENABLED=1 10 | ``` 11 | 12 | This allows you to reuse the first connection established across lambda invocations. 13 | 14 | See [Reusing Connections with Keep-Alive in Node.js](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/node-reusing-connections.html) 15 | -------------------------------------------------------------------------------- /website/docs/best-practices/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 8 # float position is supported 2 | label: 'Best Practices' 3 | collapsible: true 4 | collapsed: true 5 | link: 6 | type: generated-index 7 | title: Best Practices 8 | -------------------------------------------------------------------------------- /website/docs/events/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 6 # float position is supported 2 | label: 'AWS Event Examples' 3 | collapsible: true # make the category collapsible 4 | collapsed: true # keep the category open by default 5 | className: red 6 | link: 7 | type: generated-index 8 | title: AWS Event Examples 9 | -------------------------------------------------------------------------------- /website/docs/events/alexa.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Alexa 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | 12 | ## AWS Documentation 13 | - [Using AWS Lambda with Alexa](https://docs.aws.amazon.com/lambda/latest/dg/services-alexa.html) 14 | 15 | ## Example 16 | ```javascript 17 | import middy from '@middy/core' 18 | 19 | export const handler = middy() 20 | .handler((event, context, {signal}) => { 21 | // ... 22 | }) 23 | ``` 24 | -------------------------------------------------------------------------------- /website/docs/events/api-gateway-authorizer.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API Gateway Authorizer 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | 13 | - [Working with AWS Lambda authorizers for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html) 14 | - [Input to an Amazon API Gateway Lambda authorizer](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-input.html) 15 | 16 | ## Example 17 | 18 | ```javascript 19 | import middy from '@middy/core' 20 | export const handler = middy().handler((event, context, { signal }) => { 21 | // ... 22 | }) 23 | ``` 24 | -------------------------------------------------------------------------------- /website/docs/events/api-gateway-ws.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API Gateway (WebSocket) 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon API Gateway](https://docs.aws.amazon.com/lambda/latest/dg/services-apigateway.html) 13 | - [Working with WebSocket APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html) 14 | 15 | ## Example 16 | ```javascript 17 | import middy from '@middy/core' 18 | import wsJsonBodyParserMiddleware from '@middy/ws-json-body-parser' 19 | import wsResponseMiddleware from '@middy/ws-response' 20 | import wsRouterHandler from '@middy/ws-router' 21 | 22 | import { handler as connectHandler } from './handlers/connect.js' 23 | import { handler as disconnectHandler } from './handlers/disconnect.js' 24 | import { handler as defaultHandler } from './handlers/default.js' 25 | 26 | const routes = [ 27 | { 28 | routeKey: '$connect', 29 | handler: connectHandler 30 | }, 31 | { 32 | routeKey: '$disconnect', 33 | handler: disconnectHandler 34 | }, 35 | { 36 | routeKey: 'default', 37 | handler: defaultHandler 38 | } 39 | ] 40 | 41 | export const handler = middy() 42 | .use(wsJsonBodyParserMiddleware()) 43 | .use(wsResponseMiddleware()) 44 | .handler(wsRouterHandler(routes)) 45 | 46 | ``` 47 | -------------------------------------------------------------------------------- /website/docs/events/appsync.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: AppSync 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | 13 | - [Using AWS Lambda with AppSync](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html) 14 | 15 | ## Example 16 | 17 | ```javascript 18 | import middy from '@middy/core' 19 | 20 | export const handler = middy().handler((event, context, { signal }) => { 21 | // ... 22 | }) 23 | ``` 24 | -------------------------------------------------------------------------------- /website/docs/events/cloud-front.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CloudFront Lambda@Edge 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with CloudFront Lambda@Edge](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | //.use(cfHeaderNormalizer()) // Let use know if this would have value 20 | .handler((event, context, {signal}) => { 21 | // ... 22 | }) 23 | ``` 24 | -------------------------------------------------------------------------------- /website/docs/events/cloud-trail.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CloudTrail 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with AWS CloudTrail](https://docs.aws.amazon.com/lambda/latest/dg/with-cloudtrail.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/cloud-watch-alarm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CloudWatch Alarm 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | 13 | - [Using AWS Lambda with CloudWatch Alarm](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarms-and-actions) 14 | 15 | ## Example 16 | 17 | ```javascript 18 | import middy from '@middy/core' 19 | 20 | export const handler = middy().handler((event, context, { signal }) => { 21 | // ... 22 | }) 23 | ``` 24 | -------------------------------------------------------------------------------- /website/docs/events/cloud-watch-logs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CloudWatch Logs 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | 13 | - [Using Lambda with CloudWatch Logs](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchlogs.html) 14 | 15 | ## Example 16 | 17 | ```javascript 18 | import middy from '@middy/core' 19 | import eventNormalizerMiddleware from '@middy/event-normalizer' 20 | 21 | export const handler = middy() 22 | .use(eventNormalizerMiddleware()) 23 | .handler((event, context, { signal }) => { 24 | // ... 25 | }) 26 | ``` 27 | -------------------------------------------------------------------------------- /website/docs/events/code-commit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Code Commit 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with AWS CodeCommit](https://docs.aws.amazon.com/lambda/latest/dg/services-codecommit.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/code-pipeline.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CodePipeline 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with AWS CodePipeline](https://docs.aws.amazon.com/lambda/latest/dg/services-codepipeline.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/cognito.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cognito 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon Cognito](https://docs.aws.amazon.com/lambda/latest/dg/services-cognito.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/config.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Config 3 | --- 4 | 5 | 6 | :::caution 7 | 8 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 9 | 10 | ::: 11 | 12 | ## AWS Documentation 13 | - [Using AWS Lambda with AWS Config](https://docs.aws.amazon.com/lambda/latest/dg/services-config.html) 14 | 15 | ## Example 16 | ```javascript 17 | import middy from '@middy/core' 18 | import eventNormalizerMiddleware from '@middy/event-normalizer' 19 | 20 | export const handler = middy() 21 | .use(eventNormalizerMiddleware()) 22 | .handler((event, context, {signal}) => { 23 | // ... 24 | }) 25 | ``` 26 | -------------------------------------------------------------------------------- /website/docs/events/connect.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Connect 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using Lambda with Amazon Connect](https://docs.aws.amazon.com/lambda/latest/dg/services-connect.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/documentdb.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DocumentDB 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | 13 | - [Using AWS Lambda with Amazon DocumentDB](https://docs.aws.amazon.com/lambda/latest/dg/with-documentdb.html) 14 | 15 | ## Example 16 | 17 | ```javascript 18 | import middy from '@middy/core' 19 | 20 | export const handler = middy().handler((event, context, { signal }) => { 21 | // ... 22 | }) 23 | ``` 24 | -------------------------------------------------------------------------------- /website/docs/events/dynamodb.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DynamoDB 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon DynamoDB](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/ec2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EC2 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon EC2](https://docs.aws.amazon.com/lambda/latest/dg/services-ec2.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/event-bridge.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EventBridge 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | 13 | - [Using AWS Lambda with Amazon EventBridge (CloudWatch Events)](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html) 14 | 15 | ## Example 16 | 17 | ```javascript 18 | import middy from '@middy/core' 19 | 20 | export const handler = middy().handler((event, context, { signal }) => { 21 | // ... 22 | }) 23 | ``` 24 | -------------------------------------------------------------------------------- /website/docs/events/iot-events.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: IoT Events 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with AWS IoT Events](https://docs.aws.amazon.com/lambda/latest/dg/services-iotevents.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/iot.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Internet of things (IoT) 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with AWS IoT](https://docs.aws.amazon.com/lambda/latest/dg/services-iot.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/kafka-managed-streaming.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kafka, Managed Streaming (MSK) 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using Lambda with Amazon MSK](https://docs.aws.amazon.com/lambda/latest/dg/with-msk.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/kafka-self-managed.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kafka, Self-Managed 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using Lambda with self-managed Apache Kafka](https://docs.aws.amazon.com/lambda/latest/dg/with-kafka.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/kinesis-firehose.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kinesis Firehose 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon Kinesis Data Firehose](https://docs.aws.amazon.com/lambda/latest/dg/services-kinesisfirehose.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/kinesis-streams.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kinesis Streams 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon Kinesis](https://docs.aws.amazon.com/lambda/latest/dg/with-kinesis.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/lex.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Lex 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon Lex](https://docs.aws.amazon.com/lambda/latest/dg/services-lex.html) 13 | - [Using an AWS Lambda function](https://docs.aws.amazon.com/lexv2/latest/dg/lambda.html) with Amazon Lex V2 14 | 15 | ## Example 16 | ```javascript 17 | import middy from '@middy/core' 18 | 19 | export const handler = middy() 20 | .handler((event, context, {signal}) => { 21 | // ... 22 | }) 23 | ``` 24 | -------------------------------------------------------------------------------- /website/docs/events/mq.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: MQ 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using Lambda with Amazon MQ](https://docs.aws.amazon.com/lambda/latest/dg/with-mq.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/rds.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: RDS 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon RDS](https://docs.aws.amazon.com/lambda/latest/dg/services-rds.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) // RDS -> SNS -> Lambda 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/s3-batch.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: S3 Batch 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon S3 batch operations](https://docs.aws.amazon.com/lambda/latest/dg/services-s3-batch.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/s3-object.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: S3 Object 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | 13 | - [Transforming S3 Objects with S3 Object Lambda](https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html) 14 | - [Transforming objects with S3 Object Lambda](https://docs.aws.amazon.com/AmazonS3/latest/userguide/transforming-objects.html) 15 | 16 | ## Example 17 | 18 | ```javascript 19 | import middy from '@middy/core' 20 | import s3ObjectResponseMiddleware from '@middy/s3-object-response' 21 | import {captureAWSv3Client} from 'aws-xray-sdk-core' 22 | import {captureFetchGlobal} from 'aws-xray-sdk-fetch' 23 | 24 | captureFetchGlobal() 25 | 26 | export const handler = middy() 27 | .use(s3ObjectResponseMiddleware({ 28 | awsClientCapture: captureAWSv3Client, 29 | bodyType: 'promise' 30 | })) 31 | .handler((event, context, {signal}) => { 32 | // ... 33 | }) 34 | ``` 35 | -------------------------------------------------------------------------------- /website/docs/events/s3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: S3 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon S3](https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) // S3 -> SNS -> SQS -> Lambda 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/secrets-manager.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Secrets Manager 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Secrets Manager](https://docs.aws.amazon.com/lambda/latest/dg/with-secrets-manager.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/ses.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SES 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon SES](https://docs.aws.amazon.com/lambda/latest/dg/services-ses.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/events/sns.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SNS 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon SNS](https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | 19 | export const handler = middy() 20 | .use(eventNormalizerMiddleware()) 21 | .handler((event, context, {signal}) => { 22 | // ... 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /website/docs/events/sqs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SQS 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Using AWS Lambda with Amazon SQS](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | import eventNormalizerMiddleware from '@middy/event-normalizer' 18 | import sqsPartialBatchFailure from '@middy/sqs-partial-batch-failure' 19 | 20 | export const handler = middy() 21 | .use(eventNormalizerMiddleware()) 22 | .use(sqsPartialBatchFailure()) 23 | .handler((event, context, {signal}) => { 24 | // ... 25 | }) 26 | ``` 27 | -------------------------------------------------------------------------------- /website/docs/events/workmail.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: WorkMail 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ## AWS Documentation 12 | - [Configuring AWS Lambda for Amazon WorkMail](https://docs.aws.amazon.com/workmail/latest/adminguide/lambda.html) 13 | 14 | ## Example 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | export const handler = middy() 19 | .handler((event, context, {signal}) => { 20 | // ... 21 | }) 22 | ``` 23 | -------------------------------------------------------------------------------- /website/docs/faq.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FAQ 3 | sidebar_position: 10 4 | --- 5 | 6 | ### My lambda keep timing out without responding, what do I do? 7 | 8 | Likely your event loop is not empty. This happens when you have a database connect still open for example. Checkout `@middy/do-not-wait-for-empty-event-loop`. 9 | -------------------------------------------------------------------------------- /website/docs/integrations/01-intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Integrations 3 | position: 1 4 | --- 5 | 6 | :::caution 7 | 8 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 9 | 10 | ::: 11 | -------------------------------------------------------------------------------- /website/docs/integrations/RDS.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: AWS Relational Database Service (RDS) 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | First, you need to pass in a password. In order from most secure to least: `RDS.Signer`, `SecretsManager`, `SSM` using SecureString. 12 | `SSM` can be considered equally secure to `SecretsManager` if you have your own password rotation system. 13 | 14 | Additionally, you will want to verify the RDS certificate and the domain of your connection. You can use this sudo code to get you started: 15 | 16 | ```javascript 17 | import tls from 'tls' 18 | 19 | // https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html 20 | const ca = `-----BEGIN CERTIFICATE----- ...` 21 | 22 | connectionOptions = { 23 | ..., 24 | ssl: { 25 | rejectUnauthorized: true, 26 | ca, 27 | checkServerIdentity: (host, cert) => { 28 | const error = tls.checkServerIdentity(host, cert) 29 | if ( 30 | error && 31 | !cert.subject.CN.endsWith('.rds.amazonaws.com') 32 | ) { 33 | return error 34 | } 35 | } 36 | } 37 | } 38 | ``` 39 | 40 | Corresponding `RDS.ParameterGroups` values should be set to enforce TLS connections. 41 | -------------------------------------------------------------------------------- /website/docs/integrations/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 7 # float position is supported 2 | label: 'Integrations' 3 | collapsible: true # make the category collapsible 4 | collapsed: true # keep the category open by default 5 | className: red 6 | link: 7 | type: generated-index 8 | title: Integrations 9 | -------------------------------------------------------------------------------- /website/docs/integrations/apollo-server.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Apollo Server 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | ```javascript 12 | import middy from '@middy/core' 13 | import { ApolloServer, gql } from 'apollo-server-lambda' 14 | import { buildFederatedSchema } from '@apollo/federation' 15 | import { resolvers } from './graphql/resolvers.js' 16 | import { graphqlFileToStr } from './graphql/schema.js' 17 | 18 | const graphQL = new ApolloServer({ 19 | schema: buildFederatedSchema({ 20 | typeDefs: gql(graphqlFileToStr), 21 | resolvers 22 | }) 23 | }) 24 | 25 | // Do not use: `@middy/http-json-body-parser` it is already handled within apollo 26 | export const handler = middy().handler(graphQL.createHandler()) 27 | ``` 28 | -------------------------------------------------------------------------------- /website/docs/integrations/pino.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pino 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | -------------------------------------------------------------------------------- /website/docs/integrations/serverless-framework.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Serverless Framework 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | 11 | TODO comment about serverless-warmup 12 | -------------------------------------------------------------------------------- /website/docs/integrations/serverless-stack.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Serverless Stack 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | -------------------------------------------------------------------------------- /website/docs/intro/05-handling-errors.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Handling Errors 3 | position: 5 4 | --- 5 | 6 | But, what happens when there is an error? 7 | 8 | When there is an error, the regular control flow is stopped and the execution is 9 | moved back to all the middlewares that implemented a special phase called `onError`, following 10 | the same order as `after`. 11 | 12 | Every `onError` middleware can decide to handle the error and create a proper response or 13 | to delegate the error to the next middleware. 14 | 15 | When a middleware handles the error and creates a response, the execution is still propagated to all the other 16 | error middlewares and they have a chance to update or replace the response as 17 | needed. At the end of the error middlewares sequence, the response is returned 18 | to the user. 19 | 20 | If no middleware manages the error, the Lambda execution fails reporting the unmanaged error. 21 | 22 | ```javascript 23 | // Initialize response 24 | request.response = request.response ?? {} 25 | 26 | // Add to response 27 | request.response.add = 'more' 28 | 29 | // Override an error 30 | request.error = new Error('...') 31 | 32 | // handle the error 33 | return request.response 34 | ``` 35 | -------------------------------------------------------------------------------- /website/docs/intro/07-hooks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hooks 3 | position: 2 4 | --- 5 | 6 | Middy provides hooks into it's core to allow for monitoring, setup, and cleaning that may not be possible within a middleware. 7 | 8 | In order of execution 9 | 10 | - `beforePrefetch`(): Triggered once before middlewares are attached and prefetches are executed. 11 | - `requestStart`(): Triggered on every request before the first middleware. 12 | - `beforeMiddleware`/`afterMiddleware`(fctName): Triggered before/after every `before`, `after`, and `onError` middleware function. The function name is passed in, this is why all middlewares use a verbose naming pattern. 13 | - `beforeHandler`/`afterHandler`(): Triggered before/after the handler. 14 | - `requestEnd`(request): Triggered right before the response is returned, including thrown errors. 15 | 16 | See [Profiling](https://middy.js.org/docs/best-practices/profiling) for example usage. 17 | -------------------------------------------------------------------------------- /website/docs/intro/08-history.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: History 3 | --- 4 | 5 | ## A brief history of Middy 6 | 7 | - Middy was started in the early days of AWS Lambda (~2016) and it was initially only used to remove duplication in a big serverless project with tons of lambdas. Only in August 2017 Middy's source code was released on GitHub making it an open source project. 8 | - 2017-08-03: First commit 9 | - 2017-09-04: v0.2.1 First release 10 | - 2020-04-25: [v1.0.0](https://loige.co/middy-1-is-here/) Released 11 | - [2020 Review](https://loige.co/2020-a-year-in-review/#middy) by [@lmammino](https://github.com/lmammino) 12 | - [2020 Review](https://github.com/middyjs/middy/issues/590) by [@willfarrell](https://github.com/willfarrell) 13 | - 2021: [v2.0.0 Coming soon](https://github.com/middyjs/middy/issues/585) 14 | - 2021-04-01: v2.0.0 Released 15 | - 2021-02-02: [2021 Review](https://loige.co/2021-a-year-in-review#middy) from [@lmammino](https://github.com/lmammino) 16 | - 2022-05-12: v3.0.0 Released 17 | - 2022-11-24: v4.0.0 Released 18 | - 2023-08-22: [JSAwardsIE 2023 Most valued JavaScript open source project](https://www.linkedin.com/posts/jsdayie_javascript-nodejs-activity-7099445347520757760-hsUQ) 19 | - 2023-11-15: v5.0.0 Released 20 | - 2024-11-??: v6.0.0 Released 21 | 22 | **Fun Fact**: The adding of the emoji-icon was the [2nd commit](https://github.com/middyjs/middy/commit/a0acf430bb72f6f6f604e38cfd8a571912b6b4d7) to the project. 23 | -------------------------------------------------------------------------------- /website/docs/intro/08-influence.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Influence 3 | --- 4 | 5 | Middy has been one of the first projects to encourage the adoption of middlewares to simplify code reuse and best practices within the context of Lambda. 6 | 7 | Since middy started to gain popularity in the Node.js ecosystem, we have seen some independent projects taking the same ideas to other ecosystems: 8 | 9 | - .Net port [Voxel.MiddyNet](https://github.com/VoxelGroup/Voxel.MiddyNet) [@vgaltes](https://twitter.com/vgaltes/status/1366371605337825284) 10 | - GoLang port [Vesper](https://github.com/mefellows/vesper) 11 | 12 | Do you have a similar project? Let us know. 13 | -------------------------------------------------------------------------------- /website/docs/intro/08-utilities.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Utilities 3 | --- 4 | 5 | :::caution 6 | 7 | This page is a work in progress. If you want to help us to make this page better, please consider contributing on GitHub. 8 | 9 | ::: 10 | -------------------------------------------------------------------------------- /website/docs/intro/09-release-cycle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Release Cycle 3 | --- 4 | 5 | Each major release has a two (2) month `Alpha` period, one (1) month `Beta`, before a full release and becomes `Stable`. 6 | Each release goes into `Maintenance` after nine (9) months, as the next release enters `Alpha`. 7 | This time period is chosen for alignment with AWS Lambda `nodejs` runtime releases. 8 | All Node.js Long-Term Support (LTS) releases that have AWS Lambda runtimes are supported. 9 | 10 | | Version | Status | Alpha Release | Stable Release | End-of-Life | 11 | | ------- | ---------- | ------------- | -------------- | ----------- | 12 | | v7 | Scoping | 2025-??-?? | 2025-10-28 | 2027-04-30 | 13 | | v6 | Stable | 2024-10-16 | 2024-11-23 | 2026-04-30 | 14 | | v5 | Deprecated | 2023-06-01 | 2023-11-15 | 2025-04-30 | 15 | | v4 | Deprecated | 2022-10-17 | 2022-11-24 | 2023-11-15 | 16 | | v3 | Deprecated | 2022-01-04 | 2022-05-12 | 2022-12-31 | 17 | | v2 | Deprecated | 2021-01-24 | 2021-04-01 | 2022-05-12 | 18 | | v1 | Deprecated | 2018-05-20 | 2020-04-25 | 2021-04-01 | 19 | | v0 | Deprecated | 2017-08-03 | 2017-09-04 | 2020-04-25 | 20 | 21 | Dates are subject to change. 22 | 23 | If your organization requires a longer maintenance period of Middy, please reach out. 24 | -------------------------------------------------------------------------------- /website/docs/intro/10-contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contributing 3 | --- 4 | 5 | 6 | In the spirit of Open Source Software, everyone is very welcome to contribute to this repository. Feel free to [raise issues](https://github.com/middyjs/middy/issues) or to [submit Pull Requests](https://github.com/middyjs/middy/pulls). 7 | 8 | Before contributing to the project, make sure to have a look at our [Code of Conduct](https://github.com/middyjs/middy/blob/main/.github/CONTRIBUTING.md). 9 | -------------------------------------------------------------------------------- /website/docs/intro/11-sponsoring.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sponsoring 3 | --- 4 | 5 | If Middy is adding value to your project or organization and you would like to support its long term maintenance, becoming a sponsor is a great way to do that. 6 | 7 | [GitHub Sponsors](https://github.com/sponsors/willfarrell) 8 | -------------------------------------------------------------------------------- /website/docs/intro/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 1 # float position is supported 2 | label: "Intro to Middy" 3 | collapsible: true 4 | collapsed: true 5 | link: 6 | type: generated-index 7 | title: Middy Intro 8 | -------------------------------------------------------------------------------- /website/docs/middlewares/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 2 # float position is supported 2 | label: "Middlewares" 3 | collapsible: true # make the category collapsible 4 | collapsed: true # keep the category open by default 5 | className: red 6 | link: 7 | type: generated-index 8 | title: Middlewares 9 | -------------------------------------------------------------------------------- /website/docs/middlewares/cloudformation-response.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: cloudformation-response 3 | --- 4 | 5 | Manage CloudFormation Custom Resource responses. 6 | 7 | ## Install 8 | 9 | To install this middleware you can use NPM: 10 | 11 | ```bash npm2yarn 12 | npm install --save @middy/cloudformation-response 13 | ``` 14 | 15 | ## Options 16 | 17 | None 18 | 19 | ## Sample usage 20 | 21 | ### General 22 | 23 | ```javascript 24 | import middy from '@middy/core' 25 | import cloudformationResponse from '@middy/cloudformation-response' 26 | 27 | export const handler = middy((event, context) => { 28 | return { 29 | PhysicalResourceId:'...' 30 | } 31 | }) 32 | 33 | handler.use(cloudformationResponse()) 34 | ``` 35 | -------------------------------------------------------------------------------- /website/docs/middlewares/do-not-wait-for-empty-event-loop.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: do-not-wait-for-empty-event-loop 3 | --- 4 | 5 | This middleware sets `context.callbackWaitsForEmptyEventLoop` property to `false`. 6 | This will prevent Lambda from timing out because of open database connections, etc. 7 | 8 | ## Install 9 | 10 | To install this middleware you can use NPM: 11 | 12 | ```bash npm2yarn 13 | npm install --save @middy/do-not-wait-for-empty-event-loop 14 | ``` 15 | 16 | ## Options 17 | 18 | By default the middleware sets the `callbackWaitsForEmptyEventLoop` property to `false` only in the `before` phase, 19 | meaning you can override it in handler to `true` if needed. You can set it in all steps with the options: 20 | 21 | - `runOnBefore` (defaults to `true`) - sets property before running your handler 22 | - `runOnAfter` (defaults to `false`) 23 | - `runOnError` (defaults to `false`) 24 | 25 | ## Sample usage 26 | 27 | ```javascript 28 | import middy from '@middy/core' 29 | import doNotWaitForEmptyEventLoop from '@middy/do-not-wait-for-empty-event-loop' 30 | 31 | const lambdaHandler = (event, context) => { 32 | return {} 33 | } 34 | 35 | export const handler = middy() 36 | .use(doNotWaitForEmptyEventLoop({ runOnError: true })) 37 | .handler(lambdaHandler) 38 | ``` 39 | -------------------------------------------------------------------------------- /website/docs/middlewares/error-logger.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: error-logger 3 | --- 4 | 5 | Logs the error and propagates it to the next middleware. 6 | 7 | By default AWS Lambda does not print errors in the CloudWatch logs. If you want to make sure that you don't miss error logs, you would have to catch any error and pass it through `console.error` yourself. 8 | 9 | This middleware will take care to intercept any error and log it for you. The middleware is not going to interfere with other error handlers because it will propagate the error to the next error handler middleware without handling it. You just have to make sure to attach this middleware before any other error handling middleware. 10 | 11 | By default, the logging operate by using the `console.error` function. You can pass as a parameter a custom logger with additional logic if you need. It can be useful if you want to process the log by doing a http call or anything else. 12 | 13 | ## Install 14 | 15 | To install this middleware you can use NPM: 16 | 17 | ```bash npm2yarn 18 | npm install --save @middy/error-logger 19 | ``` 20 | 21 | ## Options 22 | 23 | - `logger` property: a function (default `(request) => console.error(request.error)`) that is used to define the logging logic. It receives the Error object as first and only parameter. 24 | 25 | ## Sample usage 26 | 27 | ```javascript 28 | import middy from '@middy/core' 29 | import errorLogger from '@middy/error-logger' 30 | 31 | const lambdaHandler = (event, context) => { 32 | // your handler logic 33 | } 34 | 35 | export const handler = middy().use(errorLogger()).handler(lambdaHandler) 36 | ``` 37 | -------------------------------------------------------------------------------- /website/docs/middlewares/http-security-headers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: http-security-headers 3 | --- 4 | 5 | Applies best practice security headers to responses. It's a simplified port of HelmetJS. See [HelmetJS](https://helmetjs.github.io/) documentation for more details. 6 | 7 | ## Install 8 | 9 | To install this middleware you can use NPM: 10 | 11 | ```bash npm2yarn 12 | npm install --save @middy/http-security-headers 13 | ``` 14 | 15 | ## Features 16 | - `dnsPrefetchControl` controls browser DNS prefetching 17 | - `frameguard` to prevent clickjacking 18 | - `hidePoweredBy` to remove the Server/X-Powered-By header 19 | - `hsts` for HTTP Strict Transport Security 20 | - `ieNoOpen` sets X-Download-Options for IE8+ 21 | - `noSniff` to keep clients from sniffing the MIME type 22 | - `referrerPolicy` to hide the Referer header 23 | - `xssFilter` adds some small XSS protections 24 | 25 | ## Options 26 | 27 | There are a lot, see [source](https://github.com/middyjs/middy/blob/main/packages/http-security-headers/index.js#L5) 28 | 29 | ## Sample usage 30 | 31 | ```javascript 32 | import middy from '@middy/core' 33 | import httpSecurityHeaders from '@middy/http-security-headers' 34 | 35 | const lambdaHandler = (event, context) => { 36 | return {} 37 | } 38 | 39 | export const handler = middy().use(httpSecurityHeaders()).handler(lambdaHandler) 40 | ``` 41 | -------------------------------------------------------------------------------- /website/docs/middlewares/http-urlencode-body-parser.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: http-urlencode-body-parser 3 | --- 4 | 5 | This middleware automatically parses HTTP requests with URL-encoded body (typically the result 6 | of a form submit). Also handles gracefully broken URL encoding as _Unsupported Media Type_ (415 errors) 7 | 8 | ## Install 9 | 10 | To install this middleware you can use NPM: 11 | 12 | ```bash npm2yarn 13 | npm install --save @middy/http-urlencode-body-parser 14 | ``` 15 | 16 | ## Options 17 | 18 | - `disableContentTypeError` (`boolean`) (optional): Skip throwing 415 when `Content-Type` is invalid. Default: `false`. 19 | 20 | ## Sample usage 21 | 22 | ```javascript 23 | import middy from '@middy/core' 24 | import httpHeaderNormalizer from '@middy/http-header-normalizer' 25 | import httpUrlEncodeBodyParser from '@middy/http-urlencode-body-parser' 26 | 27 | const lambdaHandler = (event, context) => { 28 | return event.body // propagates the body as response 29 | } 30 | 31 | export const handler = middy() 32 | .use(httpHeaderNormalizer()) 33 | .use(httpUrlEncodeBodyParser()) 34 | .handler(lambdaHandler) 35 | 36 | // When Lambda runs the handler with a sample event... 37 | const event = { 38 | headers: { 39 | 'Content-Type': 'application/x-www-form-urlencoded' 40 | }, 41 | body: 'frappucino=muffin&goat%5B%5D=scone&pond=moose' 42 | } 43 | 44 | handler(event, {}, (_, body) => { 45 | deepEqual(body, { 46 | frappucino: 'muffin', 47 | 'goat[]': 'scone', 48 | pond: 'moose' 49 | }) 50 | }) 51 | ``` 52 | -------------------------------------------------------------------------------- /website/docs/middlewares/http-urlencode-path-parser.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: http-urlencode-path-parser 3 | --- 4 | 5 | This middleware automatically parses HTTP requests with URL-encoded paths. This can happen when using path variables (ie `/{name}/`) for an endpoint and the UI `encodeURIComponent` the values before making the request. 6 | 7 | 8 | ## Install 9 | 10 | To install this middleware you can use NPM: 11 | 12 | ```bash npm2yarn 13 | npm install --save @middy/http-urlencode-path-parser 14 | ``` 15 | 16 | 17 | ## Options 18 | 19 | None 20 | 21 | 22 | ## Sample usage 23 | 24 | ```javascript 25 | import middy from '@middy/core' 26 | import httpUrlEncodePathParser from '@middy/http-urlencode-path-parser' 27 | 28 | const handler = middy((event, context) => { 29 | return event.body // propagates the body as response 30 | }) 31 | 32 | handler.use(httpUrlEncodePathParser()) 33 | 34 | // When Lambda runs the handler with a sample event... 35 | const event = { 36 | 37 | pathParameters: { 38 | name: encodeURIComponent('Mîddy') 39 | } 40 | } 41 | 42 | handler(event, {}, (_, body) => { 43 | deepEqual(body, { 44 | name: 'Mîddy' 45 | }) 46 | }) 47 | ``` 48 | -------------------------------------------------------------------------------- /website/docs/middlewares/ws-json-body-parser.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ws-json-body-parser 3 | --- 4 | 5 | This middleware automatically parses WebSocket requests with a JSON body and converts the body into an 6 | object. 7 | 8 | It can also be used in combination with validator as a prior step to normalize the 9 | event body input as an object so that the content can be validated. 10 | 11 | If the body has been parsed as JSON, you can access the original body through the `request.event.rawBody`. 12 | 13 | ## Install 14 | 15 | To install this middleware you can use NPM: 16 | 17 | ```bash 18 | npm install --save @middy/ws-json-body-parser 19 | ``` 20 | 21 | ## Options 22 | 23 | - `reviver` (function) (default `undefined`): A [reviver](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Parameters) parameter may be passed which will be used `JSON.parse`ing the body. 24 | 25 | ## Sample usage 26 | 27 | ```javascript 28 | import middy from '@middy/core' 29 | import wsJsonBodyParserMiddleware from '@middy/ws-json-body-parser' 30 | import wsResponseMiddleware from '@middy/ws-response' 31 | 32 | const lambdaHandler = (event) => { 33 | return event.body.message 34 | } 35 | 36 | export const handler = middy() 37 | .use(wsJsonBodyParserMiddleware()) 38 | .use(wsResponseMiddleware()) 39 | .handler(lambdaHandler) 40 | ``` 41 | -------------------------------------------------------------------------------- /website/docs/routers/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 4 # float position is supported 2 | label: "Routers" 3 | collapsible: true # make the category collapsible 4 | collapsed: true # keep the category open by default 5 | className: red 6 | link: 7 | type: generated-index 8 | title: Routers 9 | -------------------------------------------------------------------------------- /website/docs/upgrade/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 5 # float position is supported 2 | label: 'Upgrade' 3 | collapsible: true # make the category collapsible 4 | collapsed: true # keep the category open by default 5 | className: red 6 | link: 7 | type: generated-index 8 | title: Upgrade 9 | -------------------------------------------------------------------------------- /website/docs/writing-middlewares/01-intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Custom Middlewares 3 | position: 1 4 | --- 5 | 6 | A middleware is an object that should contain at least 1 of 3 possible keys: 7 | 8 | 1. `before`: a function that is executed in the before phase 9 | 2. `after`: a function that is executed in the after phase 10 | 3. `onError`: a function that is executed in case of errors 11 | 12 | `before`, `after` and `onError` functions need to have the following signature: 13 | 14 | ```javascript 15 | const defaults = { 16 | // ... 17 | } 18 | 19 | const nameMiddleware = (opts = {}) => { 20 | const options = { ...defaults, ...opts } 21 | 22 | const nameMiddlewareBefore = async (request) => { 23 | // ... 24 | } 25 | 26 | const nameMiddlewareAfter = async (request) => { 27 | // ... 28 | } 29 | 30 | const nameMiddlewareOnError = async (request) => { 31 | // ... 32 | } 33 | 34 | return { 35 | before: nameMiddlewareBefore, 36 | after: nameMiddlewareAfter, 37 | onError: nameMiddlewareOnError 38 | } 39 | } 40 | 41 | export default nameMiddleware 42 | ``` 43 | 44 | Where: 45 | 46 | - `request`: is a reference to the current context and allows access to (and modification of) 47 | the current `event` (request), the `response` (in the _after_ phase), and `error` 48 | (in case of an error). 49 | 50 | -------------------------------------------------------------------------------- /website/docs/writing-middlewares/03-inline-middlewares.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Inline Middlewares 3 | position: 3 4 | --- 5 | 6 | Sometimes you want to create handlers that serve a very small need and that are not 7 | necessarily re-usable. In such cases, you probably will need to hook only into one of 8 | the different phases (`before`, `after` or `onError`). 9 | 10 | In these cases you can use **inline middlewares** which are shortcut functions to hook 11 | logic into Middy's control flow. 12 | 13 | Let's see how inline middlewares work with a simple example: 14 | 15 | ```javascript 16 | import middy from '@middy/core' 17 | 18 | const lambdaHandler = (event, context) => { 19 | // do stuff 20 | } 21 | 22 | export const handler = middy() 23 | .before(async (request) => { 24 | // do something in the before phase 25 | }) 26 | .after(async (request) => { 27 | // do something in the after phase 28 | }) 29 | .onError(async (request) => { 30 | // do something in the on error phase 31 | }) 32 | .handler(lambdaHandler) 33 | ``` 34 | 35 | As you can see above, a middy instance also exposes the `before`, `after` and `onError` 36 | methods to allow you to quickly hook in simple inline middlewares. 37 | -------------------------------------------------------------------------------- /website/docs/writing-middlewares/05-timeouts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Handle Timeouts 3 | position: 5 4 | --- 5 | 6 | When a lambda times out it throws an error that cannot be caught by middy. To work around this middy maintains an `AbortController` that can be signalled early to allow time to clean up and log the error properly. 7 | 8 | You can set `timeoutEarlyInMillis` to 0 to disable this functionality. If you want to override during testing, mock the lambda context to set `getRemainingTimeInMillis` to a function that returns a very large value (e.g. `() => 99999`). 9 | 10 | ```javascript 11 | import middy from '@middy/core' 12 | 13 | const lambdaHandler = (event, context, { signal }) => { 14 | signal.onabort = () => { 15 | // cancel events 16 | } 17 | // ... 18 | } 19 | 20 | export const handler = middy({ 21 | timeoutEarlyInMillis: 50, 22 | timeoutEarlyResponse: () => { 23 | return { 24 | statusCode: 408 25 | } 26 | } 27 | }).handler(lambdaHandler) 28 | ``` 29 | -------------------------------------------------------------------------------- /website/docs/writing-middlewares/06-more-examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: More Examples 3 | position: 6 4 | --- 5 | 6 | Check the [code for existing middlewares](https://github.com/middyjs/middy/tree/main/packages) to see more examples on how to write a middleware. 7 | -------------------------------------------------------------------------------- /website/docs/writing-middlewares/07-with-typescript.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: With TypeScript 3 | position: 7 4 | --- 5 | 6 | here's an example of how you can write a custom middleware for a Lambda receiving events from API Gateway: 7 | 8 | ```typescript 9 | import middy from '@middy/core' 10 | import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' 11 | 12 | const middleware = (): middy.MiddlewareObj => { 13 | const before: middy.MiddlewareFn = async ( 14 | request 15 | ): Promise => { 16 | // Your middleware logic 17 | } 18 | 19 | const after: middy.MiddlewareFn = async ( 20 | request 21 | ): Promise => { 22 | // Your middleware logic 23 | } 24 | 25 | return { 26 | before, 27 | after 28 | } 29 | } 30 | 31 | export default middleware 32 | ``` 33 | 34 | **Note**: The Middy core team does not use TypeScript often and we can't certainly claim that we are TypeScript experts. We tried our best to come up 35 | with type definitions that should give TypeScript users a good experience. There is certainly room for improvement, so we would be more than happy to receive contributions 😊 36 | 37 | See `devDependencies` for each middleware for list of dependencies that may be required with transpiling TypeScript. 38 | -------------------------------------------------------------------------------- /website/docs/writing-middlewares/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 3 # float position is supported 2 | label: "Writing Middlewares" 3 | collapsible: true # make the category collapsible 4 | collapsed: true # keep the category open by default 5 | className: red 6 | link: 7 | type: generated-index 8 | title: Writing Middlewares 9 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middy", 3 | "version": "0.0.0", 4 | "private": true, 5 | "engines": { 6 | "node": ">=18.0" 7 | }, 8 | "scripts": { 9 | "docusaurus": "docusaurus", 10 | "start": "docusaurus start", 11 | "build": "docusaurus build", 12 | "swizzle": "docusaurus swizzle", 13 | "deploy": "docusaurus deploy", 14 | "clear": "docusaurus clear", 15 | "serve": "docusaurus serve", 16 | "write-translations": "docusaurus write-translations", 17 | "write-heading-ids": "docusaurus write-heading-ids" 18 | }, 19 | "dependencies": { 20 | "@docusaurus/core": "^3.0.0", 21 | "@docusaurus/preset-classic": "^3.0.0", 22 | "@docusaurus/remark-plugin-npm2yarn": "^3.0.0", 23 | "@mdx-js/react": "^3.0.0", 24 | "classnames": "^2.3.2", 25 | "clsx": "^2.0.0", 26 | "docusaurus-lunr-search": "^3.3.0", 27 | "prism-react-renderer": "^2.1.0", 28 | "react": "^18.2.0", 29 | "react-dom": "^18.2.0" 30 | }, 31 | "browserslist": { 32 | "production": [">0.5%", "not dead", "not op_mini all"], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | }, 39 | "devDependencies": { 40 | "@docusaurus/module-type-aliases": "^3.0.0", 41 | "@docusaurus/types": "^3.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{ type: "autogenerated", dirName: "." }], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | { 23 | type: 'category', 24 | label: 'Tutorial', 25 | items: ['hello'], 26 | }, 27 | ], 28 | */ 29 | }; 30 | 31 | module.exports = sidebars; 32 | -------------------------------------------------------------------------------- /website/src/components/Example.module.css: -------------------------------------------------------------------------------- 1 | .example { 2 | margin: 6em 0; 3 | } 4 | 5 | .heading2 { 6 | text-align: center; 7 | font-size: 3em; 8 | margin-bottom: 2rem; 9 | } 10 | 11 | .heading3 { 12 | text-align: center; 13 | font-size: 2.5em; 14 | margin-bottom: 1.5rem; 15 | } 16 | 17 | .buttons_list { 18 | text-align: center; 19 | line-height: 3rem; 20 | } 21 | -------------------------------------------------------------------------------- /website/src/components/GetStartedHero.js: -------------------------------------------------------------------------------- 1 | import Link from "@docusaurus/Link"; 2 | import clsx from "clsx"; 3 | import React from "react"; 4 | import styles from "./GetStartedHero.module.css"; 5 | 6 | export default function GetStartedHero() { 7 | return ( 8 |
9 |
10 |

Ready to get started?

11 | {/*

{siteConfig.tagline}

*/} 12 |
13 | 14 | Read the docs 15 | 16 |
17 |
18 |
19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /website/src/components/GetStartedHero.module.css: -------------------------------------------------------------------------------- 1 | .heroBanner { 2 | padding: 4rem 0; 3 | text-align: center; 4 | position: relative; 5 | overflow: hidden; 6 | } 7 | 8 | @media screen and (max-width: 966px) { 9 | .heroBanner { 10 | padding: 2rem; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /website/src/components/HomepageFeatures.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | margin: 6em 0; 7 | } 8 | 9 | .featureSvg { 10 | height: 64px; 11 | width: 64px; 12 | } 13 | -------------------------------------------------------------------------------- /website/src/components/HomepageSponsors.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | text-align: center; 7 | } 8 | 9 | .features h2 { 10 | font-size: 2.5rem; 11 | margin-bottom: 2.75rem; 12 | } 13 | 14 | .featureSvg { 15 | width: 100%; 16 | max-width: 250px; 17 | max-height: 100px; 18 | } 19 | -------------------------------------------------------------------------------- /website/src/components/HomepageWhatUsersSay.js: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React from "react"; 3 | import styles from "./HomepageFeatures.module.css"; 4 | 5 | /* 6 | AWS Powertools team 7 | */ 8 | 9 | const UseList = [ 10 | { 11 | id: "awslabs", 12 | title: "Amazon Web Services - Labs", 13 | url: "https://github.com/awslabs/aws-lambda-powertools-typescript", // https://github.com/awslabs/aws-lambda-powertools-typescript 14 | img: "/img/logo/awslabs.png", 15 | }, 16 | 17 | /* 18 | { 19 | title: 'Organization Name', 20 | url: 'https://github.com/{github username}', // https://github.com/{username}/{repo} 21 | img: '/img/logo/{from github}.png' 22 | }, 23 | */ 24 | ]; 25 | 26 | function Feature({ title, url, img }) { 27 | return ( 28 |
29 | 30 | {title} 31 | 32 |
33 | ); 34 | } 35 | 36 | export default function HomepageWhatUsersSay() { 37 | return ( 38 |
39 |
40 |

What users say

41 |
42 | {UseList.map((props) => ( 43 | 44 | ))} 45 |
46 |
47 |
48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #2e8555; 10 | --ifm-color-primary-dark: #29784c; 11 | --ifm-color-primary-darker: #277148; 12 | --ifm-color-primary-darkest: #205d3b; 13 | --ifm-color-primary-light: #33925d; 14 | --ifm-color-primary-lighter: #359962; 15 | --ifm-color-primary-lightest: #3cad6e; 16 | --ifm-code-font-size: 95%; 17 | } 18 | 19 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 20 | html[data-theme="dark"] { 21 | --ifm-color-primary: #25c2a0; 22 | --ifm-color-primary-dark: #21af90; 23 | --ifm-color-primary-darker: #1fa588; 24 | --ifm-color-primary-darkest: #1a8870; 25 | --ifm-color-primary-light: #29d5b0; 26 | --ifm-color-primary-lighter: #32d8b4; 27 | --ifm-color-primary-lightest: #4fddbf; 28 | } 29 | 30 | .docusaurus-highlight-code-line { 31 | background-color: rgba(0, 0, 0, 0.1); 32 | display: block; 33 | margin: 0 calc(-1 * var(--ifm-pre-padding)); 34 | padding: 0 var(--ifm-pre-padding); 35 | } 36 | 37 | html[data-theme="dark"] .docusaurus-highlight-code-line { 38 | background-color: rgba(181, 24, 24, 0.3); 39 | } 40 | 41 | html[data-theme="dark"] .navbar__logo img, 42 | html[data-theme="dark"] img[alt="Middy middleware engine diagram"] { 43 | filter: invert(1); 44 | } 45 | 46 | .token-line.theme-code-block-highlighted-line { 47 | background-color: rgba(245, 203, 67, 0.154) !important; 48 | } 49 | -------------------------------------------------------------------------------- /website/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | } 12 | 13 | @media screen and (max-width: 966px) { 14 | .heroBanner { 15 | padding: 2rem; 16 | } 17 | } 18 | 19 | .buttons { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | 25 | .logo { 26 | max-width: 360px; 27 | width: 100%; 28 | } 29 | -------------------------------------------------------------------------------- /website/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /website/src/theme/NotFound.js: -------------------------------------------------------------------------------- 1 | import Link from "@docusaurus/Link"; 2 | import Layout from "@theme/Layout"; 3 | /** 4 | * Copyright (c) Facebook, Inc. and its affiliates. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE file in the root directory of this source tree. 8 | */ 9 | import React from "react"; 10 | 11 | function NotFound() { 12 | return ( 13 | 14 |
15 |
16 |
17 |

404

18 |

19 | 404 20 |

21 |

22 | Sorry, we could not find what you were looking for! 23 |

24 |

25 | Please contact the owner of the site that linked you to the 26 | original URL and let them know their link is broken. 27 |

28 | 29 |

37 | 38 | Go to the home 39 | 40 | 41 | Read the docs 42 | 43 |

44 |
45 |
46 |
47 |
48 | ); 49 | } 50 | 51 | export default NotFound; 52 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/CNAME: -------------------------------------------------------------------------------- 1 | middy.js.org -------------------------------------------------------------------------------- /website/static/img/batteries-included.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /website/static/img/blazing-fast.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /website/static/img/extensible.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /website/static/img/favicon.svg: -------------------------------------------------------------------------------- 1 | 🛵 2 | -------------------------------------------------------------------------------- /website/static/img/focus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /website/static/img/middy-404.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/website/static/img/middy-404.gif -------------------------------------------------------------------------------- /website/static/img/middy-middleware-engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/website/static/img/middy-middleware-engine.png -------------------------------------------------------------------------------- /website/static/img/middy-og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/middyjs/middy/99e3c00f138330dc29b616156d177e01a795797a/website/static/img/middy-og-image.png -------------------------------------------------------------------------------- /website/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | --------------------------------------------------------------------------------