diff --git a/.github/workflows/reusable-run-linting-check-and-unit-tests.yml b/.github/workflows/reusable-run-linting-check-and-unit-tests.yml index 7ba4e7590d..846b17673a 100644 --- a/.github/workflows/reusable-run-linting-check-and-unit-tests.yml +++ b/.github/workflows/reusable-run-linting-check-and-unit-tests.yml @@ -90,3 +90,19 @@ jobs: uses: ./.github/actions/cached-node-modules - name: Run linting run: npm run lint -w docs/snippets + check-docs: + runs-on: ubuntu-latest + env: + NODE_ENV: dev + steps: + - name: Checkout code + uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - name: Setup NodeJS + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: 20 + cache: "npm" + - name: Setup dependencies + uses: ./.github/actions/cached-node-modules + - name: Run linting + run: npm run lint:markdown diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 0000000000..bf812e66ca --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,226 @@ +# Rules: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md + +# Default state for all rules +default: true + +# Path to configuration file to extend +extends: null + +# MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time +MD001: true + +# MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading +# NOTE: We use h2 due to font size +MD002: false + +# MD003/heading-style/header-style - Heading style +MD003: + # Heading style + style: "consistent" + +# MD004/ul-style - Unordered list style +MD004: + # List style + style: "consistent" + +# MD005/list-indent - Inconsistent indentation for list items at the same level +MD005: true + +# MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line +MD006: true + +# MD007/ul-indent - Unordered list indentation +MD007: + # Spaces for indent + indent: 4 + # Whether to indent the first level of the list + start_indented: false + # Spaces for first level indent (when start_indented is set) + start_indent: 2 + +# MD009/no-trailing-spaces - Trailing spaces +MD009: + # Spaces for line break + br_spaces: 2 + # Allow spaces for empty lines in list items + list_item_empty_lines: false + # Include unnecessary breaks + strict: false + +# MD010/no-hard-tabs - Hard tabs +# NOTE: Mkdocs Material theme features like code annotations, tabbed content require it +MD010: false + +# MD011/no-reversed-links - Reversed link syntax +MD011: true + +# MD012/no-multiple-blanks - Multiple consecutive blank lines +MD012: + # Consecutive blank lines + maximum: 1 + +# MD013/line-length - Line length +MD013: + # Number of characters + line_length: 380 + # Number of characters for headings + heading_line_length: 80 + # Number of characters for code blocks + code_block_line_length: 265 + # Include code blocks + code_blocks: true + # Include tables + tables: false + # Include headings + headings: true + # Strict length checking + strict: false + # Stern length checking + stern: false + +# MD014/commands-show-output - Dollar signs used before commands without showing output +MD014: true + +# MD018/no-missing-space-atx - No space after hash on atx style heading +MD018: true + +# MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading +MD019: true + +# MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading +MD020: true + +# MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading +MD021: true + +# MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines +MD022: + # Blank lines above heading + lines_above: 1 + # Blank lines below heading + lines_below: 1 + +# MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line +MD023: true + +# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content +MD024: + # Only check sibling headings + siblings_only: false + +# MD025/single-title/single-h1 - Multiple top-level headings in the same document +MD025: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD026/no-trailing-punctuation - Trailing punctuation in heading +MD026: + # Punctuation characters + punctuation: ".,;:!。,;:!" + +# MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol +MD027: true + +# MD028/no-blanks-blockquote - Blank line inside blockquote +MD028: true + +# MD029/ol-prefix - Ordered list item prefix +MD029: + # List style + style: "one_or_ordered" + +# MD030/list-marker-space - Spaces after list markers +MD030: + # Spaces for single-line unordered list items + ul_single: 1 + # Spaces for single-line ordered list items + ol_single: 1 + # Spaces for multi-line unordered list items + ul_multi: 1 + # Spaces for multi-line ordered list items + ol_multi: 1 + +# MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines +MD031: + # Include list items + list_items: true + +# MD032/blanks-around-lists - Lists should be surrounded by blank lines +MD032: true + +# MD033/no-inline-html - Inline HTML +# NOTE: Some content like Logger '' triggers false positives +MD033: false + +# MD034/no-bare-urls - Bare URL used +MD034: true + +# MD035/hr-style - Horizontal rule style +MD035: + # Horizontal rule style + style: "consistent" + +# MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading +# NOTE: We use **** instead of yet another sub-heading that might not appear in the navigation. +# this is a trade-off we make to not a gigantic right-navigation +MD036: false + +# MD037/no-space-in-emphasis - Spaces inside emphasis markers +MD037: true + +# MD038/no-space-in-code - Spaces inside code span elements +# mkdocs-material requires these in tab content +MD038: false + +# MD039/no-space-in-links - Spaces inside link text +MD039: true + +# MD040/fenced-code-language - Fenced code blocks should have a language specified +MD040: true + +# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading +MD041: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD042/no-empty-links - No empty links +# NOTE: Clipboard links like Lambda Layers use empty links +MD042: false + +# MD043/required-headings/required-headers - Required heading structure +MD043: false + +# MD044/proper-names - Proper names should have the correct capitalization +MD044: + # List of proper names + names: [] + # Include code blocks + code_blocks: true + # Include HTML elements + html_elements: true + +# MD045/no-alt-text - Images should have alternate text (alt text) +MD045: true + +# MD046/code-block-style - Code block style +# Material theme tabbed content feature use indented and simple use fenced; can't support both +MD046: false + +# MD047/single-trailing-newline - Files should end with a single newline character +MD047: true + +# MD048/code-fence-style - Code fence style +MD048: false + +# MD051/link-fragments - Link fragments should be valid +MD051: true + +# MD052/reference-links-images - Reference links and images should use a label that is defined +MD052: true + +# MD053/link-image-reference-definitions - Link and image reference definitions should be needed +MD053: true \ No newline at end of file diff --git a/.markdownlintignore b/.markdownlintignore new file mode 100644 index 0000000000..ef3b366abb --- /dev/null +++ b/.markdownlintignore @@ -0,0 +1,22 @@ +# built artifacts +site/** +api/** +# changelogs - these are not linted as they are auto-generated +CHANGELOG.md +packages/*/CHANGELOG.md +examples/*/CHANGELOG.md +layers/*/CHANGELOG.md +# other files +LICENSE +.github/** +**node_modules/** */ +# these will be removed from the ignore and linted in future PRs +packages/batch/README.md +packages/commons/README.md +packages/idempotency/README.md +packages/jmespath/README.md +packages/logger/README.md +packages/metrics/README.md +packages/parameters/README.md +packages/parser/README.md +packages/tracer/README.md \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 5b627cfa60..240d2275c4 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,5 @@ -## Code of Conduct +# Code of Conduct + This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact -opensource-codeofconduct@amazon.com with any additional questions or comments. + with any additional questions or comments. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cedafa950d..b53bd99888 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,24 +1,26 @@ +# Contributing Guidelines + ## Table of contents - [Reporting Bugs/Feature Requests](#reporting-bugsfeature-requests) - [Contributing via Pull Requests](#contributing-via-pull-requests) - - [Dev setup](#dev-setup) - - [Gitpod](#gitpod) - - [GitHub Codespaces](#github-codespaces) - - [Local environment](#local-environment) - - [Sending a pull request](#sending-a-pull-request) - - [Local documentation](#local-documentation) + - [Dev setup](#dev-setup) + - [Gitpod](#gitpod) + - [GitHub Codespaces](#github-codespaces) + - [Local environment](#local-environment) + - [Sending a pull request](#sending-a-pull-request) + - [Local documentation](#local-documentation) - [Conventions](#conventions) - - [General terminology and practices](#general-terminology-and-practices) - - [Testing definition](#testing-definition) + - [General terminology and practices](#general-terminology-and-practices) + - [Testing definition](#testing-definition) - [Finding contributions to work on](#finding-contributions-to-work-on) - [Code of Conduct](#code-of-conduct) - [Security issue notifications](#security-issue-notifications) - [Licensing](#licensing) -# Contributing Guidelines - + Thank you for your interest in contributing to our project. Whether it's a [bug report](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=type%2Fbug%2Ctriage&projects=aws-powertools%2F7&template=bug_report.yml&title=Bug%3A+TITLE), [new feature](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=type%2Ffeature-request%2Ctriage&projects=aws-powertools%2F7&template=feature_request.yml&title=Feature+request%3A+TITLE), [correction](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose), or [additional documentation](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=area%2Fdocumentation%2Ctriage&projects=aws-powertools%2F7&template=documentation_improvements.yml&title=Docs%3A+TITLE), we greatly value feedback and contributions from our community. + Please read through this document before submitting any issues or pull requests to ensure we have all the necessary information to effectively respond to your bug report or contribution. @@ -26,7 +28,9 @@ Please read through this document before submitting any issues or pull requests We welcome you to use the GitHub issue tracker to report bugs, suggest features, or documentation improvements. + [When filing an issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose), please check [existing open](https://github.com/aws-powertools/powertools-lambda-typescript/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc), or [recently closed](https://github.com/aws-powertools/powertools-lambda-typescript/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed), issues to make sure somebody else hasn't already reported the issue. Please try to include as much information as you can. + ## Contributing via Pull Requests @@ -34,7 +38,7 @@ Contributions via pull requests are much appreciated. Before sending us a pull r 1. You are working against the latest source on the **main** branch, unless instructed otherwise. 2. You check existing open, and recently merged pull requests to make sure someone else hasn't addressed the problem already. -3. You discuss and agree your proposed changes under [an existing issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues?q=is%3Aopen+is%3Aupdated-desc) or a [new issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose){target="_blank" rel="nofollow"} before you begin any implementation. We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful. +3. You discuss and agree the proposed changes under [an existing issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues?q=is%3Aopen+is%3Aupdated-desc) or a new one before you begin any implementation. We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful. At a high level, these are the steps to get code merged in the repository - don't worry, nearly all of them are automated. @@ -49,6 +53,7 @@ timeline : Local tests Pre-commit checks
(git commit) : Code linting (standards) + : Markdown linting Pre-Pull Request
(git push) : Tests (unit) @@ -111,7 +116,7 @@ GitHub provides additional document on [forking a repository](https://help.githu You might find useful to run both the documentation website and the API reference locally while contributing: - **Docs website**: `npm run docs-runLocalDocker` - * If this is your first time running the docs, you need to build the image: `npm run docs-buildDockerImage` + - If this is your first time running the docs, you need to build the image: `npm run docs-buildDockerImage` - **API reference**: `npm run docs-api-build-run` ## Conventions diff --git a/MAINTAINERS.md b/MAINTAINERS.md index e9e6d1e941..068e42dfcd 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,2 +1,4 @@ + + > [!IMPORTANT] -> Maintainers' playbook moved: https://docs.powertools.aws.dev/lambda/typescript/latest/maintainers/ +> Maintainers' playbook moved: diff --git a/README.md b/README.md index b405d9d883..ecc403048d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # Powertools for AWS Lambda (TypeScript) ![NodeSupport](https://img.shields.io/static/v1?label=node&message=%2016|%2018|%2020&color=green?style=flat-square&logo=node) @@ -13,99 +14,42 @@ You can use the library in both TypeScript and JavaScript code bases. > Also available in [Python](https://github.com/aws-powertools/powertools-lambda-python), [Java](https://github.com/aws-powertools/powertools-lambda-java), and [.NET](https://github.com/aws-powertools/powertools-lambda-dotnet). -**[Documentation](https://docs.powertools.aws.dev/lambda/typescript/)** | **[npm](https://www.npmjs.com/org/aws-lambda-powertools)** | **[Roadmap](https://docs.powertools.aws.dev/lambda/typescript/latest/roadmap)** | **[Examples](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples)** | **[Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo)** - -## Table of contents - -- [Features](#features) -- [Getting started](#getting-started) - - [Installation](#installation) - - [Lambda layers](#lambda-layers) - - [NPM modules](#npm-modules) - - [Examples](#examples) - - [Demo applications](#demo-applications) -- [Contribute](#contribute) -- [Roadmap](#roadmap) -- [Connect](#connect) -- [How to support Powertools for AWS Lambda (TypeScript)?](#how-to-support-powertools-for-aws-lambda-typescript) - - [Becoming a reference customer](#becoming-a-reference-customer) - - [Sharing your work](#sharing-your-work) - - [Using Lambda Layer](#using-lambda-layer) -- [Credits](#credits) -- [License](#license) +**[Documentation](https://docs.powertools.aws.dev/lambda/typescript/latest)** | **[npmjs.com](https://www.npmjs.com/org/aws-lambda-powertools)** | **[Roadmap](https://docs.powertools.aws.dev/lambda/typescript/latest/roadmap)** | **[Examples](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples)** ## Features -* **[Tracer](https://docs.powertools.aws.dev/lambda/typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions -* **[Logger](https://docs.powertools.aws.dev/lambda/typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context -* **[Metrics](https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) -* **[Parameters](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM Parameter Store, AWS Secrets Manager, AWS AppConfig, and Amazon DynamoDB -* **[Idempotency](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/idempotency/)** - Class method decorator, Middy middleware, and function wrapper to make your Lambda functions idempotent and prevent duplicate execution based on payload content -* **[Batch Processing](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/batch/)** - Utility to handle partial failures when processing batches from Amazon SQS, Amazon Kinesis Data Streams, and Amazon DynamoDB Streams. +Find the complete project's [documentation here](https://docs.powertools.aws.dev/lambda/typescript/latest). -## Getting started +- **[Tracer](https://docs.powertools.aws.dev/lambda/typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions +- **[Logger](https://docs.powertools.aws.dev/lambda/typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context +- **[Metrics](https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) +- **[Parameters](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM Parameter Store, AWS Secrets Manager, AWS AppConfig, and Amazon DynamoDB +- **[Idempotency](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/idempotency/)** - Class method decorator, Middy middleware, and function wrapper to make your Lambda functions idempotent and prevent duplicate execution based on payload content +- **[Batch Processing](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/batch/)** - Utility to handle partial failures when processing batches from Amazon SQS, Amazon Kinesis Data Streams, and Amazon DynamoDB Streams. +- **[JMESPath Functions](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/jmespath/)** - Built-in JMESPath functions to easily deserialize common encoded JSON payloads in Lambda functions. +- **[Parser (Zod)](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/batch/)** - Utility that provides data validation and parsing using Zod, a TypeScript-first schema declaration and validation library. -Find the complete project's [documentation here](https://docs.powertools.aws.dev/lambda/typescript). +## Install -### Installation +You can use Powertools for AWS Lambda (TypeScript) by installing it with your favorite dependency management, or [via Lambda Layers](https://docs.powertools.aws.dev/lambda/typescript/latest/#lambda-layer_1). All features are available as individual packages, so you can install only the ones you need, for example: -You have 2 ways of consuming those utilities: -* NPM modules -* Lambda Layer - -#### Lambda layers - -The Powertools for AWS Lambda (TypeScript) utilities is packaged as a single [AWS Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-layer) - -👉 [Installation guide for the **Powertools for AWS Lambda (TypeScript)** layer](https://docs.powertools.aws.dev/lambda/typescript/latest/#lambda-layer) - -#### NPM modules - -The Powertools for AWS Lambda (TypeScript) utilities follow a modular approach, similar to the official [AWS SDK v3 for JavaScript](https://github.com/aws/aws-sdk-js-v3). -Each TypeScript utility is installed as standalone NPM package. - -Install all three core utilities at once with this single command: - -```shell -npm install @aws-lambda-powertools/logger @aws-lambda-powertools/tracer @aws-lambda-powertools/metrics -``` - -Or refer to the installation guide of each utility: - -👉 [Installation guide for the **Tracer** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/core/tracer#getting-started) - -👉 [Installation guide for the **Logger** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/core/logger#getting-started) - -👉 [Installation guide for the **Metrics** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics#getting-started) - -👉 [Installation guide for the **Parameters** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#getting-started) - -👉 [Installation guide for the **Idempotency** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/idempotency/#getting-started) +- **Logger**: `npm install @aws-lambda-powertools/logger` +- **Metrics**: `npm install @aws-lambda-powertools/metrics` +- **Tracer**: `npm install @aws-lambda-powertools/tracer` +- **Parameters**: `npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm` see [documentation](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#installation) for other providers +- **Idempotency**: `npm install @aws-lambda-powertools/idempotency @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb` +- **Batch**: `npm install @aws-lambda-powertools/batch` +- **JMESPath Functions**: `npm install @aws-lambda-powertools/jmespath` +- **Parser**: `npm install @aws-lambda-powertools/parser zod@~3` ### Examples You can find examples of how to use Powertools for AWS Lambda (TypeScript) in the [examples](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples/app) directory. The application is a simple REST API that can be deployed via either AWS CDK or AWS SAM. -### Demo applications +Community-contributed examples: -The [Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo) shows how to use Powertools for AWS Lambda (TypeScript). -You can find instructions on how to deploy and load test this application in the [repository](https://github.com/aws-samples/serverless-typescript-demo). - -The [AWS Lambda performance tuning](https://github.com/aws-samples/optimizations-for-lambda-functions) repository also uses Powertools for AWS Lambda (TypeScript) as well as demonstrating other performance tuning techniques for Lambda functions written in TypeScript. - -## Contribute - -If you are interested in contributing to this project, please refer to our [Contributing Guidelines](https://github.com/aws-powertools/powertools-lambda-typescript/blob/main/CONTRIBUTING.md). - -## Roadmap - -The roadmap of Powertools for AWS Lambda (TypeScript) is driven by customers’ demand. -Help us prioritize upcoming functionalities or utilities by [upvoting existing RFCs and feature requests](https://github.com/aws-powertools/powertools-lambda-typescript/issues), or [creating new ones](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose), in this GitHub repository. - -## Connect - -* **Powertools for AWS Lambda on Discord**: `#typescript` - **[Invite link](https://discord.gg/B8zZKbbyET)** -* **Email**: aws-lambda-powertools-feedback@amazon.com +- [Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo) +- [AWS Lambda performance tuning](https://github.com/aws-samples/optimizations-for-lambda-functions) ## How to support Powertools for AWS Lambda (TypeScript)? @@ -115,17 +59,17 @@ Knowing which companies are using this library is important to help prioritize t The following companies, among others, use Powertools: -* [Hashnode](https://hashnode.com/) -* [Trek10](https://www.trek10.com/) -* [Elva](https://elva-group.com) -* [globaldatanet](https://globaldatanet.com/) -* [Bailey Nelson](https://www.baileynelson.com.au) -* [Perfect Post](https://www.perfectpost.fr) -* [Sennder](https://sennder.com/) -* [Certible](https://www.certible.com/) -* [tecRacer GmbH & Co. KG](https://www.tecracer.com/) -* [AppYourself](https://appyourself.net) -* [Alma Media](https://www.almamedia.fi) +- [Hashnode](https://hashnode.com/) +- [Trek10](https://www.trek10.com/) +- [Elva](https://elva-group.com) +- [globaldatanet](https://globaldatanet.com/) +- [Bailey Nelson](https://www.baileynelson.com.au) +- [Perfect Post](https://www.perfectpost.fr) +- [Sennder](https://sennder.com/) +- [Certible](https://www.certible.com/) +- [tecRacer GmbH & Co. KG](https://www.tecracer.com/) +- [AppYourself](https://appyourself.net) +- [Alma Media](https://www.almamedia.fi) ### Sharing your work @@ -133,11 +77,21 @@ Share what you did with Powertools for AWS Lambda (TypeScript) 💞💞. Blog po ### Using Lambda Layer -This helps us understand who uses Powertools for AWS Lambda (TypeScript) in a non-intrusive way, and helps us gain future investments for other Powertools for AWS Lambda languages. When [using Layers](#lambda-layers), you can add Powertools for AWS Lambda (TypeScript) as a dev dependency (or as part of your virtual env) to not impact the development process. +This helps us understand who uses Powertools for AWS Lambda (Typescript) in a non-intrusive way, and helps us gain future investments for other Powertools for AWS Lambda languages. When [using Layers](https://docs.powertools.aws.dev/lambda/typescript/latest/#lambda-layer), you can add Powertools for AWS Lambda as a dev dependency to not impact the development process. ## Credits -Credits for the Powertools for AWS Lambda (TypeScript) idea go to [DAZN](https://github.com/getndazn) and their [DAZN Lambda Powertools](https://github.com/getndazn/dazn-lambda-powertools/). +- Structured logging initial implementation from [aws-lambda-logging](https://gitlab.com/hadrien/aws_lambda_logging) +- Powertools for AWS Lambda idea [DAZN Powertools](https://github.com/getndazn/dazn-lambda-powertools/) + +## Connect + +- **Powertools for AWS Lambda on Discord**: `#typescript` - **[Invite link](https://discord.gg/B8zZKbbyET)** +- **Email**: + +## Security disclosures + +If you think you’ve found a potential security issue, please do not post it in the Issues. Instead, please follow the instructions [here](https://aws.amazon.com/security/vulnerability-reporting/) or [email AWS security directly](mailto:aws-security@amazon.com). ## License diff --git a/SECURITY.md b/SECURITY.md index 8db8c1dccb..9fb5d9cd38 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,5 @@ -## Reporting a Vulnerability +# Reporting a vulnerability -If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security -via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com. -Please do **not** create a public GitHub issue. \ No newline at end of file +If you discover a potential security issue in this project, we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to . + +Please do **not** create a public GitHub issue. diff --git a/docs/.markdownlint.yaml b/docs/.markdownlint.yaml new file mode 100644 index 0000000000..ac9ea50ab2 --- /dev/null +++ b/docs/.markdownlint.yaml @@ -0,0 +1,27 @@ +# Rules: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md + +extends: ../.markdownlint.yaml + +# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading +MD041: + # Heading level + level: 2 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD043/required-headings/required-headers - Required heading structure +# NOTE: Enforce our minimum headers across the docs +MD043: + # List of headings + headings: + [ + "*", + "## Key features", + "*", + "## Getting started", + "*", + "## Advanced", + "*", + "## Testing your code", + "*", + ] \ No newline at end of file diff --git a/docs/contributing/conventions.md b/docs/contributing/conventions.md index 84efdc0dfc..c7034ba386 100644 --- a/docs/contributing/conventions.md +++ b/docs/contributing/conventions.md @@ -3,6 +3,8 @@ title: Conventions description: General conventions and practices that are applicable throughout to Powertools for AWS Lambda (TypeScript) --- + + ## General terminology and practices These are common conventions we keep on building as the project gains new contributors and grows in complexity. @@ -26,7 +28,9 @@ The repository uses a monorepo structure managed using [npm workspaces](https:// The Powertools for AWS Lambda (TypeScript) repository utilities live under the `packages/` directory. Each utility is a separate package and has its own `package.json` file. For example, the `@aws-lambda-powertools/logger` source code can be found under the `packages/logger/src` directory. -Whenever possible, we use the same directory structure for all utilities. This makes it easier for contributors to navigate the repository and find what they need. Additionally, we try to share common runtime code between utilities to reduce maintenance overhead and runtime footprint. The shared runtime code lives under the `packages/commons/src` directory and is published to npm as the `@aws-lambda-powertools/commons` package. +Whenever possible, we use the same directory structure for all utilities. This makes it easier for contributors to navigate the repository and find what they need. + +Additionally, we try to share common runtime code between utilities to reduce maintenance overhead and runtime footprint. The shared runtime code lives under the `packages/commons/src` directory and is published to npm as the `@aws-lambda-powertools/commons` package. There are also a few other workspaces that are not utilities published to npm, but that still share dependencies and/or runtime code with the utilities. These workspaces are: @@ -42,4 +46,4 @@ We group tests in different categories | ----------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | | Unit tests | Verify the smallest possible unit works. | Networking access is prohibited. Keep mocks and spies at minimum. | Fast (ms to few seconds at worst) | | End-to-end tests | Gain confidence that a Lambda function with our code operates as expected. Also referred to as integration tests. | It simulates how customers configure, deploy, and run their Lambda function - Event Source configuration, IAM permissions, etc. | Slow (minutes) | -| Performance tests | Ensure critical operations won't increase latency and costs to customers. | CI arbitrary hardware can make it flaky. We'll resume writing perf test after we revamp our unit/functional tests with internal utilities. | Fast to moderate (a few seconds to a few minutes) | \ No newline at end of file +| Performance tests | Ensure critical operations won't increase latency and costs to customers. | CI arbitrary hardware can make it flaky. We'll resume writing perf test after we revamp our unit/functional tests with internal utilities. | Fast to moderate (a few seconds to a few minutes) | diff --git a/docs/contributing/getting_started.md b/docs/contributing/getting_started.md index d2166b4af7..b007cf3616 100644 --- a/docs/contributing/getting_started.md +++ b/docs/contributing/getting_started.md @@ -3,6 +3,8 @@ title: Your first contribution description: All you need to know for your first contribution to Powertools for AWS Lambda (TypeScript) --- + + Thank you for your interest in contributing to our project - we couldn't be more excited!
@@ -61,7 +63,7 @@ Before sending us a pull request, please ensure that: * You are working against the latest source on the **main** branch, unless instructed otherwise. * You check existing [open, and recently merged](https://github.com/aws-powertools/powertools-lambda-typescript/pulls?q=is%3Apr+is%3Aopen%2Cmerged+sort%3Aupdated-desc){target="_blank" rel="nofollow"} pull requests to make sure someone else hasn't addressed the problem already. -* You discuss and agree your proposed changes under [an existing issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues?q=is%3Aopen+is%3Aupdated-desc) or a [new issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose){target="_blank" rel="nofollow"} before you begin any implementation. We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful. +* You discuss and agree the proposed changes under [an existing issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues?q=is%3Aopen+is%3Aupdated-desc) or a new one before you begin any implementation. We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful. * Create a new branch named after the change you are contributing _e.g._ `feat/logger-debug-sampling` **Ready?** @@ -83,4 +85,4 @@ For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of ## Security issue notifications -If you discover a potential security issue in this project, we kindly ask you to notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. \ No newline at end of file +If you discover a potential security issue in this project, we kindly ask you to notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. diff --git a/docs/contributing/setup.md b/docs/contributing/setup.md index d105488b24..de4c8416d7 100644 --- a/docs/contributing/setup.md +++ b/docs/contributing/setup.md @@ -3,6 +3,8 @@ title: Development environment description: Setting up your development environment for contribution --- + + [![Join our Discord](https://dcbadge.vercel.app/api/server/B8zZKbbyET)](https://discord.gg/B8zZKbbyET){target="_blank" rel="nofollow"} This page describes how to setup your development environment (Cloud or locally) to contribute to Powertools for AWS Lambda (TypeScript). @@ -36,7 +38,7 @@ Unless you're using the pre-configured Cloud environment, you'll need the follow ## Cloud environment !!! warning "A word of caution" - Before using a Cloud environment, be mindful of the pricing structure. You can find more information about each service pricing respectively on [Gitpod](https://www.gitpod.io/pricing){target="_blank" rel="nofollow"} and [GitHub Codespaces](https://docs.github.com/en/billing/managing-billing-for-github-codespaces/about-billing-for-github-codespaces){target="_blank" rel="nofollow"} pages. When in doubt, use the local environment below. + Before using one of the services below check out their pricing. You can find more information about each service pricing respectively on [Gitpod](https://www.gitpod.io/pricing){target="_blank" rel="nofollow"} and [GitHub Codespaces](https://docs.github.com/en/billing/managing-billing-for-github-codespaces/about-billing-for-github-codespaces){target="_blank" rel="nofollow"} pages. Once provisioned, each Cloud environment will come with all development dependencies and tools you'll need to contribute already installed. @@ -69,4 +71,4 @@ You might find useful to run both the documentation website and the API referenc * **Docs website**: `npm run docs-runLocalDocker` * If this is your first time running the docs, you need to build the image: `npm run docs-buildDockerImage` -* **API reference**: `npm run docs-api-build-run` \ No newline at end of file +* **API reference**: `npm run docs-api-build-run` diff --git a/docs/contributing/testing.md b/docs/contributing/testing.md index 0184b095b0..8fd9c09ed3 100644 --- a/docs/contributing/testing.md +++ b/docs/contributing/testing.md @@ -3,6 +3,8 @@ title: Testing description: How to write tests for Powertools for AWS Lambda (TypeScript) --- + + ## General practices As discussed in the [conventions](./conventions.md) page, we have different types of tests that aim to verify different aspects of the code. @@ -67,7 +69,6 @@ To run unit tests, you can use of the following commands from the root folder: * `npm test -w packages/metrics` to run all the unit tests for the `metrics` module * `npm run jest -w packages/metrics -- --group=unit/metrics/middleware` to run all the unit tests for the `metrics` module that are tagged with the `unit/metrics/middleware` group - We enforce 100% code coverage for unit tests. The test command will fail if the coverage is not 100% both on your local machine and in CI. ## Integration tests @@ -77,14 +78,14 @@ Integration tests are used to verify that the code works as expected when deploy When writing integration tests, you should follow the same conventions used for existing tests. For example, each test file should correspond to an utility and a specific usage type. For example, the test for the middleware usage for the `@aws-lambda-powertools/logger` module has a single test file named `basicFeatures.middy.test.ts`. !!! warning "A word of caution" - Running integration tests will deploy AWS resources in your AWS account, which might incur costs. The cost from **some services** are covered by the [AWS Free Tier](https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=*all&awsf.Free%20Tier%20Categories=*all) but not all of them. We recommend you to use a dedicated AWS account for testing purposes, and when in doubt, let the CI on our repository run the tests for you. + Running integration tests will deploy AWS resources in your AWS account, which might incur costs. The cost from **some services** are covered by the [AWS Free Tier](https://aws.amazon.com/free/) but not all of them. We recommend you to use a dedicated AWS account for testing purposes, and when in doubt, let the CI on our repository run the tests for you. To run integration tests you'll need to set up an AWS account and obtain credentials as described in the [prerequisites](./setup.md#requirements). Once ready, you can use of the following commands from the root folder: * `npm test:e2e -ws` to run all the integration tests for all the modules sequentially * `test:e2e:parallel` to run all the integration tests for all the modules in parallel * `npm test:e2e -w packages/metrics` to run all the integration tests for the `metrics` module -* `npm run test:e2e:nodejs20x -w packages/metrics` to run all the integration tests for the `metrics` module using the `nodejs20x` runtime +* `npm run test:e2e:nodejs20x -w packages/metrics` to run all the integration tests for the `metrics` module using the `nodejs20x` runtime The tests will deploy the necessary AWS resources using AWS CDK, and will run the Lambda functions using the AWS SDK. After that, the tests will verify the Lambda functions behave as expected by checking logs, metrics, traces, and other resources as needed. Finally, the tests will destroy all the AWS resources created at the beginning. @@ -100,4 +101,4 @@ sequenceDiagram Jest-->Jest: Assert logs/result Jest->>+AWS: Destroy Stack Jest->>+Dev Environment / CI: show test results -``` \ No newline at end of file +``` diff --git a/docs/core/logger.md b/docs/core/logger.md index 56aff581fc..ada54070a5 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -41,6 +41,7 @@ The `Logger` utility must always be instantiated outside the Lambda handler. By ``` ### Utility settings + The library has three optional settings, which can be set via environment variables or passed in the constructor. These settings will be used across all logs emitted: @@ -120,7 +121,10 @@ This functionality will include the following keys in your structured logs: === "Decorator" !!! note - The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. Additionally, they are implemented in a way that fits asynchronous methods. When decorating a synchronous method, the decorator replaces its implementation with an asynchronous one causing the caller to have to `await` the now decorated method. + The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. + + Additionally, they are implemented to decorate async methods. When decorating a synchronous one, the decorator replaces its implementation with an async one causing the caller to have to `await` the now decorated method. + If this is not the desired behavior, you can call the `logger.injectLambdaContext()` method directly in your handler. ```typescript hl_lines="8" @@ -186,7 +190,6 @@ You can append additional persistent keys and values in the logs generated durin To remove the keys you added, you can use the `removeKeys` method. - === "handler.ts" ```typescript hl_lines="5-13 17-25 32" @@ -223,7 +226,6 @@ To remove the keys you added, you can use the `removeKeys` method. } ``` - !!! tip "Logger will automatically ignore any key with an `undefined` value" #### Clearing all state @@ -290,7 +292,6 @@ In each case, the printed log will look like this: } ``` - ### Appending additional data to a single log item You can append additional data to a single log item by passing objects as additional parameters. @@ -359,7 +360,7 @@ The error will be logged with default key name `error`, but you can also pass yo ``` === "Example CloudWatch Logs excerpt" - + ```json hl_lines="7-12 20-25" { "level": "ERROR", @@ -374,7 +375,7 @@ The error will be logged with default key name `error`, but you can also pass yo "stack": "Error: Unexpected error #1 at lambdaHandler (/path/to/my/source-code/my-service/handler.ts:18:11) at Object. (/path/to/my/source-code/my-service/handler.ts:35:1) at Module._compile (node:internal/modules/cjs/loader:1108:14) at Module.m._compile (/path/to/my/source-code/node_modules/ts-node/src/index.ts:1371:23) at Module._extensions..js (node:internal/modules/cjs/loader:1137:10) at Object.require.extensions. [as .ts] (/path/to/my/source-code/node_modules/ts-node/src/index.ts:1374:12) at Module.load (node:internal/modules/cjs/loader:973:32) at Function.Module._load (node:internal/modules/cjs/loader:813:14) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12) at main (/path/to/my/source-code/node_modules/ts-node/src/bin.ts:331:12)" } } - { + { "level": "ERROR", "message": "This is the second error", "service": "serverlessAirline", @@ -388,6 +389,7 @@ The error will be logged with default key name `error`, but you can also pass yo } } ``` + !!! tip "Logging errors and log level" You can also log errors using the `warn`, `info`, and `debug` methods. Be aware of the log level though, you might miss those errors when analyzing the log later depending on the log level configuration. @@ -430,7 +432,9 @@ By setting the log level to `SILENT`, which can be done either through the `logL #### AWS Lambda Advanced Logging Controls (ALC) -With [AWS Lambda Advanced Logging Controls (ALC)](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-advanced), you can control the output format of your logs as either `TEXT` or `JSON` and specify the minimum accepted log level for your application. Regardless of the output format setting in Lambda, we will always output JSON formatted logging messages. +With [AWS Lambda Advanced Logging Controls (ALC)](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-advanced), you can control the output format of your logs as either `TEXT` or `JSON` and specify the minimum accepted log level for your application. + +Regardless of the output format setting in Lambda, we will always output JSON formatted logging messages. When you have this feature enabled, log messages that don’t meet the configured log level are discarded by Lambda. For example, if you set the minimum log level to `WARN`, you will only receive `WARN` and `ERROR` messages in your AWS CloudWatch Logs, all other log levels will be discarded by Lambda. @@ -467,7 +471,9 @@ In the event you have set a log level in Powertools to a level that is lower tha ### Using multiple Logger instances across your code -The `createChild` method allows you to create a child instance of the Logger, which inherits all of the attributes from its parent. You have the option to override any of the settings and attributes from the parent logger, including [its settings](#utility-settings), any [persistent attributes](#appending-persistent-additional-log-keys-and-values), and [the log formatter](#custom-log-formatter-bring-your-own-formatter). Once a child logger is created, the logger and its parent will act as separate instances of the Logger class, and as such any change to one won't be applied to the other. +The `createChild` method allows you to create a child instance of the Logger, which inherits all of the attributes from its parent. You have the option to override any of the settings and attributes from the parent logger, including [its settings](#utility-settings), any [persistent attributes](#appending-persistent-additional-log-keys-and-values), and [the log formatter](#custom-log-formatter-bring-your-own-formatter). + +Once a child logger is created, the logger and its parent will act as separate instances of the Logger class, and as such any change to one won't be applied to the other. The following example shows how to create multiple Loggers that share service name and persistent attributes while specifying different logging levels within a single Lambda invocation. As the result, only ERROR logs with all the inherited attributes will be displayed in CloudWatch Logs from the child logger, but all logs emitted will have the same service name and persistent attributes. diff --git a/docs/core/metrics.md b/docs/core/metrics.md index e4525d3c1a..a626c85170 100644 --- a/docs/core/metrics.md +++ b/docs/core/metrics.md @@ -3,6 +3,8 @@ title: Metrics description: Core utility --- + + Metrics creates custom metrics asynchronously by logging metrics to standard output following [Amazon CloudWatch Embedded Metric Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html). These metrics can be visualized through [Amazon CloudWatch Console](https://console.aws.amazon.com/cloudwatch/). @@ -32,11 +34,10 @@ If you're new to Amazon CloudWatch, there are two terminologies you must be awar * **Resolution**. It's a value representing the storage resolution for the corresponding metric. Metrics can be either Standard or High resolution. Read more [here](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Resolution_definition).
- + metrics terminology diagram
Metric terminology, visually explained
- ## Getting started ### Installation @@ -48,8 +49,8 @@ npm install @aws-lambda-powertools/metrics ``` !!! warning "Caution" - - Using the Lambda [Advanced Logging Controls](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-advanced) feature requires you to update your version of Powertools for AWS Lambda (TypeScript) to at least v1.15.0 to ensure metrics are reported correctly to Amazon CloudWatch Metrics. + + When using the Lambda [Advanced Logging Controls](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-advanced) feature you must install version of Powertools for AWS Lambda (TypeScript) v1.15.0 or newer. ### Usage @@ -128,7 +129,7 @@ You can create metrics using the `addMetric` method, and you can create dimensio ### Adding high-resolution metrics -You can create [high-resolution metrics](https://aws.amazon.com/about-aws/whats-new/2023/02/amazon-cloudwatch-high-resolution-metric-extraction-structured-logs/) passing `resolution` as parameter to `addMetric`. +You can create [high-resolution metrics](https://aws.amazon.com/about-aws/whats-new/2023/02/amazon-cloudwatch-high-resolution-metric-extraction-structured-logs/) passing `resolution` as parameter to `addMetric`. !!! tip "When is it useful?" High-resolution metrics are data with a granularity of one second and are very useful in several situations such as telemetry, time series, real-time incident management, and others. @@ -216,7 +217,10 @@ You can add default dimensions to your metrics by passing them as parameters in === "with logMetrics decorator" !!! note - The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. Additionally, they are implemented in a way that fits asynchronous methods. When decorating a synchronous method, the decorator replaces its implementation with an asynchronous one causing the caller to have to `await` the now decorated method. + The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. + + Additionally, they are implemented to decorate async methods. When decorating a synchronous one, the decorator replaces its implementation with an async one causing the caller to have to `await` the now decorated method. + If this is not the desired behavior, you can use the `logMetrics` middleware instead. ```typescript hl_lines="12" @@ -282,7 +286,10 @@ See below an example of how to automatically flush metrics with the Middy-compat #### Using the class decorator !!! note - The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. Additionally, they are implemented in a way that fits asynchronous methods. When decorating a synchronous method, the decorator replaces its implementation with an asynchronous one causing the caller to have to `await` the now decorated method. + The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. + + Additionally, they are implemented to decorate async methods. When decorating a synchronous one, the decorator replaces its implementation with an async one causing the caller to have to `await` the now decorated method. + If this is not the desired behavior, you can use the `logMetrics` middleware instead. The `logMetrics` decorator of the metrics utility can be used when your Lambda handler function is implemented as method of a Class. diff --git a/docs/core/tracer.md b/docs/core/tracer.md index f3f4f5cc00..057f53efca 100644 --- a/docs/core/tracer.md +++ b/docs/core/tracer.md @@ -98,8 +98,9 @@ You can quickly start by importing the `Tracer` class, initialize it outside the === "Decorator" !!! note - The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. Additionally, they are implemented in a way that fits asynchronous methods. When decorating a synchronous method, the decorator replaces its implementation with an asynchronous one causing the caller to have to `await` the now decorated method. - If this is not the desired behavior, you can use one of the other patterns instead. + The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. + + Additionally, they are implemented to decorate async methods. When decorating a synchronous one, the decorator replaces its implementation with an async one causing the caller to have to `await` the now decorated method. ```typescript hl_lines="8" --8<-- "docs/snippets/tracer/decorator.ts" @@ -113,7 +114,6 @@ You can quickly start by importing the `Tracer` class, initialize it outside the --8<-- "docs/snippets/tracer/manual.ts" ``` - When using the `captureLambdaHandler` decorator or middleware, Tracer performs these additional tasks to ease operations: * Handles the lifecycle of the subsegment @@ -134,7 +134,8 @@ When using the `captureLambdaHandler` decorator or middleware, Tracer performs t --8<-- "docs/snippets/tracer/putAnnotation.ts" ``` - 1. When Lambda starts an invocation [the X-Ray SDk creates a segment called `facade`](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs-subsegments.html#xray-sdk-nodejs-subsegments-lambda). This segment cannot be annotated or modified by your code, so you need to create a new subsegment. This is done automatically by Tracer when using the [decorator or middleware patterns](./tracer.md/#lambda-handler) + 1. When Lambda starts an invocation [the X-Ray SDk creates a segment called `facade`](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs-subsegments.html#xray-sdk-nodejs-subsegments-lambda). + This segment cannot be annotated or modified by your code, so you need to create a new subsegment. This is done automatically by Tracer when using the [decorator or middleware patterns](./tracer.md/#lambda-handler) 2. To correctly trace the current and subsequent invocations you need to restore the original segment, this is done automatically by Tracer when using the [decorator or middleware patterns](./tracer.md/#lambda-handler). === "Metadata" You can add metadata using `putMetadata` method. @@ -143,7 +144,8 @@ When using the `captureLambdaHandler` decorator or middleware, Tracer performs t --8<-- "docs/snippets/tracer/putMetadata.ts" ``` - 1. When Lambda starts an invocation [the X-Ray SDk creates a segment called `facade`](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs-subsegments.html#xray-sdk-nodejs-subsegments-lambda). This segment cannot be modified by your code, so you need to create a new subsegment. This is done automatically by Tracer when using the [decorator or middleware patterns](./tracer.md/#lambda-handler) + 1. When Lambda starts an invocation [the X-Ray SDk creates a segment called `facade`](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs-subsegments.html#xray-sdk-nodejs-subsegments-lambda). + This segment cannot be modified by your code, so you need to create a new subsegment. This is done automatically by Tracer when using the [decorator or middleware patterns](./tracer.md/#lambda-handler) 2. To correctly trace the current and subsequent invocations you need to restore the original segment, this is done automatically by Tracer when using the [decorator or middleware patterns](./tracer.md/#lambda-handler).
@@ -158,8 +160,9 @@ You can trace other class methods using the `captureMethod` decorator or any arb === "Decorator" !!! note - The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. Additionally, they are implemented in a way that fits asynchronous methods. When decorating a synchronous method, the decorator replaces its implementation with an asynchronous one causing the caller to have to `await` the now decorated method. - If this is not the desired behavior, you can use manual instrumentation instead. + The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. + + Additionally, they are implemented to decorate async methods. When decorating a synchronous one, the decorator replaces its implementation with an async one causing the caller to have to `await` the now decorated method. ```typescript hl_lines="8" --8<-- "docs/snippets/tracer/captureMethodDecorator.ts" @@ -174,7 +177,6 @@ You can trace other class methods using the `captureMethod` decorator or any arb --8<-- "docs/snippets/tracer/captureMethodManual.ts" ``` - ### Patching AWS SDK clients Tracer can patch any [AWS SDK clients](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs-awssdkclients.html) and create traces when your application makes calls to AWS services. diff --git a/docs/index.md b/docs/index.md index 5d61c7577d..e9fcc7b2db 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,6 +3,8 @@ title: Homepage description: Powertools for AWS Lambda (TypeScript) --- + + Powertools for AWS Lambda (TypeScript) is a developer toolkit to implement Serverless best practices and increase developer velocity. You can use Powertools for AWS Lambda in both TypeScript and JavaScript code bases. @@ -248,8 +250,6 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa ? Do you want to edit the local lambda function now? No ``` - - ### Lambda Layer [Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html){target="_blank"} is a `.zip` file archive that can contain additional code, pre-packaged dependencies, data, or configuration files. We compile and optimize [all dependencies](#install) to achieve an optimal build. @@ -287,7 +287,6 @@ You can use the Lambda Layer both with CommonJS and ESM (ECMAScript modules) for | `me-south-1` | [arn:aws:lambda:me-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:5](#){: .copyMe}:clipboard: | | `il-central-1` | [arn:aws:lambda:il-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:5](#){: .copyMe}:clipboard: | - **Want to inspect the contents of the Layer?** The pre-signed URL to download this Lambda Layer will be within `Location` key in the CLI output. The CLI output will also contain the Powertools for AWS Lambda version it contains. @@ -302,9 +301,9 @@ aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{aws::region}:094274105 Many of the utilities provided by Powertools for AWS Lambda (TypeScript) can be used with different programming paradigms: -* **Middy** middleware. It is the best choice if your existing code base relies on the [Middy 4.x](https://middy.js.org/docs/) middleware engine. Powertools for AWS Lambda (TypeScript) offers compatible Middy middleware to make this integration seamless. -* **Method decorator**. Use [TypeScript method decorators](https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators) if you prefer writing your business logic using [TypeScript Classes](https://www.typescriptlang.org/docs/handbook/classes.html). If you aren’t using Classes, this requires the most significant refactoring. -* **Manually**. It provides the most granular control. It’s the most verbose approach, with the added benefit of no additional dependency and no refactoring to TypeScript Classes. +- **Middy** middleware. It is the best choice if your existing code base relies on the [Middy 4.x](https://middy.js.org/docs/) middleware engine. Powertools for AWS Lambda (TypeScript) offers compatible Middy middleware to make this integration seamless. +- **Method decorator**. Use [TypeScript method decorators](https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators) if you prefer writing your business logic using [TypeScript Classes](https://www.typescriptlang.org/docs/handbook/classes.html). If you aren’t using Classes, this requires the most significant refactoring. +- **Manually**. It provides the most granular control. It’s the most verbose approach, with the added benefit of no additional dependency and no refactoring to TypeScript Classes. The examples in this documentation will feature all the approaches described above wherever applicable. @@ -353,7 +352,6 @@ Each Utility page provides information on example values and allowed values. ## Support Powertools for AWS Lambda (TypeScript) - There are many ways you can help us gain future investments to improve everyone's experience:
diff --git a/docs/maintainers.md b/docs/maintainers.md index 6570c5a6de..4eb19e2b14 100644 --- a/docs/maintainers.md +++ b/docs/maintainers.md @@ -3,6 +3,8 @@ title: Maintainers playbook description: Playbook for active maintainers in Powertools for AWS Lambda (TypeScript) --- + + ## Overview !!! note "Please treat this content as a living document." @@ -307,7 +309,9 @@ Finally, add the new region to the [`region` matrix](https://github.com/aws-powe ### Negative Impact on the Project + Actions that negatively impact the project will be handled by the admins, in coordination with other maintainers, in balance with the urgency of the issue. Examples would be [Code of Conduct](https://github.com/aws-powertools/powertools-lambda-typescript/blob/develop/CODE_OF_CONDUCT.md){target="_blank"} violations, deliberate harmful or malicious actions, spam, monopolization, and security risks. + ### Becoming a maintainer @@ -353,4 +357,4 @@ Make use of `help-wanted` and `good-first-issue` to signal additional contributi Try offering a 1:1 call in the attempt to get to a mutual understanding and clarify areas that maintainers could help. -In the rare cases where both parties don't have the bandwidth or expertise to continue, it's best to use the `on-hold` or `revisit-in-3-months` labels. After some time has passed, see if it's possible to break the PR or issue in smaller chunks, and eventually close if there is no progress. \ No newline at end of file +In the rare cases where both parties don't have the bandwidth or expertise to continue, it's best to use the `on-hold` or `revisit-in-3-months` labels. After some time has passed, see if it's possible to break the PR or issue in smaller chunks, and eventually close if there is no progress. diff --git a/docs/roadmap.md b/docs/roadmap.md index 052a7b3e4e..3afdfbbd38 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,10 +1,17 @@ -# Overview +--- +title: Roadmap +description: Public roadmap for Powertools for AWS Lambda (TypeScript) +--- + + + +## Overview Our public roadmap outlines the high level direction we are working towards. We update this document when our priorities change: security and stability are our top priority. !!! info "For most up-to-date information, see our [board of activities](https://github.com/orgs/aws-powertools/projects/7/views/3?query=is%3Aopen+sort%3Aupdated-desc){target="_blank"}." -## Key areas +### Key areas Security and operational excellence take precedence above all else. This means bug fixing, stability, customer's support, and internal compliance may delay one or more key areas below. @@ -14,7 +21,7 @@ You can help us prioritize by [upvoting existing feature requests](https://githu [![Join our Discord](https://dcbadge.vercel.app/api/server/B8zZKbbyET)](https://discord.gg/B8zZKbbyET){target="_blank"} -### Event Handler REST +#### Event Handler REST - [ ] [RFC to discuss initial thoughts and feasibility for TS/JS ecosystem](https://github.com/aws-powertools/powertools-lambda-typescript/issues/413) - [ ] Explore pros & cons of whether to build atop lean frameworks (e.g., Hono) or from scratch @@ -32,13 +39,13 @@ You can help us prioritize by [upvoting existing feature requests](https://githu - [ ] Support for injecting request details _(consider not doing globals like Python legacy)_ - [ ] Support for Router _(multi-file routes)_ -### Improve operational excellence +#### Improve operational excellence We continue to work on increasing operational excellence to remove as much undifferentiated heavy lifting for maintainers, so that we can focus on delivering features that help you. This means improving our automation workflows, project management, and test coverage. -## Roadmap status definition +### Roadmap status definition
```mermaid @@ -58,7 +65,7 @@ Within our [public board](https://github.com/orgs/aws-powertools/projects/7/view > Tasks or issues with empty `Status` will be categorized in upcoming review cycles. -## Process +### Process
```mermaid @@ -76,7 +83,7 @@ graph LR Our end-to-end mechanism follows four major steps: -- **Feature Request**. Ideas start with a [feature request](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=type%2Ffeature-request%2Ctriage&projects=aws-powertools%2F7&template=feature_request.yml&title=Feature+request%3A+TITLE){target="_blank"} to outline their use case at a high level. For complex use cases, maintainers might ask for/write a RFC. +- **Feature Request**. Ideas start with a [feature request](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=type%2Ffeature-request%2Ctriage&template=feature_request.yml&title=Feature+request%3A+TITLE){target="_blank"} to outline their use case at a high level. For complex use cases, maintainers might ask for/write a RFC. - Maintainers review requests based on [project tenets](index.md#tenets){target="_blank"}, customers reaction (👍), and use cases. - **Request-for-comments (RFC)**. Design proposals use our [RFC issue template](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=type%2FRFC%2Ctriage&projects=aws-powertools%2F7&template=rfc.yml&title=RFC%3A+TITLE){target="_blank"} to describe its implementation, challenges, developer experience, dependencies, and alternative solutions. - This helps refine the initial idea with community feedback before a decision is made. @@ -85,13 +92,13 @@ Our end-to-end mechanism follows four major steps: ??? info "See [Maintainers](./maintainers.md){target="_blank"} document to understand how we triage issues and pull requests, labels and governance." -## Disclaimer +### Disclaimer The Powertools for AWS Lambda (TypeScript) team values feedback and guidance from its community of users, although final decisions on inclusion into the project will be made by AWS. We determine the high-level direction for our open roadmap based on customer feedback and popularity (👍🏽 and comments), security and operational impacts, and business value. Where features don’t meet our goals and longer-term strategy, we will communicate that clearly and openly as quickly as possible with an explanation of why the decision was made. -## FAQs +### FAQs **Q: Why did you build this?** @@ -105,9 +112,9 @@ A: Because job zero is security and operational stability, we can't provide spec A: For existing features, you can directly comment on issues. For anything else, please open an issue. -## Launched +### Launched -### JMESPath Functions +#### JMESPath Functions > [Docs](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/jmespath/) @@ -120,7 +127,7 @@ Feature parity on JMESPath Powertools Functions feature - [x] Support for built-in `powertools_base64_gzip` JMESPath function - [x] Support for Bring Your Own JMESPath function -### Parser (Zod) +#### Parser (Zod) > [Docs](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parser/) @@ -131,7 +138,7 @@ Feature parity on Parser feature - [x] Support for envelope (wrapping before schema validation) - [x] Support for user-defined envelopes -### Version 2 release +#### Version 2 release > [Docs](https://docs.powertools.aws.dev/lambda/typescript/latest/upgrade/) @@ -139,7 +146,7 @@ Over the past year, we have gathered a number of feature requests and improvemen - [x] **ES Modules support ([#521](https://github.com/aws-powertools/powertools-lambda-typescript/issues/521))** - Thanks to the work of the community we have been able to validate the feasibility of dual support for CommonJS and ES Modules. We are currently working on a plan to implement this. - [x] **TypeScript 5.x support ([#1375](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1375))** - This new version of TypeScript brings breaking changes to the experimental decorators API, which we use in our core utilities. We need to investigate the impact of this change and how to best support it. -- [x] **Support for 3rd party observability providers ([#1500](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1500))** - Many of our customers would like to use Powertools for AWS to send logs, traces, and metrics to providers other than Amazon CloudWatch. At the moment we are investigating the feasibility of this for the Logger utility, while the Python version of Powertools for AWS Lambda is considering this also for Tracer and Metrics. +- [x] **Support for 3rd party observability providers ([#1500](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1500))** - Many of our customers would like to use Powertools for AWS to send logs, traces, and metrics to providers other than Amazon CloudWatch. You can find the full list of changes in the [v2 RFC](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1714) and follow the progress in the [v2 milestone](https://github.com/aws-powertools/powertools-lambda-typescript/milestone/12). diff --git a/docs/upgrade.md b/docs/upgrade.md index ab2d14be0c..a79384a996 100644 --- a/docs/upgrade.md +++ b/docs/upgrade.md @@ -3,6 +3,8 @@ title: Upgrade guide description: Guide to update between major Powertools for AWS Lambda (TypeScript) versions --- + + ## End of support v1 !!! warning "On March 13th, 2024, Powertools for AWS Lambda (TypeScript) v1 entered maintenance mode, and will reach end-of-life on September 1st, 2024. If you are still using v1, we strongly recommend you to read our upgrade guide and update to the latest version." @@ -25,7 +27,6 @@ V2 is focused on official support for ESM (ECMAScript modules). We've made other | **Logger** | Removed `ContextExamples` from `@aws-lambda-powertools/commons` package. | Yes | | **Logger and Tracer** | Removed deprecated `createLogger` and `createTracer` helper functions in favor of direct instantiation. | Yes | - ### First steps Before you start, we suggest making a copy of your current working project or create a new git branch. @@ -61,7 +62,7 @@ If you're unable to use ESM, you can still use the `require` syntax to import th You might still need the `require` syntax when using a dependency or a transitive dependency that doesn't support ESM. For example, Tracer _(`@aws-lambda-powertools/tracer`)_ relies on the AWS X-Ray SDK for Node.js which uses `require`. -When that happens, you can instruct your bundler to use the `require` syntax for specific dependencies while using ESM for everything else. This is commonly known as [polyfill](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill){target="_blank"}. +When that happens, you can instruct your bundler to use the `require` syntax for specific dependencies while using ESM for everything else. This is commonly known as [polyfill](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill){target="_blank"}. Here is an example using `esbuild` bundler. === "With AWS CDK" @@ -178,7 +179,7 @@ In v2, you can now directly import from the `types` subpath export, e.g., `@aws- !!! note "Disregard if you are not using the [log sampling feature](./core/logger.md#sampling-logs)." -In v1, log sampling implementation was inconsistent from other Powertools for AWS Lambda languages _(Python, .NET, and Java)_. +In v1, log sampling implementation was inconsistent from other Powertools for AWS Lambda languages _(Python, .NET, and Java)_. In v2, we changed these behaviors for consistency across languages: @@ -291,7 +292,7 @@ In v2, you have more control over **standard** (`attributes`) and [**custom keys In v1, we have provided a `ContextExamples` object to help you with testing. -In v2, we have removed the `ContextExamples` from the `@aws-lambda-powertools/commons` package, so you need to create it in your tests: +In v2, we have removed the `ContextExamples` from the `@aws-lambda-powertools/commons` package, so you need to create it in your tests: === "Before" @@ -335,8 +336,6 @@ In v2, we have removed the `ContextExamples` from the `@aws-lambda-powertools/co }); ``` - - ## Helper functions We removed the deprecated `createLogger` and `createTracer` heper functions. diff --git a/docs/utilities/batch.md b/docs/utilities/batch.md index 0e3ef1ad3b..be76460edc 100644 --- a/docs/utilities/batch.md +++ b/docs/utilities/batch.md @@ -67,6 +67,7 @@ This behavior changes when you enable [ReportBatchItemFailures feature](https:// ### Installation Install the library in your project + ```shell npm i @aws-lambda-powertools/batch ``` @@ -141,15 +142,15 @@ Processing batches from SQS works in three stages: #### FIFO queues When using [SQS FIFO queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html){target="_blank"}, we will stop processing messages after the first failure, and return all failed and unprocessed messages in `batchItemFailures`. -This helps preserve the ordering of messages in your queue. +This helps preserve the ordering of messages in your queue. ```typescript hl_lines="1-4 13 28-30" --8<-- "docs/snippets/batch/gettingStartedSQSFifo.ts" ``` -1. **Step 1**. Creates a partial failure batch processor for SQS FIFO queues. See [partial failure mechanics for details](#partial-failure-mechanics) +1. **Step 1**. Creates a partial failure batch processor for SQS FIFO queues. See [partial failure mechanics for details](#partial-failure-mechanics) -!!! Note +!!! Note Note that SqsFifoPartialProcessor is synchronous using `processPartialResponseSync`. This is because we need to preserve the order of messages in the queue. See [Async or sync processing section](#async-or-sync-processing) for more details. @@ -373,16 +374,16 @@ There are two processors you can use with this utility: In most cases your function will be `async` returning a `Promise`. Therefore, the `BatchProcessor` is the default processor handling your batch records asynchronously. There are use cases where you need to process the batch records synchronously. For example, when you need to process multiple records at the same time without conflicting with one another. -For such cases we recommend to use the `BatchProcessorSync` and `processPartialResponseSync` functions. +For such cases we recommend to use the `BatchProcessorSync` and `processPartialResponseSync` functions. !!! info "Note that you need match your processing function with the right batch processor" - * If your function is `async` returning a `Promise`, use `BatchProcessor` and `processPartialResponse` + *If your function is `async` returning a `Promise`, use `BatchProcessor` and `processPartialResponse` * If your function is not `async`, use `BatchProcessorSync` and `processPartialResponseSync` -The difference between the two processors in implementation is that `BatchProcessor` uses `Promise.all()` while `BatchProcessorSync` loops through each record to preserve the order. +The difference between the two processors in implementation is that `BatchProcessor` uses `Promise.all()` while `BatchProcessorSync` loops through each record to preserve the order. ???+ question "When is this useful?" - + For example, imagine you need to process multiple loyalty points and incrementally save in a database. While you await the database to confirm your records are saved, you could start processing another request concurrently. The reason this is not the default behaviour is that not all use cases can handle concurrency safely (e.g., loyalty points must be updated in order). @@ -396,13 +397,12 @@ Use the `BatchProcessor` directly in your function to access a list of all retur * **When successful**. We will include a tuple with `success`, the result of `recordHandler`, and the batch record * **When failed**. We will include a tuple with `fail`, exception as a string, and the batch record - ```typescript hl_lines="25 27-28 30-33 38" title="Accessing processed messages" --8<-- "docs/snippets/batch/accessProcessedMessages.ts" ``` -1. The processor requires the records array. This is typically handled by `processPartialResponse`. -2. You need to register the `batch`, the `recordHandler` function, and optionally the `context` to access the Lambda context. +1. The processor requires the records array. This is typically handled by `processPartialResponse`. +2. You need to register the `batch`, the `recordHandler` function, and optionally the `context` to access the Lambda context. ### Accessing Lambda Context @@ -461,14 +461,14 @@ classDiagram * **`processRecordSync()`** – handles all processing logic for each individual message of a batch, including calling the `recordHandler` (`this.handler`) You can then use this class as a context manager, or pass it to `processPartialResponseSync` to process the records in your Lambda handler function. - + ```typescript hl_lines="21 35 56 61 73 86" title="Creating a custom batch processor" --8<-- "docs/snippets/batch/customPartialProcessor.ts" ``` ## Tracing with AWS X-Ray -You can use Tracer to create subsegments for each batch record processed. To do so, you can open a new subsegment for each record, and close it when you're done processing it. When adding annotations and metadata to the subsegment, you can do so directly without calling `tracer.setSegment(subsegment)`. This allows you to work with the subsegment directly and avoid having to either pass the parent subsegment around or have to restore the parent subsegment at the end of the record processing. +You can use Tracer to create subsegments for each batch record processed. To do so, you can open a new subsegment for each record, and close it when you're done processing it. When adding annotations and metadata to the subsegment, you can do so directly without calling `tracer.setSegment(subsegment)`. This allows you to work with the subsegment directly and avoid having to either pass the parent subsegment around or have to restore the parent subsegment at the end of the record processing. ```typescript --8<-- "docs/snippets/batch/advancedTracingRecordHandler.ts" @@ -502,4 +502,4 @@ Given a SQS batch where the first batch record succeeds and the second fails pro ```json title="events/sqs_event.json" --8<-- "docs/snippets/batch/samples/sampleSQSEvent.json" - ``` \ No newline at end of file + ``` diff --git a/docs/utilities/idempotency.md b/docs/utilities/idempotency.md index 273d7a551b..34f1ba905f 100644 --- a/docs/utilities/idempotency.md +++ b/docs/utilities/idempotency.md @@ -3,6 +3,8 @@ title: Idempotency description: Utility --- + + The idempotency utility provides a simple solution to convert your Lambda functions into idempotent operations which are safe to retry. ## Key features @@ -52,17 +54,16 @@ classDiagram ### Installation Install the library in your project + ```shell npm i @aws-lambda-powertools/idempotency @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb ``` While we support Amazon DynamoDB as a persistence layer out of the box, you need to bring your own AWS SDK for JavaScript v3 DynamoDB client. - ???+ note This utility supports **[AWS SDK for JavaScript v3](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/){target="_blank"} only**. If you are using the `nodejs18.x` runtime or newer, the AWS SDK for JavaScript v3 is already installed and you can install only the utility. - ### IAM Permissions Your Lambda function IAM Role must have `dynamodb:GetItem`, `dynamodb:PutItem`, `dynamodb:UpdateItem` and `dynamodb:DeleteItem` IAM permissions before using this feature. If you're using one of our examples: [AWS Serverless Application Model (SAM)](#required-resources) or [Terraform](#required-resources) the required permissions are already included. @@ -109,10 +110,10 @@ If you're not [changing the default configuration for the DynamoDB persistence l Larger items cannot be written to DynamoDB and will cause exceptions. ???+ info "Info: DynamoDB" - Each function invocation will make only 1 request to DynamoDB by using DynamoDB's [conditional expressions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html){target="_blank"} to ensure that we don't overwrite existing records, + Each function invocation will make only 1 request to DynamoDB by using DynamoDB's [conditional expressions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html){target="_blank"} to ensure that we don't overwrite existing records, and [ReturnValuesOnConditionCheckFailure](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html#DDB-PutItem-request-ReturnValuesOnConditionCheckFailure){target="_blank"} to return the record if it exists. - See [AWS Blog post on handling conditional write errors](https://aws.amazon.com/blogs/database/handle-conditional-write-errors-in-high-concurrency-scenarios-with-amazon-dynamodb/) for more details. - For retried invocations, you will see 1WCU and 1RCU. + See [AWS Blog post on handling conditional write errors](https://aws.amazon.com/blogs/database/handle-conditional-write-errors-in-high-concurrency-scenarios-with-amazon-dynamodb/) for more details. + For retried invocations, you will see 1WCU and 1RCU. Review the [DynamoDB pricing documentation](https://aws.amazon.com/dynamodb/pricing/){target="_blank"} to estimate the cost. ### MakeIdempotent function wrapper @@ -133,12 +134,10 @@ You can quickly start by initializing the `DynamoDBPersistenceLayer` class and u After processing this request successfully, a second request containing the exact same payload above will now return the same response, ensuring our customer isn't charged twice. - ???+ note In this example, the entire Lambda handler is treated as a single idempotent operation. If your Lambda handler can cause multiple side effects, or you're only interested in making a specific logic idempotent, use the `makeIdempotent` high-order function only on the function that needs to be idempotent. - - See [Choosing a payload subset for idempotency](#choosing-a-payload-subset-for-idempotency) for more elaborate use cases. + See [Choosing a payload subset for idempotency](#choosing-a-payload-subset-for-idempotency) for more elaborate use cases. You can also use the `makeIdempotent` function wrapper on any method that returns a response to make it idempotent. This is useful when you want to make a specific logic idempotent, for example when your Lambda handler performs multiple side effects and you only want to make a specific one idempotent. @@ -159,14 +158,17 @@ When using `makeIdempotent` on arbitrary functions, you can tell us which argume --8<-- "docs/snippets/idempotency/types.ts:3:16" ``` -The function this example has two arguments, note that while wrapping it with the `makeIdempotent` high-order function, we specify the `dataIndexArgument` as `1` to tell the decorator that the second argument is the one that contains the data we should use to make the function idempotent. Remember that arguments are zero-indexed, so the first argument is `0`, the second is `1`, and so on. +The function this example has two arguments, note that while wrapping it with the `makeIdempotent` high-order function, we specify the `dataIndexArgument` as `1` to tell the decorator that the second argument is the one with the data we should use to make the function idempotent. Remember that arguments are zero-indexed, so the first argument is `0`, the second is `1`, etc. ### Idempotent Decorator You can also use the `@idempotent` decorator to make your Lambda handler idempotent, similar to the `makeIdempotent` function wrapper. !!! info - The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. Additionally, they are implemented in a way that fits asynchronous methods. When decorating a synchronous method, the decorator replaces its implementation with an asynchronous one causing the caller to have to `await` the now decorated method. + The class method decorators in this project follow the experimental implementation enabled via the [`experimentalDecorators` compiler option](https://www.typescriptlang.org/tsconfig#experimentalDecorators) in TypeScript. + + Additionally, they are implemented to decorate async methods. When decorating a synchronous one, the decorator replaces its implementation with an async one causing the caller to have to `await` the now decorated method. + If this is not the desired behavior, you can use one of the other patterns to make your logic idempotent. === "index.ts" @@ -181,7 +183,6 @@ You can also use the `@idempotent` decorator to make your Lambda handler idempot --8<-- "docs/snippets/idempotency/types.ts" ``` - You can use the decorator on your Lambda handler or on any function that returns a response to make it idempotent. This is useful when you want to make a specific logic idempotent, for example when your Lambda handler performs multiple side effects and you only want to make a specific one idempotent. The configuration options for the `@idempotent` decorator are the same as the ones for the `makeIdempotent` function wrapper. @@ -191,7 +192,9 @@ The configuration options for the `@idempotent` decorator are the same as the on Currently we support Middy up to `v4.x` that you can install it by running `npm i @middy/core@~4`. Check their docs to learn more about [Middy and its middleware stack](https://middy.js.org/docs/intro/getting-started){target="_blank"} as well as [best practices when working with Powertools](https://middy.js.org/docs/integrations/lambda-powertools#best-practices){target="_blank"}. -If you are using [Middy](https://middy.js.org){target="_blank"} as your middleware engine, you can use the `makeHandlerIdempotent` middleware to make your Lambda handler idempotent. Similar to the `makeIdempotent` function wrapper, you can quickly make your Lambda handler idempotent by initializing the `DynamoDBPersistenceLayer` class and using it with the `makeHandlerIdempotent` middleware. +If you are using [Middy.js](https://middy.js.org){target="_blank"} as your middleware engine, you can use the `makeHandlerIdempotent` middleware to make your Lambda handler idempotent. + +Similar to the `makeIdempotent` function wrapper, you can quickly make your Lambda handler idempotent by initializing the `DynamoDBPersistenceLayer` class and using it with the `makeHandlerIdempotent` middleware. === "index.ts" @@ -242,10 +245,8 @@ Imagine the function executes successfully, but the client never receives the re ### Lambda timeouts - - To prevent against extended failed retries when a [Lambda function times out](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-verify-invocation-timeouts/), Powertools for AWS Lambda calculates and includes the remaining invocation available time as part of the idempotency record. -This is automatically done when you wrap your Lambda handler with the [makeIdempotent](#makeIdempotent-function-wrapper) function wrapper, or use the [`makeHandlerIdempotent`](#makeHandlerIdempotent-middy-middleware) Middy middleware. +This is automatically done when you wrap your Lambda handler with the [makeIdempotent](#makeidempotent-function-wrapper) function wrapper, or use the [`makeHandlerIdempotent`](#makehandleridempotent-middy-middleware) Middy middleware. ???+ example If a second invocation happens **after** this timestamp, and the record is marked as `INPROGRESS`, we will execute the invocation again as if it was in the `EXPIRED` state (e.g, `expire_seconds` field elapsed). @@ -253,7 +254,7 @@ This is automatically done when you wrap your Lambda handler with the [makeIdemp This means that if an invocation expired during execution, it will be quickly executed again on the next retry. ???+ important - If you are only using the [makeIdempotent function wrapper](#makeIdempotent-function-wrapper) to guard isolated parts of your code outside of your handler, you must use `registerLambdaContext` available in the [idempotency config object](#customizing-the-default-behavior) to benefit from this protection. + If you are only using the [makeIdempotent function wrapper](#makeidempotent-function-wrapper) to guard isolated parts of your code outside of your handler, you must use `registerLambdaContext` available in the [idempotency config object](#customizing-the-default-behavior) to benefit from this protection. Here is an example on how you register the Lambda context in your handler: @@ -653,12 +654,10 @@ This means that we will raise **`IdempotencyKeyError`** if the evaluation of **` You can easily integrate with [Batch](batch.md) utility by using idempotency wrapper around your processing function. This ensures that you process each record in an idempotent manner, and guard against a [Lambda timeout](#lambda-timeouts) idempotent situation. -???+ "Choosing a unique batch record attribute" +???+ "Choosing a unique batch record attribute" In this example, we choose `messageId` as our idempotency key since we know it'll be unique. Depending on your use case, it might be more accurate [to choose another field](#choosing-a-payload-subset-for-idempotency) your producer intentionally set to define uniqueness. - - === "Integration with batch processor" ```typescript hl_lines="27 31-34 41" @@ -742,7 +741,7 @@ Below an example implementation of a custom persistence layer backed by a generi ???+ danger Pay attention to the documentation for each - you may need to perform additional checks inside these methods to ensure the idempotency guarantees remain intact. - + For example, the `_putRecord()` method needs to throw an error if a non-expired record already exists in the data store with a matching key. ## Extra resources diff --git a/docs/utilities/jmespath.md b/docs/utilities/jmespath.md index cf6c94aac1..ee7f266941 100644 --- a/docs/utilities/jmespath.md +++ b/docs/utilities/jmespath.md @@ -3,6 +3,8 @@ title: JMESPath Functions description: Utility --- + + Built-in [JMESPath](https://jmespath.org/){target="_blank" rel="nofollow"} functions to easily deserialize common encoded JSON payloads in Lambda functions. ## Key features @@ -13,6 +15,14 @@ Built-in [JMESPath](https://jmespath.org/){target="_blank" rel="nofollow"} funct ## Getting started +### Installation + +Install the utility in your project: + +```sh +npm install @aws-lambda-powertools/jmespath +``` + You might have events that contain encoded JSON payloads as string, base64, or even in compressed format. It is a common use case to decode and extract them partially or fully as part of your Lambda function invocation. Powertools for AWS Lambda (TypeScript) also have utilities like [idempotency](idempotency.md){target="_blank"} where you might need to extract a portion of your data before using them. @@ -55,6 +65,7 @@ We provide built-in envelopes for popular AWS Lambda event sources to easily dec These are all built-in envelopes you can use along with their expression as a reference: + | Envelope | JMESPath expression | | --------------------------------- | ----------------------------------------------------------------------------------------- | | **`API_GATEWAY_HTTP`** | `powertools_json(body)` | @@ -70,6 +81,7 @@ These are all built-in envelopes you can use along with their expression as a re | **`S3_SQS`** | `Records[*].powertools_json(body).Records[0]` | | **`SNS`** | `Records[0].Sns.Message | powertools_json(@)` | | **`SQS`** | `Records[*].powertools_json(body)` | + ???+ tip "Using SNS?" If you don't require SNS metadata, enable [raw message delivery](https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html). It will reduce multiple payload layers and size, when using SNS in combination with other services (_e.g., SQS, S3, etc_). @@ -203,4 +215,4 @@ Here is an example of how to decompress messages compressed using the [Brotli co ```json --8<-- "docs/snippets/jmespath/powertoolsCustomFunction.json" - ``` \ No newline at end of file + ``` diff --git a/docs/utilities/parameters.md b/docs/utilities/parameters.md index df89ef8a62..dc87c5f108 100644 --- a/docs/utilities/parameters.md +++ b/docs/utilities/parameters.md @@ -3,7 +3,9 @@ title: Parameters description: Utility --- + The Parameters utility provides high-level functions to retrieve one or multiple parameter values from [AWS Systems Manager Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html){target="_blank"}, [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html){target="_blank"}, [AWS AppConfig](https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html){target="_blank"}, [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html){target="_blank"}, or your own parameter store. + ## Key features @@ -135,7 +137,7 @@ You can adjust how long values should be kept in cache by using the param `maxAg --8<-- "docs/snippets/parameters/adjustingCacheTTL.ts" ``` -1. Options passed to `get()`, `getMultiple()`, and `getParametersByName()` will override the values set in `POWERTOOLS_PARAMETERS_MAX_AGE` environment variable. +1. Options passed to `get()`, `getMultiple()`, and `getParametersByName()` will override the values set in `POWERTOOLS_PARAMETERS_MAX_AGE` environment variable. ???+ info The `maxAge` parameter is also available in high level functions like `getParameter`, `getSecret`, etc. @@ -175,7 +177,7 @@ The AWS Systems Manager Parameter Store provider supports two additional argumen --8<-- "docs/snippets/parameters/ssmProviderDecryptAndRecursive.ts" ``` -1. Options passed to `get()`, `getMultiple()`, and `getParametersByName()` will override the values set in `POWERTOOLS_PARAMETERS_SSM_DECRYPT` environment variable. +1. Options passed to `get()`, `getMultiple()`, and `getParametersByName()` will override the values set in `POWERTOOLS_PARAMETERS_SSM_DECRYPT` environment variable. #### SecretsProvider @@ -263,7 +265,7 @@ DynamoDB provider can be customized at initialization to match your table struct | Parameter | Mandatory | Default | Description | | ------------- | --------- | ------- | --------------------------------------------------------------------------------------------------------- | -| **tableName** | **Yes** | *(N/A)* | Name of the DynamoDB table containing the parameter values. | +| **tableName** | **Yes** | _(N/A)_ | Name of the DynamoDB table containing the parameter values. | | **keyAttr** | No | `id` | Hash key for the DynamoDB table. | | **sortAttr** | No | `sk` | Range key for the DynamoDB table. You don't need to set this if you don't use the `getMultiple()` method. | | **valueAttr** | No | `value` | Name of the attribute containing the parameter value. | @@ -318,7 +320,7 @@ If you use `transform` with `getMultiple()`, you can have a single malformed par You can override this by setting the `throwOnTransformError` argument to `true`. If you do so, a single transform error will throw a **`TransformParameterError`** error. -For example, if you have three parameters, */param/a*, */param/b* and */param/c*, but */param/c* is malformed: +For example, if you have three parameters, _/param/a_, _/param/b_ and _/param/c_, but _/param/c_ is malformed: ```typescript hl_lines="23" title="Throwing TransformParameterError at first malformed parameter" --8<-- "docs/snippets/parameters/transformPartialFailures.ts" @@ -423,7 +425,6 @@ The **`clientConfig`** parameter enables you to pass in a custom [config object] When using VPC private endpoints, you can pass a custom client altogether. It's also useful for testing when injecting fake instances. - ```typescript hl_lines="2 4-5" --8<-- "docs/snippets/parameters/clientConfig.ts" ``` @@ -458,7 +459,7 @@ A similar pattern can be applied also to any of the built-in provider classes - --8<-- "docs/snippets/parameters/testingYourCodeProvidersHandler.ts" ``` -In some other cases, you might want to mock the AWS SDK v3 client itself, in these cases we recommend using the [`aws-sdk-client-mock`](https://www.npmjs.com/package/aws-sdk-client-mock) and [`aws-sdk-client-mock-jest`](https://www.npmjs.com/package/aws-sdk-client-mock-jest) libraries. This is useful when you want to test how your code behaves when the AWS SDK v3 client throws an error or a specific response. +For when you want to mock the AWS SDK v3 client directly, we recommend using the [`aws-sdk-client-mock`](https://www.npmjs.com/package/aws-sdk-client-mock) and [`aws-sdk-client-mock-jest`](https://www.npmjs.com/package/aws-sdk-client-mock-jest) libraries. This is useful when you want to test how your code behaves when the AWS SDK v3 client throws an error or a specific response. === "handler.test.ts" ```typescript hl_lines="2-8 11 14 18 23-30" @@ -479,4 +480,4 @@ Within your tests, you can use `clearCache` method available in [every provider] === "handler.test.ts" ```typescript hl_lines="1 9" --8<-- "docs/snippets/parameters/testingYourCodeClearCache.ts" - ``` \ No newline at end of file + ``` diff --git a/docs/utilities/parser.md b/docs/utilities/parser.md index 4947f86a2c..21281db6d6 100644 --- a/docs/utilities/parser.md +++ b/docs/utilities/parser.md @@ -4,6 +4,8 @@ descrition: Utility status: new --- + + This utility provides data validation and parsing using [Zod](https://zod.dev){target="_blank"}. Zod is a TypeScript-first schema declaration and validation library. @@ -34,7 +36,7 @@ You can define your schema using Zod: --8<-- "docs/snippets/parser/schema.ts" ``` -This is a schema for `Order` object using Zod. +This is a schema for `Order` object using Zod. You can create complex schemas by using nested objects, arrays, unions, and other types, see [Zod documentation](https://zod.dev) for more details. ## Parse events @@ -43,22 +45,21 @@ You can parse inbound events using `parser` decorator, Middy.js middleware, or [ Both are also able to parse either an object or JSON string as an input. ???+ warning - The decorator and middleware will replace the event object with the parsed schema if successful. + The decorator and middleware will replace the event object with the parsed schema if successful. Be cautious when using multiple decorators that expect event to have a specific structure, the order of evaluation for decorators is from bottom to top. === "Middy middleware" ```typescript hl_lines="34" --8<-- "docs/snippets/parser/middy.ts" - ``` + ``` -=== "Decorator" +=== "Decorator" ```typescript hl_lines="25" --8<-- "docs/snippets/parser/decorator.ts" ``` ## Built-in schemas - Parser comes with the following built-in schemas: | Model name | Description | @@ -101,7 +102,6 @@ You can extend every built-in schema to include your own schema, and yet have al 2. Pass the extended schema to `parser` decorator or middy middleware 3. `event` is validated including your custom schema and now available in your handler - === "Example payload" ```json @@ -133,10 +133,8 @@ Here's an example of parsing a custom schema in an event coming from EventBridge 1. Pass `eventBridgeEnvelope` to `parser` decorator 2. `event` is parsed and replaced as `Order` object - - The envelopes are functions that take an event and the schema to parse, and return the result of the inner schema. -Depending on the envelope it can be something simple like extracting a key. +Depending on the envelope it can be something simple like extracting a key. We have also complex envelopes that parse the payload from a string, decode base64, uncompress gzip, etc. !!! tip "Envelopes vs schema extension" @@ -164,13 +162,12 @@ Parser comes with the following built-in envelopes: | **vpcLatticeEnvelope** | 1. Parses data using `VpcLatticeSchema`.
2. Parses `value` key using your schema and returns it. | | **vpcLatticeV2Envelope** | 1. Parses data using `VpcLatticeSchema`.
2. Parses `value` key using your schema and returns it. | - ## Safe parsing -If you want to parse the event without throwing an error, use the `safeParse` option. -The handler `event` object will be replaced with `ParsedResult`, for example `ParsedResult`, where `SqsEvent` is the original event and `Order` is the parsed schema. +If you want to parse the event without throwing an error, use the `safeParse` option. +The handler `event` object will be replaced with `ParsedResult`, for example `ParsedResult`, where `SqsEvent` is the original event and `Order` is the parsed schema. -The `ParsedResult` object will have `success`, `data`, or `error` and `originalEvent` fields, depending on the outcome. +The `ParsedResult` object will have `success`, `data`, or `error` and `originalEvent` fields, depending on the outcome. If the parsing is successful, the `data` field will contain the parsed event, otherwise you can access the `error` field and the `originalEvent` to handle the error and recover the original event. === "Middy middleware" @@ -188,19 +185,17 @@ If the parsing is successful, the `data` field will contain the parsed event, ot ```typescript hl_lines="29 35 37 40 41" --8<-- "docs/snippets/parser/safeParseDecorator.ts" ``` - + 1. Use `safeParse` option to parse the event without throwing an error 2. Check if the result is successful or not and handle the error accordingly 3. Use `data` to access the parsed event 4. Use `error` to handle the error message 5. Use `originalEvent` to get the original event and recover - ## Manual parsing You can use built-in envelopes and schemas to parse the incoming events manually, without using middy or decorator. - === "Manual parse" ```typescript hl_lines="28 31" --8<-- "docs/snippets/parser/manual.ts" @@ -232,24 +227,24 @@ For example, you can use `refine` to validate a field or a combination of fields Zod provides a lot of other features and customization, see [Zod documentation](https://zod.dev) for more details. - ## Types ### Schema and Type inference + Use `z.infer` to extract the type of the schema, so you can use types during development and avoid type errors. === "Types" ```typescript hl_lines="22 25 30" --8<-- "docs/snippets/parser/types.ts" ``` - + 1. Use `z.infer` to extract the type of the schema, also works for nested schemas 2. `event` is of type `Order` 3. infer types from deeply nested schemas -### Compatibility with @types/aws-lambda +### Compatibility with `@types/aws-lambda` -The package `@types/aws-lambda` is a popular project that contains type definitions for many AWS service event invocations. +The package `@types/aws-lambda` is a popular project that contains type definitions for many AWS service event invocations. Powertools parser utility also bring AWS Lambda event types based on the built-in schema definitions. -We recommend to use the types provided by the parser utility. If you encounter any issues or have any feedback, please [submit an issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose). +We recommend to use the types provided by the parser utility. If you encounter any issues or have any feedback, please [submit an issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose). diff --git a/docs/we_made_this.md b/docs/we_made_this.md index 2d2d9bc886..b3d8f6ee0f 100644 --- a/docs/we_made_this.md +++ b/docs/we_made_this.md @@ -3,6 +3,8 @@ title: We Made This (Community) description: Blog posts, tutorials, and videos about Powertools for AWS Lambda (TypeScript) created by the Powertools Community. --- + + This space is dedicated to highlight our awesome community content featuring Powertools 🙏! !!! info "[Get your content featured here](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=community-content&template=share_your_work.yml&title=%5BI+Made+This%5D%3A+%3CTITLE%3E){target="_blank"}!" @@ -15,7 +17,9 @@ Join us on [Discord](https://discord.gg/B8zZKbbyET){target="_blank"} to connect ## Blog posts + ### Lambda Powertools - great defaults for batteries that aren't quite (but should be) included + > **Author: [Mike Roberts](mailto:mike@symphonia.io) [:material-twitter:](https://twitter.com/mikebroberts){target="_blank"}** diff --git a/layers/README.md b/layers/README.md index 128996a4d4..774fb4ff5e 100644 --- a/layers/README.md +++ b/layers/README.md @@ -2,7 +2,7 @@ This CDK app is meant to be used to publish Powertools for AWS Lambda (TypeScript) Lambda Layer. It is composed of a single stack deploying the Layer into the target account. -# Usage +## Usage ```sh npm ci @@ -10,19 +10,20 @@ npm run cdk deploy ``` By default it will package the layer with the latest version publicly available but you can force the public version to use with `PowerToolsPackageVersion` context variable: + ```sh npm run cdk deploy -- --context PowerToolsPackageVersion='0.9.0' ``` -# Tests +## Tests -## Units +### Units ```sh npm run test ``` -## E2E +### E2E This will deploy and destroy several stacks in your AWS Account @@ -30,24 +31,30 @@ This will deploy and destroy several stacks in your AWS Account npm run test:e2e ``` -PS: You can force +PS: You can force + * the lambda runtime to test with the RUNTIME env variable * the Powertools for AWS Lambda (TypeScript) version with VERSION env variable -```sh + +```sh RUNTIME=node12.x VERSION=0.9.0 npm run test:e2e ``` -# How to add new region +## How to add new region * Activate new region in your TEST and PROD accounts * Bootstrap a CDKToolkit stack in the new region + ```shell cdk bootstrap aws://AWS_ACCOUNT/NEW_REGION ``` + * Deploy the first layer version to the new region, make sure to set the NEW_REGION in your AWS CLI configuration correctly, otherwise you will deploy to the wrong region + ```shell npm run cdk -w layers -- deploy --app cdk.out --context region=NEW_REGION 'LayerPublisherStack' --require-approval never --verbose ``` + * Run the bumper script to bring all layers to the same version across all regions * Add new region to the worklflow in `./github/workflows/reusable_deploy_layer_stack.yml` -* Document new region in `docs/index.md` \ No newline at end of file +* Document new region in `docs/index.md` diff --git a/package-lock.json b/package-lock.json index 7f22131289..dd0d8a6fdc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "jest-runner-groups": "^2.2.0", "lerna": "^8.1.2", "lint-staged": "^15.2.2", + "markdownlint-cli2": "^0.13.0", "prettier": "^3.2.5", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", @@ -4116,6 +4117,18 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@sinonjs/commons": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", @@ -7573,6 +7586,18 @@ "node": ">=8.6" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -11288,6 +11313,15 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/lint-staged": { "version": "15.2.2", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", @@ -11927,6 +11961,133 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdownlint": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.34.0.tgz", + "integrity": "sha512-qwGyuyKwjkEMOJ10XN6OTKNOVYvOIi35RNvDLNxTof5s8UmyGHlCdpngRHoRGNvQVGuxO3BJ7uNSgdeX166WXw==", + "dev": true, + "dependencies": { + "markdown-it": "14.1.0", + "markdownlint-micromark": "0.1.9" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli2": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.13.0.tgz", + "integrity": "sha512-Pg4nF7HlopU97ZXtrcVISWp3bdsuc5M0zXyLp2/sJv2zEMlInrau0ZKK482fQURzVezJzWBpNmu4u6vGAhij+g==", + "dev": true, + "dependencies": { + "globby": "14.0.1", + "js-yaml": "4.1.0", + "jsonc-parser": "3.2.1", + "markdownlint": "0.34.0", + "markdownlint-cli2-formatter-default": "0.0.4", + "micromatch": "4.0.5" + }, + "bin": { + "markdownlint-cli2": "markdownlint-cli2.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli2-formatter-default": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.4.tgz", + "integrity": "sha512-xm2rM0E+sWgjpPn1EesPXx5hIyrN2ddUnUwnbCsD/ONxYtw3PX6LydvdH6dciWAoFDpwzbHM1TO7uHfcMd6IYg==", + "dev": true, + "peerDependencies": { + "markdownlint-cli2": ">=0.0.4" + } + }, + "node_modules/markdownlint-cli2/node_modules/globby": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdownlint-cli2/node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, + "node_modules/markdownlint-cli2/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdownlint-cli2/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdownlint-micromark": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.9.tgz", + "integrity": "sha512-5hVs/DzAFa8XqYosbEAEg6ok6MF2smDj89ztn9pKkCtdKHVdPQuGMH7frFfYL9mLkvfFe4pTyAMffLbjf3/EyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -11939,6 +12100,12 @@ "node": ">= 12" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, "node_modules/meow": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", @@ -14175,6 +14342,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", @@ -16748,6 +16924,12 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, "node_modules/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", @@ -16781,6 +16963,18 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unique-filename": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", diff --git a/package.json b/package.json index ea87efdd6d..e186c54208 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "docs-api-build-run": "npm run docs-generateApiDoc && npx live-server api", "docs-generateApiDoc": "typedoc .", "docs-runLocalApiDoc": "npx live-server api", - "postpublish": "git restore ." + "postpublish": "git restore .", + "lint:markdown": "markdownlint-cli2 '**/*.md' '#node_modules' '#**/*/node_modules' '#docs/changelog.md' '#LICENSE.md' '#.github' '#**/*/CHANGELOG.md' '#examples/app/README.md' '#packages/batch/README.md' '#packages/commons/README.md' '#packages/idempotency/README.md' '#packages/jmespath/README.md' '#packages/logger/README.md' '#packages/metrics/README.md' '#packages/parameters/README.md' '#packages/parser/README.md' '#packages/tracer/README.md'" }, "repository": { "type": "git", @@ -65,6 +66,7 @@ "jest-runner-groups": "^2.2.0", "lerna": "^8.1.2", "lint-staged": "^15.2.2", + "markdownlint-cli2": "^0.13.0", "prettier": "^3.2.5", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", @@ -72,7 +74,10 @@ "typedoc-plugin-missing-exports": "^2.2.0", "typescript": "^5.4.5" }, + "lint-staged": { + "*.md": "markdownlint-cli2 --fix" + }, "engines": { "node": ">=16" } -} +} \ No newline at end of file