diff --git a/packages/idempotency/LICENSE-THIRD-PARTY b/packages/idempotency/LICENSE-THIRD-PARTY new file mode 100644 index 0000000000..628bcd5982 --- /dev/null +++ b/packages/idempotency/LICENSE-THIRD-PARTY @@ -0,0 +1,189 @@ +@aws-lambda-powertools/commons +0.0.2 +license: MIT* +authors: Amazon Web Services + +****************************** + +@types/aws-lambda +8.10.87 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +lodash +4.17.21 +Copyright OpenJS Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +****************************** + +lodash.clonedeep +4.5.0 +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +****************************** + +lodash.merge +4.6.2 +Copyright OpenJS Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. diff --git a/packages/idempotency/README.md b/packages/idempotency/README.md new file mode 100644 index 0000000000..848588fe31 --- /dev/null +++ b/packages/idempotency/README.md @@ -0,0 +1,83 @@ +# AWS Lambda Powertools for TypeScript + +A suite of utilities for AWS Lambda functions to ease the adoption of best practices such as tracing, structured logging, custom metrics, and more. + +You can use the library in both TypeScript and JavaScript code bases. + +AWS Lambda Powertools for [Python](https://github.com/awslabs/aws-lambda-powertools-python) and AWS Lambda Powertools for [Java](https://github.com/awslabs/aws-lambda-powertools-java) are also available. + +**[๐Ÿ“œ Documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/)** | **[NPM](https://www.npmjs.com/org/aws-lambda-powertools)** | **[Roadmap](https://github.com/awslabs/aws-lambda-powertools-roadmap/projects/1)** | **[Examples](https://github.com/awslabs/aws-lambda-powertools-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) + - [Examples](#examples) + - [Serverless TypeScript Demo](#serverless-typescript-demo-application) +- [Contribute](#contribute) +- [Roadmap](#roadmap) +- [Connect](#connect) +- [Credits](#credits) +- [License](#license) + +## Features + +* **[Tracer](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions +* **[Logger](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context +* **[Metrics](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) + +## Getting started + +Find the complete project's [documentation here](https://awslabs.github.io/aws-lambda-powertools-typescript). + +### Installation + +The AWS Lambda Powertools for 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://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/tracer#getting-started) + +๐Ÿ‘‰ [Installation guide for the **Logger** utility](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/logger#getting-started) + +๐Ÿ‘‰ [Installation guide for the **Metrics** utility](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/metrics#getting-started) + +### Examples + +* [CDK](https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/examples/cdk) +* [SAM](https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/examples/sam) + +### Serverless TypeScript Demo application + +The [Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo) shows how to use Lambda Powertools for 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). + +## Contribute + +If you are interested in contributing to this project, please refer to our [Contributing Guidelines](https://github.com/awslabs/aws-lambda-powertools-typescript/blob/main/CONTRIBUTING.md). + +## Roadmap + +The roadmap of Powertools is driven by customersโ€™ demand. +Help us prioritize upcoming functionalities or utilities by [upvoting existing RFCs and feature requests](https://github.com/awslabs/aws-lambda-powertools-typescript/issues), or [creating new ones](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/new/choose), in this GitHub repository. + +## Connect + +* **AWS Lambda Powertools on Discord**: `#typescript` - **[Invite link](https://discord.gg/B8zZKbbyET)** +* **Email**: aws-lambda-powertools-feedback@amazon.com + +## Credits + +Credits for the Lambda Powertools idea go to [DAZN](https://github.com/getndazn) and their [DAZN Lambda Powertools](https://github.com/getndazn/dazn-lambda-powertools/). + +## License + +This library is licensed under the MIT-0 License. See the LICENSE file. \ No newline at end of file diff --git a/packages/idempotency/jest.config.js b/packages/idempotency/jest.config.js new file mode 100644 index 0000000000..dd0e63cc41 --- /dev/null +++ b/packages/idempotency/jest.config.js @@ -0,0 +1,45 @@ +module.exports = { + displayName: { + name: 'AWS Lambda Powertools utility: IDEMPOTENCY', + color: 'cyan', + }, + 'runner': 'groups', + 'preset': 'ts-jest', + 'transform': { + '^.+\\.ts?$': 'ts-jest', + }, + moduleFileExtensions: [ 'js', 'ts' ], + 'collectCoverageFrom': [ + '**/src/**/*.ts', + '!**/node_modules/**', + ], + 'testMatch': ['**/?(*.)+(spec|test).ts'], + 'roots': [ + '/src', + '/tests', + ], + 'testPathIgnorePatterns': [ + '/node_modules/', + ], + 'testEnvironment': 'node', + 'coveragePathIgnorePatterns': [ + '/node_modules/', + '/types/', + ], + 'coverageThreshold': { + 'global': { + 'statements': 100, + 'branches': 100, + 'functions': 100, + 'lines': 100, + }, + }, + 'coverageReporters': [ + 'json-summary', + 'text', + 'lcov' + ], + 'setupFiles': [ + '/tests/helpers/populateEnvironmentVariables.ts' + ] +}; \ No newline at end of file diff --git a/packages/idempotency/package.json b/packages/idempotency/package.json new file mode 100644 index 0000000000..fc03dbd523 --- /dev/null +++ b/packages/idempotency/package.json @@ -0,0 +1,57 @@ +{ + "name": "@aws-lambda-powertools/idempotency", + "version": "0.0.11", + "description": "TBD", + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "commit": "commit", + "test": "npm run test:unit", + "test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose", + "test:e2e:nodejs12x": "RUNTIME=nodejs12x jest --group=e2e", + "test:e2e:nodejs14x": "RUNTIME=nodejs14x jest --group=e2e", + "test:e2e:nodejs16x": "RUNTIME=nodejs16x jest --group=e2e", + "test:e2e": "jest --group=e2e", + "watch": "jest --watch --group=unit", + "build": "tsc", + "lint": "eslint --ext .ts --fix --no-error-on-unmatched-pattern src tests", + "format": "eslint --fix --ext .ts --fix --no-error-on-unmatched-pattern src tests", + "package": "mkdir -p dist/ && npm pack && mv *.tgz dist/", + "package-bundle": "../../package-bundler.sh logger-bundle ./dist", + "prepare": "npm run build", + "prepublishOnly": "npm test && npm run lint", + "preversion": "npm run lint", + "version": "npm run format && git add -A src", + "postversion": "git push && git push --tags" + }, + "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/master/packages/idempotency#readme", + "license": "MIT", + "main": "./lib/index.js", + "types": "./lib/index.d.ts", + "typedocMain": "src/index.ts", + "files": [ + "lib" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/awslabs/aws-lambda-powertools-typescript.git" + }, + "bugs": { + "url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues" + }, + "dependencies": { + "@aws-lambda-powertools/commons": "^1.2.1" + }, + "keywords": [ + "aws", + "lambda", + "powertools", + "serverless", + "nodejs" + ] +} diff --git a/packages/idempotency/src/IdempotencyOptions.ts b/packages/idempotency/src/IdempotencyOptions.ts new file mode 100644 index 0000000000..53893cfe42 --- /dev/null +++ b/packages/idempotency/src/IdempotencyOptions.ts @@ -0,0 +1,8 @@ +import { PersistenceLayer } from './persistence/PersistenceLayer'; + +type IdempotencyOptions = { + dataKeywordArgument: string + persistenceStore: PersistenceLayer +}; + +export { IdempotencyOptions }; diff --git a/packages/idempotency/src/makeFunctionIdempotent.ts b/packages/idempotency/src/makeFunctionIdempotent.ts new file mode 100644 index 0000000000..dc851396d6 --- /dev/null +++ b/packages/idempotency/src/makeFunctionIdempotent.ts @@ -0,0 +1,10 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { AnyFunction } from './types/AnyFunction'; +import { IdempotencyOptions } from './IdempotencyOptions'; + +const makeFunctionIdempotent = ( + fn: AnyFunction, + _options: IdempotencyOptions +): (...args: Array) => Promise => (...args) => fn(...args); + +export { makeFunctionIdempotent }; diff --git a/packages/idempotency/src/persistence/DynamoDbPersistenceLayer.ts b/packages/idempotency/src/persistence/DynamoDbPersistenceLayer.ts new file mode 100644 index 0000000000..6592841b3f --- /dev/null +++ b/packages/idempotency/src/persistence/DynamoDbPersistenceLayer.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ +import { IdempotencyRecord, PersistenceLayer } from './PersistenceLayer'; + +class DynamoDBPersistenceLayer extends PersistenceLayer { + public constructor(_tableName: string, _key_attr: string = 'id') { + super(); + } + protected async _deleteRecord(): Promise {} + protected async _getRecord(): Promise { + return Promise.resolve({} as IdempotencyRecord); + } + protected async _putRecord(_record: IdempotencyRecord): Promise {} + protected async _updateRecord(): Promise {} +} + +export { + DynamoDBPersistenceLayer +}; \ No newline at end of file diff --git a/packages/idempotency/src/persistence/PersistenceLayer.ts b/packages/idempotency/src/persistence/PersistenceLayer.ts new file mode 100644 index 0000000000..c7a1b30c63 --- /dev/null +++ b/packages/idempotency/src/persistence/PersistenceLayer.ts @@ -0,0 +1,45 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ +import { PersistenceLayerInterface } from './PersistenceLayerInterface'; + +class IdempotencyRecord { + public constructor(public idempotencyKey: string, + private status: string = '', + public expiryTimestamp: number | undefined, + public inProgressExpiryTimestamp: number | undefined, + public responseData: string = '', + public payloadHash: string | undefined) {} + + public getStatus(): string { + return ''; + } + + public isExpired(): boolean { + return false; + } + + public responseJsonAsObject(): Record | undefined { + return; + } + +} + +abstract class PersistenceLayer implements PersistenceLayerInterface { + public constructor() { } + public configure(_functionName: string = ''): void {} + public async deleteRecord(): Promise { } + public async getRecord(): Promise { + return Promise.resolve({} as IdempotencyRecord); + } + public async saveInProgress(): Promise { } + public async saveSuccess(): Promise { } + + protected abstract _deleteRecord(): Promise; + protected abstract _getRecord(): Promise; + protected abstract _putRecord(record: IdempotencyRecord): Promise; + protected abstract _updateRecord(): Promise; +} + +export { + IdempotencyRecord, + PersistenceLayer +}; \ No newline at end of file diff --git a/packages/idempotency/src/persistence/PersistenceLayerInterface.ts b/packages/idempotency/src/persistence/PersistenceLayerInterface.ts new file mode 100644 index 0000000000..4b2da46b38 --- /dev/null +++ b/packages/idempotency/src/persistence/PersistenceLayerInterface.ts @@ -0,0 +1,11 @@ +import { IdempotencyRecord } from './PersistenceLayer'; + +interface PersistenceLayerInterface { + configure(functionName: string): void + saveInProgress(): Promise + saveSuccess(): Promise + deleteRecord(): Promise + getRecord(): Promise +} + +export { PersistenceLayerInterface }; diff --git a/packages/idempotency/src/types/AnyFunction.ts b/packages/idempotency/src/types/AnyFunction.ts new file mode 100644 index 0000000000..bddcd8fc15 --- /dev/null +++ b/packages/idempotency/src/types/AnyFunction.ts @@ -0,0 +1,6 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AnyFunction = (...args: Array) => Promise; + +export { + AnyFunction +}; \ No newline at end of file diff --git a/packages/idempotency/tsconfig-dev.json b/packages/idempotency/tsconfig-dev.json new file mode 100644 index 0000000000..6f766859ea --- /dev/null +++ b/packages/idempotency/tsconfig-dev.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declarationMap": true, + "esModuleInterop": false + }, + "include": [ "src/**/*", "examples/**/*", "**/tests/**/*" ], + "types": [ + "jest" + ] +} \ No newline at end of file diff --git a/packages/idempotency/tsconfig.es.json b/packages/idempotency/tsconfig.es.json new file mode 100644 index 0000000000..6f766859ea --- /dev/null +++ b/packages/idempotency/tsconfig.es.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declarationMap": true, + "esModuleInterop": false + }, + "include": [ "src/**/*", "examples/**/*", "**/tests/**/*" ], + "types": [ + "jest" + ] +} \ No newline at end of file diff --git a/packages/idempotency/tsconfig.json b/packages/idempotency/tsconfig.json new file mode 100644 index 0000000000..555c42c9e8 --- /dev/null +++ b/packages/idempotency/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "noImplicitAny": true, + "target": "ES2019", + "module": "commonjs", + "declaration": true, + "outDir": "lib", + "strict": true, + "inlineSourceMap": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "pretty": true, + "baseUrl": "src/", + "rootDirs": [ "src/" ], + "esModuleInterop": true + }, + "include": [ "src/**/*" ], + "exclude": [ "./node_modules"], + "watchOptions": { + "watchFile": "useFsEvents", + "watchDirectory": "useFsEvents", + "fallbackPolling": "dynamicPriority" + }, + "lib": [ "es2019" ], + "types": [ + "node" + ] +} \ No newline at end of file